代码之家  ›  专栏  ›  技术社区  ›  Matthew

Identity Server 3+ASP。NET Core 2.0 MVC应用程序-联合单一注销,不包括在结束会话之前重定向到ADFS

  •  1
  • Matthew  · 技术社区  · 7 年前

    我的web应用程序是Identity Server 3 STS的客户端,它与外部IdP的ADF联合。登录效果很好。从STS注销即可。但在IdSrv3会话结束并最终重定向到应用程序之前,我一直无法让IdSrv3重定向到ADFS进行注销。

    如果我理解正确,我应该能够在注销后将ADFS发回RP(IdSrv3),此时IdSrv3

    阅读文档: https://identityserver.github.io/Documentation/docsv2/advanced/federated-post-logout-redirect.html

    通过IdSrv3进行跟踪,我从来没有看到过重定向到ADFS进行注销的尝试,所以我假设我缺少这里的配置。

    在IdSrv3上,以下是(我相信)相关的配置组件:

    其他身份提供者的配置:

            var wsFed = new WsFederationAuthenticationOptions
            {
                Wtrealm = ConfigurationManager.AppSettings["Wtrealm"],
                MetadataAddress = metaDataAddress,
                AuthenticationType = "ADFS",
                Caption = "ACME ADFS",
                SignInAsAuthenticationType = signInAsType
            };
    

    IdSrv3中间件:

    coreApp.UseIdentityServer(
                        new IdentityServerOptions
                        {
    
                            SiteName = "eFactoryPro Identity Server",
                            SigningCertificate = Cert.Load(),
                            Factory = factory,
                            RequireSsl = true,
    
                            AuthenticationOptions = new AuthenticationOptions
                            {
                                IdentityProviders = ConfigureAdditionalIdentityProviders,
                                EnablePostSignOutAutoRedirect = true,
                                EnableSignOutPrompt = false,
                                EnableAutoCallbackForFederatedSignout = true
                            },
                            LoggingOptions = new LoggingOptions
                            {
                                EnableHttpLogging = true,
                                EnableKatanaLogging = true,
                                //EnableWebApiDiagnostics = true,
                                //WebApiDiagnosticsIsVerbose = true
                            }
                        });
                    coreApp.Map("/signoutcallback", cleanup =>
                    {
                        cleanup.Run(async ctx =>
                        {
                            var state = ctx.Request.Cookies["state"];
                            await ctx.Environment.RenderLoggedOutViewAsync(state);
                        });
                    });
                });
    

    使现代化 :请参阅已接受的答案-应在IdSrv3侧处理重定向到IdP以注销,以重定向到 外部IdP(ADFS)

           public static void ConfigureAuth(this IServiceCollection services,
          ITicketStore distributedStore,
          Options.AuthenticationOptions authOptions)
        {
    
            services.AddDataProtection();
    
            services.AddAuthentication(options =>
                {
                    options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                    options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
                    options.DefaultSignOutScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                }).AddCookie(options =>
                {
                    options.ExpireTimeSpan = TimeSpan.FromHours(8);
                    options.SlidingExpiration = true;
                    options.SessionStore = distributedStore;
                })
                .AddOpenIdConnect(options =>
                {
                    options.Authority = authOptions.Authority;
                    options.ClientId = authOptions.ClientId;
                    options.ClientSecret = authOptions.ClientSecret;
    
                    options.ResponseType = "code id_token";
    
                    options.Scope.Add("openid");
                    options.Scope.Add("profile");
                    options.Scope.Add("roles");
                    options.Scope.Add("email");
                    options.Scope.Add("offline_access");
    
                    options.RequireHttpsMetadata = false;
    
                    options.GetClaimsFromUserInfoEndpoint = true;
    
                    options.SaveTokens = true;
    
                    options.Events = new OpenIdConnectEvents()
                    {
                        OnRedirectToIdentityProviderForSignOut = n =>
                        {
    
                            var idTokenHint = n.ProtocolMessage.IdTokenHint;
    
                            if (!string.IsNullOrEmpty(idTokenHint))
                            {
                                var sessionId = n.HttpContext?.Session?.Id;
                                var signOutRedirectUrl = n.ProtocolMessage.BuildRedirectUrl();
    
                                if (sessionId != null)
                                {                                    
                                    n.HttpContext.Response.Cookies.Append("state", sessionId);
                                }
    
                                n.HttpContext?.Session?.Clear();
    
                                n.Response.Redirect(signOutRedirectUrl);
                            }
    
                            return Task.FromResult(0);
                        }
                    };
                });
    
        }
    

    从文档中,我应该将“注销消息id”传递到该“状态”cookie中。然而,这种扩展方法在ASP中不起作用。NET Core 2.0,因为我们再也无法访问OwinContext了。

    var signOutMessageId = n.OwinContext.Environment.GetSignOutMessageId();

    看起来这个cookie实际上只是在所有重定向中保持状态所必需的,这样在我的客户端应用程序的PostLogoutUri被命中后,它当前设置为“ https://myapp/signout-callback-oidc “,消息id可用于完成会话清理。

    我还不清楚“EnableAutoCallbackForFederatedSignout=true”设置在IdSrv3配置中扮演什么角色。

    从这个描述和代码可以看出,这使我不必在ADFS注销时设置“WReply”参数: https://github.com/IdentityServer/IdentityServer3/issues/2613 " https://myIdSrv3/core/signoutcallback “如果此设置为“true”,则自动执行。

    如果有人能提供任何指导,我们将不胜感激。

    1 回复  |  直到 7 年前
        1
  •  2
  •   Matthew    7 年前

    这个问题的根本原因是我的UserService实现。在那里,我重写了“AuthenticateExternalAsync()”方法,但没有指定 外部身份提供者 在AuthenticateResult对象中。

    以下是正确的实现:

            public override Task AuthenticateExternalAsync(ExternalAuthenticationContext context)
            {
    
             ...
    
                    context.AuthenticateResult = new AuthenticateResult(
                        user.Id, 
                        user.UserName, 
                        new List<Claim>(), 
                        context.ExternalIdentity.Provider);
    
                return Task.FromResult(0);
            }
    

    一旦在AuthenticateResult中指定了外部Idp,我就能够处理WsFederationAuthenticationNotifications。重定向到IdentityProvider事件。

    为了完整性起见,下面是我处理ADFS与WsFed的联合注销(客户端初始化)的代码。它或多或少直接来自IdSrv3文档:

     Notifications = new WsFederationAuthenticationNotifications()
                {
                    RedirectToIdentityProvider = n =>
                    {
    
                        if (n.ProtocolMessage.IsSignOutMessage)
                        {
                            var signOutMessageId = n.OwinContext.Environment.GetSignOutMessageId();
                            if (signOutMessageId != null)
                            {
                                n.OwinContext.Response.Cookies.Append("state", signOutMessageId);
                            }
    
                            var cleanUpUri =
                                $@"{n.Request.Scheme}://{n.Request.Host}{n.Request.PathBase}/external-signout-cleanup";
    
                            n.ProtocolMessage.Wreply = cleanUpUri;
                        }
    
                        return Task.FromResult(0);
                    }
                }
    

    最后,我的/外部注销清理实现:

                    coreApp.Map("/external-signout-cleanup", cleanup =>
                    {
                        cleanup.Run(async ctx =>
                        {
                            var state = ctx.Request.Cookies["state"];
                            await ctx.Environment.RenderLoggedOutViewAsync(state);
                        });
                    });