No authentication handler is registered for the scheme windows

Hi , I'm trying to use windowsauthentication, but end up with an error: InvalidOperationException: No authentication handler is registered for the scheme 'Windows'. The registered schem...

Hi ,

I’m trying to use windowsauthentication, but end up with an error:
InvalidOperationException: No authentication handler is registered for the scheme 'Windows'. The registered schemes are: Identity.Application, Identity.External, Identity.TwoFactorRememberMe, Identity.TwoFactorUserId, idsrv, idsrv.external, Google. Did you forget to call AddAuthentication().Add[SomeAuthHandler]("Windows",...)?

Happens when calling:
var result = await HttpContext.AuthenticateAsync(AccountOptions.WindowsAuthenticationSchemeName);

Startup.cs

using System.Collections.Generic;
using IdentityServer4.Models;
using IdentityServerApi.Data;
using IdentityServerApi.Models;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
//using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace IdentityServerApi
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            // Block 2: Add IdentityServer4 with InMemory Configuration
            Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true;
            services.AddControllersWithViews();

            // configures IIS out-of-proc settings (see https://github.com/aspnet/AspNetCore/issues/14882)
            services.Configure<IISOptions>(iis =>
            {
                iis.AuthenticationDisplayName = "Windows";
                iis.AutomaticAuthentication = false;
            });

            // configures IIS in-proc settings
            services.Configure<IISServerOptions>(iis =>
            {
                iis.AuthenticationDisplayName = "Windows";
                iis.AutomaticAuthentication = false;
            });
            services.AddDbContext<ApplicationDbContext>(config =>  
            {  
                // for in memory database  
                config.UseInMemoryDatabase("InMemDb");  
            });
            
            // AddIdentity :-  Registers the services  
            services.AddIdentity<ApplicationUser, IdentityRole>()
                .AddEntityFrameworkStores<ApplicationDbContext>()  
                .AddDefaultTokenProviders();  
            
            
            services.AddCors(setup =>
            {
                setup.AddDefaultPolicy(policy =>
                {
                    policy.AllowAnyHeader();
                    policy.AllowAnyMethod();
                    policy.WithOrigins("https://localhost:44386");
                    policy.AllowCredentials();
                });
            });
           
            var builder = services
                .AddIdentityServer(options =>
                {
                    options.Events.RaiseErrorEvents = true;
                    options.Events.RaiseInformationEvents = true;
                    options.Events.RaiseFailureEvents = true;
                    options.Events.RaiseSuccessEvents = true;
                    options.IssuerUri = "https://localhost:44323";
                })
              .AddAspNetIdentity<ApplicationUser>()
              //  .AddInMemoryIdentityResources(Config.GetIdentityResources())
                .AddInMemoryApiScopes((IEnumerable<ApiScope>) Config.GetScopes())
                .AddInMemoryApiResources((IEnumerable<ApiResource>) Config.GetApis())
                .AddInMemoryClients((IEnumerable<Client>) Config.GetClients());
         #if DEBUG
            builder.AddDeveloperSigningCredential();
        #endif
            
//some code is not mentioend here for the sake of brevity
            services.AddAuthentication()
                .AddGoogle(options =>
            {
                // register your IdentityServer with Google at https://console.developers.google.com
                // enable the Google+ API
                // set the redirect URI to http://localhost:5000/signin-google
                options.ClientId = "copy client ID from Google here";
                options.ClientSecret = "copy client secret from Google here";
            });;
           
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseHttpsRedirection();
            app.UseCors();
            app.UseRouting();

            // Block 4:
            //  UseIdentityServer include a call to UseAuthentication
            app.UseIdentityServer();
            app.UseAuthentication();
            app.UseStaticFiles();
            app.UseEndpoints(endpoints => endpoints.MapDefaultControllerRoute());
        }
    }
}

Best Regards,
Rauno

I want to enable Windows Authentication for my IdentityServer hosted by IIS (in process). The doc from IdentityServer4 stated that «You trigger Windows authentication by calling ChallengeAsync on the Windows scheme» but it does say where and how. I was assuming it is in the Login function of the AccountController but it doesn’t seem to work for me.

Here is the error I am getting when running my IdentityServer
enter image description here

But to my knowledge, I had registered the authentication for Windows scheme. Here is the ConfigurtionServices and Confiuration functions of the Startup.cs for the identityserver:

public void ConfigureServices(IServiceCollection services)
{
    IdentityModelEventSource.ShowPII = true; 
    services.AddControllersWithViews();

    var connstr = Configuration.GetConnectionString("DBConnection");
    services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(connstr));

    services.AddIdentity<ApplicationUser, IdentityRole>()
        .AddEntityFrameworkStores<ApplicationDbContext>()
        .AddDefaultTokenProviders();

    var builder = services.AddIdentityServer(options =>
    {
        options.Events.RaiseErrorEvents = true;
        options.Events.RaiseInformationEvents = true;
        options.Events.RaiseFailureEvents = true;
        options.Events.RaiseSuccessEvents = true;
        options.EmitStaticAudienceClaim = true;
    })
        .AddAspNetIdentity<ApplicationUser>()
        .AddConfigurationStore(options =>
        {
            options.ConfigureDbContext = b => b.UseSqlServer(connstr,
                sql => sql.MigrationsAssembly(migrationsAssembly));
        })
        .AddOperationalStore(options =>
        {
            options.ConfigureDbContext = b => b.UseSqlServer(connstr,
                sql => sql.MigrationsAssembly(migrationsAssembly));
        });

    // not recommended for production - you need to store your key material somewhere secure
    builder.AddDeveloperSigningCredential();
    //services.AddIdentityServer().AddSigningCredential(
    //    new X509Certificate2(Path.Combine(_environment.ContentRootPath, "certs", "IdentityServer4Auth.pfx")));

    // configures IIS in-proc settings
    services.Configure<IISServerOptions>(iis =>
    {
        iis.AuthenticationDisplayName = "Windows";
        iis.AutomaticAuthentication = false;
    });

    // for Windows authentication 
    services.AddAuthentication(IISDefaults.AuthenticationScheme);
}

public void Configure(IApplicationBuilder app)
{
    if (Environment.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseDatabaseErrorPage();
    }

    // use MVC
    app.UseStaticFiles();
    app.UseRouting();

    app.UseIdentityServer();
    // use MVC
    app.UseAuthorization();
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

As you can see the very last line in ConfigurationServices function, I registered authentication handler for Windows by calling services.AddAuthentication(IISDefaults.AuthenticationScheme).

Here is the Login function in the AccountController.cs, in which I call ChallengeWindowsAsync — I thought this is how the IdentityServer4 Doc suggested to do but I am not sure. If it is not the right way, how should I correct it?

[HttpGet]
public async Task<IActionResult> Login(string returnUrl)
{
    // trigger Windows authentication by calling ChallengeAsync
    await ChallengeWindowsAsync(returnUrl);

    // build a model so we know what to show on the login page
    var vm = await BuildLoginViewModelAsync(returnUrl);

    if (vm.IsExternalLoginOnly)
    {
        // we only have one option for logging in and it's an external provider
        return RedirectToAction("Challenge", "External", new { scheme = vm.ExternalLoginScheme, returnUrl });
    }

    return View(vm);
}

And here is the ChallengeWindowsAsync function

private async Task<IActionResult> ChallengeWindowsAsync(string returnUrl)
{
    // see if windows auth has already been requested and succeeded
    var result = await HttpContext.AuthenticateAsync("Windows");
    if (result?.Principal is WindowsPrincipal wp)
    {
        // we will issue the external cookie and then redirect the
        // user back to the external callback, in essence, treating windows
        // auth the same as any other external authentication mechanism
        var props = new AuthenticationProperties()
        {
            RedirectUri = Url.Action("Callback"),
            Items =
            {
                { "returnUrl", returnUrl },
                { "scheme", "Windows" },
            }
        };

        var id = new ClaimsIdentity("Windows");

        // the sid is a good sub value
        id.AddClaim(new Claim(JwtClaimTypes.Subject, wp.FindFirst(ClaimTypes.PrimarySid).Value));

        // the account name is the closest we have to a display name
        id.AddClaim(new Claim(JwtClaimTypes.Name, wp.Identity.Name));

        // add the groups as claims -- be careful if the number of groups is too large
        var wi = wp.Identity as WindowsIdentity;

        // translate group SIDs to display names
        var groups = wi.Groups.Translate(typeof(NTAccount));
        var roles = groups.Select(x => new Claim(JwtClaimTypes.Role, x.Value));
        id.AddClaims(roles);


        await HttpContext.SignInAsync(
            IdentityServerConstants.ExternalCookieAuthenticationScheme,
            new ClaimsPrincipal(id),
            props);
        return Redirect(props.RedirectUri);
    }
    else
    {
        // trigger windows auth
        // since windows auth don't support the redirect uri,
        // this URL is re-triggered when we call challenge
        return Challenge("Windows");
    }
}

  • Remove From My Forums
  • Question

  • User1554758465 posted

    I’m using Asp.Net Core 3.1 with Identity. And here is my all configuration in Startup class. I’m trying to force the logged in user to logout if their accounts expired while using the app. I should configure the cookie correctly but i’m stuck on how to do
    this while having AddIdentity.

    Here is my Startup

    // This method gets called by the runtime. Use this method to add services to the container.
            public void ConfigureServices(IServiceCollection services)
            {
            services.AddDbContext<ApplicationDbContext>(options =>
               options.UseSqlServer(
                   Configuration.GetConnectionString("DefaultConnection")));
    
            services.AddIdentity<IdentityUser, IdentityRole>(options => {
                options.SignIn.RequireConfirmedAccount = false;
            })
                .AddEntityFrameworkStores<ApplicationDbContext>()
                .AddDefaultTokenProviders(); 
    
            services.AddIdentityCore<ApplicationUser>()
                .AddRoles<IdentityRole>()
                .AddClaimsPrincipalFactory<UserClaimsPrincipalFactory<ApplicationUser, IdentityRole>>()
                .AddEntityFrameworkStores<ApplicationDbContext>()
                //.AddDefaultTokenProviders()  
                .AddDefaultUI(); 
    
            services.AddSingleton<IEmailSender, EmailSender>();
            services.Configure<EmailOptions>(Configuration);
       
            services.AddHangfire(config => config.UseSqlServerStorage(Configuration.GetConnectionString("DefaultConnection")));
            services.AddHangfireServer();
    
            services.AddControllersWithViews(); //?
            services.AddRazorPages().AddRazorRuntimeCompilation(); //?
            services.AddScoped<IExpirationJob, ExpirationJob>();
            services.AddScoped<IReminderJob, EmailReminder>();
            services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
            services.Configure<IdentityOptions>(options =>
            {
                // Password settings.
                //options.Password.RequireDigit = true;
                //options.Password.RequireLowercase = true;
                //options.Password.RequireNonAlphanumeric = true;
                //options.Password.RequireUppercase = true;
                //options.Password.RequiredLength = 6;
                //options.Password.RequiredUniqueChars = 1;
    
                // Lockout settings.
                //options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
                //options.Lockout.MaxFailedAccessAttempts = 5;
                //options.Lockout.AllowedForNewUsers = true;
    
                // User settings.
                //options.User.AllowedUserNameCharacters =
                //    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+ ";
                //options.User.RequireUniqueEmail = false;
            });
    
                     //services.ConfigureApplicationCookie(options =>
            //{
            //    options.Events = new CookieAuthenticationEvents
            //    {
            //        OnValidatePrincipal = ValidateAsync.ValidatingAsync
            //    };
            //}).Configure<SecurityStampValidatorOptions>(options =>
            //{
            //    options.ValidationInterval = TimeSpan.Zero;
            //});
         }
    
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app,
            IWebHostEnvironment env,
            IRecurringJobManager recurringJobManager,
            IServiceProvider serviceProvider)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseDatabaseErrorPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                // 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.UseHttpsRedirection();
            app.UseStaticFiles();
    
    
            app.UseHangfireDashboard();
            //app.UseHangfireDashboard("/hangfire", new DashboardOptions()
            //{
            //    Authorization = new[] { new CustomAuthorizeFilter() }
            //});
    
            app.UseRouting();
    
            app.UseAuthentication();
            app.UseAuthorization();
          
            recurringJobManager.AddOrUpdate(
               "End Users Subscription",
               () => serviceProvider.GetService<IExpirationJob>().SetExpired(),
               Cron.Minutely
               );
    
            recurringJobManager.AddOrUpdate(
               "Send End of Subscription Reminder",
               () => serviceProvider.GetService<IReminderJob>().SendReminder(),
               Cron.Daily
               );
    
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
                endpoints.MapRazorPages();
            });
        }

    Here is my ValidateAsync class

    public class ValidateAsync
    {
        public static async Task ValidatingAsync(CookieValidatePrincipalContext context)
        {
            context = context ?? throw new ArgumentNullException(nameof(context));
            var claimsIdentity = context.Principal.Identity as ClaimsIdentity;
            if (claimsIdentity?.Claims == null || !claimsIdentity.Claims.Any())
            {
                await RejectPrincipal();
                return;
            }
            UserManager<IdentityUser> userManager = context.HttpContext.RequestServices.GetRequiredService<UserManager<IdentityUser>>();
            var user = await userManager.FindByNameAsync(context.Principal.FindFirstValue(ClaimTypes.NameIdentifier));
            if (user == null || user.SecurityStamp != context.Principal.FindFirst(new ClaimsIdentityOptions().SecurityStampClaimType)?.Value)
            {
                await RejectPrincipal();
                return;
            }
            async Task RejectPrincipal()
            {
                context.RejectPrincipal();
                await context.HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
            }
        }
    }

    Here is my SetExpired method

    public interface IExpirationJob
            {
                Task SetExpired();
            }
    
     public class ExpirationJob : IExpirationJob
        {
            private readonly ApplicationDbContext _db;
            private readonly IEmailSender _emailSender;
    
            public ExpirationJob(ApplicationDbContext db, IEmailSender emailSender)
            {
                _db = db;
                _emailSender = emailSender;
            }
    
             public async Task SetExpired()
        {
            foreach(var item in _db.Institution)
            {
                if (item.SubscriptionEndDate != null)
                {
                    if (item.SubscriptionEndDate == DateTime.Today) 
                    {
                        item.Status = SD.StatusExpired;
                      //Here I want to check if the user is logged in, then force logout should be done.     
                      Guid securityStamp = Guid.NewGuid();
                      item.SecurityStamp = securityStamp;
                    }
                }
            }
            await _db.SaveChangesAsync();
        }
        }
    }

    Any help or guidance is appreciated.

Answers

  • User475983607 posted

    ShahadAlshuhail

    Ok, just forget that. 

    I have another issue which is after adding that line. I cannot login into my account.

    The log shows that user is logged in successfully. but in real, it’s not. the user is redirected to the Homepage.

    Does this have anything to do with Identity? Is it preventing something or overriding it ?

    I have no idea what you are doing…  I simple followed the reference documentation and it worked.

    services.ConfigureApplicationCookie(options =>
    {
        options.Cookie.HttpOnly = true;
        options.ExpireTimeSpan = TimeSpan.FromMinutes(60);
        options.SlidingExpiration = true;
    }).Configure<SecurityStampValidatorOptions>(options =>
    {
        options.ValidationInterval = TimeSpan.FromMinutes(2);
    }); 

    For testing I just update the security stamp and the user was logged after 2 minutes passed then making a new request.  Very simple…

    I tried 10 seconds as well.  

    • Marked as answer by

      Thursday, October 7, 2021 12:00 AM

June 28, 2017 by Anuraj Estimated read time : 2 mins

ASP.NET Core

This post is about ASP.NET Core authentication, which throws an InvalidOperationException — No authentication handler is configured to handle the scheme Cookies. In ASP.NET Core 1.x version, the runtime will throw this exception when you are running ASP.NET Cookie authentication. This can be fixed by setting options.AutomaticChallenge = true in the Configure method.

Here is the full code.

app.UseCookieAuthentication(options =>
{
    options.AutomaticAuthenticate = true;
    options.AutomaticChallenge = true;
});

And here is the SignIn method.

var claims = new[] 
{ 
    new Claim("name", authUser.Username)
};

var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
HttpContext.Authentication.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme,
    new ClaimsPrincipal(identity));

Recently I upgraded on of ASP.NET Core 1.x solution to ASP.NET Core 2.0. In ASP.NET Core 2.0, ASP.NET Core team changed the authentication methods and now there is nothing like UseCookieAuthentication. I got some compilation issues with the existing solution. Since most of the documentation it only talking about ASP.NET 1.x, I had to spent time, and I fixed it.

Here is the new Startup.cs code for authentication.

public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    });

    services.AddCookieAuthentication();
}

And in the configure method, you need to use app.UseAuthentication(); method.

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseAuthentication();
    //More code.
}

But when I am running, I got the same exception.

No authentication handler is configured to handle the scheme Cookies

After spending sometime, I figured out the issue. You don’t need to call the HttpContext.Authentication.SignInAsync method. Instead you need to call the HttpContext.SignInAsync method for authentication.

Here is the updated Signin code.

var claims = new[] 
{ 
    new Claim("name", authUser.Username)
};

var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme,
    new ClaimsPrincipal(identity));

Happy Programming :)

The second box of code showing 2.0 setup doesn’t work. I have used this which isn’t exactly as per the sample, since I don’t use EF and does use roles, so I would imagine this would work having read this page, but it doesn’t. In fact, I have spent more than 2 weeks without successfully getting OAuth working. There’s something really wrong with the documentation or the API design.

Note that I am using AddIdentityCore because there is no AddIdentity taking just the single <TUser> and also note that I had to add a DI container registration for my user store to silence an error activating that.

// My code which gives error in title

        services.AddIdentityCore&lt;MyUser&gt;();

        // If you want to tweak Identity cookies, they're no longer part of IdentityOptions.
        services.ConfigureApplicationCookie(options =&gt; options.LoginPath = "/Account/LogIn");
        services.AddAuthentication()
                .AddFacebook(options =&gt;
                {
                    options.AppId = Configuration["auth:facebook:appid"];
                    options.AppSecret = Configuration["auth:facebook:appsecret"];
                });

Document Details

Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.

  • ID: 1f4b263b-e8f9-8b44-8c13-5bc0128fb1c9
  • Version Independent ID: 985774b6-a165-f22c-c354-6c12a6783063
  • Content: Migrate authentication and Identity to ASP.NET Core 2.0
  • Content Source: aspnetcore/migration/1x-to-2x/identity-2x.md
  • Product: aspnet-core
  • Technology: aspnetcore-migration
  • GitHub Login: @scottaddie
  • Microsoft Alias: scaddie

All 21 comments

does use roles => don’t use roles

The error appears with this stack.

System.InvalidOperationException: No authentication handler is registered for the scheme 'Identity.Application'. The registered schemes are: Facebook. Did you forget to call AddAuthentication().Add[SomeAuthHandler]("Identity.Application",...)?
   at Microsoft.AspNetCore.Authentication.AuthenticationService.AuthenticateAsync(HttpContext context, String scheme)
   at Microsoft.AspNetCore.Authorization.Policy.PolicyEvaluator.AuthenticateAsync(AuthorizationPolicy policy, HttpContext context)
   at Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter.OnAuthorizationAsync(AuthorizationFilterContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
   at Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
dbug: Microsoft.AspNetCore.Server.Kestrel[9]

Gah! Its my fault, I found I left code for an authorization policy for IdentityConstants.ApplicationScheme.

Actually I can get similar code using Google to fail with

System.InvalidOperationException: No authenticationScheme was specified, and there was no DefaultSignInScheme found

Using this.

        services.AddIdentityCore<TimesheetsUser>();

        // If you want to tweak Identity cookies, they're no longer part of IdentityOptions.
        services.ConfigureApplicationCookie(options => options.LoginPath = "/Account/LogIn");
        services.AddAuthentication()
                .AddGoogle(googleOptions =>
            {
                this.Configuration.Bind("OAuth2:Providers:Google", googleOptions);

                googleOptions.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "sub", "string");
            });

This happens on the redirect back to localhost/oauth2/google?etc

With this stack.

Microsoft.AspNetCore.Authentication.AuthenticationService.SignInAsync(HttpContext context, string scheme, ClaimsPrincipal principal, AuthenticationProperties properties)
Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler<TOptions>.HandleRequestAsync()
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

It shouldn’t take me 2 weeks to get OAuth setup. I’ve been coding for 20 years, I feel like this isn’t my fault. The code I’ve added isn’t much different to the sample at the top of this page and yet it doesn’t work.

AddIdentity also configures authentication schemes and cookies. If you’re using AddIdentityCore, you need to do this yourself, as you’ve taken more direct control of the setup. To emulate the functionality you’re missing, the following should work:

services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = IdentityConstants.ApplicationScheme;
    options.DefaultChallengeScheme = IdentityConstants.ApplicationScheme;
    options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
})
.AddIdentityCookies()
.AddGoogle(...);

as you’ve taken more direct control of the setup

Unwittingly. Nothing about that method name indicates that I have taken more control. That’s the problem with all this. It’s a mess.

But thank you, not your fault.

Just for correctness, .AddGoogle(...) cannot be appended to the return of .AddIdentityCookies(...), but it does compile the other way around.

Thanks for reporting back on that. :+1:

My AccountController.ExternalLoginCallback(..) runs and this.SignInManager.GetExternalLoginInfoAsync() returns non-null at last, so thanks for helping me get this far.

I call

externalLoginResult = await this.SignInManager.ExternalLoginSignInAsync(
      externalLoginInfo.LoginProvider, externalLoginInfo.ProviderKey, isPersistent: persistCookieAfterBrowserClose);

Which fails, so I setup some the new user/login and call it again, which succeeds and I redirect. Good. However, on the next page request, this.HttpContext.User doesn’t have a my expected principal.

And calling

var authenticateResult = await this.HttpContext.AuthenticateAsync();

Results in

InvalidOperationException: No service for type ‘Microsoft.AspNetCore.Identity.ISecurityStampValidator’ has been registered

I’m clearly still missing some piece of this puzzle.

How are you registering SignInManager with DI?

I was using .AddUserStore and .AddSignInManager extensions but I decided to take everything out and return to basics/the docs and start over. So I have resolved any DI errors the more traditional way, i.e.

            services.AddTransient<IUserStore<MyUser>, MyUserStore>();
            services.AddTransient(typeof(UserManager<MyUser>));
            services.AddTransient(typeof(SignInManager<MyUser>));

The call to AddSignInManager adds additional services — most notably, an ISecurityStampValidator implementation. You can see this in the source.

Sorry, I’ve again tried helping myself. Thanks for your patience.

Everything is working, I see the cookie being passed up by the browser after signing-in via Google, Cosmos DB has new accounts setup, all good except that this.HttpContext.User has an «empty» principal.

From what I have read, I think app.UseAuthentication() is supposed to just read this off the cookie into the principal using authOptions.DefaultAuthenticateScheme which is IdentityConstants.ApplicationScheme.

Interestingly, when I call this.HttpContext.AuthenticateAsync() it returns a result with the principal I’d expect in the .User so some last little thing is missing in my setup.

Here’s my MVC setup.

        services.AddMvc(mvcOptions =>
        {
            if (!this.HostingEnvironment.IsDevelopment())
            {
                mvcOptions.Filters.Add(new RequireHttpsAttribute());
            }

            var policy = new AuthorizationPolicyBuilder()
                             .RequireAuthenticatedUser()
                             .Build();

            mvcOptions.Filters.Add(new AuthorizeFilter(policy));

        }).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

My login routes have [AllowAnonymous] and a test route with [Authorize] does hit a breakpoint within, but this.User has no claims.

I’m able to request and hit

Thanks again.

It’s no problem at all. I’m more than happy to try and help.

You’re right in that DefaultAuthenticateScheme is the real driver for getting that HttpContext.User populated correctly. The call to HttpContext.AuthenticateAsync() uses the same value so, as you suggest, I’d expect it to be working if that is.

If you can convert what you have into a GitHub repo, I’d be happy to take a look at the full picture.

Capture

Rather worryingly, with a global filter in place and the attribute, and cookies cleared and the VS debugging session restarted, I’m still able to access routes I don’t think I should. See image.

@serpent5 Kirk, thank you. If you’ll agree that I should not be able to hit that breakpoint, then I can’t trust this codebase anymore and I’ll have to start over from a whole new app.

That depends. Do you have AllowAnonymous on the controller there? If so, that actually overrides the Authorize you have on the action itself. See the warning at the bottom of this docs page.

I guess I’m relieved, there’s still hope in these 71,851 lines of code. I thought filters were applied in order of «proximity» to the action!

Yeah, they are — it’s just that authorisation stuff gets special treatment there.

It’s really no hassle. I’m pleased to be able to help and especially pleased that you’ve got it working. I’m sure you will finally sleep well tonight. :)

Was this page helpful?

0 / 5 — 0 ratings

В дополнение к @Ответ Люка:

Причина, по которой SignInManager::SignOutAsync() throws, заключается в том, что этот метод также подпишет TwoFactorUserIdScheme за кулисами:

public virtual async Task SignOutAsync()
{
    await Context.SignOutAsync(IdentityConstants.ApplicationScheme);
    await Context.SignOutAsync(IdentityConstants.ExternalScheme);
    await Context.SignOutAsync(IdentityConstants.TwoFactorUserIdScheme);
}

(См. исходный код)

Обычно эти схемы аутентификации дерева регистрируются автоматически по AddIdentity<TUser, TRole>():

public static IdentityBuilder AddIdentity<TUser, TRole>(
    this IServiceCollection services,
    Action<IdentityOptions> setupAction)
{
    services.AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = IdentityConstants.ApplicationScheme;
        options.DefaultChallengeScheme = IdentityConstants.ApplicationScheme;
        options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
    })
    ...
    .AddCookie(IdentityConstants.TwoFactorUserIdScheme, o =>
    {
        o.Cookie.Name = IdentityConstants.TwoFactorUserIdScheme;
        o.ExpireTimeSpan = TimeSpan.FromMinutes(5);
    });
    ... // other services
}

(См. исходный код)

Однако вы добавили услуги Identity от AddIdentityCore<>() вместо AddIdentity<>().

Поскольку AddIdentityCore<>() не регистрирует схему TwoFactorUserIdScheme (см. исходный код) автоматически, для CookieAuthenticationHandler нет связанного TwoFactorUserIdScheme. В результате бросает.


Как решить

Чтобы работать с SignInManager.SignOutAsync(), согласно приведенному выше описанию, нам необходимо убедиться, что карта <scheme>-<handler> зарегистрирована для TwoFactorUserIdScheme.

Итак, я изменил ваш код, как показано ниже, теперь он отлично работает для меня:

serviceCollection.AddAuthentication(IdentityConstants.ApplicationScheme)
    .AddCookie(IdentityConstants.ApplicationScheme, options =>
    {
        options.SlidingExpiration = true;
    })
    .AddCookie(IdentityConstants.TwoFactorUserIdScheme, o =>
    {
        o.Cookie.Name = IdentityConstants.TwoFactorUserIdScheme;
        o.ExpireTimeSpan = TimeSpan.FromMinutes(5);
    })
    .AddGoogle(googleOptions =>
    {
        this.Configuration.Bind("OAuth2:Providers:Google", googleOptions);
        googleOptions.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "sub", "string");
    })
    .AddExternalCookie();

i’m fairy new to the .net core world and am trying to setup a identityServer. I followed the guide from https://identityserver4.readthedocs.io/en/release/quickstarts/6_aspnet_identity.html and managed to get the basics working. I now want to use .Net core Identity in combination with identityServer but it’s giving an exception i don’t know how to solve. The exception:

No authentication handler is configured to authenticate for the scheme: idsrv

 Executed action IdentityServer4.Quickstart.UI.GrantsController.Index (IdentityServer) in 22.9784ms
fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[0]
      An unhandled exception has occurred while executing the request
System.InvalidOperationException: No authentication handler is configured to authenticate for the scheme: idsrv
   at Microsoft.AspNetCore.Http.Authentication.Internal.DefaultAuthenticationManager.<GetAuthenticateInfoAsync>d__12.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()

I’ve tried browsing github issues for simmilar issues and some people said it was related to the order IdentityServer and Identity are loaded. But in my case they should be correct?

My Startup.cs class:

 public void ConfigureServices(IServiceCollection services)
        {

            services.AddDbContext<ApplicationDbContext>(options =>
                options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

            services.AddIdentity<IdentityUser, IdentityRole>()
                .AddEntityFrameworkStores<ApplicationDbContext>()
                .AddDefaultTokenProviders();

            services.AddMvc();

            // Adds IdentityServer
            services.AddIdentityServer()
                .AddTemporarySigningCredential()
                .AddInMemoryIdentityResources(Resources.GetIdentityResources())
                .AddInMemoryApiResources(Resources.GetApiResources())
                .AddInMemoryClients(Clients.Get())
                .AddAspNetIdentity<IdentityUser>();

        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {

            loggerFactory.AddConsole(Configuration.GetSection("Logging"));
            loggerFactory.AddDebug();

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseBrowserLink();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }

            app.UseIdentity();

            // Adds IdentityServer
            app.UseIdentityServer();

            app.UseStaticFiles();

            app.UseMvcWithDefaultRoute();
        }

I am trying to develop a project in .NET Core 3.1. I am trying to implement cookie based authentication in my project. My login function is:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(UserLoginModel userModel)
{
    if (!ModelState.IsValid)
    {
        return View(userModel);
    }

    if (userModel.Email == "admin@test.com" && userModel.Password == "123")
    {
        var identity = new ClaimsIdentity(IdentityConstants.ApplicationScheme);
        identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, "User Id"));
        identity.AddClaim(new Claim(ClaimTypes.Name, "User Name"));

        var principal = new ClaimsPrincipal(identity);

        await HttpContext.SignInAsync(IdentityConstants.ApplicationScheme, principal);

        return RedirectToAction(nameof(HomeController.Index), "Home");
    }
    else
    {
        ModelState.AddModelError("", "Invalid UserName or Password");
        return View();
    }
}

To implement cookie based authentication, I put the below code in my ConfigureService method of Startup class:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();

    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.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
        .AddCookie(options =>
        {
            options.Cookie.Name = "_auth";
            options.Cookie.HttpOnly = true;
            options.LoginPath = new PathString("/account/login");
            options.LogoutPath = new PathString("/account/logout");
            options.AccessDeniedPath = new PathString("/account/login");
            options.ExpireTimeSpan = TimeSpan.FromDays(1);
            options.SlidingExpiration = false;
        });

    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Latest);
}

And the configure method of Startup class is:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseStaticFiles();
    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
    });
}

But the problem is each time I try to login, the below exception occur in below code of login action method.

await HttpContext.SignInAsync(IdentityConstants.ApplicationScheme,
principal)

The exception occured is given below:

InvalidOperationException: No sign-in authentication handler is
registered for the scheme ‘Identity.Application’. The registered
sign-in schemes are: Cookies. Did you forget to call
AddAuthentication().AddCookies(«Identity.Application»,…)?
Microsoft.AspNetCore.Authentication.AuthenticationService.SignInAsync(HttpContext
context, string scheme, ClaimsPrincipal principal,
AuthenticationProperties properties)
_01_AuthenticationDemo.Controllers.AccountController.Login(UserLoginModel userModel) in AccountController.cs
+
await HttpContext.SignInAsync(IdentityConstants.ApplicationScheme,
principal);

Can anyone give me suggestion to solve the problem.

I am implementing query uvdos oauth-2.0 Aspnet.security.openidconnect (ASOS) with query uvdos oauth-2.0 .net core 2.1 application. Now the issue is query uvdos oauth-2.0 when I am trying to execute this chunk in query uvdos oauth-2.0 controller,

        public async Task<IActionResult> Authorize()
        {
            if (Response.StatusCode != 200)
            {
                return View("AuthorizeError");
            }

            var ticket = await AuthenticationHttpContextExtensions.AuthenticateAsync(HttpContext, CookieAuthenticationDefaults.AuthenticationScheme);
            var identity = ticket != null && ticket.Principal != null ? ticket.Ticket.Principal : null;
            if (identity == null)
            {
                await AuthenticationHttpContextExtensions.ChallengeAsync(HttpContext, CookieAuthenticationDefaults.AuthenticationScheme, null);
                return Unauthorized();
            }
            ViewData["Name"] = ticket.Principal.Identity.Name;
           var scopes = (HttpContext.Request.Query["scope"].ToString() ?? "").Split(' ');
            ViewData["Scopes"] = scopes;

            //var claimsIdentity = new ClaimsIdentity(identity.Claims, "Bearer", identity.NameClaimType, identity.RoleClaimType);
            var claimsIdentity = new ClaimsIdentity(identity.Claims, "Bearer");
            foreach (var scope in scopes)
            {
                claimsIdentity.AddClaim(new Claim("urn:oauth:scope", scope));
            }
            var claimsPrincipal = new ClaimsPrincipal(claimsIdentity);
            await AuthenticationHttpContextExtensions.SignInAsync(HttpContext, claimsPrincipal);
            logger.Info("Authorize request received");
            return View();
        }

The error I am getting on this line:

 var ticket = await AuthenticationHttpContextExtensions.AuthenticateAsync(HttpContext, CookieAuthenticationDefaults.AuthenticationScheme);

And here is the implementation of ASOS in query uvdos oauth-2.0 startup:

            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.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
                   .AddCookie("Application", options =>
                   {
                       options.LoginPath = new PathString(LoginPath);
                       options.LogoutPath = new PathString(LogoutPath);
                       options.ExpireTimeSpan = TimeSpan.FromMinutes(5);

                       //options.AccessDeniedPath = new PathString(); 
                   });

            //services.AddAuthentication("External")
            // .AddCookie("Cookies", options =>
            // {
            //     options.Cookie.Name = CookieAuthenticationDefaults.CookiePrefix + "External";
            //     options.ExpireTimeSpan = TimeSpan.FromMinutes(5);
            // });

            services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie();

            services.AddAuthentication(OAuthValidationDefaults.AuthenticationScheme).AddOAuthValidation()
            .AddOpenIdConnectServer(options =>
            {
                options.AuthorizationEndpointPath = new PathString(AuthorizePath);
                // Enable the token endpoint.
                options.TokenEndpointPath = new PathString(TokenPath);
                options.ApplicationCanDisplayErrors = true;
                options.AccessTokenLifetime = TimeSpan.FromMinutes(5);
#if DEBUG
                 options.AllowInsecureHttp = true;
#endif
                options.Provider.OnValidateAuthorizationRequest = context =>
                {
                    if (string.Equals(context.ClientId, Configuration["OpenIdServer:ClientId"], StringComparison.Ordinal))
                    {
                        context.Validate(context.RedirectUri);
                    }
                    return Task.CompletedTask;
                };
                // Implement OnValidateTokenRequest to support flows using the token endpoint.
                options.Provider.OnValidateTokenRequest = context =>
                {
                // Reject token requests that don't use grant_type=password or grant_type=refresh_token.
                if (!context.Request.IsClientCredentialsGrantType() && !context.Request.IsPasswordGrantType()
                    && !context.Request.IsRefreshTokenGrantType())
                    {
                       context.Reject(
                       error: OpenIdConnectConstants.Errors.UnsupportedGrantType,
                       description: "Only grant_type=password and refresh_token " +
                                    "requests are accepted by this server.");

                        return Task.CompletedTask;
                    }

                    if (string.IsNullOrEmpty(context.ClientId))
                    {
                        context.Skip();

                        return Task.CompletedTask;
                    }

                    if (string.Equals(context.ClientId, Configuration["OpenIdServer:ClientId"], StringComparison.Ordinal) &&
                        string.Equals(context.ClientSecret, Configuration["OpenIdServer:ClientSecret"], StringComparison.Ordinal))
                    {
                        context.Validate();
                    }

                    return Task.CompletedTask;
                };

                // Implement OnHandleTokenRequest to support token requests.
                options.Provider.OnHandleTokenRequest = context =>
                {
                 // Only handle grant_type=password token requests and let
                 // the OpenID Connect server handle the other grant types.
                  if (context.Request.IsClientCredentialsGrantType() || context.Request.IsPasswordGrantType())
                  {
                     //var identity = new ClaimsIdentity(context.Scheme.Name,
                     //    OpenIdConnectConstants.Claims.Name,
                     //    OpenIdConnectConstants.Claims.Role);
                     ClaimsIdentity identity = null;
                        if (context.Request.IsClientCredentialsGrantType())
                        {
                            identity = new ClaimsIdentity(new GenericIdentity(context.Request.ClientId, "Bearer"), context.Request.GetScopes().Select(x => new Claim("urn:oauth:scope", x)));
                        }
                        else if (context.Request.IsPasswordGrantType())
                        {
                            identity = new ClaimsIdentity(new GenericIdentity(context.Request.Username, "Bearer"), context.Request.GetScopes().Select(x => new Claim("urn:oauth:scope", x)));
                        }


                        // Add the mandatory subject/user identifier claim.
                        // By default, claims are not serialized in the access/identity tokens.
                        // Use the overload taking a "destinations" parameter to make sure
                        // your claims are correctly inserted in the appropriate tokens.
                        identity.AddClaim(OpenIdConnectConstants.Claims.Subject, Guid.NewGuid().ToString("n") + Guid.NewGuid().ToString("n"), OpenIdConnectConstants.Destinations.AccessToken, OpenIdConnectConstants.Destinations.IdentityToken);


                        var ticket = new Microsoft.AspNetCore.Authentication.AuthenticationTicket(
                         new ClaimsPrincipal(identity),
                         new Microsoft.AspNetCore.Authentication.AuthenticationProperties(),
                         context.Scheme.Name);

                     // Call SetScopes with the list of scopes you want to grant
                     // (specify offline_access to issue a refresh token).
                     ticket.SetScopes(
                         OpenIdConnectConstants.Scopes.Profile,
                         OpenIdConnectConstants.Scopes.OfflineAccess);

                        context.Validate(ticket);
                   }

                   return Task.CompletedTask;
                };

Now the error I am getting is:

InvalidOperationException: No authentication query uvdos oauth-2.0 handler is registered for
the scheme query uvdos oauth-2.0 ‘Cookies’. The registered schemes are: query uvdos oauth-2.0 Application, Bearer,
ASOS. Did you forget query uvdos oauth-2.0 to call
query uvdos oauth-2.0 AddAuthentication().AddSomeAuthHandler?

What am I missing here. Any help?

26

Answers 1 : of No authentication handler is registered for the scheme Cookies. The registered schemes are: Application, Bearer, ASOS

So found the issue, actually I was using post uvdos asp.net-core «Application» name for cookie scheme and post uvdos asp.net-core in controller I was using default name post uvdos asp.net-core «Cookies». So just had to remove the post uvdos asp.net-core explicit «Application» name to default post uvdos asp.net-core «Cookies» name
No authenticationScheme post uvdos asp.net-core was specified, and there was no post uvdos asp.net-core DefaultChallengeScheme found Cookies post uvdos asp.net-core Authentication

0

2023-02-01T17:22:56+00:00 2023-02-01T17:22:56+00:00Answer Link

mRahman

3

Answers 2 : of No authentication handler is registered for the scheme Cookies. The registered schemes are: Application, Bearer, ASOS

In my case I was using «Cookies» when post uvdos asp.net-core adding authentication and «Cookie» when post uvdos asp.net-core calling the SiginOut method.
Changed post uvdos asp.net-core both the places to use «Cookies»

Startup:

services.AddAuthentication(config => {
                config.DefaultScheme = "Cookies";
                config.DefaultChallengeScheme = "oidc";
            })
                .AddCookie("Cookies")<---- Change here.
                .AddOpenIdConnect("oidc", config => {
                    config.Authority = "https://localhost:44392/";
                    config.ClientId = "client_id_mvc";
                    config.ClientSecret = "client_secret_mvc";
                    config.SaveTokens = true;
                    config.ResponseType = "code";
                    //config.SignedOutCallbackPath = "/Privacy";

                });

Calling SignOut:

public async Task<IActionResult> OnPostAsync()
    {
        return SignOut("Cookies", "oidc");
    }

0

2023-02-01T17:22:56+00:00 2023-02-01T17:22:56+00:00Answer Link

yousuf

Понравилась статья? Поделить с друзьями:
  • No any hdaudio device is found windows 10
  • No any device exists при загрузке как убрать windows 10
  • No amd graphics driver is installed windows 10
  • Nnusetup latest exe для windows 7
  • Nnm windows 7 скачать торрент 64 bit rus