I was told that the issue I will describe here is not a bug in the IdentityServer, so I'm probably doing something wrong:
This code works, using a single WSFederation-instance as identity provider in the QuickStart-project using EFCore.
Registering the provider:
services.AddAuthentication()
.AddWsFederation("WsFederation", options =>
{
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
options.Wtrealm = realm;
options.MetadataAddress = metadata;
options.Events.OnTicketReceived += OnTicketReceived;
})
OnTicketReceived-Eventhandler:
/// <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")));
}
As soon as I add a second provider, I will get an exception when trying to use the second provider, because the first provider added takes the request and throws an exception as soon as it receives the request:
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;
})
The exception I get is this - if I fix it by allowing unsolicited logins other exceptions will occure as it still tries to use the wrong provider:
System.Exception: Unsolicited logins are not allowed. at Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler`1.d__12.MoveNext()
I found the point where it is raised in IdentityServer4:
public async Task<bool> HandleRequestAsync()
{
var result = await _inner.HandleRequestAsync();
I can fix this if I change the above code to catch the Exception, as it will afterwards pass the correct provider and the login succeeds:
var result = false;
try
{
result = await _inner.HandleRequestAsync();
}
catch (Exception) {}
I am not happy with having to fork IdentityServer4 to resolve this problem, so I am asking for a solution without changing the code of the IdentityServer. The place where I could step in and change something is either the configuration of my WSFederation-endpoint, right before starting the ExternalLogin or at the callback in the AccountController.
Callback in the 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);
Any hints where I should start are greatly appreciated.
Got it - the solution is to set different CallbackPaths for the different providers:
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";
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With