Multiple IDP's in SAML configuration

Hi,
I am a new user here and we are started implementing SSO for our organization.
We have Version 1:
Here we Implemented 1 IDP and 1 SP by referring the ExampleIdentityProvider and ExampleServiceProvider, Its working now.

Now we have Version2:
Here we want to implement 2 different IDP’s and 1 SP
so my question is that is if it’s possible to setup two IdP’s with 1 SP?

If possible then plz give me clear idea about that like What exactly need to configure in appsettings.json for adding 2 IDP’s and code inside startup.cs - ConfigureSaml(), Is that any other code or configuration required then also plz mention over there that would be beneficial for me. I am implementing this using asp.net core .


Thanks in advance!

Regards,
Nishikant

Hi Nishikant,

Yes, that’s definitely possible and in fact if you take a look at the ExampleServiceProvider’s appsetting.json you’ll see it contains multiple partner IdP configuration entries.

Under the PartnerIdentityProviderConfigurations, add an entry for each partner IdP to be supported. There are no restrictions on the number of IdPs.

No changes are required to the Startup class.

If you’re calling _samlServiceProvider.InitiateSsoAsync to support SP-initiated SSO, you must specify the partnerName parameter to identify which partner IdP to initiate SSO to. The partnerName must match the name of one of the configured partner IdPs (ie PartnerIdentityProviderConfiguration.Name).

In the ExampleServiceProvider, we specify the PartnerName parameter in the appsettings.json. In a real world application you’d have some other mechanism to identify which IdP to SSO to.

[quote]
ComponentSpace - 6/7/2021
Hi Nishikant,

Yes, that's definitely possible and in fact if you take a look at the ExampleServiceProvider's appsetting.json you'll see it contains multiple partner IdP configuration entries.

Under the PartnerIdentityProviderConfigurations, add an entry for each partner IdP to be supported. There are no restrictions on the number of IdPs.

No changes are required to the Startup class.

If you're calling _samlServiceProvider.InitiateSsoAsync to support SP-initiated SSO, you must specify the partnerName parameter to identify which partner IdP to initiate SSO to. The partnerName must match the name of one of the configured partner IdPs (ie PartnerIdentityProviderConfiguration.Name).

In the ExampleServiceProvider, we specify the PartnerName parameter in the appsettings.json. In a real world application you'd have some other mechanism to identify which IdP to SSO to.
[/quote]

Thanks for Quick response...
I have added partner IdP configuration Under the PartnerIdentityProviderConfigurations in service providers appsettings.json
but I have doubt about setting partner name parameter, instead of Partner name I have added "Idp1": "XYZ" and "Idp2": "ABC" is that correct?
if I am wrong Plz help me to set that partner name.
And How to identify which IDP request come for SSO/SLO is from either by id "Tenant1" or "Tenant2", or by name "XYZ" or "ABC"

This is my service providers appsettings.json for your reference
"SAML": {
"Configurations": [
{
"ID": "Tenant1",
"LocalServiceProviderConfiguration": {
"Name": "XYZ",
"Description": "****** Service Provider",
"AssertionConsumerServiceUrl": "https://localhost:44395/SAML/AssertionConsumerService",
"SingleLogoutServiceUrl": "https://localhost:44395/SAML/SingleLogoutService",
"ArtifactResolutionServiceUrl": "https://localhost:44395/SAML/ArtifactResolutionService",
"LocalCertificates": [
{
"FileName": "certificates/*****.pfx",
"Password": "*******"
}
]
},
"PartnerIdentityProviderConfigurations": [
{
"Name": "**********",
"Description": "******** Identity Provider2",
"SignAuthnRequest": true,
"SignLogoutRequest": true,
"SignLogoutResponse": true,
"WantLogoutRequestSigned": true,
"WantLogoutResponseSigned": true,
"SingleSignOnServiceUrl": "https://localhost:44313/SAML/SingleSignOnService",
"SingleLogoutServiceUrl": "https://localhost:44313/SAML/SingleSignOnService",
"ArtifactResolutionServiceUrl": "https://localhost:44313/SAML/ArtifactResolutionService",
"PartnerCertificates": [
{
"FileName": "certificates/******.cer"
}
]
}
]
},
{
"ID": "Tenant2",
"LocalServiceProviderConfiguration": {
"Name": "ABC",
"Description": "****** Service Provider",
"AssertionConsumerServiceUrl": "https://localhost:44395/SAML/AssertionConsumerService",
"SingleLogoutServiceUrl": "https://localhost:44395/SAML/SingleLogoutService",
"ArtifactResolutionServiceUrl": "https://localhost:44395/SAML/ArtifactResolutionService",
"LocalCertificates": [
{
"FileName": "certificates/*****.pfx",
"Password": "*******"
}
]
},
"PartnerIdentityProviderConfigurations": [
{
"Name": "**********",
"Description": "******** Identity Provider",
"SignAuthnRequest": true,
"SignLogoutRequest": true,
"SignLogoutResponse": true,
"WantLogoutRequestSigned": true,
"WantLogoutResponseSigned": true,
"SingleSignOnServiceUrl": "https://localhost:44311/SAML/SingleSignOnService",
"SingleLogoutServiceUrl": "https://localhost:44311/SAML/SingleSignOnService",
"ArtifactResolutionServiceUrl": "https://localhost:44311/SAML/ArtifactResolutionService",
"PartnerCertificates": [
{
"FileName": "certificates/******.cer"
}
]
}
]
}
]
},
"Idp1": "XYZ"
"Idp2": "ABC",

The Configuration IDs and PartnerIdentityProviderConfiguration Names have very different purposes.

We support multiple SAML configurations. This is typically used in multi-tenanted applications. The ID uniquely identifies a SAML configuration. The ID values can be anything you like and don’t have to match with any partner IdP configuration. The application must identify which SAML configuration should be used prior to calling the SAML SSO APIs. This is done by calling, for example, _samlServiceProvider.SetConfigurationIDAsync(tenantID). Unless you wish to support multiple tenants, each with their own separate configuration, you’re better to just have the one SAML configuration as this is simpler to manage.

More information about multi-tenancy support may be found in our Configuration Guide.

https://www.componentspace.com/Forums/8234/Configuration-Guide

PartnerIdentityProviderConfiguration Names uniquely identify a partner IdP. The Name must match the entityID specified in the IdP’s SAML metadata. This is sometimes referred to as the provider name, entity ID or issuer name. This name is supplied to you by the partner IdP as part of their configuration information either as SAML metadata or in an ad hoc format. When a SAML message is received, we attempt to match the Issuer field in the message with one of the PartnerIdentityProviderConfiguration Names so we know how to process the message.


[quote]
ComponentSpace - 6/8/2021
The Configuration IDs and PartnerIdentityProviderConfiguration Names have very different purposes.

We support multiple SAML configurations. This is typically used in multi-tenanted applications. The ID uniquely identifies a SAML configuration. The ID values can be anything you like and don't have to match with any partner IdP configuration. The application must identify which SAML configuration should be used prior to calling the SAML SSO APIs. This is done by calling, for example, _samlServiceProvider.SetConfigurationIDAsync(tenantID). Unless you wish to support multiple tenants, each with their own separate configuration, you're better to just have the one SAML configuration as this is simpler to manage.

More information about multi-tenancy support may be found in our Configuration Guide.

https://www.componentspace.com/Forums/8234/Configuration-Guide

PartnerIdentityProviderConfiguration Names uniquely identify a partner IdP. The Name must match the entityID specified in the IdP's SAML metadata. This is sometimes referred to as the provider name, entity ID or issuer name. This name is supplied to you by the partner IdP as part of their configuration information either as SAML metadata or in an ad hoc format. When a SAML message is received, we attempt to match the Issuer field in the message with one of the PartnerIdentityProviderConfiguration Names so we know how to process the message.


[/quote]


1.) I have 2 IDPs so How to add 2 partners name in appsettings.json and that partnerName get dynamically in InitiateSingleSignOn()(SP-initiated SSO).

var partnerName = _configuration["PartnerName"];
// To login automatically at the service provider,
// initiate single sign-on to the identity provider (SP-initiated SSO).
// The return URL is remembered as SAML relay state.
await _samlServiceProvider.InitiateSsoAsync(partnerName, returnUrl);


2.) When I click on logout button, then I have below exception.
An unhandled exception occurred while processing the request.
SamlProtocolException: A SAML authn request was expected. Instead samlp:LogoutRequest was received.
ComponentSpace.Saml2.SamlIdentityProvider.ValidateAuthnRequest(XmlElement authnRequestElement)

calling this on OnGetAsync()
await _signInManager.SignOutAsync();
_logger.LogInformation("User logged out.");
var ssoState = await _samlServiceProvider.GetStatusAsync();

if (await ssoState.CanSloAsync())
{
// Initiate SAML logout.
return RedirectToAction("InitiateSingleLogout", "Saml");
}
what I am doing wrong here?

We are now facing the Single logout issue.
When I Click sign out from my SP it InitiateSingleLogout() and
// Request logout at the identity provider.
await _samlServiceProvider.InitiateSloAsync(relayState: returnUrl);
but in the middle i dont know how it calls ComponentSpace.Saml2.SamlIdentityProvider.ReceiveSsoAsync()
idp.Controllers.SamlController.SingleSignOnService() in SamlController.cs
await _samlIdentityProvider.ReceiveSsoAsync();
and it throughs exception -
An unhandled exception occurred while processing the request.
SamlProtocolException: A SAML authn request was expected. Instead samlp:LogoutRequest was received.
ComponentSpace.Saml2.SamlIdentityProvider.ValidateAuthnRequest(XmlElement authnRequestElement)

Does anyone have ideas what is wrong with our SLO implementation?

[quote]
ComponentSpace - 6/8/2021
The Configuration IDs and PartnerIdentityProviderConfiguration Names have very different purposes.

We support multiple SAML configurations. This is typically used in multi-tenanted applications. The ID uniquely identifies a SAML configuration. The ID values can be anything you like and don't have to match with any partner IdP configuration. The application must identify which SAML configuration should be used prior to calling the SAML SSO APIs. This is done by calling, for example, _samlServiceProvider.SetConfigurationIDAsync(tenantID). Unless you wish to support multiple tenants, each with their own separate configuration, you're better to just have the one SAML configuration as this is simpler to manage.

More information about multi-tenancy support may be found in our Configuration Guide.

https://www.componentspace.com/Forums/8234/Configuration-Guide

PartnerIdentityProviderConfiguration Names uniquely identify a partner IdP. The Name must match the entityID specified in the IdP's SAML metadata. This is sometimes referred to as the provider name, entity ID or issuer name. This name is supplied to you by the partner IdP as part of their configuration information either as SAML metadata or in an ad hoc format. When a SAML message is received, we attempt to match the Issuer field in the message with one of the PartnerIdentityProviderConfiguration Names so we know how to process the message.


[/quote]


1.) I have 2 IDPs so How to add 2 partners name in appsettings.json and that partnerName get dynamically in InitiateSingleSignOn()(SP-initiated SSO).

var partnerName = _configuration["PartnerName"];
// To login automatically at the service provider,
// initiate single sign-on to the identity provider (SP-initiated SSO).
// The return URL is remembered as SAML relay state.
await _samlServiceProvider.InitiateSsoAsync(partnerName, returnUrl);


2.) When I click on logout button, then I have below exception.
An unhandled exception occurred while processing the request.
SamlProtocolException: A SAML authn request was expected. Instead samlp:LogoutRequest was received.
ComponentSpace.Saml2.SamlIdentityProvider.ValidateAuthnRequest(XmlElement authnRequestElement)

calling this on OnGetAsync()
await _signInManager.SignOutAsync();
_logger.LogInformation("User logged out.");
var ssoState = await _samlServiceProvider.GetStatusAsync();

if (await ssoState.CanSloAsync())
{
// Initiate SAML logout.
return RedirectToAction("InitiateSingleLogout", "Saml");
}
what I am doing wrong here?
[/quote]
1.) In our example, we have a PartnerName setting in the appsettings.json. However, you wouldn't do this in a production environment. Instead, you might display a number of options to the end user. The user gets to choose the identity provider to SSO to. When they click a button or link, you call _samlServiceProvider.InitiateSsoAsync with the corresponding partner name. Alternatively, you might be able to automatically determine which partner identity provider applies for the end user. You could do this by using different URLs etc. How you do this is up to your application.

2.) It sounds like the SAML logout request is being sent to the identity provider's SSO service where it's expecting a SAML authn request. The SAML logout request should be sent to the identity provider's single logout (SLO) service.

In the configuration above you have:

"SingleLogoutServiceUrl": "https://localhost:44311/SAML/SingleSignOnService"

This should be:

"SingleLogoutServiceUrl": "https://localhost:44311/SAML/SingleLogoutService"

[quote]
nishikantk - 6/10/2021
We are now facing the Single logout issue.
When I Click sign out from my SP it InitiateSingleLogout() and
// Request logout at the identity provider.
await _samlServiceProvider.InitiateSloAsync(relayState: returnUrl);
but in the middle i dont know how it calls ComponentSpace.Saml2.SamlIdentityProvider.ReceiveSsoAsync()
idp.Controllers.SamlController.SingleSignOnService() in SamlController.cs
await _samlIdentityProvider.ReceiveSsoAsync();
and it throughs exception -
An unhandled exception occurred while processing the request.
SamlProtocolException: A SAML authn request was expected. Instead samlp:LogoutRequest was received.
ComponentSpace.Saml2.SamlIdentityProvider.ValidateAuthnRequest(XmlElement authnRequestElement)

Does anyone have ideas what is wrong with our SLO implementation?
[/quote]

In the configuration above you have:

"SingleLogoutServiceUrl": "https://localhost:44311/SAML/SingleSignOnService"

This should be:

"SingleLogoutServiceUrl": "https://localhost:44311/SAML/SingleLogoutService"