C# app service service principal role based authorization

82 views Asked by At

I am struggling to understand how role based authorization is working in Azure app services. It works for the user, but not service principals (app registrations). My setp:

  1. I create app roles for app registration: App roles Role creation
  2. I assign users and principals to some roles: App role assignment
  3. I assign this app registration to some app service with Microsoft as provider App service assignment

In my code I have the following setup:

  1. Install package Microsoft.Indeitity.Web (2.17 version, currently latest)
  2. Program.cs:
// Makes the roles come in 'role' claim
System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.DefaultMapInboundClaims = false;

builder.Services.AddMicrosoftIdentityWebAppAuthentication(builder.Configuration)
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddInMemoryTokenCaches();

builder.Services.AddAuthorization();

builder.Services.Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
    // Sets up the claim name which will be used by Authorize attribute
    options.TokenValidationParameters.RoleClaimType = "roles"; 
});
  1. My controller:
[ApiController]
[Route("[controller]")]
public class Test : ControllerBase
{
    [HttpGet("Reader")]
    [Authorize(Roles = "Reader")]
    public IActionResult Reader() =>
        Ok("Success")
}

  1. My appSettings.json
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "Domain": "{mytenant}.onmicrosoft.com",
    "TenantId": "{tenantid}",
    "ClientId": "{AR client id}",
    "ClientSecret": "{AR client secret}",
    "Scopes": "access_as_user",
    "CallbackPath": "/signin-oidc"
  },

Now when I deploy this app to app service, for the user Accessing Reader controller is working as expected.

I also created claims controller:

        [HttpGet("GetClaims")]
        public IActionResult GetClaims()
        {
            var sb = new System.Text.StringBuilder("Claims:\r\n\r\n");
            User.Claims.ToList().ForEach(_ => sb.AppendLine($"Key: '{_.Type}'\tValue: '{_.Value}'"));
            sb.AppendLine();
            sb.AppendLine("\r\n\r\nHeaders:\r\n\r\n");
            ClaimsPrincipal.Current?.Claims.ToList().ForEach(_ => sb.AppendLine($"Type: '{_.Type}'\tSubject: '{_.Subject}'\tIssuer: '{_.Issuer}'\tValueType: '{_.ValueType}'\tValue: '{_.Value}'"));
            return Ok(sb.ToString());
        }

And for the user I can see roles coming up from the claim: Claims for the user

But when I try to access it with service principal (for example via logic app), it gives me empty claims, what means that authorization is also not working, while accessing Reader controller:

Service principal claims

I believe I am missing something small in here and it would be hard to believe MS did not implemented service principal authorization based on roles.

As other workaround I believe I would create a middleware to map claims from the token for service principals, but I would really like to avoid this if possible.

0

There are 0 answers