openiddict / openiddict-core

Flexible and versatile OAuth 2.0/OpenID Connect stack for .NET
https://openiddict.com/
Apache License 2.0
4.36k stars 510 forks source link

[help] Client can't sign in new Server from migrated sample #313

Closed HolyHorseman closed 7 years ago

HolyHorseman commented 7 years ago

Dear Kevin, I must make a mistake when I used this lib. I was in trouble, and this problem perplex me about two weeks. So I hope you could guide me, thank you very very much. The details are as below:

  1. I taken a little time to learning about the RFC document of OAuth, ASP.NET Core Identity, ASOS articles on your website and code sample here.

  2. I created a new project with individual user account. It included some new classes named AppUser, AppRole, AppUserStore, AppRoleStore, AppDbContext. It worked well.

  3. Base on modified project, I went on migrating codes from openiddict-core-sample. It seemed a right work, however client in sample can't connect to server in the project by Sign In button.(P.S. Authority in startup.cs and Action in HomeController.cs had been pointed to new server.) Web shown error page, in ErrorController the OpenIdConnectResponse is null. In VS output shown: Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://localhost:16212/connect/authorize?client_id=myClient&redirect_uri=http%3A%2F%2Flocalhost%3A53507%2Fsignin-oidc&response_type=code&scope=openid%20profile%20email%20roles%20offline_access&response_mode=form_post&nonce=636190448885462000.YTM0N2E4YzYtNzgyYS00OTZhLTgwNzAtYjI1ZmE4OWNkY2ExMTA0ZjVkZTgtNzc5Yi00OWI4LTkzNWMtMDkzMDdlNGMxN2U0&state=CfDJ8KpUMaFXWrVKqd2df-1DIomu5v5zZi6tP00Oj4bcZRBMFiFNJcNXx80QsaYYqhrSVtknvaIaTlmYh2N-L20GSdxf_bUwKdaxtLBJy4Ojx4wKFXE--AtR-WfUFJBjYcDoFOdn9R8mI3gYrFQfMVS89KZp00Q6FojeNqbdV2xkbnRo-rZUsJ8dPBj0j2fmjTPFplTxnyivbI9pL0RJXW47AX9ZBiI_hwjENFjnTyyl2SRXQkJXmWepuntRz25Am-FwkPrDvz4hH9X9aFLYXoUtSpVmHf5CkuI9yRttUvX5yiU89jXeZQeu8we-EMdvfz_gjGyK1HV04PJ1CPy5pt0QEiE Microsoft.EntityFrameworkCore.Storage.IRelationalCommandBuilderFactory:Information: Executed DbCommand (0ms) [Parameters=[@__identifier_0='?' (Size = 450)], CommandType='Text', CommandTimeout='30'] SELECT TOP(2) [application].[Id], [application].[ClientId], [application].[ClientSecret], [application].[DisplayName], [application].[LogoutRedirectUri], [application].[RedirectUri], [application].[Type] FROM [OpenIddictApplications] AS [application] WHERE [application].[ClientId] = @__identifier_0 Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Request","time":"2017-01-03T12:54:48.5532044Z","tags":{"ai.device.roleInstance":"lidewang","ai.user.userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.87 Safari/537.36","ai.operation.name":"GET /connect/authorize","ai.operation.id":"33WPbSglNKo=","ai.internal.sdkVersion":"aspnet5c:1.0.0"},"data":{"baseType":"RequestData","baseData":{"ver":2,"id":"33WPbSglNKo=","name":"GET /connect/authorize","startTime":"2017-01-03T12:54:48.5532044+00:00","duration":"00:00:00.0049845","success":true,"responseCode":"302","url":"http://localhost:16212/connect/authorize?client_id=myClient&redirect_uri=http:%2F%2Flocalhost:53507%2Fsignin-oidc&response_type=code&scope=openid profile email roles offline_access&response_mode=form_post&nonce=636190448885462000.YTM0N2E4YzYtNzgyYS00OTZhLTgwNzAtYjI1ZmE4OWNkY2ExMTA0ZjVkZTgtNzc5Yi00OWI4LTkzNWMtMDkzMDdlNGMxN2U0&state=CfDJ8KpUMaFXWrVKqd2df-1DIomu5v5zZi6tP00Oj4bcZRBMFiFNJcNXx80QsaYYqhrSVtknvaIaTlmYh2N-L20GSdxf_bUwKdaxtLBJy4Ojx4wKFXE--AtR-WfUFJBjYcDoFOdn9R8mI3gYrFQfMVS89KZp00Q6FojeNqbdV2xkbnRo-rZUsJ8dPBj0j2fmjTPFplTxnyivbI9pL0RJXW47AX9ZBiI_hwjENFjnTyyl2SRXQkJXmWepuntRz25Am-FwkPrDvz4hH9X9aFLYXoUtSpVmHf5CkuI9yRttUvX5yiU89jXeZQeu8we-EMdvfz_gjGyK1HV04PJ1CPy5pt0QEiE","httpMethod":"GET","properties":{"DeveloperMode":"true"}}}} Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 7.803ms 302 Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://localhost:16212/connect/authorize?request_id=53a694e3-4272-4b7b-b588-a962e8b74f3e Microsoft.EntityFrameworkCore.Storage.IRelationalCommandBuilderFactory:Information: Executed DbCommand (0ms) [Parameters=[@__identifier_0='?' (Size = 450)], CommandType='Text', CommandTimeout='30'] SELECT TOP(2) [application].[Id], [application].[ClientId], [application].[ClientSecret], [application].[DisplayName], [application].[LogoutRedirectUri], [application].[RedirectUri], [application].[Type] FROM [OpenIddictApplications] AS [application] WHERE [application].[ClientId] = @__identifier_0 Microsoft.AspNetCore.Authorization.DefaultAuthorizationService:Information: Authorization failed for user: (null). Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Warning: Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'. Microsoft.AspNetCore.Mvc.ChallengeResult:Information: Executing ChallengeResult with authentication schemes (). AspNet.Security.OAuth.Validation.OAuthValidationMiddleware:Information: AuthenticationScheme: Bearer was challenged. Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware:Information: AuthenticationScheme: Identity.Application was challenged. Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executing action method OpenAuthServerCoreMigration.Controllers.ErrorController.Error (OpenAuthServerCoreMigration) with arguments () - ModelState is Valid Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.ViewResultExecutor:Information: Executing ViewResult, running view at path /Views/Shared/Error.cshtml. Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action OpenAuthServerCoreMigration.Controllers.ErrorController.Error (OpenAuthServerCoreMigration) in 3091.4939ms Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Request","time":"2017-01-03T12:54:48.5648255Z","tags":{"ai.device.roleInstance":"lidewang","ai.user.userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.87 Safari/537.36","ai.operation.name":"GET Authorization/Authorize","ai.operation.id":"T4CWO/We4XE=","ai.internal.sdkVersion":"aspnet5c:1.0.0"},"data":{"baseType":"RequestData","baseData":{"ver":2,"id":"T4CWO/We4XE=","name":"GET Authorization/Authorize","startTime":"2017-01-03T12:54:48.5648255+00:00","duration":"00:00:03.1113601","success":false,"responseCode":"401","url":"http://localhost:16212/connect/authorize?request_id=53a694e3-4272-4b7b-b588-a962e8b74f3e","httpMethod":"GET","properties":{"DeveloperMode":"true"}}}} Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 3115.3799ms 401 text/html; charset=utf-8

My project details are as below:

global.json:

"version": "1.0.0-preview2-003131"

Controllers and Views: Authorization, Resource, Error (migrate from code sample and unmodified)

Classes: `public class AppRole : IdentityRole { }

public class AppUser : IdentityUser { }

public class AppUserStore : UserStore<AppUser, AppRole, AppDbContext, long>
{
    public AppUserStore(AppDbContext context) : base(context) { }
}

public class AppRoleStore : RoleStore<AppRole, AppDbContext, long>
{
    public AppRoleStore(AppDbContext context) : base(context) { }
}

public class AppDbContext : IdentityDbContext<AppUser, AppRole, long>
{
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }

    public DbSet<AppUser> AppUser { get; set; }
    public DbSet<AppRole> AppRole { get; set; }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);
        // Customize the ASP.NET Identity model and override the defaults if needed.
        // For example, you can rename the ASP.NET Identity table names and more.
        // Add your customizations after calling base.OnModelCreating(builder);

        builder.Entity<AppUser>().ToTable("AppUser", "Identity");
        builder.Entity<AppRole>().ToTable("AppRole", "Identity");
    }
}

public class Startup
{
    public Startup(IHostingEnvironment env)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);

        if(env.IsDevelopment())
        {
             builder.AddUserSecrets();

             builder.AddApplicationInsightsSettings(developerMode: true);
        }

        builder.AddEnvironmentVariables();
        Configuration = builder.Build();
    }

    public IConfigurationRoot Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddApplicationInsightsTelemetry(Configuration);

        services.AddMvc();

        services.AddDbContext<AppDbContext>(options =>
        {
            options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
            options.UseOpenIddict();
        });

        services.AddIdentity<AppUser, AppRole>(options =>
        {
            options.Password.RequiredLength = 6;
            options.Password.RequireDigit = false;
            options.Password.RequireLowercase = false;
            options.Password.RequireUppercase = false;
            options.Password.RequireNonAlphanumeric = false;
        })
            .AddEntityFrameworkStores<AppDbContext, long>()
            .AddUserStore<AppUserStore>()
            .AddRoleStore<AppRoleStore>()
            .AddDefaultTokenProviders();

        services.AddOpenIddict()
            .AddEntityFrameworkCoreStores<AppDbContext>()
            .AddMvcBinders()
            .EnableAuthorizationEndpoint("/connect/authorize")
            .EnableLogoutEndpoint("/connect/logout")
            .EnableTokenEndpoint("/connect/token")
            .EnableUserinfoEndpoint("/Account/Userinfo")
            .AllowAuthorizationCodeFlow()
            .AllowRefreshTokenFlow()
            .RequireClientIdentification()
            .DisableHttpsRequirement()
            .EnableRequestCaching()
            .AddEphemeralSigningKey();

        services.AddTransient<IEmailSender, AuthMessageSender>();
        services.AddTransient<ISmsSender, AuthMessageSender>();
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        loggerFactory.AddConsole(Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();

        app.UseApplicationInsightsRequestTelemetry();

        app.UseDeveloperExceptionPage();

        app.UseApplicationInsightsExceptionTelemetry();

        app.UseStaticFiles();

        app.UseIdentity();

        app.UseOAuthValidation();

        app.UseCsp(options => options.DefaultSources(directive => directive.Self())
            .ImageSources(directive => directive.Self()
                .CustomSources("*"))
            .ScriptSources(directive => directive.Self()
                .UnsafeInline())
            .StyleSources(directive => directive.Self()
                .UnsafeInline()));

        app.UseXContentTypeOptions();

        app.UseXfo(options => options.Deny());

        app.UseXXssProtection(options => options.EnabledWithBlockMode());

        app.UseStatusCodePagesWithReExecute("/error");

        app.UseOpenIddict();

        app.UseMvcWithDefaultRoute();

        using(var context = new AppDbContext(app.ApplicationServices.GetRequiredService<DbContextOptions<AppDbContext>>()))
        {
            context.Database.EnsureCreated();

            var applications = context.Set<OpenIddictApplication>();

            // Add Mvc.Client to the known applications.
            if(!applications.Any())
            {
                applications.Add(new OpenIddictApplication
                {
                    ClientId = "myClient",
                    ClientSecret = Crypto.HashPassword("secret_secret_secret"),
                    DisplayName = "My client application",
                    LogoutRedirectUri = "http://localhost:53507/",
                    RedirectUri = "http://localhost:53507/signin-oidc",
                    Type = OpenIddictConstants.ClientTypes.Confidential
                });

                applications.Add(new OpenIddictApplication
                {
                    ClientId = "postman",
                    DisplayName = "Postman",
                    RedirectUri = "https://www.getpostman.com/oauth2/callback",
                    Type = OpenIddictConstants.ClientTypes.Public
                });

                context.SaveChanges();
            }
        }
    }
}

`

HolyHorseman commented 7 years ago

OMG, a part of above comment can't show format. Classes used 'long' as TKey in AppUser and AppRole. public class AppUser : IdentityUser<long> { } public class AppRole : IdentityRole<long> { }

kevinchalet commented 7 years ago

Can you please share your project.json?

HolyHorseman commented 7 years ago

Thank you for reply! The two json files are my project.json, the first is main web project, the second is class lib. They were all created in .NET Core by VS 2015 U3(version 14.0.25424.00 and framework version 4.6.01038).

First: (P.S. I check version in NuGet Manager. OpenIddict, OpenIddict.MVC and OpenIddict.EntityFrameworkCore are all 1.0.0-beta2-0537. )

`{ "userSecretsId": "aspnet-OpenIddictServerCoreMigration-30850025-e251-4045-aa8e-7341609985a0",

"dependencies": { "Microsoft.NETCore.App": { "version": "1.0.1", "type": "platform" }, "Microsoft.ApplicationInsights.AspNetCore": "1.0.0", "Microsoft.AspNetCore.Authentication.Cookies": "1.1.0", "Microsoft.AspNetCore.Diagnostics": "1.0.0", "Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore": "1.0.0", "Microsoft.AspNetCore.Identity.EntityFrameworkCore": "1.1.0", "Microsoft.AspNetCore.Mvc": "1.0.1", "Microsoft.AspNetCore.Razor.Tools": { "version": "1.0.0-preview2-final", "type": "build" }, "Microsoft.AspNetCore.Routing": "1.0.1", "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", "Microsoft.AspNetCore.Server.Kestrel": "1.0.1", "Microsoft.AspNetCore.StaticFiles": "1.0.0", "Microsoft.EntityFrameworkCore.SqlServer": "1.0.1", "Microsoft.EntityFrameworkCore.SqlServer.Design": { "version": "1.0.1", "type": "build" }, "Microsoft.EntityFrameworkCore.Tools": { "version": "1.0.0-preview2-final", "type": "build" }, "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", "Microsoft.Extensions.Configuration.Json": "1.0.0", "Microsoft.Extensions.Configuration.UserSecrets": "1.0.0", "Microsoft.Extensions.Logging": "1.1.0", "Microsoft.Extensions.Logging.Console": "1.0.0", "Microsoft.Extensions.Logging.Debug": "1.0.0", "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", "Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.0.0", "Microsoft.VisualStudio.Web.CodeGeneration.Tools": { "version": "1.0.0-preview2-final", "type": "build" }, "Microsoft.VisualStudio.Web.CodeGenerators.Mvc": { "version": "1.0.0-preview2-final", "type": "build" }, "OpenIddictServerCoreMigration.Model": "1.0.0-", "AspNet.Security.OAuth.Introspection": "1.0.0-alpha3-final", "AspNet.Security.OAuth.Validation": "1.0.0-alpha3-final", "NWebsec.AspNetCore.Middleware": "1.0.0-gamma1-15", "OpenIddict": "1.0.0-", "OpenIddict.EntityFrameworkCore": "1.0.0-", "OpenIddict.Mvc": "1.0.0-" },

"tools": { "BundlerMinifier.Core": "2.0.238", "Microsoft.AspNetCore.Razor.Tools": "1.0.0-preview2-final", "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final", "Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final", "Microsoft.Extensions.SecretManager.Tools": "1.0.0-preview2-final", "Microsoft.VisualStudio.Web.CodeGeneration.Tools": { "version": "1.0.0-preview2-final", "imports": [ "portable-net45+win8" ] } },

"frameworks": { "netcoreapp1.0": { "imports": [ "dotnet5.6", "portable-net45+win8" ] } },

"buildOptions": { "emitEntryPoint": true, "preserveCompilationContext": true, "warningsAsErrors": true, "embed": { "include": [ "Certificate.pfx" ] } },

"runtimeOptions": { "configProperties": { "System.GC.Server": true } },

"publishOptions": { "include": [ "wwwroot", "*/.cshtml", "appsettings.json", "web.config" ] },

"scripts": { "prepublish": [ "bower install", "dotnet bundle" ], "postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ] } }`

Second: `{ "version": "1.0.0-*",

"dependencies": { "Microsoft.AspNetCore.Identity.EntityFrameworkCore": "1.1.0", "NETStandard.Library": "1.6.1" },

"frameworks": { "netstandard1.6": { "imports": "dnxcore50" } } } `

kevinchalet commented 7 years ago

You're using 1.1.0 bits and I suspect your issue is caused by an important breaking/design change in ASP.NET Core. You can find more information here: https://github.com/openiddict/openiddict-core/pull/273#issuecomment-267634518 and https://github.com/aspnet/Security/issues/1044.

HolyHorseman commented 7 years ago

Perfect! It's much more important information. Now the practise project had run well. But it is weird to process dealing with the question. I had read two references and the others in those links. Finally, what I do is as below:

  1. According to #273(comment), remove some middlewares. It work well to signing in server from client. Browser can view page, but error happen after accepting authorization.

  2. So I read again your comment, and taken notice of update about MS lib(version 1.1.0). Well, I tried update all references by NuGet. That is a big surprise, the problem was resolved completely!

  3. That should be finish. However, I reverted some middlewares in step 1. Aha! It work well again.

Ok, I hope this comment could help the other people. Thank you once again, Kevin!

This is my new project.json.

`{ "userSecretsId": "aspnet-OpenIddictServerCoreMigration-30850025-e251-4045-aa8e-7341609985a0",

"dependencies": { "Microsoft.AspNetCore.Authentication.Cookies": "1.1.0", "Microsoft.AspNetCore.Identity.EntityFrameworkCore": "1.1.0", "Microsoft.AspNetCore.Razor.Tools": { "version": "1.0.0-preview2-final", "type": "build" }, "Microsoft.EntityFrameworkCore.Tools": { "version": "1.0.0-preview2-final", "type": "build" }, "Microsoft.Extensions.Logging": "1.1.0", "Microsoft.VisualStudio.Web.CodeGeneration.Tools": { "version": "1.0.0-preview2-final", "type": "build" }, "Microsoft.VisualStudio.Web.CodeGenerators.Mvc": { "version": "1.0.0-preview2-final", "type": "build" }, "OpenIddictServerCoreMigration.Model": "1.0.0-", "AspNet.Security.OAuth.Introspection": "1.0.0-", "AspNet.Security.OAuth.Validation": "1.0.0-", "NWebsec.AspNetCore.Middleware": "1.0.0-", "OpenIddict": "1.0.0-", "OpenIddict.EntityFrameworkCore": "1.0.0-", "OpenIddict.Mvc": "1.0.0-*", "Microsoft.EntityFrameworkCore.SqlServer.Design": { "version": "1.1.0", "type": "build" }, "Microsoft.Extensions.Configuration.UserSecrets": "1.1.0", "Microsoft.Extensions.Logging.Console": "1.1.0", "Microsoft.Extensions.Logging.Debug": "1.1.0", "Microsoft.Extensions.Options.ConfigurationExtensions": "1.1.0", "Microsoft.NETCore.App": { "version": "1.1.0", "type": "platform" }, "Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.1.0", "Microsoft.ApplicationInsights.AspNetCore": "1.0.2", "Microsoft.AspNetCore.Diagnostics": "1.1.0", "Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore": "1.1.0", "Microsoft.AspNetCore.Mvc": "1.1.0", "Microsoft.AspNetCore.Routing": "1.1.0", "Microsoft.AspNetCore.Server.Kestrel": "1.1.0", "Microsoft.AspNetCore.StaticFiles": "1.1.0", "Microsoft.EntityFrameworkCore.SqlServer": "1.1.0", "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.1.0", "Microsoft.AspNetCore.Server.IISIntegration": "1.1.0" },

"tools": { "BundlerMinifier.Core": "2.2.306", "Microsoft.AspNetCore.Razor.Tools": "1.0.0-preview2-final", "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final", "Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final", "Microsoft.Extensions.SecretManager.Tools": "1.0.0-preview2-final", "Microsoft.VisualStudio.Web.CodeGeneration.Tools": { "version": "1.0.0-preview2-final", "imports": [ "portable-net45+win8" ] } },

"frameworks": { "netcoreapp1.0": { "imports": [ "dotnet5.6", "portable-net45+win8" ] } },

"buildOptions": { "emitEntryPoint": true, "preserveCompilationContext": true, "warningsAsErrors": true, "embed": { "include": [ "Certificate.pfx" ] } },

"runtimeOptions": { "configProperties": { "System.GC.Server": true } },

"publishOptions": { "include": [ "wwwroot", "*/.cshtml", "appsettings.json", "web.config" ] },

"scripts": { "prepublish": [ "bower install", "dotnet bundle" ], "postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ] } } `