Transient Infinite Login Loop on Azure App Service - OpenIDConnect Auth with Azure AD

蓝咒 提交于 2020-01-25 07:33:06

问题


Background

So we have an app service that authenticates from Azure AD in another tenancy using OpenIdConnect.

Login works on a dev instance of IIS, and it works on our test app service. We saw the issue on test, and it vanished and didn't return during the entire testing phase of the project.

Now we've deployed to production, and we're seeing the issue again.

The Issue

What we're seeing is that everything will work fine for some time, and then after several hours, the issue will emerge again.

We have a work around fix to restore service - that is to enable and then disable app service authentication in the azure control panel. The opposite works too - to disable and then enable will restore service.

The Code

public void ConfigureAuth(IAppBuilder app)
        {
            //Azure AD Configuration
            app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
            app.UseCookieAuthentication(new CookieAuthenticationOptions());


            app.UseOpenIdConnectAuthentication(
                new OpenIdConnectAuthenticationOptions
                {
                    //sets client ID, authority, and RedirectUri as obtained from web config
                    ClientId = clientId,
                    ClientSecret = appKey,
                    Authority = authority,
                    RedirectUri = redirectUrl,

                    CallbackPath = new PathString("/"), //use this line for production and test


                    //page that users are redirected to on logout
                    PostLogoutRedirectUri = redirectUrl,

                    //scope - the claims that the app will make
                    Scope = OpenIdConnectScope.OpenIdProfile,
                    ResponseType = OpenIdConnectResponseType.CodeIdToken,

                    //setup multi-tennant support here, or set ValidateIssuer = true to config for single tennancy
                    TokenValidationParameters = new TokenValidationParameters()
                    {
                        ValidateIssuer = true,
                        //SaveSigninToken = true
                    },
                    Notifications = new OpenIdConnectAuthenticationNotifications
                    {
                        AuthenticationFailed = OnAuthenticationFailed,
                        AuthorizationCodeReceived = OnAuthorizationCodeReceived,
                    }
                }
                );
        }

        private async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedNotification context)
        {
            var code = context.Code;
            ClientCredential cred = new ClientCredential(clientId, appKey);
            string userObjectId = context.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
            //this token cache is stateful, we're going to populate it here, but we'll store it elsewhere in-case the user ends up accessing a different instance
            AuthenticationContext authContext = new AuthenticationContext(authority, new NaiveSessionCache(userObjectId));

            // If you create the redirectUri this way, it will contain a trailing slash.  
            // Make sure you've registered the same exact Uri in the Azure Portal (including the slash).
            Uri uri = new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path));
            AuthenticationResult result = await authContext.AcquireTokenByAuthorizationCodeAsync(code, uri, cred, "https://graph.windows.net");

            //populate the persistent token cache
            testdb2Entities5 db = new testdb2Entities5();
            PersistentTokenCache tc = await db.PersistentTokenCaches.FindAsync(userObjectId);
            //if null, populate a new item
            if (tc == null)
            {
                tc = new PersistentTokenCache();
                tc.object_id = userObjectId;
                tc.token = code;
                db.PersistentTokenCaches.Add(tc);
                await db.SaveChangesAsync();

            }
            else
            {
                tc.token = code;
                await db.SaveChangesAsync();
            }

        }

        //authentication failed notifications
        private Task OnAuthenticationFailed(AuthenticationFailedNotification<Microsoft.IdentityModel.Protocols
                                                                            .OpenIdConnect.OpenIdConnectMessage,
                                                                            OpenIdConnectAuthenticationOptions> context)
        {
            context.HandleResponse();
            context.Response.Redirect("/?errormessage=" + context.Exception.Message);
            return Task.FromResult(0);
        }

The Question

So, based on whatever enabling and disabling app-service authentication does, it's clearly fixing thing temporarily. So I'm thinking this is a cookie related problem - as that'd be the only thing transferring state between sessions. What on earth could be the issue here? And what steps do I need to take to diagnose and resolve the issue?


回答1:


So far, it seems like it was a problem with a known bug in Katana where the Katana cookie manager and the ASP .NET cookie manager clash and overwrite each other's cookies.

Here are some troubleshoots you could refer to:

1.Setting app.UseCookieAuthentication(new CookieAuthenticationOptions {CookieSecure == CookieSecureOption.Always}). This means that cookie could leak along with your auth.

2.Add SystemWebCookieManager in UseCookieAuthentication which is in the Microsoft.Owin.Host.SystemWeb Nuget package. Please refer to this thread.

3.Split cookie. Someone noticed that it was issue if Cookie characters are more than browsers limit (> 4096). So to overcome that issue, in set-cookie with around 4000 characters with each and when needed combine all cookie together to get original value.

For more details about how to add sign-in with Microsoft to an ASP.NET web app, please refer to this article.

Update:

Fix with install Kentor.OwinCookieSaver nuget package and add app.UseKentorOwinCookieSaver(); before app.UseCookieAuthentication(new CookieAuthenticationOptions());



来源:https://stackoverflow.com/questions/54191943/transient-infinite-login-loop-on-azure-app-service-openidconnect-auth-with-azu

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!