我的网络应用程序是Identity Server 3 STS的客户端,它与外部IdP的ADFS联合。登录效果很好。从STS退出是好的。但是在结束IdSrv3会话并最终重定向到应用程序之前,我从来没有能够让IdSrv3重定向到ADFS以进行注销。
如果我理解正确,我应该能够在退出后将ADFS回复到RP(IdSrv3),此时IdSrv3
阅读文档: https://identityserver.github.io/Documentation/docsv2/advanced/federated-post-logout-redirect.html
以及关于联合单点退出主题的GitHub问题的大部分内容。
通过IdSrv3进行跟踪我从未看到尝试重定向到ADFS进行注销,因此我假设我在这里缺少配置。
一旦复杂性,我正在运行IdSrv3但是我的客户端应用程序是ASP.NET Core 2.0,因此很多样本都不能与最新的Microsoft身份客户端中间件完全协调。
在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);
});
});
});
现在,对于客户端,ASP.NET Core 2.0 MVC应用程序:
更新:请参阅已接受的答案 - 重定向到外部IdP(ADFS),应该在IdSrv3端处理重定向到IdP以进行注销
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();
我甚至尝试过实例化一个新的OwinContext(n.HttpContext)来获取环境字典 - 但是,“GetSignOutMessageId()”获得的值具有“id”键,我无法在其中找到Owin变量。
似乎这个cookie实际上只需要通过所有重定向来保持状态,以便在我的客户端应用程序的PostLogoutUri被命中后,当前设置为“https://myapp/signout-callback-oidc”,可以使用消息ID完成清理会议。
我还对“EnableAutoCallbackForFederatedSignout = true”设置在IdSrv3配置中扮演什么角色感到困惑。
从这个描述和查看代码,它将使我不必在ADFS注销上设置“WReply”参数: https://github.com/IdentityServer/IdentityServer3/issues/2613 我希望ADFS会重定向到: 如果此设置为“true”,则会自动“https://myIdSrv3/core/signoutcallback。”
如果有人有任何指导分享,我们非常感谢。
答案 0 :(得分:2)
事实证明,我正在混淆IdSrv3中描述由外部Idp发起的联合单点注销的一些概念,而不是我的用例 - 由IdSrv3客户端应用程序发起的注销,级联" up& #34;到外部IdP。
此问题的根本原因在于我的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中指定了External Idp之后,我能够处理WsFederationAuthenticationNotifications.RedirectToIdentityProvider事件。
为了完整起见,这是我的代码,用于处理来自ADFS vis 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);
}
}
最后,我的/ external-signout-cleanup实现:
coreApp.Map("/external-signout-cleanup", cleanup =>
{
cleanup.Run(async ctx =>
{
var state = ctx.Request.Cookies["state"];
await ctx.Environment.RenderLoggedOutViewAsync(state);
});
});