November Happy Hour will be moved to Thursday December 5th.

Multi-Domain Authentication Cookie (ADFS)

Vote:
 

We are facing an issue using authentication cookies for our multi-domain setup.

We've referenced serveral documents including: 

https://world.episerver.com/forum/developer-forum/-Episerver-75-CMS/Thread-Container/2020/2/how-to-integrate-adfs-with-episerver-in-case-run-as-multiple-sites/

It seems I have a disconnect understanding how the site-level cookie domains are created in a way that any domain under EpiServer can recognize/validate them after the user logs in using ADFS.

For example:

User visits into site1.domainone.com => redirected to ADFS login => succesfully logs in => saml assertion sent to EPI server => site level cookie created and user authenticated.

User now visits site2.domaintwo.com (still same epi server instance) => redirected to ADFS login repeatedly no matter how many times user logs in.

Here is our startup configuration:

public class Startup
    {
        const string LogoutUrl = "/util/logout.aspx";
        public void Configuration(IAppBuilder app)
        {
            string environmentName = ConfigurationManager.AppSettings["episerver:EnvironmentName"]?.ToLower();
            if (environmentName == "preproduction" || environmentName == "production")  {
                var wtrealm = ConfigurationManager.AppSettings["wtrealm"];
                var ADFSMetadata = ConfigurationManager.AppSettings["ADFSMetadata"];

                //Enable cookie authentication, used to store the claims between requests
                app.SetDefaultSignInAsAuthenticationType(WsFederationAuthenticationDefaults.AuthenticationType);
                app.UseCookieAuthentication(new CookieAuthenticationOptions
                {
                    AuthenticationType = WsFederationAuthenticationDefaults.AuthenticationType
                    CookieDomain = ".domainone.com"
                });
                //Enable federated authentication
                app.UseWsFederationAuthentication(new WsFederationAuthenticationOptions()
                {
                    //Trusted URL to federation server meta data
                    MetadataAddress = ADFSMetadata,
                    //Value of Wtreal must *exactly* match what is configured in the federation server
                    Wtrealm = wtrealm,

                    //TokenValidationParameters defines how the identity is evaluated for .IsInRole() and .Name
                    //Setting the NameClaimType to identify Identity.Name by the ADFS claim "nameidentifier".
                    //Typically, nameidentifier is the ID of the user in the IDP, and Name is username (i.e. name:{sid-value}, nameidentifier:{mxh018})
                    TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
                    {
                        NameClaimType = ClaimTypes.NameIdentifier
                    },
                    Notifications = new WsFederationAuthenticationNotifications()
                    {
                        RedirectToIdentityProvider = (ctx) =>
                        {
                            //HandleMultiSiteReturnUrl(ctx);
                            //To avoid a redirect loop to the federation server send 403 when user is authenticated but does not have access
                            if (ctx.OwinContext.Response.StatusCode == 401 && ctx.OwinContext.Authentication.User.Identity.IsAuthenticated)
                            {
                                ctx.OwinContext.Response.StatusCode = 403;
                                ctx.HandleResponse();
                            }

                            ctx.ProtocolMessage.Wreply = SiteDefinition.Current.SiteUrl.ToString() + "EPiServer";
                            return Task.FromResult(0);
                        },
                        SecurityTokenValidated = (ctx) =>
                        {
                            //Ignore scheme/host name in redirect Uri to make sure a redirect to HTTPS does not redirect back to HTTP
                            var redirectUri = new Uri(ctx.AuthenticationTicket.Properties.RedirectUri, UriKind.RelativeOrAbsolute);

                            if (redirectUri.IsAbsoluteUri)
                            {
                              if(redirectUri.PathAndQuery.ToLower().Contains("/cms")){
                               ctx.AuthenticationTicket.Properties.RedirectUri = redirectUri.PathAndQuery;
                              }
                              else {
                                ctx.AuthenticationTicket.Properties.RedirectUri = redirectUri.PathAndQuery + "/CMS/";
                              }
                            }

                            //Sync user and the roles to EPiServer in the background
                            ServiceLocator.Current.GetInstance<ISynchronizingUserService>().SynchronizeAsync(ctx.AuthenticationTicket.Identity);

                            return Task.FromResult(0);
                        }

                    }
                });
                //Add stage marker to make sure WsFederation runs on Authenticate (before URL Authorization and virtual roles)
                app.UseStageMarker(PipelineStage.Authenticate);

                //Tell antiforgery to use the name claim
                AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;

                app.Map(LogoutUrl, map =>
                {
                    map.Run(ctx =>
                    {
                        ctx.Authentication.SignOut();
                        return Task.FromResult(0);
                    });
                });
            }
        }
    }

We think the root issue might be related to the explicit setting of the cookie domain ".domainone.com", but the original developers indicated that this was needed for some reason.

I'm just a little confused about how the application would know the authentication cookie is good, if there are multiple domains.

#253359
Apr 16, 2021 15:59
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.