I'm adding SSO support to a service, and I have the basic code working.
However, the service needs to support multiple customers, each with their own IdP, and I've hit a bit of a problem trying to work out how to do this.
Assuming I'm understanding it correctly the login flow goes something like this:
However, the sticking point is in the assertion consumer endpoint; in order for the response to be parsed, we need a Saml2AuthnResponse object. To create one of those, we need a Saml2Configuration object, which includes information such as the SAML signing cert, so the response can be validated.
But, in order to create the correct Saml2Configuration object we need to know which IdP it's come from. That information is included in the SAML response (e.g. as the Issuer field), but we can't read that info without a config object, and we can't create one of those without knowing which IdP the response is coming from...
At first I thought we could just pass the customer ID via the RelayState parameter, but I can't get the RelayState from the authentication response until I create the Sam2PostBinding and read the response, which I can't do until I've got a Saml2Configuration object. Same issue.
How do I resolve this catch-22 situation?
You can provide a AssertionConsumerService (acs) endpoint that includes a URL GET parameter with the customer ID ../mysite/acs?customerid=xxx
and then pars the customerid parameter into the method:
public async Task<IActionResult> AssertionConsumerService([FromQuery] string customerId)
An alternative and cleaner solution is to add FoxIDs in between the IdPs and your application. Then FoxIDs handle the trust to multiple SAML 2.0 IdPs and the IdP-dependent validations. Then you application only need to trust one IdP, which would be a SAML 2.0 (or OpenID Connect) down-party configured in FoxIDs.
You can configure the SAML 2.0 bridge (SAML to SAML or SAML to OIDC) in a free FoxIDs tenant.