aspnet / Security

[Archived] Middleware for security and authorization of web apps. Project moved to https://github.com/aspnet/AspNetCore
Apache License 2.0
1.27k stars 600 forks source link

OpenIDConnect Correlation Error Amazon Cognito #1867

Closed devnull closed 5 years ago

devnull commented 5 years ago

Background

I am using Amazon Cognito (https://aws.amazon.com/cognito/) as an Identity Provider. I've been able to successfully configure it using the OpenIDConnect Middleware. Logging in and out works, however, when you log out of the ASP.NET Core app, and log back in, a 'Correlation Error' occurs. It's consistent - it happens every time after the first login, and is easily reproducible.

With Amazon Cognito - I'm just using the defaults. There's no special configuration or anything custom here. Amazon Cognito has a free tier with Amazon Web Services.

Investigation

I've performed a lot of research trying to find the cause. I have previously read that Load Balancers in front of several web app servers, or the DataProtection framework can cause these issues, but I'm not using either. (example: https://stackoverflow.com/questions/50459764/error-correlation-failed-in-asp-net-core-mvc-with-azure-ad-authentication)

I still don't know exactly what the cause is.

Steps to Reproduce

  1. Open Visual Studio -> New Project -> New ASP.NET Core Web Application
  2. Create a new AWS Cognito UserPool with all default settings
  3. Add the following for configure services
        public void ConfigureServices(IServiceCollection services)
        {
            //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;
            //});

            var clientSecret = "AMAZONCOGNITOCLIENTSECRETHERE";
            var clientId = "AMAZONCOGNITOCLIENTIDHERE";
            var metadataAddress = "https://cognito-idp.ap-southeast-2.amazonaws.com/ap-southeast-2_USERPOOLIDGOESHERE/.well-known/openid-configuration";
            var logOutUrl = "https://AMAZON-COGNITO-USERPOOL-SUBDOMAIN-GOES-HERE.auth.ap-southeast-2.amazoncognito.com/logout?client_id=" + clientId;
            var baseUrl = "http://localhost:15153/";

            services.AddAuthentication(options =>
            {
                options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
            })
            .AddCookie()
            .AddOpenIdConnect(options =>
            {
                options.ResponseType = "code";
                options.MetadataAddress = metadataAddress;
                options.ClientId = clientId;
                options.ClientSecret = clientSecret;
                options.GetClaimsFromUserInfoEndpoint = true;
                options.Scope.Add("email");
                options.Events = new OpenIdConnectEvents
                {
                    OnRedirectToIdentityProviderForSignOut = (context) =>
                    {
                        var logoutUri = logOutUrl;

                        logoutUri += $"&redirect_uri={Uri.EscapeDataString(baseUrl + "signin-oidc")}";
                        logoutUri += $"&response_type={options.ResponseType}";

                        context.Response.Redirect(logoutUri);
                        context.HandleResponse();

                        return Task.CompletedTask;
                    }
                };
            });

            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
        }
  1. Add app.UseAuthentication(); in the Configure method.
  2. Save and Run Project
  3. Login - works! Redirected to the Home page
  4. Logout by hitting http://localhost:15153/Home/Logout. Works fine, redirects to Amazon Cognito login screen
  5. Login again
  6. Correlation Error.

I can then navigate to http://localhost:15153/Home and it works as expected - I am logged in even though I receive this correlation error, upon redirection from AWS Cognito.

Logs

correlation-failed

Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://localhost:15153/home/logout
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Route matched with {action = "LogOut", controller = "Home"}. Executing action OpenIDConnectWithCognito.Controllers.HomeController.LogOut (OpenIDConnectWithCognito) Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executing action method OpenIDConnectWithCognito.Controllers.HomeController.LogOut (OpenIDConnectWithCognito) - Validation state: Valid Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action method OpenIDConnectWithCognito.Controllers.HomeController.LogOut (OpenIDConnectWithCognito), returned result Microsoft.AspNetCore.Mvc.SignOutResult in 0.0082ms. Microsoft.AspNetCore.Mvc.SignOutResult:Information: Executing SignOutResult with authentication schemes (Cookies, OpenIdConnect). Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler:Information: AuthenticationScheme: Cookies signed out. Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action OpenIDConnectWithCognito.Controllers.HomeController.LogOut (OpenIDConnectWithCognito) in 13.8532ms Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 25.2191ms 302 Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://localhost:15153/signin-oidc?code=92176e28-ba79-46c6-816b-14befe7e84e8
Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler:Warning: .AspNetCore.Correlation. state property not found. Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler:Information: Error from RemoteAuthentication: Correlation failed.. Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware:Error: An unhandled exception has occurred while executing the request.

System.Exception: An error was encountered while handling the remote login. ---> System.Exception: Correlation failed. --- End of inner exception stack trace --- at Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler`1.HandleRequestAsync() at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context) Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 77.4666ms 500 text/html; charset=utf-8

Git Repository

I've pushed up a project to GitHub with the code I used to reproduce the issue. https://github.com/devnull/AmazonCognitoASPNetCoreOpenIdConnect

Tratcher commented 5 years ago

Can you share a Fiddler trace of the success and failure scenarios? That's the best way to track down what's missing and why.

devnull commented 5 years ago

Yeah sure! Please find them attached.

Captures.zip

Tratcher commented 5 years ago

That failure trace seems to be skipping a step. Here's what I see:

  1. localhost logout, 302 to auth server
  2. Auth server logout, 302 to auth server login
  3. Auth server log in page, 200
  4. POST to Auth server login, 302 to localhost signin-oidc
  5. Localhost signin-oidc failure

Step 4 is invalid. The OIDC middleware does not support sign-in requests initiated from the identity server, all sign-in requests have to be initiated from the application. This allows the middleware to track each signin and prevent some forms of spoofing.

Your other trace worked because the signin was initiated from the app, not from the auth server.

I suggest changing step 3 to give a link back to the application to re-initiate login.

devnull commented 5 years ago

Thank you very much for looking at this.

At first when I read your answer, I was confused because I thought the redirection was happening between my app, not at the IdP! As you pointed out, the failure exists when AWS Cognito redirects itself back to the logout endpoint.

The bit that caught me out was: If the Logout_URI does not match exactly what is configured in AWS Cognito app client settings, it will initiate the re-login flow as described in this stackoverflow answer. In my case I left a trailing slash.

I'm going to write a blog post about this, because I'm sure it will catch people out - thanks again @Tratcher .

Eilon commented 5 years ago

Closing because no further action required on this issue.