Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Blazor WASM Authorization not working with AAD Roles

I am trying to set up AAD Authorization based on user defined roles following this doc https://learn.microsoft.com/en-us/aspnet/core/blazor/security/webassembly/azure-active-directory-groups-and-roles?view=aspnetcore-3.1#user-defined-roles I am able to set it up in the app manifest and get the API authorization working. However when I try to do it on the UI side I cannot get the claim to appear. I did the json interpreting classes (DirectoryObjects, CustomUserAccount and Value(used by directory object)). I also added the CustomUserFactory removing the group stuff since I only care about roles:

        private readonly ILogger<CustomUserFactory> _logger;
        private readonly IHttpClientFactory _clientFactory;

        public CustomUserFactory(IAccessTokenProviderAccessor accessor,
            IHttpClientFactory clientFactory,
            ILogger<CustomUserFactory> logger)
            : base(accessor)
        {
            _clientFactory = clientFactory;
            _logger = logger;
        }

        public async override ValueTask<ClaimsPrincipal> CreateUserAsync(
            CustomUserAccount account,
            RemoteAuthenticationUserOptions options)
        {
            var initialUser = await base.CreateUserAsync(account, options);

            if (initialUser.Identity.IsAuthenticated)
            {
                var userIdentity = (ClaimsIdentity)initialUser.Identity;

                foreach (var role in account.Roles)
                {
                    userIdentity.AddClaim(new Claim("role", role));
                }

                
            }

            return initialUser;
        }

and then I modified the program.cs as the doc mentioned:

    builder.Services.AddMsalAuthentication<RemoteAuthenticationState,
    CustomUserAccount>(options =>
    {
        builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
        options.ProviderOptions.DefaultAccessTokenScopes.Add("apiaccessguid");
        options.UserOptions.RoleClaim = "role";
    }).AddAccountClaimsPrincipalFactory<RemoteAuthenticationState, CustomUserAccount,
    CustomUserFactory>();

when that didn't work I tried adding it as a policy with no luck as well:

 builder.Services.AddAuthorizationCore(options =>
    {
        options.AddPolicy("Admin", policy =>
            policy.RequireClaim("role", "admin"));
    });

for restricting the view I tried in code with the user.IsInRole("admin") and in the UI with

<AuthorizeView Roles="admin">
    <li class="nav-item px-3">
        <NavLink class="nav-link" href="Admin">
            Admin
        </NavLink>
    </li>
</AuthorizeView>

and with policy:

<AuthorizeView Policy="Admin">
    <Authorized>
        <p>
            The user is in the 'Administrator' AAD Administrative Role
            and can see this content.
        </p>
    </Authorized>
    <NotAuthorized>
        <p>
            The user is NOT in the 'Administrator' role and sees this
            content.
        </p>
    </NotAuthorized>
</AuthorizeView>

and none of them worked. Is there something I am missing? I also verified that the token has the admin role.

like image 359
Tacot Avatar asked Oct 27 '22 18:10

Tacot


2 Answers

I got it working by using RequireRole in the policy options.

For example, I added the app role to the manifest:

"appRoles": [
    {
        "allowedMemberTypes": [
            "User"
        ],
        "description": "Reader role.",
        "displayName": "Reader",
        "id": "41d9ba42-456e-4471-8946-24216e5f6c64",
        "isEnabled": true,
        "lang": null,
        "origin": "Application",
        "value": "Reader"
    }
]

Configure the policy via RequireRole:

builder.Services.AddAuthorizationCore(options =>
{
    options.AddPolicy("app-reader", policy => policy.RequireRole("Reader"));
});

And then use as per:

<AuthorizeView Policy="app-reader">
    <Authorized>
        <p>
            The user is in the 'Reader' Role
            and can see this content.
        </p>
    </Authorized>
    <NotAuthorized>
        <p>
            The user is NOT in the 'Reader' role 
            and sees this content.
        </p>
    </NotAuthorized>
</AuthorizeView>

Or, as an attribute on a razor page:

@attribute [Authorize(Policy = "app-reader")]
like image 64
fuzzy_logic Avatar answered Nov 11 '22 20:11

fuzzy_logic


Found my problem, the code was fine, the problem was on the Azure registration side, The client uses the roles registered in the client app in Azure while the server uses the ones in the server app. so make sure you register the user in both with the same role.

like image 21
Tacot Avatar answered Nov 11 '22 19:11

Tacot