dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.58k stars 10.06k forks source link

Null value being passed to the Claim constructor in the UserClaimsPrincipalFactory<TUser> on Identity Endpoint Login .Net 8 #54669

Open BillyMartin1964 opened 8 months ago

BillyMartin1964 commented 8 months ago

Is there an existing issue for this?

Describe the bug

When trying to login with Identity Endpoint, I get a null reference exception having to do with User Claims, even when using Swagger.

Expected Behavior

I expect the endpoint to log the user in

Steps To Reproduce

No response

Exceptions (if any)

System.ArgumentNullException: Value cannot be null. (Parameter 'value') at System.ArgumentNullException.Throw(String paramName) at System.ArgumentNullException.ThrowIfNull(Object argument, String paramName) at System.Security.Claims.Claim..ctor(String type, String value, String valueType, String issuer, String originalIssuer, ClaimsIdentity subject, String propertyKey, String propertyValue) at System.Security.Claims.Claim..ctor(String type, String value) at Microsoft.AspNetCore.Identity.UserClaimsPrincipalFactory1.GenerateClaimsAsync(TUser user) at Microsoft.AspNetCore.Identity.UserClaimsPrincipalFactory1.CreateAsync(TUser user) at Microsoft.AspNetCore.Identity.SignInManager1.CreateUserPrincipalAsync(TUser user) at Microsoft.AspNetCore.Identity.SignInManager1.SignInWithClaimsAsync(TUser user, AuthenticationProperties authenticationProperties, IEnumerable1 additionalClaims) at Microsoft.AspNetCore.Identity.SignInManager1.SignInOrTwoFactorAsync(TUser user, Boolean isPersistent, String loginProvider, Boolean bypassTwoFactor) at Microsoft.AspNetCore.Identity.SignInManager1.PasswordSignInAsync(TUser user, String password, Boolean isPersistent, Boolean lockoutOnFailure) at Microsoft.AspNetCore.Identity.SignInManager1.PasswordSignInAsync(String userName, String password, Boolean isPersistent, Boolean lockoutOnFailure) at Microsoft.AspNetCore.Routing.IdentityApiEndpointRouteBuilderExtensions.<>c1`1.<b1_1>d.MoveNext() --- End of stack trace from previous location --- at Microsoft.AspNetCore.Http.Generated.F69328E0708B4B584C5AACA22FE2C51A1CF192D6622828F613FC57C583CA77B63GeneratedRouteBuilderExtensionsCore.<>cDisplayClass4_0.<g__RequestHandler|4>d.MoveNext() --- End of stack trace from previous location --- at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext) at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider) at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)

HEADERS

Accept: application/json Host: localhost:7084 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Accept-Encoding: gzip, deflate, br Accept-Language: en-US,en;q=0.9 Content-Type: application/json Cookie: .AspNetCore.Antiforgery.BE_PV6cpjCg=CfDJ8JbHcuPH-DZNo-GwGXZOpygZQENsHXZjq8U-Es8VQl2bbpxJkZ13tAc9WwxIcgDo5zCL59gI7gZqKQYFZDItiG9S3YBj6uwZPAqjcG7x7hKuROCRFATbBKp4EopAtOPj9olJ18mWPJUrHAN69uTGH9Y Origin: https://localhost:7084 Referer: https://localhost:7084/swagger/index.html Content-Length: 65 sec-ch-ua: "Chromium";v="122", "Not(A:Brand";v="24", "Google Chrome";v="122" sec-ch-ua-mobile: ?0 sec-ch-ua-platform: "Windows" sec-fetch-site: same-origin sec-fetch-mode: cors sec-fetch-dest: empty

.NET Version

8

Anything else?

Using Blazor webapp with Identity Endpoints enabled. Tried it with and without authorization.

using Serilog;
using BlazorApp.Client.Pages;
using BlazorApp.Components;
using BlazorApp.Components.Account;
using BlazorApp.Data;
using BlazorApp.Features.Account;
using Microsoft.AppCenter.Ingestion.Models;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Log = Serilog.Log;
using Microsoft.OpenApi.Models;
using Microsoft.Extensions.Options;
using Swashbuckle.AspNetCore.Filters;
using System;

Log.Logger = new LoggerConfiguration()
      // .ReadFrom.Configuration(builder.Configuration).CreteLogger();// This line is when using appsettings. 
      .WriteTo.Console()
      .WriteTo.File("zlogs/log.txt", rollingInterval: RollingInterval.Day)
      .CreateLogger();

try
{

    var builder = WebApplication.CreateBuilder(args);

    builder.Services.AddControllers();
    builder.Services.AddEndpointsApiExplorer();

    builder.Services.AddDbContextPool<ApplicationDbContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("BlazorServerConnection"), b => b.MigrationsAssembly("BlazorServer")));

    //builder.Services.AddAuthentication();

    builder.Services.AddAuthentication(options =>
        {
            options.DefaultScheme = IdentityConstants.ApplicationScheme;
            options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
        })
        .AddBearerToken();

    builder.Services.AddIdentityCore<User>(options => options.SignIn.RequireConfirmedAccount = true)
        .AddEntityFrameworkStores<ApplicationDbContext>()
        .AddSignInManager()
        .AddDefaultTokenProviders();

    builder.Services.AddIdentityApiEndpoints<User>(opt =>
    {
        opt.Password.RequiredLength = 8;
        opt.User.RequireUniqueEmail = true;
        opt.Password.RequireNonAlphanumeric = false;
        opt.SignIn.RequireConfirmedEmail = false;
        opt.SignIn.RequireConfirmedPhoneNumber = false;
        opt.SignIn.RequireConfirmedAccount = false;
    })
      .AddEntityFrameworkStores<ApplicationDbContext>();

    // AddSwaggerGen configuration
    builder.Services.AddSwaggerGen(options =>
    {
        options.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });

        // Add security definition for OAuth2
        options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
        {
            In = ParameterLocation.Header,
            Name = "Authorization",
            Type = SecuritySchemeType.ApiKey
        });

        // Add security requirement for OAuth2
        options.OperationFilter<SecurityRequirementsOperationFilter>();
    });

    // Add services to the container.
    builder.Services.AddRazorComponents()
        .AddInteractiveServerComponents()
        .AddInteractiveWebAssemblyComponents();

    builder.Services.AddScoped<IUserRepository, UserRepository>();
    builder.Services.AddScoped<ITokenService, TokenService>();

    builder.Services.AddCascadingAuthenticationState();
    builder.Services.AddScoped<IdentityUserAccessor>();
    builder.Services.AddScoped<IdentityRedirectManager>();
    builder.Services.AddScoped<AuthenticationStateProvider, PersistingRevalidatingAuthenticationStateProvider>();

    //   builder.Services.AddAuthorization();

    builder.Services.AddDatabaseDeveloperPageExceptionFilter();

    // builder.Services.AddSingleton<IEmailSender<MobileUser>, IdentityNoOpEmailSender>();

    var app = builder.Build();

    app.UseSwagger();
    app.UseSwaggerUI(c =>
    {
        c.SwaggerEndpoint("/swagger/v1/swagger.json", "v1");
    });

    // Configure the HTTP request pipeline.
    if (app.Environment.IsDevelopment())
    {
        app.UseWebAssemblyDebugging();
        app.UseMigrationsEndPoint();
    }
    else
    {
        app.UseExceptionHandler("/Error", createScopeForErrors: true);
        // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
        app.UseHsts();
    }

   // app.UseAuthorization();

    app.MapIdentityApi<User>();

    app.UseHttpsRedirection();

    app.UseStaticFiles();
    app.UseAntiforgery();

    app.MapRazorComponents<App>()
        .AddInteractiveServerRenderMode()
        .AddInteractiveWebAssemblyRenderMode()
        .AddAdditionalAssemblies(typeof(BlazorApp.Client._Imports).Assembly);

app.MapControllers();

    app.Run();

}
catch (Exception ex)
{
    Log.Fatal(ex, "Host terminated unexpectedly");
}
finally
{
    Log.CloseAndFlush();
}
BillyMartin1964 commented 8 months ago

Also, when I use the identity endpoint to register, only the the Normalized Email, Normalized Username, PasswordHash, SecurityStamp, and ConcurrencyStamp get filled in.

BillyMartin1964 commented 8 months ago

No Problem. Here it is:

https://github.com/BillyMartin1964/IdentityEndpointError.git

BillyMartin1964 commented 7 months ago

What more feedback do you need?

BillyMartin1964 commented 7 months ago

Is there any activity on this?