Identityserver4: Cannot authenticate using the IdentityServer4 ver. 2.0

Created on 15 Oct 2017  路  16Comments  路  Source: IdentityServer/IdentityServer4

Here's how I changed my _Startup.cs_ file when I upgraded to IdentityServer4 ver. 2.0 in my ASP.NET Core 2.0 project (uses .NET Framework 4.7).

OLD:

public void ConfigureServices(IServiceCollection services)
{
  services.AddLogging();
  services.AddSingleton(Configuration);

  services
    .AddScoped<IDbContextFactory<AppDbContext>, AppDbContextFactory>()
    .AddScoped(sp => sp.GetService<IDbContextFactory<AppDbContext>>().Create())
    .AddScoped<IUserClaimsPrincipalFactory<User>, AppUserClaimsPrincipalFactory>()
    .AddScoped<AppUserStore>()
    .AddScoped<AppRoleStore>()
    .AddScoped<AppUserManager>();

  services.AddIdentity<User, Role>()
    .AddUserStore<AppUserStore>()
    .AddRoleStore<AppRoleStore>()
    .AddUserManager<AppUserManager>()
    .AddClaimsPrincipalFactory<AppUserClaimsPrincipalFactory>();

  services.AddIdentityServer()
    .AddDeveloperSigningCredential()
    .AddInMemoryIdentityResources(IdentityConfig.GetIdentityResources())
    .AddInMemoryApiResources(IdentityConfig.GetApiResources())
    .AddInMemoryClients(IdentityConfig.GetClients())
    .AddAspNetIdentity<User>();   

  services.AddMvc()
}     

public void Configure(IApplicationBuilder app, ...)
{
  ...

  app.UseIdentity()
     .UseIdentityServer()
     .UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
     {
       Authority = Constants.AppUrl,
       ApiName = Constants.ApiScope,
       ApiSecret = Constants.XamarinClientSecret,
       EnableCaching = true,
       AutomaticAuthenticate = true,
       RequireHttpsMetadata = false,
     });

  app.UseMvc();
}

New:

public void ConfigureServices(IServiceCollection services)
{
  services.AddLogging();
  services.AddSingleton(Configuration);

  services
    .AddScoped<IDbContextFactory<AppDbContext>, AppDbContextFactory>()
    .AddScoped(sp => sp.GetService<IDbContextFactory<AppDbContext>>().Create())
    .AddScoped<IUserClaimsPrincipalFactory<User>, AppUserClaimsPrincipalFactory>()
    .AddScoped<AppUserStore>()
    .AddScoped<AppRoleStore>()
    .AddScoped<AppUserManager>();

  services.AddIdentity<User, Role>()
    .AddUserStore<AppUserStore>()
    .AddRoleStore<AppRoleStore>()
    .AddUserManager<AppUserManager>()
    .AddClaimsPrincipalFactory<AppUserClaimsPrincipalFactory>();

  services.AddIdentityServer(options=> {           
  })
    .AddDeveloperSigningCredential()
    .AddInMemoryIdentityResources(IdentityConfig.GetIdentityResources())
    .AddInMemoryApiResources(IdentityConfig.GetApiResources())
    .AddInMemoryClients(IdentityConfig.GetClients())
    .AddAspNetIdentity<User>()
    .AddJwtBearerClientAuthentication();


  services.AddMvc()
    .AddJsonOptions(o =>
    {
      var settings = JsonSerializerSettingsProvider.CreateSerializerSettings();
      var hSettings = new MyAppSerializerSettings();
      hSettings.DeepCopy(o.SerializerSettings);
    });

  services.AddAuthentication(o =>
    {
      o.DefaultScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme;          
    })
    .AddIdentityServerAuthentication(o =>
    {
      o.Authority = Constants.AppUrl;
      o.ApiName = Constants.ApiScope;
      o.ApiSecret = Constants.XamarinClientSecret;
      o.EnableCaching = true;
      o.RequireHttpsMetadata = false;
      o.SupportedTokens = SupportedTokens.Both;
    });      
}

public void Configure(IApplicationBuilder app, ...)
{
  ...

  app        
    .UseAuthentication()        
    .UseIdentityServer();         

  app.UseMvc();
}

_MyProject.csproj_ changes:

Old:

<PackageReference Include="IdentityServer4.AccessTokenValidation" Version="1.2.1" />
<PackageReference Include="IdentityServer4.AspNetIdentity" Version="1.0.1" />
<PackageReference Include="IdentityServer4" Version="1.5.2" />

New:

<PackageReference Include="IdentityServer4.AccessTokenValidation" Version="2.0.0" />
<PackageReference Include="IdentityServer4.AspNetIdentity" Version="2.0.0" />
<PackageReference Include="IdentityServer4" Version="2.0.0" />

Looks like the sign-in works properly, as I'm able to get the claims and the token in the client side, but when I try to access protected resources (i.e. controllers decorated with Authorize), I get a 404 NotFound error.
This is what I see in the server-side console when trying to access the protected resource:

info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
      Request starting HTTP/1.1 GET http://localhost:52493/api/Lists/All
info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
      Authorization failed for user: (null).
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[3]
      Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
info: Microsoft.AspNetCore.Mvc.ChallengeResult[1]
      Executing ChallengeResult with authentication schemes ().
info: Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler[12]
      AuthenticationScheme: Identity.Application was challenged.
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
      Executed action MyProject.Controllers.ListsController.Get (MyProject.Api) in 65.0737ms
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
      Request finished in 240.0852ms 302
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
      Request starting HTTP/1.1 GET http://localhost:52493/account/login?returnUrl=%2Fapi%2FLists%2FAll
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
      Request finished in 0.8721ms 404

One line before the bottom line I can see this link:
http://localhost:52493/account/login?returnUrl=%2Fapi%2FLists%2FAll, but I'm wondering why is there such a link anyway, I'm using bearer authorization. There shouldn't be any redirects at all.
That's how it used to work so far and it broke.

What am I missing?

question

Most helpful comment

That worked!
But instead of changing it in the controller, I added the following to the _Startup.cs_ file, from:

    services.AddAuthentication(o =>
    {
      o.DefaultScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme;
 +    o.DefaultAuthenticateScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme;
    })

All 16 comments

if you move this

 services.AddAuthentication(o =>
    {
      o.DefaultScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme;          
    })
    .AddIdentityServerAuthentication(o =>
    {
      o.Authority = Constants.AppUrl;
      o.ApiName = Constants.ApiScope;
      o.ApiSecret = Constants.XamarinClientSecret;
      o.EnableCaching = true;
      o.RequireHttpsMetadata = false;
      o.SupportedTokens = SupportedTokens.Both;
    });   

above

 services.AddMvc()

does that fix it?

@PureWeen Unfortunately, that did not solve the issue.

What if you annotate the authorize with the scheme?


    [Authorize(AuthenticationSchemes = IdentityServerAuthenticationDefaults.AuthenticationScheme)]

That worked!
But instead of changing it in the controller, I added the following to the _Startup.cs_ file, from:

    services.AddAuthentication(o =>
    {
      o.DefaultScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme;
 +    o.DefaultAuthenticateScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme;
    })

Awesome!!! I just went through this process last week and was having similar issues :-)

I am having the same issue, in trying to migrate to 2.0, but the above fix does not seem to work for me. My controller used to be decorated as [Authorize(Roles = "administrator,agent")] and it all worked fine. Now it does not authenticate unless I specifically make it [Authorize(AuthenticationSchemes = IdentityServerAuthenticationDefaults.AuthenticationScheme, Roles ="administrator,agent")].

If I try to set the following then I cannot even get past the login page itself. Console output says user is not authenticated.

services.AddAuthentication(options =>
{
    options.DefaultScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme;
    options.DefaultAuthenticateScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme;
 })

Is there some other config I am missing so I do not have to verbosely decorate every controller in this new way? I should note I am using asp.net identity so not sure if now that there are dual scheme support in 2.0 that the default cookie scheme of asp.net identity is munging things up with my attempt to use bearer and identityserver?

Getting stuck in Loop on Login Page can happen due to either your credentials do not match or The Session Cookie is not being set properly. Check for the scheme that is passed to SignInAsync Method. It should match with the one configured in your Startup.cs file.

Actually it looks like adding the following has fixed the issue:
services .AddMvc(options => { var defaultPolicy = new AuthorizationPolicyBuilder(new[] { JwtBearerDefaults.AuthenticationScheme, IdentityConstants.ApplicationScheme }) .RequireAuthenticatedUser() .Build(); options.Filters.Add(new AuthorizeFilter(defaultPolicy));
I came across this part of adding a default policy on AddMvc as referenced in on this stackoverflow question: https://stackoverflow.com/questions/45778679/dotnet-core-2-0-authentication-multiple-schemas-identity-cookies-and-jwt.

I am not overly clear though on what exactly is happening with this fix in case someone understands this better?

services.AddMvc(options => { var defaultPolicy = new AuthorizationPolicyBuilder( new[] { JwtBearerDefaults.AuthenticationScheme, IdentityConstants.ApplicationScheme }) .RequireAuthenticatedUser() .Build(); options.Filters.Add(new AuthorizeFilter(defaultPolicy));

The above code simply adds a global AuthorizationFilter to with the two mentioned schemes.
It's same as putting an Authorize Attribute with the two mentioned schemes on every action of every controller in your application.
It will check for authentication on every incoming request.

So in essence was the behavior of asp.net core 1.0 allowing my previous headers to work like that by default but now 2.0 is more explicit in nature? Always like to know the nuance of what has changed and why given this is all security related! Thank you for the insight.

migrating from asp.net core 1.0 to asp.net core 2.0, will cause break things. So upgrading to does from IdentityServer4 1.x.x to IdentityServer4 2.x.x.

Indeed things are more explicit in nature now. Both in ASP.NET Core and IdentityServer4.

The more magic that the framework automatically does, the more work someone has to do to prevent it. @brockallen

Thank you so much @weitzhandler was fighting with the issue for 20 hours.

This should be mentioned in the documentation of IdentityServer4. Thanks @weitzhandler your solution works great. Nothing more needed!

Thank you @weitzhandler and @PureWeen,

The @PureWeen solution seemed cleaner for me so i tried it but i did not work, but i realised that the problem was because my controller had an Authorize attribute, but WITHOUT the AuthenticationScheme set, so it would block there and not even reach my method that had the Authorize attribute WITH the authentication scheme.

That worked!
But instead of changing it in the controller, I added the following to the _Startup.cs_ file, from:

    services.AddAuthentication(o =>
    {
      o.DefaultScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme;
 +    o.DefaultAuthenticateScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme;
    })

Newer versions of IS4 2.x output error on service startup with such configuration. So proper way would be to use attribute with bearer auth schema:
[Authorize(AuthenticationSchemes = IdentityServerAuthenticationDefaults.AuthenticationScheme)].

See docs for info.

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

wangkanai picture wangkanai  路  3Comments

agilenut picture agilenut  路  3Comments

cixonline picture cixonline  路  3Comments

klioqc picture klioqc  路  3Comments

user1336 picture user1336  路  3Comments