Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

User.Identity.Name is null after federated Azure AD login with aspnetcore 2.2

I've followed AzureAD aspnetcore sample as closely as possible to try and implement Azure AD authentication in our aspnetcore 2.2 webapp. I am able to login successfully using Azure AD. However, the user's name is not being displayed AFTER login.

https://github.com/Azure-Samples/active-directory-b2c-dotnetcore-webapp

This value should be read in the view from the User.Identity.Name property.

User.Identity.Name

On further inspection, I can see that the principal claims are being correctly returned to the application. However, for some reason the HttpContext.User object is not correctly populated. I don't know why this is happening. When I look at the same value from the sample above, HttpContext is correctly set. For clarification, I have implemented OnSecurityTokenValidated handler and I use this context:

context

As can be seen, userPrincipal has the claims as expected.

userPrincipal

However, the httpContext has no claims. Also User.Identity.Name therefore is null:

httoContext

I've tried to carry out a manual signin, but that doesn't work either:

private async Task SignInUser(TokenValidatedContext tokenValidatedContext)
{
    var httpContext = tokenValidatedContext.HttpContext;
    var userPrincipal = tokenValidatedContext.Principal;

    await httpContext.SignOutAsync(AppSettings.CookieName);
    await httpContext.SignInAsync(AppSettings.CookieName, userPrincipal,
      new AuthenticationProperties
      {
          ExpiresUtc = DateTime.UtcNow.AddDays(1),
          IsPersistent = false,
          AllowRefresh = false
      });
}

Update

name

I am setting the NameClaimType as shown above. The NameClaimType is set in Configure

Anyone have any idea what I am doing wrong?

I am using Visual Studio 2017 & aspnetcore 2.2 libraries. I've upgraded Microsoft.Identity.Client to 2.7

like image 707
ossentoo Avatar asked Mar 04 '23 15:03

ossentoo


2 Answers

Do you set the NameClaimType in OpenIdConnectOptions configuration:

options.TokenValidationParameters = new TokenValidationParameters() { NameClaimType = "name" };

To test the scenario , i create a new asp.net core 2.2 application with default MVC template :

  1. Install Microsoft.Identity.Client version 2.7
  2. Copy the MSALSessionCache,AzureAdB2COptions,OpenIdConnectOptionsSetupfrom the code sample
  3. Update Startup.csand appsettings.json based on code sample's configuration .

I haven't create my own application & Api , just use fabrikamb2cdomain as code sample provides , even though some method is obsolete in .net core 2.2 , for example ,cache.HasStateChanged . The authecation still works and get correct name with User.Identity.Name , HttpContext.User.Claims also be set :

enter image description here

You might provide more detiails to help reproduce your issue .

like image 154
Nan Yu Avatar answered Apr 28 '23 10:04

Nan Yu


I think I've got the answer to this, although it leads to new questions.

Basically, our code uses Identity as well as AzureADB2C. The Identity is conflicting with the AzureADB2C login process. Login is successful and the token is being returned, but on return it is somehow being erased by Identity.

This is the code that I have in Startup.cs:

            services.AddAuthentication(sharedOptions =>
            {
                sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
            })
            .AddAzureAdB2C(options => Configuration.Bind("Authentication:AzureAdB2C", options))
            .AddCookie();

        services.Configure<CookiePolicyOptions>(options =>
        {
            // This lambda determines whether user consent for non-essential cookies is needed for a given request.
            options.CheckConsentNeeded = context => true;
            options.MinimumSameSitePolicy = SameSiteMode.None;
        });

        services.Configure<ApiBehaviorOptions>(options =>
        {
            options.InvalidModelStateResponseFactory = ctx => new ValidationProblemDetailsResult();
        });

        services.AddOptions();

        ConfigureMvc(services);

        // Add Identity services to the services container.
        services.SetupIdentity();

SetupIdentity is an extension method that contains the following:

            services.AddIdentity<ApplicationUser, ApplicationRole>(o => {
            o.Password.RequiredLength = 8;
            o.Password.RequireDigit = true;
            o.Password.RequireLowercase = true;
            o.Password.RequireUppercase = true;
            o.Password.RequireNonAlphanumeric = true;
        })
            .AddEntityFrameworkStores<ApplicationContext>()
            .AddDefaultTokenProviders()
            .AddUserStore<UserStore<ApplicationUser, ApplicationRole, ApplicationContext, Guid>>()
            .AddRoleStore<RoleStore<ApplicationRole, ApplicationContext, Guid>>();

The idea is that AAD will be used for authentication, and local Identity roles will be used for giving the user various permissions on the app. Based on this issue, looks like we will have to rethink our security.

The question is, can AAD and Identity really not be used together? I'd want a scenario where a user id from AAD is returned, stored in local sql, and then this user id used in the local database to connect the user to variable entities. If AAD and Identity can't be used together, what is the alternative? I.e. what's the best way to connect an AAD user to a local database? Can anyone point me to some MS articles that discuss this?

like image 30
ossentoo Avatar answered Apr 28 '23 10:04

ossentoo