0

I am using Microsoft OWIN library with the Webform App and my app faces timeout and redirects to ADFS around almost an hour. I already tried extending the app session through web.config

<SessionState timeout = 90 />

I also tried extending the owin session with SlidingExpiration set to true.

app.UseCookieAuthentication sets to SlidingExpiration=true but it wont extend. Now after trying multiple approaches i wrote my own CookieProvider class and want to confirm with the devs if its right. My startup file looks like this

        public void ConfigureAuth(IAppBuilder app)
        {
            try
            {
                Util.Logger.Info("SSO additional logs: Entering the ActiveDirectory Startup file. \n");
                OAuth2Service.Instance = new OAuth2ServiceImplementation();
                GetSsoConfigValues();

                app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
                app.UseCookieAuthentication(new CookieAuthenticationOptions
                {
                    AuthenticationMode = AuthenticationMode.Active,
                    AuthenticationType = OpenIdConnectAuthenticationDefaults.AuthenticationType,
                    LoginPath = new PathString("/Pages/Login.aspx"),
                    CookieManager = new SystemWebChunkingCookieManager(),
                    CookieSameSite = Microsoft.Owin.SameSiteMode.None,
                    CookieName = "AspNet.Cookies." + Guid.NewGuid(),
                    SlidingExpiration =  true,
                    Provider =  new CookieAuthenticationProvider
                    {
                        OnResponseSignIn = context =>
                        {
                            context.Properties.AllowRefresh = true;
                        },
                        OnValidateIdentity = CustomOwinCookieProvider.OwinCookieCustomSlideExpiration
                    }
                });

                

                app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
                {
                    ClientId = _clientId,
                    ClientSecret = _clientSecret,
                    //Authority = _authority,
                    MetadataAddress = _metaDataAddress,
                    RedirectUri = _redirectUri,
                    PostLogoutRedirectUri = _redirectUri,
                    ResponseType = OpenIdConnectResponseType.CodeIdToken,
                    Scope = OpenIdConnectScope.OpenIdProfile,
                    TokenValidationParameters = new TokenValidationParameters { NameClaimType = "name" },
                    Notifications = new OpenIdConnectAuthenticationNotifications
                    {
                        AuthorizationCodeReceived = async n =>
                        {
                            string userName = n.AuthenticationTicket.Identity.Claims.ToList()?.FirstOrDefault(x => x.Type.Equals("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn", StringComparison.OrdinalIgnoreCase))?.Value;

                            Util.Logger.Info("SSO additional logs: AuthorizationCodeReceived for the username: " + userName + "\n");
                            IEnumerable<Claim> claimsTobeProcessed = n.AuthenticationTicket.Identity.Claims;

                            Util.Logger.Info("SSO additional logs: Exiting AuthorizationCodeReceived event");
                            OAuth2Service.Instance.ProcessSso(userName, claimsTobeProcessed, n.JwtSecurityToken);

                        },

                        AuthenticationFailed = async n =>
                        {
                            Util.Logger.Info("SSO additional logs: Entering in AuthenticationFailed event");
                            Util.HandleException(new Exception(message: n.Exception.Message, n.Exception), Framework.General.Severity.SsoError);
                            // Specific sporadic error which requires cache clean up
                            if (n.Exception.Message.Contains("IDX21323"))
                            {
                                OAuth2Service.Instance.LogoutPageRedirect(SingleSignOnAuthenticationState.CacheIssue,null);
                            }
                            else
                            {
                                OAuth2Service.Instance.LogoutPageRedirect(SingleSignOnAuthenticationState.SsoSystemFailure, null);
                            }
                            await Task.FromResult(true);
                        }
                    },
                });

            }
            catch(Exception ex)
            {
                if (ex is ThreadAbortException)
                {
                    return;
                }

                Util.HandleException(ex, Framework.General.Severity.SsoError);
                OAuth2Service.Instance.LogoutPageRedirect(Framework.Plugins.SingleSignOn.SingleSignOnAuthenticationState.SsoSystemFailure, null);
                
            }
        }
public static class CustomOwinCookieProvider
    {
        public static Task OwinCookieCustomSlideExpiration(CookieValidateIdentityContext ctx)
        {
            Util.Logger.Debug("********START OwinCookieCustomSlideExpiration********");

            try
            {
                var expireUtc = ctx.Properties.ExpiresUtc.Value;
                var issuedUtc = ctx.Properties.IssuedUtc.Value;

                var diff = expireUtc-issuedUtc;
                var halfTimeInMins = diff.TotalMinutes / 2;

                Util.Logger.Debug("maxOwinCookieTimeinMins: " + diff.TotalMinutes.ToString());

                var issuedTime = issuedUtc;
                long halftimeTicks = issuedTime.AddMinutes(halfTimeInMins).Ticks;

                long currentUtcTicks = DateTimeOffset.UtcNow.Ticks;

                var timeElapsedSinceTokenIssued = DateTimeOffset.UtcNow.Subtract(issuedTime);

                if(timeElapsedSinceTokenIssued.TotalMinutes >= 0)
                {
                    Util.Logger.Debug("timeElapsedSinceCookieIssuedinMins: " + timeElapsedSinceTokenIssued.TotalMinutes.ToString() + "\n");
                }

                

                if (currentUtcTicks > expireUtc.Ticks)
                {
                    Util.Logger.Debug("OwinCookie is expired. Redirecting to IDP... \n");

                    ctx.OwinContext.Authentication.SignOut(ctx.Options.AuthenticationType);
                    ctx.RejectIdentity();
                    return Task.FromResult(0);
                }


                var timeLeftBeforeCookieRenewal =  halfTimeInMins - timeElapsedSinceTokenIssued.TotalMinutes;

                if(timeLeftBeforeCookieRenewal >= 0)
                {
                    Util.Logger.Debug("timeLeftBeforeCookieRenewalinMins: " + timeLeftBeforeCookieRenewal.ToString() + "\n");
                }

                if (currentUtcTicks >= halftimeTicks)
                {
                    Util.Logger.Debug("OwinCookie passed the halftime mark. Extendng the cookie expiry for " + diff.TotalMinutes.ToString() + " mins.\n");

                    var identity = ctx.Identity;
                    var authTicket = new AuthenticationProperties() { //IsPersistent = true, 
                                                                      ExpiresUtc = DateTime.UtcNow.AddMinutes(diff.TotalMinutes), 
                                                                      IssuedUtc = DateTime.UtcNow };

                    HttpContext.Current.GetOwinContext().Authentication.SignIn(authTicket, identity);
                }
            }
            catch(Exception ex)
            {
                var exception = new Exception("Error occurred in CustomOwinCookieProvider.OwinCookieCustomSlideExpiration ", ex);
                Util.HandleException(exception, Framework.General.Severity.SsoError);
            }

            Util.Logger.Debug("********END OwinCookieCustomSlideExpiration********");

            return Task.FromResult(0);
        }
    }

I am expecting devs to verify my ValidateIdentity on cookie approach and let me know if it is right thing to do with the Microsoft OWIN.

0 Answers0