This quickstart will walk you through how to configure Duende IdentityServer as a SAML IdentityProvider (IdP) using the Rock Solid Knowledge SAML component.
This quickstart will build upon the basic in-memory IdentityServer template, which adds a basic UI, test users, and in-memory clients and resources. To create a project using this template, you need to first install the IdentityServer templates. This can be done by running the following line at a command prompt
dotnet new install Duende.IdentityServer.Templates
You can create a project using the newly installed template by running the following command in an empty folder
dotnet new isinmem
Alternatively, if you do not wish to install the Duende IdentityServer templates, starter code for this quickstart can be found here
You can find the completed source code for this quickstart on GitHub.
Configuring SAML for Duende IdentityServer
License
Our SAML component requires a valid license. You can get a demo license by signing up on our products page or reaching out to us at support@identityserver.com.
Install the RSK SAML2P library
You will need to install our IdentityServer-specific SAML library.
Duende IdentityServer SAML library:
dotnet add package Rsk.Saml.DuendeIdentityServer
IdentityServer as a SAML Identity Provider
To enable SAML applications to authenticate using your IdentityServer, you must register our plugin by updating the call to AddIdentityServer
with the following:
services.AddIdentityServer()
// the rest of IdentityServer registrations (clients, resources, users, etc)
.AddSamlPlugin(options => {
options.Licensee = "DEMO";
options.LicenseKey = "your DEMO licenseKey";
})
.AddInMemoryServiceProviders(new List<Rsk.Saml.Models.ServiceProvider>());
The AddSamlPlugin
method adds the necessary SAML dependencies to receive SAML requests and send SAML responses. You will need to provide the licencee and license key that you acquired in the Getting Started section.
Next, there is a call to .AddInMemoryServiceProviders
, which registers an in-memory collection of ServiceProviders that can authenticate with your IdentityServer. This will be populated once you add a Service Provider later in this quickstart.
The SAML component requires X509 certificates and RS256 keys. When used with IdentityServer, the component uses the IdentityServer key store to provide key material for signing. This means that you won’t be able to use the AddDeveloperSigningCredential registration from IdentityServer.
Instead, you will need to use AddSigningCredential or use the Duende Automatic Key Management feature. Although the Automatic Key Management feature requires some additional configuration to generate X509 RS256 compatible keys, for more information see automatic key management.
If you are still developing, you can find a private key for development in the completed source code for this repository. Otherwise, you can use makecert, OpenSSL, or PowerShell to generate a new key. In this case, the certificate is only a vehicle for the public/private key-pair so a self-signed certificate is sufficient.
And finally, you need to add the SAML middleware by chaining a call to UseIdentityServerSamlPlugin
on the UseIdentityServer
method.
app.UseIdentityServer()
.UseIdentityServerSamlPlugin();
SAML Identity Provider Metadata
You can now retrieve your SAML Identity Provider metadata document by visiting the Metadata Path, the default is /saml/metadata.
Your metadata document contains all the information that Service Providers need to integrate with you, such as your EntityId, Single Sign-On (SSO) endpoints, supported signing methods, and public signing key. Check out an Example IdP Metadata document in our product documentation.
Add a SAML Service Provider
Now that IdentityServer has been configured to handle SAML, you can define a Service Provider that can authenticate using your IdentityServer.
To do this, you need to create the usual Client entry within IdentityServer and configure the SAML specifics using the ServiceProvider object.
To configure a Client and ServiceProvider you'll need some information from the partner service provider, including their unique Entity ID, Assertion Consumer Services (ACS endpoints), and public signing key. You can obtain all this information from the Service Provider’s metadata document.
The Client entry needs to be added to the IdentityServer client store, for example, in your call to AddInMemoryClients.
new Client
{
ClientId = "https://localhost:5001/saml",
ClientName = "RSK SAML2P Test Client",
ProtocolType = IdentityServerConstants.ProtocolTypes.Saml2p,
AllowedScopes = { "openid", "profile" }
}
The ClientId and the ServiceProvider EntityId must match, by SAML convention the EntityId is the URL of the SAML application, although in this case, the EntityId of the ServiceProvider is https://localhost:5001/saml
which is obtained from the ServiceProvider metadata.
The ProtocolType
is set to saml2p
using the constant IdentityServerConstants.ProtocolTypes.Saml2p
to tell IdentityServer this is a SAML application.
The SAML component uses the corresponding IdentityServer Client's scopes to control what data to use when generating SAML assertions. All of the Client's AllowedScopes
will be included in the request sent to your IdentityServer IProfileService
. The openid
scope is required to obtain the sub
claim but the profile is optional. You may want to use a custom IdentityResource with fewer ClaimTypes to prevent unnecessary PII exposure.
Note: SAML Responses require at least one assertion, and the sub claim does not count as an assertion. To prevent errors when generating SAML Responses ensure Clients have at least one additional scope and that scope contains at least one ClaimType present on the User
The ServiceProvider entry needs to be added to your Service Provider store, for example, in your call to AddInMemoryServiceProviders.
new Rsk.Saml.Models.ServiceProvider
{
EntityId = "https://localhost:5001/saml",
SigningCertificates = {new X509Certificate2("/*The SP’s public signing key*/")},
AssertionConsumerServices = { new Service(SamlConstants.BindingTypes.HttpPost, "https://localhost:5001/signin-saml") }
}
The ClientId and EntityId must be identical.
The public signing key is only necessary if you want the incoming SAML requests to be signed.
The AssertionConsumerService is made up of the endpoint URL and the binding type to use for sending SAML responses. We currently support HTTP Redirect, HTTP POST, and HTTP Artifact bindings.
To implement a persistent store for ServiceProvider configuration, please check out our Data Storage and Persistence documentation.
You should now have a correctly configured ServiceProvider. If the integration is not successful the component will display validation errors via logging. Check out our troubleshooting page or FAQ for common issues. If you are still having issues see our support page for next steps.