aws / aws-aspnet-cognito-identity-provider

ASP.NET Core Identity Provider for Amazon Cognito
https://aws.amazon.com/developer/language/net/
Apache License 2.0
213 stars 89 forks source link

Using the Cognito provider and debugging in iis it works but when using docker the sign in fails #184

Closed jamesneizer closed 3 years ago

jamesneizer commented 3 years ago

The Question

I have used the sample application as reference to add login and user management to my application, however I cannot wokr out how or why it doesn't work within docker if I run it in iis express it works just like the sample app however if I try it from docker it fails with the following:

An unhandled exception occurred while processing the request. IOException: The server returned an invalid or unrecognized response. System.Net.Http.HttpConnection.FillAsync()

HttpRequestException: An error occurred while sending the request. System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken)

Im clearly missing something obvious but cannot figure it out any ideas would be appreciated, guessing it communication between docker and cognito via the sdk.

Environment


This is a :question: general question

ashishdhingra commented 3 years ago

Hi @jamesneizer,

Good morning.

Could you please share the sample code and the steps used to deploy application to Docker to troubleshoot the issue? As you pointed out, it appears to be some connection issue between docker and Cognito service.

Thanks, Ashish

jamesneizer commented 3 years ago

Thanks for getting back to me I am using docker desktop and it deploys from visual studio 2019 debugging using docker.

jamesneizer commented 3 years ago
 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)
        {
            services.AddCognitoIdentity();

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

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseDatabaseErrorPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseCookiePolicy();

            app.UseAuthentication();

            app.UseMvc();
        }
    }
}
jamesneizer commented 3 years ago

Thats the startup using the sample project just inject my credentials from the appsettings file

jamesneizer commented 3 years ago
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
        {
            returnUrl = returnUrl ?? Url.Content("~/");

            if (ModelState.IsValid)
            {
                **var result = await _signInManager.PasswordSignInAsync(Input.UserName, Input.Password, Input.RememberMe, lockoutOnFailure: false);**
                if (result.Succeeded)
                {
                    _logger.LogInformation("User logged in.");
                    return LocalRedirect(returnUrl);
                }
                else if (result.RequiresTwoFactor)
                {
                    return RedirectToPage("./LoginWith2fa", new { ReturnUrl = returnUrl, RememberMe = Input.RememberMe });
                }
                else if (result.IsCognitoSignInResult())
                {
                    if (result is CognitoSignInResult cognitoResult)
                    {
                        if (cognitoResult.RequiresPasswordChange)
                        {
                            _logger.LogWarning("User password needs to be changed");
                            return RedirectToPage("./ChangePassword");
                        }
                        else if (cognitoResult.RequiresPasswordReset)
                        {
                            _logger.LogWarning("User password needs to be reset");
                            return RedirectToPage("./ResetPassword");
                        }
                    } 

                }

                ModelState.AddModelError(string.Empty, "Invalid login attempt.");
                return Page();
            }

            // If we got this far, something failed, redisplay form
            return Page();
        }
jamesneizer commented 3 years ago

An unhandled exception occurred while processing the request. IOException: The server returned an invalid or unrecognized response. System.Net.Http.HttpConnection.FillAsync()

HttpRequestException: An error occurred while sending the request. System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken)

jamesneizer commented 3 years ago

ystem.Net.Http.HttpRequestException: An error occurred while sending the request. ---> System.IO.IOException: The server returned an invalid or unrecognized response. at System.Net.Http.HttpConnection.FillAsync() at System.Net.Http.HttpConnection.ReadNextResponseHeaderLineAsync(Boolean foldedHeadersAllowed) at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken) --- End of inner exception stack trace --- at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken) at System.Net.Http.HttpConnectionPool.SendWithNtConnectionAuthAsync(HttpConnection connection, HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken) at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken) at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) at System.Net.Http.HttpClient.FinishSendAsyncUnbuffered(Task1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts) at System.Net.Http.HttpClient.GetStringAsyncCore(Task1 getTask) at Amazon.Runtime.Internal.Util.AsyncHelpers.<>c__DisplayClass1_11.<<RunSync>b__0>d.MoveNext() --- End of stack trace from previous location where exception was thrown --- at Amazon.Runtime.Internal.Util.AsyncHelpers.ExclusiveSynchronizationContext.BeginMessageLoop() in D:\JenkinsWorkspaces\trebuchet-stage-release\AWSDotNetPublic\sdk\src\Core\Amazon.Runtime\Internal\Util\_mobile\AsyncHelpers.cs:line 142 at Amazon.Runtime.Internal.Util.AsyncHelpers.RunSync[T](Func1 task) in D:\JenkinsWorkspaces\trebuchet-stage-release\AWSDotNetPublic\sdk\src\Core\Amazon.Runtime\Internal\Util_mobile\AsyncHelpers.cs:line 87 at Amazon.Util.AWSSDKUtils.DownloadStringContent(Uri uri, TimeSpan timeout, IWebProxy proxy) in D:\JenkinsWorkspaces\trebuchet-stage-release\AWSDotNetPublic\sdk\src\Core\Amazon.Util\AWSSDKUtils.cs:line 1008 at Amazon.Util.EC2InstanceMetadata.GetItems(String relativeOrAbsolutePath, Int32 tries, Boolean slurp) in D:\JenkinsWorkspaces\trebuchet-stage-release\AWSDotNetPublic\sdk\src\Core\Amazon.Util_bcl+netstandard\EC2InstanceMetadata.cs:line 513 at Amazon.Util.EC2InstanceMetadata.get_IAMSecurityCredentials() in D:\JenkinsWorkspaces\trebuchet-stage-release\AWSDotNetPublic\sdk\src\Core\Amazon.Util_bcl+netstandard\EC2InstanceMetadata.cs:line 311 at Amazon.Runtime.DefaultInstanceProfileAWSCredentials.FetchCredentials() in D:\JenkinsWorkspaces\trebuchet-stage-release\AWSDotNetPublic\sdk\src\Core\Amazon.Runtime\Credentials_bcl+netstandard\DefaultInstanceProfileAWSCredentials.cs:line 142 at Amazon.Runtime.DefaultInstanceProfileAWSCredentials.GetCredentials() in D:\JenkinsWorkspaces\trebuchet-stage-release\AWSDotNetPublic\sdk\src\Core\Amazon.Runtime\Credentials_bcl+netstandard\DefaultInstanceProfileAWSCredentials.cs:line 88 at Amazon.Runtime.DefaultInstanceProfileAWSCredentials.GetCredentialsAsync() in D:\JenkinsWorkspaces\trebuchet-stage-release\AWSDotNetPublic\sdk\src\Core\Amazon.Runtime\Credentials_bcl+netstandard\DefaultInstanceProfileAWSCredentials.cs:line 106 at Amazon.Runtime.Internal.CredentialsRetriever.InvokeAsync[T](IExecutionContext executionContext) in D:\JenkinsWorkspaces\trebuchet-stage-release\AWSDotNetPublic\sdk\src\Core\Amazon.Runtime\Pipeline\Handlers\CredentialsRetriever.cs:line 90 at Amazon.Runtime.Internal.RetryHandler.InvokeAsync[T](IExecutionContext executionContext) at Amazon.Runtime.Internal.RetryHandler.InvokeAsync[T](IExecutionContext executionContext) in D:\JenkinsWorkspaces\trebuchet-stage-release\AWSDotNetPublic\sdk\src\Core\Amazon.Runtime\Pipeline\RetryHandler\RetryHandler.cs:line 137 at Amazon.Runtime.Internal.CallbackHandler.InvokeAsync[T](IExecutionContext executionContext) at Amazon.Runtime.Internal.CallbackHandler.InvokeAsync[T](IExecutionContext executionContext) at Amazon.Runtime.Internal.ErrorCallbackHandler.InvokeAsync[T](IExecutionContext executionContext) at Amazon.Runtime.Internal.MetricsHandler.InvokeAsync[T](IExecutionContext executionContext) at Amazon.Extensions.CognitoAuthentication.CognitoUserPool.FindByIdAsync(String userID) at Amazon.AspNetCore.Identity.Cognito.CognitoUserStore1.FindByIdAsync(String userId, CancellationToken cancellationToken) at Amazon.AspNetCore.Identity.Cognito.CognitoUserManager1.FindByIdAsync(String userId) at Amazon.AspNetCore.Identity.Cognito.CognitoSignInManager`1.PasswordSignInAsync(String userId, String password, Boolean isPersistent, Boolean lockoutOnFailure) at Samples.Areas.Identity.Pages.Account.LoginModel.OnPostAsync(String returnUrl) in C:\Users\james.ellis\source\repos\aws-aspnet-cognito-identity-provider\samples\Samples\Areas\Identity\Pages\Account\Login.cshtml.cs:line 74 at Microsoft.AspNetCore.Mvc.RazorPages.Internal.ExecutorFactory.GenericTaskHandlerMethod.Convert[T](Object taskAsObject) at Microsoft.AspNetCore.Mvc.RazorPages.Internal.ExecutorFactory.GenericTaskHandlerMethod.Execute(Object receiver, Object[] arguments) at Microsoft.AspNetCore.Mvc.RazorPages.Internal.PageActionInvoker.InvokeHandlerMethodAsync() at Microsoft.AspNetCore.Mvc.RazorPages.Internal.PageActionInvoker.InvokeNextPageFilterAsync() at Microsoft.AspNetCore.Mvc.RazorPages.Internal.PageActionInvoker.Rethrow(PageHandlerExecutedContext context) at Microsoft.AspNetCore.Mvc.RazorPages.Internal.PageActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.RazorPages.Internal.PageActionInvoker.InvokeInnerFilterAsync() at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter() at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context) at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) 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.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.MigrationsEndPointMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.Invoke(HttpContext httpContext) at Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.Invoke(HttpContext httpContext) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

ashishdhingra commented 3 years ago

Hi @jamesneizer,

Thanks for your response. One question, how are you passing AWS credentials to Docker? I came across article Enabling Docker debug output, although it is not on Windows environment and not related to Cognito, but if you see the last debug output, it mentions the same error that you are getting.

Thanks, Ashish

jamesneizer commented 3 years ago

Thank you I'll check it out.

jamesneizer commented 3 years ago

Also I didn't pass any credentials to the container its in an appsettings file with the code which is picked up by the package I use. At least thats how I think it works.

ashishdhingra commented 3 years ago

Hi @jamesneizer,

From the stack trace, it appears to fail in DefaultInstanceProfileAWSCredentials.cs, which means it didn't pick up the credentials from appsettings.json and tried to get from EC2 instance profile (recommended for production environments). The docker container is not an EC2 instance, hence it fails. Also, appsettings.json supports the options listed on the page https://docs.aws.amazon.com/sdk-for-net/v3/developer-guide/net-dg-config-netcore.html. Are you trying to load the credentials using AWS Profile? If yes, these would not available on docker. The workaround you could use is to pass environment variables to Docker, but I'm not sure if it would work.

Thanks, Ashish

jamesneizer commented 3 years ago

Thanks you this looks like what I needed I will confirm after some more testing again thanks again James.

github-actions[bot] commented 3 years ago

This issue has not recieved a response in 2 weeks. If you want to keep this issue open, please just leave a comment below and auto-close will be canceled.