Friday, May 10, 2019

Federated Authentication with Insite Identity Server - Part 2

Customizing Insite Identity Server 

On the Insite side, we had to change the Identity Server ApplicationOptions to honor parameters that are being passed in from Sitecore:

EnableSignOutPrompt = false
EnablePostSignOutAutoRedirect = true 

These parameters the way they are set above allow for the log out redirect to bring the user back to Sitecore after the log out on the Insite side.

To make this happen we created the following class:

[BootStrapperOrder(26)]
    public class ConfigureIdentityServer : IStartupTask, IMultiInstanceDependency, IDependency, IExtension
    {
        public ConfigureIdentityServer()
        {
            DbMigrations.Run("identity");
            LogProvider.SetCurrentLogProvider(new NoopLogProvider());
            CookieAuthenticationOptions authenticationOptions = new CookieAuthenticationOptions();
            authenticationOptions.AuthenticationType = "ApplicationCookie";
            authenticationOptions.LoginPath = new PathString("/RedirectTo/SignInPage");
            authenticationOptions.ExpireTimeSpan = TimeSpan.FromMinutes(20.0);
            authenticationOptions.Provider = new CookieAuthenticationProvider()
            {
                OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<IdentityUserManager, IdentityUser>(TimeSpan.FromMinutes(20.0), (manager, user) => manager.CreateIdentityAsync(user, "ApplicationCookie"))
            };
            SecurityOptions.CookieOptions = authenticationOptions;
            ConfigureIdentityServer.ConfigureIdentityServerOptions();
            AntiForgeryConfig.UniqueClaimTypeIdentifier = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name";
        }

        /// <summary>
        /// Configures the identity server options.
        /// </summary>
        private static void ConfigureIdentityServerOptions()
        {
            string str = AppSettingProvider.Current["IdentityServerUrl"];
            SecurityOptions.IssuerUri = str.IsBlank() ? "http://www.dummy.com" : str;
            SecurityOptions.RequireSsl = AppSettingProvider.Current["IdentityServerRequireSsl"].EqualsIgnoreCase("true");
        }

        public void Run(IAppBuilder app, HttpConfiguration config)
        {
            app.CreatePerOwinContext(new Func<Insite.IdentityServer.AspNetIdentity.IdentityDbContext>(Insite.IdentityServer.AspNetIdentity.IdentityDbContext.Create));
            app.CreatePerOwinContext(new Func<IdentityFactoryOptions<IdentityUserManager>, IOwinContext, IdentityUserManager>(IdentityUserManager.Create));
            app.CreatePerOwinContext(new Func<IdentityFactoryOptions<IdentitySignInManager>, IOwinContext, IdentitySignInManager>(IdentitySignInManager.Create));
            app.UseKentorOwinCookieSaver();
            IdentityServerBearerTokenAuthenticationOptions adminTokenOptions = new IdentityServerBearerTokenAuthenticationOptions()
            {
                Authority = SecurityOptions.IssuerUri,
                RequiredScopes = new string[1]
              {
          "isc_admin_api"
              },
                NameClaimType = "preferred_username",
                RoleClaimType = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role",
                TokenProvider = new MixedOAuthBearerAuthenticationProvider(),
                IssuerName = SecurityOptions.IssuerUri,
                SigningCertificate = Certificate.Get(),
                ValidationMode = ValidationMode.Local
            };
            MapExtensions.Map(app, "/admin", admin =>
            {
                admin.UseIdentityServerBearerTokenAuthentication(adminTokenOptions);
                admin.MapSignalR();
            });

            MapExtensions.Map(app, "/secureElmah", admin => admin.UseIdentityServerBearerTokenAuthentication(adminTokenOptions));
            MapExtensions.Map(app, "/userfiles/_system", admin => admin.UseIdentityServerBearerTokenAuthentication(adminTokenOptions));
            MapExtensions.Map(app, "/api/v1/admin", admin => admin.UseIdentityServerBearerTokenAuthentication(adminTokenOptions));
            MapExtensions.Map(app, "/contentadmin", admin => admin.UseIdentityServerBearerTokenAuthentication(adminTokenOptions));
            MapExtensions.Map(app, "/webpageconverter", admin => admin.UseIdentityServerBearerTokenAuthentication(adminTokenOptions));
            foreach (string micrositeName in GetMicrositeNames())
            {
                MapExtensions.Map(app, "/" + micrositeName + "/contentadmin", admin => admin.UseIdentityServerBearerTokenAuthentication(adminTokenOptions));
            }

            foreach (string authenticationPath in SiteStartup.Instance.GetAdditionalAdminAuthenticationPaths())
            {
                MapExtensions.Map(app, authenticationPath, admin => admin.UseIdentityServerBearerTokenAuthentication(adminTokenOptions));
            }

            app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions()
            {
                Authority = SecurityOptions.IssuerUri,
                RequiredScopes = new string[1]
              {
          "iscapi"
              },
                NameClaimType = "preferred_username",
                RoleClaimType = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role",
                TokenProvider = new MixedOAuthBearerAuthenticationProvider(),
                IssuerName = SecurityOptions.IssuerUri,
                SigningCertificate = Certificate.Get(),
                ValidationMode = ValidationMode.Local
            });
            app.UseCookieAuthentication(SecurityOptions.CookieOptions);
            app.UseExternalSignInCookie("ExternalCookie");
            MapExtensions.Map(app, "/identity", identityApp => identityApp.UseIdentityServer(new IdentityServerOptions()
            {
                SiteName = "ATCC Identity Server",
                CspOptions = new CspOptions() { Enabled = false },
                SigningCertificate = Certificate.Get(),
                Factory = this.ConfigureCustomFactory(Factory.Configure(ConnectionStringProvider.Current.ConnectionStringName)),
                AuthenticationOptions = new AuthenticationOptions()
                {
                    IdentityProviders = new Action<IAppBuilder, string>(ConfigureIdentityProviders),
                    EnableSignOutPrompt = false,
                    EnablePostSignOutAutoRedirect = true
                },
                IssuerUri = SecurityOptions.IssuerUri,
                RequireSsl = SecurityOptions.RequireSsl
            }));
            IdentityUserManager.DataProtectionProvider = app.GetDataProtectionProvider();
        }

        private static IList<string> GetMicrositeNames()
        {
            return DependencyLocator.Current.GetInstance<IUnitOfWorkFactory>().GetUnitOfWork().GetRepository<Website>().GetTable().Select(o => o.MicroSiteIdentifiers).AsEnumerable().SelectMany(o => o.Split(',', ';')).Select(o => o.Trim()).Where(o => !o.IsBlank()).ToList();
        }

        private static void ConfigureIdentityProviders(IAppBuilder app, string signInAsType)
        {
            ConfigureIdentityServer.ConfigureFacebookLogin(app, signInAsType);
            ConfigureIdentityServer.ConfigureGoogleLogin(app, signInAsType);
            ConfigureIdentityServer.ConfigureWindowsAuthentication(app, signInAsType);
        }

        private static void ConfigureGoogleLogin(IAppBuilder app, string signInAsType)
        {
            GoogleSsoSettings googleSsoSettings = SettingsGroupProvider.Current.Get<GoogleSsoSettings>(default(Guid?));
            if (!googleSsoSettings.Enabled)
            {
                return;
            }

            string clientId = googleSsoSettings.ClientId;
            string clientSecret = googleSsoSettings.ClientSecret;
            if (clientId.IsBlank() || clientSecret.IsBlank())
            {
                return;
            }

            IAppBuilder app1 = app;
            GoogleOAuth2AuthenticationOptions options = new GoogleOAuth2AuthenticationOptions
            {
                Caption = "Google",
                ClientId = clientId,
                ClientSecret = clientSecret,
                SignInAsAuthenticationType = signInAsType,
                AuthenticationType = "Google"
            };
            app1.UseGoogleAuthentication(options);
        }

        private static void ConfigureFacebookLogin(IAppBuilder app, string signInAsType)
        {
            FacebookSsoSettings facebookSsoSettings = SettingsGroupProvider.Current.Get<FacebookSsoSettings>(default(Guid?));
            if (!facebookSsoSettings.Enabled)
            {
                return;
            }

            string appId = facebookSsoSettings.AppId;
            string appSecret = facebookSsoSettings.AppSecret;
            if (appId.IsBlank() || appSecret.IsBlank())
            {
                return;
            }

            FacebookAuthenticationOptions authenticationOptions = new FacebookAuthenticationOptions();
            authenticationOptions.AppId = appId;
            authenticationOptions.AppSecret = appSecret;
            authenticationOptions.Caption = "Facebook";
            authenticationOptions.SignInAsAuthenticationType = signInAsType;
            authenticationOptions.AuthenticationType = "Facebook";
            authenticationOptions.Provider = new FacebookAuthenticationProvider()
            {
                OnAuthenticated = async context =>
                {
                    foreach (KeyValuePair<string, JToken> keyValuePair in context.User)
                    {
                        string key = keyValuePair.Key;
                        if (key == "first_name")
                        {
                            context.Identity.AddClaim(new Claim("given_name", keyValuePair.Value.ToString(), "XmlSchemaString", "Facebook"));
                        }
                        else
                        {
                            if (key == "last_name")
                            {
                                context.Identity.AddClaim(new Claim("family_name", keyValuePair.Value.ToString(), "XmlSchemaString", "Facebook"));
                            }
                        }
                    }

                    int num = await Task.FromResult(false) ? 1 : 0;
                }
            };
            authenticationOptions.BackchannelHttpHandler = new ConfigureIdentityServer.FacebookBackChannelHandler();
            authenticationOptions.UserInformationEndpoint = "https://graph.facebook.com/v2.8/me?fields=id,name,email,first_name,last_name";
            FacebookAuthenticationOptions options = authenticationOptions;
            options.Scope.Add("email");
            options.Scope.Add("public_profile");
            app.UseFacebookAuthentication(options);
        }

        private static void ConfigureWindowsAuthentication(IAppBuilder app, string signInAsType)
        {
        }

        private IdentityServerServiceFactory ConfigureCustomFactory(IdentityServerServiceFactory identityServerServiceFactory)
        {
            identityServerServiceFactory.ViewService = (Registration<IViewService>)new CustomViewServiceRegistration<CustomViewService>();
            return identityServerServiceFactory;
        }

        private class FacebookBackChannelHandler : HttpClientHandler
        {
            protected override async Task<HttpResponseMessage> SendAsync(
              HttpRequestMessage request,
              CancellationToken cancellationToken)
            {
                if (!request.RequestUri.AbsolutePath.Contains("/oauth"))
                {
                    request.RequestUri = new Uri(request.RequestUri.AbsoluteUri.Replace("?access_token", "&access_token"));
                }

                return await base.SendAsync(request, cancellationToken);
            }
        }
    }

Previous: Federated Authentication with Insite Identity Server - Part 1

No comments:

Post a Comment