OpenIDConnect and AccessDenied

Vote:
 

Hello,

We are configuring OpenIDConnect during an upgrade to CMS 12 and are plagued with the AccessDenied problem (which I have seen in other posts without a clear solution)

We are forced at the moment to configure the app with "responseType: id_token" due to not being supplied with the secret. So our code contains the following:

.AddCookie("azure-cookie", options =>
{
    options.Events.OnSignedIn = async ctx =>
    {
        if (ctx.Principal?.Identity is ClaimsIdentity claimsIdentity)
        {
            // Syncs user and roles so they are available to the CMS
            var synchronizingUserService = ctx
                .HttpContext
                .RequestServices
                .GetRequiredService<ISynchronizingUserService>();

            await synchronizingUserService.SynchronizeAsync(claimsIdentity);
        }
    };
})
.AddOpenIdConnect("azure", options =>
{
    options.SignInScheme = "azure-cookie";
    options.SignOutScheme = "azure-cookie";
    options.ResponseType = OpenIdConnectResponseType.IdToken;
    options.CallbackPath = "/signin-oidc";
    options.UsePkce = true;

As you can see, the only thing differing from the recommended setup is the option.ResponseType setting. When attempting to access the back office at /episerver/cms, we get redirected to Azure AD login, and when I put a breakpoint in the above code in the OnSignedIn function I can see the role claims containing the expected "WebAdmins" role.

BUT, when continuing we are re-directed to /Account/AccessDenied?ReturnUrl=%2Fepiserver%2Fcms

What are we doing wrong?

Thanks for any help with this, Stephen

#311421
Oct 25, 2023 10:36
Vote:
 

The issue with OpenID is often that the IDP itself can be configured in a million ways. 

Since you seem to use AzureAD you can use the extension AddMicrosoftIdentityWebApp (https://learn.microsoft.com/en-us/samples/azure-samples/active-directory-aspnetcore-webapp-openidconnect-v2/active-directory-aspnetcore-webapp-openidconnect-v2/).

Here's an idea on how you can implement it. Begin by adding the package Microsoft.Identity.Web, implement the others as stated on the documentation if need be.

var configurationSection = _configuration.GetSection("AzureAd");
services
    .AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(options =>
    {
        configurationSection.Bind(options);
        options.TokenValidationParameters = new TokenValidationParameters
        {
            RoleClaimType = ClaimConstants.Roles,
            // Value will be overwritten by MicrosoftIdentity by we set it later in 
            // by configure the Options later. 
            NameClaimType = "onpremisessamaccountname", // or whatever your nameclaim is, this is for onprem synced users
            ValidateIssuer = false
        };

        options.Scope.Clear();
        options.Scope.Add(OpenIdConnectScope.OfflineAccess); // if you need refresh tokens
        options.Scope.Add(OpenIdConnectScope.Email);
        options.Scope.Add(OpenIdConnectScope.OpenIdProfile);
        options.MapInboundClaims = false;
    },
    options =>
    {
        options.AccessDeniedPath = "/AccessDenied";
        options.Cookie.Domain = null;

        options.Events.OnSignedIn = async ctx =>
        {
            if (ctx.Principal?.Identity is ClaimsIdentity claimsIdentity)
            {
                // Syncs user and roles so they are available to the CMS
                var synchronizingUserService = ctx
                    .HttpContext
                    .RequestServices
                    .GetRequiredService<ISynchronizingUserService>();

                await synchronizingUserService.SynchronizeAsync(claimsIdentity);
                await Task.CompletedTask;
            };
        };
    });

And the configuration section for AzureAD in appsettings

"AzureAd": {
  "Instance": "https://login.microsoftonline.com/",
  "Domain": "yourdomainonmicrosoft.onmicrosoft.com",
  "TenantId": "",
  "ClientId": "",
  "ClientSecret": ""
},

Configure according to your needs

#311426
Oct 25, 2023 11:20
Vote:
 

Thanks for this! It "just works" now! 🎉

#311431
Oct 25, 2023 14:00
Vote:
 

So I figured out that actual problem here. As it turns out, it had to do with the TokenValidationParameters.

options.TokenValidationParameters = new TokenValidationParameters
{
    RoleClaimType = ClaimTypes.Role,
    NameClaimType = "preferred_username",
    ValidateIssuer = false
};

The above code snippet comes from the Opti Docs when configuring OpenIdConnect and in .NET 6 ClaimTypes.Role evaluates to "http://schemas.microsoft.com/ws/2008/06/identity/claims/role" (while previously it evaluated to "roles")

Eric' post using AddMicrosoftIdentityWebApp includes the following TokenValidationParameters:

options.TokenValidationParameters = new TokenValidationParameters
{
    RoleClaimType = ClaimConstants.Roles,
    NameClaimType = "preferred_username",
    ValidateIssuer = false
};

In ClaimConstants.Roles evaluates to "roles" which is the correct value

Yikes!

#311573
Oct 27, 2023 12:07
This topic was created over six months ago and has been resolved. If you have a similar question, please create a new topic and refer to this one.
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.