IdentityServer4 多个 WSFederation 提供程序导致异常
IdentityServer4 multiple WSFederation-providers cause an exception
有人告诉我,我将在此处描述的 issue 不是 IdentityServer 中的错误,所以我可能做错了什么:
此代码有效,使用单个 WSFederation 实例作为 QuickStart-project using EFCore 中的身份提供者。
正在注册提供商:
services.AddAuthentication()
.AddWsFederation("WsFederation", options =>
{
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
options.Wtrealm = realm;
options.MetadataAddress = metadata;
options.Events.OnTicketReceived += OnTicketReceived;
})
OnTicketReceived-事件处理程序:
/// <summary>
/// Transform the UPN-claim to the sub-claim to be compatible with IdentityServer4
/// </summary>
private async Task OnTicketReceived(TicketReceivedContext ticketReceivedContext)
{
var identity = ticketReceivedContext.Principal.Identities.First();
identity.AddClaim(new Claim("sub", ticketReceivedContext.Principal.FindFirstValue("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier")));
}
一旦我添加第二个提供者,尝试使用第二个提供者时就会出现异常,因为添加的第一个提供者接受请求并在收到请求后立即抛出异常:
services.AddAuthentication()
.AddWsFederation("WsFederation_LocalHost", "WsFederation_LocalHost", options =>
{
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
options.Wtrealm = "urn:aspnetcorerp";
options.MetadataAddress = "http://localhost:5000/wsfederation";
options.Events.OnTicketReceived += OnTicketReceived;
options.RequireHttpsMetadata = false;
})
.AddWsFederation("WsFederation_SVN", "WsFederation_SVN", options =>
{
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
options.Wtrealm = realm;
options.MetadataAddress = metadata;
options.Events.OnTicketReceived += OnTicketReceived;
options.Events.OnSecurityTokenReceived += OnSecurityTokenReceived;
})
我得到的异常是这样的 - 如果我通过允许未经请求的登录来修复它,则会发生其他异常,因为它仍然尝试使用错误的提供程序:
System.Exception: Unsolicited logins are not allowed.
at Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler`1.d__12.MoveNext()
我找到了凸起的点in IdentityServer4:
public async Task<bool> HandleRequestAsync()
{
var result = await _inner.HandleRequestAsync();
如果我更改上面的代码以捕获异常,我可以解决这个问题,因为它随后会通过正确的提供程序并且登录成功:
var result = false;
try
{
result = await _inner.HandleRequestAsync();
}
catch (Exception) {}
我不喜欢必须派生 IdentityServer4 来解决这个问题,所以我要求一个不更改 IdentityServer 代码的解决方案。我可以介入并更改某些内容的地方是我的 WSFederation 端点的配置,就在 AccountController 中 before starting the ExternalLogin or at the callback。
AccountController 中的回调:
[HttpGet]
public async Task<IActionResult> ExternalLoginCallback()
{
// read external identity from the temporary cookie - I don't know how I could change which AuthenticationMiddleware gets called
var result = await HttpContext.AuthenticateAsync(IdentityServer4.IdentityServerConstants.ExternalCookieAuthenticationScheme);
非常感谢任何我应该从哪里开始的提示。
知道了 - 解决方案是为不同的提供者设置不同的 CallbackPaths:
services.AddAuthentication()
.AddWsFederation("WsFederation_LocalHost", "WsFederation_LocalHost", options =>
{
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
options.Wtrealm = "urn:aspnetcorerp";
options.MetadataAddress = "http://localhost:5000/wsfederation";
options.Events.OnTicketReceived += OnWsFedTicketReceived;
options.RequireHttpsMetadata = false;
options.CallbackPath = "/signin-wsfed-localhost";
})
.AddWsFederation("WsFederation_SVN", "WsFederation_SVN", options =>
{
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
options.Wtrealm = realm;
options.MetadataAddress = metadata;
options.Events.OnTicketReceived += OnWsFedTicketReceived;
options.CallbackPath = "/signin-wsfed-svn";
})
有人告诉我,我将在此处描述的 issue 不是 IdentityServer 中的错误,所以我可能做错了什么:
此代码有效,使用单个 WSFederation 实例作为 QuickStart-project using EFCore 中的身份提供者。
正在注册提供商:
services.AddAuthentication()
.AddWsFederation("WsFederation", options =>
{
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
options.Wtrealm = realm;
options.MetadataAddress = metadata;
options.Events.OnTicketReceived += OnTicketReceived;
})
OnTicketReceived-事件处理程序:
/// <summary>
/// Transform the UPN-claim to the sub-claim to be compatible with IdentityServer4
/// </summary>
private async Task OnTicketReceived(TicketReceivedContext ticketReceivedContext)
{
var identity = ticketReceivedContext.Principal.Identities.First();
identity.AddClaim(new Claim("sub", ticketReceivedContext.Principal.FindFirstValue("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier")));
}
一旦我添加第二个提供者,尝试使用第二个提供者时就会出现异常,因为添加的第一个提供者接受请求并在收到请求后立即抛出异常:
services.AddAuthentication()
.AddWsFederation("WsFederation_LocalHost", "WsFederation_LocalHost", options =>
{
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
options.Wtrealm = "urn:aspnetcorerp";
options.MetadataAddress = "http://localhost:5000/wsfederation";
options.Events.OnTicketReceived += OnTicketReceived;
options.RequireHttpsMetadata = false;
})
.AddWsFederation("WsFederation_SVN", "WsFederation_SVN", options =>
{
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
options.Wtrealm = realm;
options.MetadataAddress = metadata;
options.Events.OnTicketReceived += OnTicketReceived;
options.Events.OnSecurityTokenReceived += OnSecurityTokenReceived;
})
我得到的异常是这样的 - 如果我通过允许未经请求的登录来修复它,则会发生其他异常,因为它仍然尝试使用错误的提供程序:
System.Exception: Unsolicited logins are not allowed. at Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler`1.d__12.MoveNext()
我找到了凸起的点in IdentityServer4:
public async Task<bool> HandleRequestAsync()
{
var result = await _inner.HandleRequestAsync();
如果我更改上面的代码以捕获异常,我可以解决这个问题,因为它随后会通过正确的提供程序并且登录成功:
var result = false;
try
{
result = await _inner.HandleRequestAsync();
}
catch (Exception) {}
我不喜欢必须派生 IdentityServer4 来解决这个问题,所以我要求一个不更改 IdentityServer 代码的解决方案。我可以介入并更改某些内容的地方是我的 WSFederation 端点的配置,就在 AccountController 中 before starting the ExternalLogin or at the callback。
AccountController 中的回调:
[HttpGet]
public async Task<IActionResult> ExternalLoginCallback()
{
// read external identity from the temporary cookie - I don't know how I could change which AuthenticationMiddleware gets called
var result = await HttpContext.AuthenticateAsync(IdentityServer4.IdentityServerConstants.ExternalCookieAuthenticationScheme);
非常感谢任何我应该从哪里开始的提示。
知道了 - 解决方案是为不同的提供者设置不同的 CallbackPaths:
services.AddAuthentication()
.AddWsFederation("WsFederation_LocalHost", "WsFederation_LocalHost", options =>
{
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
options.Wtrealm = "urn:aspnetcorerp";
options.MetadataAddress = "http://localhost:5000/wsfederation";
options.Events.OnTicketReceived += OnWsFedTicketReceived;
options.RequireHttpsMetadata = false;
options.CallbackPath = "/signin-wsfed-localhost";
})
.AddWsFederation("WsFederation_SVN", "WsFederation_SVN", options =>
{
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
options.Wtrealm = realm;
options.MetadataAddress = metadata;
options.Events.OnTicketReceived += OnWsFedTicketReceived;
options.CallbackPath = "/signin-wsfed-svn";
})