SAML Multi-Tenancy Applications

Multi-tenancy refers to a single application acting as multiple identity providers or service providers.
For the majority of use cases, an application acts as a single identity provider, a single service provider, or, less frequently, as a combined single identity provider and service provider.

SAML Configuration

Specifying the SAML Configuration Programmatically

However, there may be circumstances where a single application must act as multiple identity providers or service providers.
For example, the following code configures multiple identity providers.

// Create the configuration for the first tenancy.
SAMLConfiguration samlConfiguration = new SAMLConfiguration();
samlConfiguration.LocalIdentityProviderConfiguration =
new LocalIdentityProviderConfiguration() {
Name = "http://localhost/ExampleIdentityProvider",
LocalCertificateFile = "idp.pfx",
LocalCertificatePassword = "password"
};

samlConfiguration.AddPartnerServiceProvider(
new PartnerServiceProviderConfiguration() {
Name = "http://localhost/ExampleIdentityProvider",
WantAuthnRequestSigned = false,
SignSAMLResponse = true,
SignAssertion = false,
EncryptAssertion = false,
AssertionConsumerServiceUrl = "http://localhost/ExampleServiceProvider/SAML/AssertionConsumerService.aspx",
SingleLogoutServiceUrl = "http://localhost/ExampleServiceProvider/SAML/SLOService.aspx",
PartnerCertificateFile = "sp.cer"
});

SAMLController.Configurations["tenantID1"] = samlConfiguration;



// Create the configuration for the second tenancy.
samlConfiguration = new SAMLConfiguration();
samlConfiguration.LocalIdentityProviderConfiguration =
new LocalIdentityProviderConfiguration() {
Name = "http://localhost/ExampleIdentityProvider2",
LocalCertificateFile = "idp.pfx",
LocalCertificatePassword = "password"
};

samlConfiguration.AddPartnerServiceProvider(
new PartnerServiceProviderConfiguration() {
Name = "http://localhost/ExampleServiceProvider2",
WantAuthnRequestSigned = false,
SignSAMLResponse = true,
SignAssertion = false,
EncryptAssertion = false,
AssertionConsumerServiceUrl = "http://localhost/ExampleServiceProvider2/SAML/AssertionConsumerService.aspx",
SingleLogoutServiceUrl = "http://localhost/ExampleServiceProvider2/SAML/SLOService.aspx",
PartnerCertificateFile = "sp.cer"
});

SAMLController.Configurations["tenantID2"] = samlConfiguration;


The SAMLController.Configurations property maintains a dictionary of SAMLConfiguration objects keyed by configuration ID.
To switch between configurations, specify the configuration ID using the SAMLController.ConfigurationID property.
For example:


// Specify the configuration for this tenant
SAMLController.ConfigurationID = “tenantID1”;

// Now call the SSO API (not shown) - the tenantID1 configuration will be used.


Typically the ConfigurationID property is set when a user HTTP request is first received.
This means a method is required to identify the appropriate tenancy/SAML configuration to use but this is application specific.
For example, a query string parameter, different endpoint URLs, or application session data may be used to identity the tenancy.

NB. Earlier versions of the API provided access to the SAML configurations dictionary and configuration ID through the SAMLConfiguration class. This has been refactored for consistency and better readability so these are now properties of the SAMLController class.

Hello,

is the SAMLConfiguration.ConfigurationID tied to current HTTP request?

Because if not, then a different HTTP request at the same time might switch the configuration before the the first request is processed.

Ondro


Yes it is. You may have simultaneous requests being processed each using different SAML configurations identified by their SAML configuration IDs.
The SAML configuration ID is stored in the SAML session data. By default the SAML session data is stored in the ASP.NET session.

Why does the component need the ASP.NET session? Is it possible to configure the component to use a store other than the ASP.NET session? I ask because I am working with an application that runs in a web farm with the ASP.NET session disabled.

We need to store SAML session information on a per browser connection basis.
By default this is stored in the ASP.NET session.
However, it may be stored in a custom database or wherever you wish.
Please refer to section 5.6 of our Developer Guide.
This describes the ISSOSessionStore interface.
The DatabaseSSOSessionStore class stores the SAML sessions in a custom database.
Or you can write your own implementation of ISSOSessionStore to store the session information elsewhere.

@ComponentSpace - We programatically load our SAML configuration in a multi-tenant environment, and would like to load the .CER and .PFX files from a database (base64 encoded) rather than a physical file on disk.
Is this something that can be accomplished?

Thanks!
Chris

Yes, this is supported. By default we support loading certificates either from the file system or the Windows certificate store.
This is done using our default CertificateManager.
You can implement your own certificate manager to load the certificates from your database.
To do this, you need to implement the ICertificateManager interface.
The following topic outlines what’s required.
http://www.componentspace.com/Forums/46/Custom-X509-Certificate-Management

[quote]ComponentSpace (1/22/2015)[hr]Yes, this is supported. By default we support loading certificates …[/quote]
Perfect, that’s exactly what we’re looking for.
Thanks!

You mentioned that the something in the request, like a query string parameter, could be used to differentiate the configuration to use. Would it then be prudent to use a parameter on the SSOService endpoint so that the proper config can be used? I’d like to be able to implement multiple identity providers and am thinking that I need to also give the service provider unique IdP entity IDs based on that tenant identifer as well. Then, specify SSOService URL be something like /SAML/SSOService/, that I would then be able to parse that and utilize that to pull up the right configuration.

Thanks,

Dariel

That would definitely work.

Hi,

I have used above code but i am getting error saying “SAMLConfiguration, does not contain a constructor that takes a 0 argument” and i dont find the property “CertificatePassword”
will you please find out what is the issue and send me the exact code to configure saml program in C#.


SAMLConfiguration samlConfiguration = new SAMLConfiguration(); – 1st Error
samlConfiguration.IdentityProviderConfiguration =
new IdentityProviderConfiguration()
{
Name = “urn:componentspace:ExampleIdentityProvider”,
Certificate = “idp.pfx”,
CertificatePassword = “password” — 2nd Error
};
samlConfiguration.AddPartnerServiceProvider(
new PartnerServiceProviderConfiguration()
{
Name = “urn:componentspace:ExampleServiceProvider”,
WantAuthnRequestSigned = false,
SignResponse = true,
SignAssertion = true,
EncryptAssertion = false,
AssertionConsumerServiceUrl = "<a href=“http://localhost/ExampleServiceProvider/SAML/AssertionConsumerService.aspx",">http://localhost/ExampleServiceProvider/SAML/AssertionConsumerService.aspx”,
Certificate = “sp.cer”
});

SAMLConfigurations.Configurations[“tenantID1”] = samlConfiguration;


Regards.
Rajneesh.

We made some minor name changes since this topic was created and missed updating the example code. The example code has been updated now. My apologies for that.
Originally the property names were CertificateFile and CertificatePassword. We’ve changed these so that for the local identity provider or service provider configuration the property names are LocalCertificateFile and LocalCertificatePassword. For the partner identity provider or service provider configuration the property name is PartnerCertificateFile.
I took the code above and made the appropriate name changes so it compiles.
I’m not sure why the compiler can’t find the default constructor for SAMLConfiguration.
Please try the code below. If you still have a compilation error, let me know.

SAMLConfiguration samlConfiguration = new SAMLConfiguration();
samlConfiguration.LocalIdentityProviderConfiguration =
new LocalIdentityProviderConfiguration() {
Name = “urn:componentspace:ExampleIdentityProvider”,
LocalCertificateFile = “idp.pfx”,
LocalCertificatePassword = “password”
};
samlConfiguration.AddPartnerServiceProvider(
new PartnerServiceProviderConfiguration() {
Name = “urn:componentspace:ExampleServiceProvider”,
WantAuthnRequestSigned = false,
SignSAMLResponse = true,
SignAssertion = true,
EncryptAssertion = false,
AssertionConsumerServiceUrl = “http://localhost/ExampleServiceProvider/SAML/AssertionConsumerService.aspx”,
PartnerCertificateFile = “sp.cer”
});

SAMLController.Configurations[“tenantID1”] = samlConfiguration;

Hi ComponentSpace,

Thanks for reply and it is working now. when i use above code i need to call this configuration in SAMLIdentityProvide.InitiateSSO(), then how to pass the partnersp( AssertionConsumerServiceUrl ) as a parameter in this method(InitiateSSO(response,username,attributes,null, partnersp).

Regards,
Rajneesh.


There's an overload of SAMLIdentityProvider.InitiateSSO that takes an assertionConsumerServiceUrl parameter. If you use this overload then this URL will be used instead of the URL configured for the partner service provider.

We have a single web app that we provide to various enterprise clients. In our system each enterprise client has their own group which contains basic settings for that group as well as a specific sub-domain for that group. All users in our app are associated with a particular group.

(example: pepsi.MYAPP.com, cocacola.MYAPP.com,
If a pepsi user logs in at cocacola.MYAPP.com, it will work because it always loads main.MYAPP.com and displays the appropriate settings.)

It works so that no matter what URL a user logs in at, we recognize the user by their e-mail and serve up the app settings according to the ‘group’ in which they are assigned. Some of our enterprise clients use SAML 2.0. Our ASP MVC app is hosted in Azure.

1) Would your product allow us to implement SAML 2.0 for different Groups?
2) Once we install your product, is configuring SAML for each Group relatively easy / simple?
3) Could my Admins configure the SAML settings on a Group Profile Settings page without having to hard-code anything under the hood?
4) We use Gonative.io to provide native apps which use our existing HTML websites. When users login with SAML, would they momentarily leave our app and launch the browser, and then return to our app once authenticated?

I’m not exactly sure how it would work but here is my idea:
If a user enters their e-mail address, we would immediately recognize which group they belong to and hide the password field and say "single-sign-on enabled’ with a continue button that would bring them to the SSO page and then return to our app once authenticated.
(See how dropbox does this here: https://auth0.com/docs/saas-apps)


[quote]
zachweisman - Thursday, January 14, 2016
We have a single web app that we provide to various enterprise clients. In our system each enterprise client has their own group which contains basic settings for that group as well as a specific sub-domain for that group. All users in our app are associated with a particular group.

(example: pepsi.MYAPP.com, cocacola.MYAPP.com,
If a pepsi user logs in at cocacola.MYAPP.com, it will work because it always loads main.MYAPP.com and displays the appropriate settings.)

It works so that no matter what URL a user logs in at, we recognize the user by their e-mail and serve up the app settings according to the 'group' in which they are assigned. Some of our enterprise clients use SAML 2.0. Our ASP MVC app is hosted in Azure.

1) Would your product allow us to implement SAML 2.0 for different Groups?
2) Once we install your product, is configuring SAML for each Group relatively easy / simple?
3) Could my Admins configure the SAML settings on a Group Profile Settings page without having to hard-code anything under the hood?
4) We use Gonative.io to provide native apps which use our existing HTML websites. When users login with SAML, would they momentarily leave our app and launch the browser, and then return to our app once authenticated?

I'm not exactly sure how it would work but here is my idea:
If a user enters their e-mail address, we would immediately recognize which group they belong to and hide the password field and say "single-sign-on enabled' with a continue button that would bring them to the SSO page and then return to our app once authenticated.
(See how dropbox does this here: https://auth0.com/docs/saas-apps)


[/quote]

I'll let them speak for their product, but this isn't much different than what my app is doing. In my app, we not only serve as a SP for multiple IdPs (no real need for multi-tenancy there), but we also serve as an IdP for multiple SPs, of which we can have multiple connections, this is where multi-tenancy makes sense for us. I'd be more than happy to guide you in your implementation should you need help. Our login experience for our customers is similar, where the user enters in their email, we don't show the password field, but they can click a button to initiate SSO to their identity provider.
  1. Each group can have its own independent SAML configuration. Once you identify which group the user belongs to, you call into our API to specify the corresponding SAML configuration that should be used for that user.
    2. Multi-tenancy SAML configuration may be specified in a SAML configuration file or programmatically.
    3. Your application could provide a Group profile Settings page and call into our API to create or update the SAML configuration for that group.
    4. The SAML SSO browser profile is the most commonly used and supported profile throughout organizations. It requires a browser user agent to transmit SAML protocol messages between the identity provider and service provider sites. You would either need to use the browser or a web view within your application.
    I recommend prototyping to get familiar with our SAML API and configuration. You could start with our SAML high-level API projects and modify them to support multi-tenancy as required.
    You’re welcome to ask more questions either on this forum or via email.

Can you explain the difference between a) having multiple SAMLConfiguration objects (one for each tenant, each having one LocalServiceProviderConfiguration and one PartnerIdentityProviderConfiguration) stored in SAMLController.Configurations and b) having a single SAMLConfiguration object with multiple PartnerIdentityProviderConfiguration objects (one for each tenant)?

In your example you add two SAMLConfiguration objects, both with the same LocalServiceProviderConfiguration - is there a reason to that? Would it work the same way if you had a single SAMLConfiguration with 2 PartnerIdentityProviderConfiguration objects?

In our case our app will be acting as the Service Provider as as such there will be a unique LocalServiceProviderConfiguration used for all Partner Identity Providers - can we have just one SAMLConfiguration and keep adding PartnerIdentityProviderConfigurations to it for all tenants?

Thanks

EDIT: I only just realized that in your example you have added a “2” to the second Service Provider configuration ; I suppose then that if I have a single Service Provider configuration I can just keep adding IdP configurations to it ; can you confirm? thanks!

A single SAML configuration for a service provider may have one LocalServiceProvider and one or more PartnerIdentityProviders.
You may then have multiple SAML configurations.
If the LocalServiceProvider is the same then you’re better off having a single SAML configuration with the one LocalServiceProvider and a PartnerIdentityProvider for each partner identity provider.

[quote]
ComponentSpace - 6/22/2017
A single SAML configuration for a service provider may have one LocalServiceProvider and one or more PartnerIdentityProviders.
You may then have multiple SAML configurations.
If the LocalServiceProvider is the same then you're better off having a single SAML configuration with the one LocalServiceProvider and a PartnerIdentityProvider for each partner identity provider.
[/quote]

Excellent thanks!