Rock Solid Knowledge

Welcome to the blog of identityserver.com hosted by Rock Solid Knowledge, the IdentityServer European Partners, offering commercial support, consultancy and training for IdentityServer 3 & 4, and all things authentication, backed by the creators of IdentityServer themselves.

SAML 2.0 Integration with IdentityServer4

The Security Assertion Markup Language (SAML) is a protocol used to communicate authentication data between two parties, favored by educational and governmental institutions. If you’re implementing IdentityServer 4 and in the world of OpenID Connect, then I guess you could safely call it a “legacy” protocol.

SAML 2.0 Integration with IdentityServer4
Scott Brady Thursday, 16 August, 2018

The Security Assertion Markup Language (SAML) is a protocol used to communicate authentication data between two parties, favored by educational and governmental institutions. If you’re implementing IdentityServer 4 and in the world of OpenID Connect, then I guess you could safely call it a “legacy” protocol.

That said, many companies still rely upon SAML for federation as they are simply not in a position to simplify their lives with OpenID Connect. So, what can we do for these systems? Leave them in the dark? Spin up some custom gateway to bridge protocols? Better yet, can we support them with our existing IdentityServer installation?

This article will discuss the SAML 2 protocol (sometimes referred to as SAML2P in the Microsoft world), not SAML tokens. For SAML token usage, check out my older article which talks about adding WS-Federation support to IdentityServer4.

Which Side of the Story

In this article, we’re going to cover both sides of the story and look at options for IdentityServer becoming a SAML Identity Provider or becoming a SAML Service Provider.

SAML Identity Provider

If you want to have legacy SAML applications log in using your IdentityServer (you hold the credentials and provide the SAML response), then check out “IdentityServer 4 as a SAML Identity Provider”.

In this role, you’ll have IdentityServer acting in its traditional role as an authorization server/identity provider.

SAML Service Provider

If you want to have legacy SAML identity providers federate with your IdentityServer (where an external service holds the credentials, and you send them SAML requests), then check out “IdentityServer 4 as a SAML Service Provider”.

In this role, you’ll have IdentityServer using an external identity provider for logins, much in the same way you would offer functionality such as “login using Google”.

SAML Flow

Both scenarios will use the IdentityServer4 SAML2P library from Rock Solid Knowledge. This component is a closed-source, commercial library, to which you can get a demo license key via identityserver.com or by directly contacting sales@rocksolidknowledge.com.

Project Setup

The example code in this article will build upon the basic demo IdentityServer 4 installation you can get from the dotnet new is4inmem, the quickstarts, or by following my IdentityServer 4 guide. The minimum you need is a working OpenID Connect installation with a UI. You’re welcome to use in-memory clients & users.

The IdentityServer4 SAML component is available on nuget, including functionality for both identity providers and service providers. So, let’s install that now:

install-package Rsk.IdentityServer4.Saml -pre

Note that this SAML2P library only works when running ASP.NET Core 2.0 and with .NET Core support current available as of version 2.2.0-preview1 (non-preview release due in September 2018).

You can find the completed source code for this article on GitHub.

IdentityServer 4 as a SAML Identity Provider

The only out of the box way to accept SAML requests and return SAML responses in IdentityServer 4, is with the IdentityServer4.Saml library from Rock Solid Knowledge.

To add SAML IdP functionality to your project, you first need to make some small modifications to the ConfigureServices and Configure methods in the Startup.cs.

In the ConfigureServices method, your call to AddIdentityServer needs to be updated with the following:

services.AddIdentityServer()
    // the rest of registrations (clients, resources, users, etc)
    .AddSigningCredential(new X509Certificate2(<your cert>))
    .AddSamlPlugin(options => {
        options.Licensee = "<your license key org name>";
        options.LicenseKey = "<your license key>";
    })
    .AddInMemoryServiceProviders(new List<ServiceProvider>());

Here we are adding the SAML dependencies using AddSamlPlugin. This adds the necessary implementations to start receiving SAMLRequests and sending SAMLResponses. A licensee and license key are required here, which can be obtained from identityserver.com.

Next, there is the call to AddInMemoryServiceProviders which will be populated once we add a service provider.

Note that for SAML2P to work you won’t be able to use the AddDeveloperSigningCredential registration from IdentityServer. Instead, you will need to use AddSigningCredential, with a full, persistent private key. If you are using an IdentityServer template, make sure you have no calls AddDeveloperSigningCredential left in your code.

If you are still developing, you can find a simple private key for development in the completed source code for this repository. Otherwise, you can create one using makecert, OpenSSL, or PowerShell.

And finally, in the Configure method the call to UseIdentityServer needs to be extended with:

app.UseIdentityServer()
   .UseIdentityServerSamlPlugin();

And that’s all that’s needed to add SAML support in your IdentityServer!

SAML2P Identity Provider Metadata

You can now retrieve the identity provider metadata by visiting the /saml/metadata. This metadata document is what you need to make available to any service providers looking to integrate with your SAML identity provide, where they will extract information such as your entityID, supported signing methods, SSO endpoints, and public signing key.

Adding a SAML Service Provider

To configure a SAML service provider to use an identity provider, you need to do two things: create them the usual client entry within IdentityServer, and then configure the SAML specifics using the new ServiceProvider object.

This will give you a Client entry that looks something like the following:

new Client {
      ClientId = "http://localhost:5001/saml",
      ClientName = "RSK SAML2P Test Client",
      ProtocolType = IdentityServerConstants.ProtocolTypes.Saml2p,
      AllowedScopes = { "openid", "profile" }
}

And a ServiceProvider entry, which will then need to be added to your service provider store:

new ServiceProvider {
      EntityId = "http://localhost:5001/saml",
      SigningCertificates = {new X509Certificate2("TestClient.cer")},
      AssertionConsumerServices = { new Service(SamlConstants.BindingTypes.HttpPost, "http://localhost:5001/signin-saml") }
};

Here, the ClientId and EntityId must be equal, and must be equal to the EntityID used by the service provider you are integrating with. You then need the public key of the service provider, and their AssertionConsumerServices, made up of what binding type that should be used and the URL of the endpoint. All of this information can be gathered from the service providers metadata. A signing certificate for the service provider is only necessary if you want incoming SAML requests to be signed.

Note that the IdentityServer4.Saml component only supports the HTTP Redirect and HTTP POST bindings for both SAML requests and responses.

A persistent store for ServiceProvider configuration can be found in our Entity Framework package, available on nuget.

IdentityServer 4 as a SAML Service Provider

Now for the other side of the story. In this case, IdentityServer is going to act as a SAML Service Provider, where you can allow users to log into IdentityServer using an account handled by an external SAML Identity Provider.

This library acts much in the same way as other ASP.NET Core authentication libraries for external providers (e.g., OpenID Connect), where you have a local authentication type (the IdentityServer cookie) and then an external authentication provider (SAML2P). So, let’s add that to the ConfigurationServices:

services.AddAuthentication()
    .AddSaml2p("saml2p", options => {
        options.Licensee = "<your license key org name>";
        options.LicenseKey = "<your license key>";

        options.IdentityProviderOptions = new IdpOptions {
            EntityId = "http://localhost:5000",
            BindingType = SamlBindingTypes.HttpRedirect,
            SsoEndpoint = "http://localhost:5000/saml/sso",
            SigningCertificate = new X509Certificate2("idsrv3test.cer")
        };

        options.ServiceProviderOptions = new SpOptions {
            EntityId = "http://localhost:5001/saml",
            MetadataPath = "/saml/metadata",
        // optional
            SignAuthenticationRequests = true,
            SigningCertificate = new X509Certificate2("testclient.pfx", "test")
        };

        options.CallbackPath = "/signin-saml";
        options.SignInScheme = IdentityServerConstants.AuthenticationScheme;    
    });

The licensee and license key are again required here, which can be obtained from identityserver.com.

You then need to define information about the identity provider we want to authenticate against, and information about ourselves, the service provider. The identity provider configuration can all be retrieved from the identity providers metadata document, while the service provider data will need to be configured for your app.

The identity provider’s signing certificate is the public key which will be used to verify SAML responses sent from that provider. You can either load it in from a file or by converting the base64 encoded value found in the identity provider’s metadata:

new X509Certificate2(Convert.FromBase64String(@"MIIDajCCAlKgAwIBAgI...);

If the identity provider requires you to sign SAML requests, you must include a signing certificate in the ServiceProviderOptions and set SignAuthenticationRequests to true.

We recommend signing SAML requests whenever possible. CallbackPath defaults to /signin-saml, and this value will be used as your assertion consumer service.

SAML2P Service Provider Metadata

You can now get the service provider metadata by visiting the path configured in your ServiceProviderOptions. This metadata document is what you need to make available to any identity providers looking to integrate with your SAML service provider, where they will extract information such as your entityID, assertion consumer endpoints, and public signing key.

Source Code

Completed source code for the above, including test keys, can be found on GitHub.

IdentityServer Blog

Welcome to the blog of identityserver.com hosted by Rock Solid Knowledge, the IdentityServer European Partners, offering commercial support, consultancy and training for IdentityServer 3 & 4, and all things authentication, backed by the creators of IdentityServer themselves.

comments powered by Disqus