Join us this Friday for AI in Action at the Virtual Happy Hour! This free virtual event is open to all—enroll now on Academy and don’t miss out.

 

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.