How to set the "AssertionConsumerServiceUrl" dynamically where the application key is unique for each logged in user

QUESTION 1: We need to maintain the AssertionConsumerServiceUrl( under the PartnerServiceProviderConfigurations.) unique per loggedin user, as the Applciation Key is different for each set of users. Please share the code snippet, i tried googling and looking in to the componenetspace documentation but could not found anything.

For e.g the ACS is different for certain set of user. We can not keep these in appsetting.json as the applciation key list is large. We need to fetch them in runtime from database based on userid .

Example
UserGroupOne
“AssertionConsumerServiceUrl”: “<a href=“https://uat-login.awardcenter.com/123-456-789-/saml/login” ,”=“”><a href=“https://uat-login.awardcenter.com/123-456-789-/saml/login” ,“=”“><a href=“https://uat-login.awardcenter.com/123-456-789-/saml/login” ,”=“”><a href=“https://uat-login.awardcenter.com/123-456-789-/saml/login",">https://uat-login.awardcenter.com/123-456-789-/saml/login",</a></a><br/><strong>UserGroupTwo</strong><br/>"AssertionConsumerServiceUrl”: “<a href=“https://uat-login.awardcenter.com/1234-456-776/saml/login” ,”=“”><a href=“https://uat-login.awardcenter.com/1234-456-776/saml/login” ,“=”“><a href=“https://uat-login.awardcenter.com/rt456-4ty-776/saml/login” ,”=“”><a href=“https://uat-login.awardcenter.com/rt456-4ty-776/saml/login",">https://uat-login.awardcenter.com/rt456-4ty-776/saml/login",</a></a><br/>.<br/>.<br/>.<br/>.<br/><strong>UserGroupN</strong><br/>"AssertionConsumerServiceUrl”: “<a href=“https://uat-login.awardcenter.com/ki90-fr56-3456/saml/login” ,”=“”><a href=“https://uat-login.awardcenter.com/ki90-fr56-3456/saml/login” ,“=”“><a href=“https://uat-login.awardcenter.com/ki90-fr56-3456/saml/login” ,”=“”><a href=“https://uat-login.awardcenter.com/ki90-fr56-3456/saml/login",">https://uat-login.awardcenter.com/ki90-fr56-3456/saml/login”,


QUESTION 2:
Also please share how can we keep the below SAML configuration in DB, like password or certificate details.




.

Changing the AssertionConsumerServiceUrl based on the logged is unusual and not something I would recommend. I’m not sure why you wish to do this and would suggest looking at alternatives.

However, if this is required, the best option to cover both questions is to implement the ISamlConfigurationResolver interface.

This interface is described in the Configuration Guide which you’ll find in the documentation folder.

Also, the ExampleIdentityProvider project includes a ConfigurationExamples class with a ConfigurationResolver demonstrating an implementation of this interface.

Your ISamlConfigurationResolver implementation can store the configuration in a custom database. It can also change the configuration dynamically (eg the AssertionConsumerServiceUrl based on the currently logged in user). You have complete control of where configuration is stored and what configuration is returned through this interface.

We ship an implementation of this interface which stores the configuration in an Entity Framework database. This is also described in the Configuration Guide. However, it doesn’t support changing the AssertionConsumerServiceUrl.

Certificate file names and passwords may be stored in the database. Alternatively, you could store the base-64 encoded string value of the certificate instead of a certificate file name.

[quote]
ComponentSpace - 10/28/2023
Changing the AssertionConsumerServiceUrl based on the logged is unusual and not something I would recommend. I'm not sure why you wish to do this and would suggest looking at alternatives.

However, if this is required, the best option to cover both questions is to implement the ISamlConfigurationResolver interface.

This interface is described in the Configuration Guide which you'll find in the documentation folder.

Also, the ExampleIdentityProvider project includes a ConfigurationExamples class with a ConfigurationResolver demonstrating an implementation of this interface.

Your ISamlConfigurationResolver implementation can store the configuration in a custom database. It can also change the configuration dynamically (eg the AssertionConsumerServiceUrl based on the currently logged in user). You have complete control of where configuration is stored and what configuration is returned through this interface.

We ship an implementation of this interface which stores the configuration in an Entity Framework database. This is also described in the Configuration Guide. However, it doesn't support changing the AssertionConsumerServiceUrl.

Certificate file names and passwords may be stored in the database. Alternatively, you could store the base-64 encoded string value of the certificate instead of a certificate file name.

[/quote]

Thanks for the updates, Quick question please.

1. How to pass the ACS url to the below webmethod-, Is there a way to pass the ACS urls apart from having it in the appsetting.json" ?
await _samlIdentityProvider.InitiateSsoAsync(partnerName, userId, attributes);
2. i looked at the code snippet you suggested(shown below) and seems like we can maintain them in DB or can modify at run time it seems. But my main concern is how to pass these configuration while calling the _samlIdentityProvider.InitiateSsoAsync(partnerName, userId, attributes); it doesnt take any configurations.


3. We do have many ACS urls which we have in our DBs. Please confirm if there is a way in componetspace lib to fecth them and use for saml login.Please share a working code snippet. We are planning to purchase this library but only if it support this requirement. So pls provide a wrkng sample. the documentation doesnt have the code of using ACS urls dynamically,

  1. No. Configuration is deliberately kept separate from the SSO API as it provides for a cleaner interface. The best option is to implement the ISamlConfigurationResolver interface as previously mentioned.

    2. You don’t pass the configuration into InitiateSsoAsync. We call into ISamlConfigurationResolver as and when we need specific configuration.

    3. We don’t have any example code of having an ACS per user as this isn’t a very likely use case or something we would recommend. However, you can support this by implementing ISamlConfigurationResolver. I suggest running the ExampleIdentityProvider and ExampleServiceProvider in the Visual Studio debugger to see SSO in action. Once you’ve confirmed that’s working, modify the ExampleIdentityProvider to use its ISamlConfigurationResolver as per the instructions in the code comments (ie calling AddConfigurationResolver) to see how it calls into the ISamlConfigurationResolver interface.
[quote]
ComponentSpace - 10/29/2023
1. No. Configuration is deliberately kept separate from the SSO API as it provides for a cleaner interface. The best option is to implement the ISamlConfigurationResolver interface as previously mentioned.

2. You don't pass the configuration into InitiateSsoAsync. We call into ISamlConfigurationResolver as and when we need specific configuration.

3. We don't have any example code of having an ACS per user as this isn't a very likely use case or something we would recommend. However, you can support this by implementing ISamlConfigurationResolver. I suggest running the ExampleIdentityProvider and ExampleServiceProvider in the Visual Studio debugger to see SSO in action. Once you've confirmed that's working, modify the ExampleIdentityProvider to use its ISamlConfigurationResolver as per the instructions in the code comments (ie calling AddConfigurationResolver) to see how it calls into the ISamlConfigurationResolver interface.
[/quote]

I tried to load the PartnerServiceProviderConfigurations using below way and i can see them coming but its only working for hard code values.

builder.Services.AddSaml(config => SSOConfigurations.ConfigureSaml(config));


i need to have them(ACS urls) come from DB so i tried to make some changes but getting issue. The ConfigurationExamples class is static class and the function which i need to use to get the ACS url is a non-static. So i am not able to find a way how to use this function inside the ConfigurationExamples class.
You can see below snippets describing same.

There are two ways to load SAML configuration programmatically. What you’re using is not correct for dynamic configuration. You need to implement the ISamlConfigurationResolver interface as previously mentioned.

The ConfigurationExamples includes a CustomConfigurationResolver class which implements ISamlConfigurationResolver. This implementation uses hard-coded values for demonstration purposes. Your implementation would retrieve configuration from your database.


// This class demonstrates loading SAML configuration dynamically using a custom configuration resolver.
// Hard-coded configuration is returned in this example but more typically configuration would be read from a custom database.
// The configurationName parameter specifies the SAML configuration in a multi-tenancy application but is not used in this example.
// The custom configuration resolver is registered by calling:
// builder.Services.AddSaml().AddConfigurationResolver<ConfigurationExamples.CustomConfigurationResolver>();
// Alternatively, it can be cached by calling:
// builder.Services.AddSaml().AddCachedConfigurationResolver<ConfigurationExamples.CustomConfigurationResolver>();
public class CustomConfigurationResolver : AbstractSamlConfigurationResolver


[quote]
ComponentSpace - 10/30/2023
There are two ways to load SAML configuration programmatically. What you're using is not correct for dynamic configuration. You need to implement the ISamlConfigurationResolver interface as previously mentioned.

The ConfigurationExamples includes a CustomConfigurationResolver class which implements ISamlConfigurationResolver. This implementation uses hard-coded values for demonstration purposes. Your implementation would retrieve configuration from your database.


// This class demonstrates loading SAML configuration dynamically using a custom configuration resolver.
// Hard-coded configuration is returned in this example but more typically configuration would be read from a custom database.
// The configurationName parameter specifies the SAML configuration in a multi-tenancy application but is not used in this example.
// The custom configuration resolver is registered by calling:
// builder.Services.AddSaml().AddConfigurationResolver();
// Alternatively, it can be cached by calling:
// builder.Services.AddSaml().AddCachedConfigurationResolver();
public class CustomConfigurationResolver : AbstractSamlConfigurationResolver


[/quote]

Hi, we are building a SSO Gateway which will handle multiple SSOs from various partners and clients.

So we need to create these configurations at later stages, not through "dependency injection".
How we can set these configurations programmatically at later stage, not through dependency injection?

Is this possible? Please let me know

We use dependency injection because this is the mechanism used within ASP.NET Core by Microsoft and it means your application deals with interfaces rather than implementations making for cleaner code.

All you have to do is call AddSaml in your Program class to hookup the dependency injection.

I'm not sure what you mean by creating the configurations at a later stage.

If you implement ISamlConfigurationResolver, we only request the specific configuration required at the time of SSO. It can't be bound any later than that.

[quote]
ComponentSpace - 11/21/2023

We use dependency injection because this is the mechanism used within ASP.NET Core by Microsoft and it means your application deals with interfaces rather than implementations making for cleaner code.

All you have to do is call AddSaml in your Program class to hookup the dependency injection.

I'm not sure what you mean by creating the configurations at a later stage.

If you implement ISamlConfigurationResolver, we only request the specific configuration required at the time of SSO. It can't be bound any later than that.

[/quote]

Hi,

As I told, we are building a SSO gateway for more than 60 Inbound SSOs for our various Clients and Vendors.
Once We get an SSO packet, we need to identify the issuer (from the SAML). Based on issuer, we need to load the certificates (configurations from Database).
So at this stage (after identfying the issues), how we can load the saml configurations?

As you mentioned, "AddSaml in your Program class" is called at startup. In our case we need to change the configuartion, each time we receive an SSO(identify the issuer and get configuration from database).
Please let me know is can be achieved?

The CustomConfigurationResolver described in an earlier posting in this thread demonstrates what you’re trying to achieve.

I encourage you to take a look at the ExampleServiceProvider project and specifically the CustomConfigurationResolver in the ConfigurationExamples class. You can run the ExampleServiceProvider along with the ExampleIdentityProvider in the Visual Studio debugger to see this in action.

Your application doesn’t identify the issuer. This is done by the SAML library.

The ISamlConfigurationResolver.GetPartnerIdentityProviderConfigurationAsync method will be called when the SAML configuration for the specified partner provider is required to process the SAML message.

Your implementation of ISamlConfigurationResolver.GetPartnerIdentityProviderConfigurationAsync is responsible for returning this configuration.

The CustomConfigurationResolver uses hardcoded configuration values. Your implementation can store the configuration in a custom database or wherever you wish.

We include a SamlDatabaseConfigurationResolver that retrieves configuration stored in an Entity Framework database.

You’ll find more information about implementing ISamlConfigurationResolver in the Configuration Guide that’s available in the documentation folder.