SAML

The SAML protocol plugin is available for integrating the Identity Server with a Federation Server. As with all protocols, there is a request interface that is meant for a Service Provider or App (acting as a Relying Party) to integrate to, as well as a response interface that responds with SAML towards a Federation Server (acting as Service Provider towards the Identity Server, and as SSO server towards the Relying Party). This interaction is shown in the following sequence diagram:

SAML Interaction Sequence

Fig. 136 SAML Interaction Sequence

The SAML protocol of the Identity Server supports the generic SAML IDP initiated SSO flow, as well as an ADFS-specific IDP initiated SSO flow. In both cases the SAML POST binding is used.

To integrate the SAML protocol plugin, both the Service Provider (App) as well as the Federation Server need to be configured. This section will describe how the protocol works, how a Service Provider (App) can integrate, as well as how to setup a Federation Server using a generic SAML federation service, Ping Federate, and ADFS.

SAML protocol

SAML protocol request

The following parameters can be provided to the authentication endpoint of the the Authentication Service as part of a SAML protocol request. Parameters must be provided in the query string of a GET request. Unknown parameters will be ignored.

Parameter name Description
serviceProviderId REQUIRED (unless client_id is provided), the Service Provider Id that the Service Provider is registered with at the Authentication Service
forceAuthN OPTIONAL, when the value is “true” or when the parameter is provided, it will enforce a fresh authentication, even when the user already has an existing session with the Authentication Service from before
acr OPTIONAL, one or more string values that specify which ACR’s may be used to authenticate the user with
freshness OPTIONAL, provide the number of seconds that indicates the maximum allowed age of a previous successful authentication. If previous authentication existed that was older than the indicated freshness, re-authentication will take place
target_url OPTIONAL, when provided, the value of the state-parameter is used as the value for the RelayState parameter in the SAML protocol response. See below.

Tip

If the downstream application is an OAuth client that will be accessed via SAML, the serviceProviderId can be omitted and the client_id can be used.

SAML protocol response

The authentication result is embedded in a generated HTML-page that uses JavaScript to auto-POST to the Assertion Consumer Service URL (acs-url) of the configured Federation Server. The parameters are as follows:

Parameter name Description
SAMLResponse The Base64 encoded SAML Response message, that is constructed for the receiving Federation Server
RelayState The generated RelayState. In the case of a generic Federation Service type, this is set to the Target URL of the Service Provider. It can be overridden by the value of the target_url parameter in a SAML protocol request. In the case of adfs see RelayState

Configuring the Authentication Service

In order for the Authentication Service to be able to communicate with a SAML Federation Server, the following must be configured:

  • An authentication service profile
  • A SAML protocol which is set as the one used by the authentication service profile
  • A singing key that will be used to digitally sign the SAML message

See also

For information about how to create an authentication service profile, refer to the section about creating a new profile earlier in this guide.

Defining a SAML protocol

When configuring the SAML protocol settings, the Authentication Service needs to know about the receiving end of the communications, as well as how to assert protocol message protection through digital signatures. The information that is required about the receiving Federation Server includes:

  • The Federation Server’s Entity ID
  • The Assertion Consumer Service URL of the Federation Server, where a SAML Response message can be posted to
  • The type of the Federation Server

For message protection, the SAML protocol needs to be configured with a signing key.

Finally, there are a number of settings that can tweak the assertion generation procedure. The details of these settings can be found below.

Configuring the SAML protocol

The following configuration snippet is a template on how to configure the SAML protocol section of an Authentication protocol:

...
<profiles>
    <profile>
        <type xmlns:auth="https://curity.se/ns/conf/profile/authentication">
            auth:authentication-service
        </type>
        ...
        <protocol-id>${ID}</protocol-id>
        ...
        <protocols>
            <protocol>
                <id>${ID}</id>
                <saml>
                    <signing-key>${reference-to-signing-key-id}</signing-key>
                    <recipient-entity-id>${federation-service-entity-id}</recipient-entity-id>
                    <acs-url>${federation-service-acs-url}</acs-url>
                    <saml-federation-service-type>${federation-service-type}</saml-federation-service-type>
                    <saml-clock-skew>${saml-clock-skew}</saml-clock-skew>
                    <saml-assertion-time-to-live>${assertion-time-to-live}</saml-assertion-time-to-live>
                </saml>
            </protocol>
        ...
        </protocols>
        ...
    </profile>
...
</profiles>
...
Configuration Element Default Value Mandatory Meaning
id N/A true The identifier of the SAML protocol configuration. Set this as the value for protocol-id to activate the protocol on the profile
saml/signing-key N/A true Reference to a key in the signing key section of the crypto facilities
saml/recipient-entity-id N/A true The SAML EntityId of the Federation Server that a SAML Response message is sent to
saml/acs-url N/A true The URL where the SAML Response message is POSTed to (including scheme, hostname, port, and path)
saml/saml-federation-service-type generic false The type of SAML Federation Service that is used. Valid choices are genric or adfs
saml/saml-clock-skew 60 false The number of seconds that timestamps may vary, to allow for clock skew between sender and receiver, e.g. used when validating inbound message expiration.
saml/saml-assertion-time-to-live 300 false The number of seconds that is used to indicate how long an issued (outbound) SAML Assertion or Message is valid.
saml/saml-message-time-to-live 300 false The number of seconds that is used to indicate how long an inbound SAML Message is valid after it was issued.

Templates

The SAML protocol uses the template plugins/protocol/saml/postback.vm to generate the HTML page that auto-POSTs the SAML Response message to the Federation Server. To change the template, create a file called postback.vm in the directory <template_dir>/third-party/protocol/saml/postback.vm and make any modifications that are needed.

For debugging, it can be helpful to disable the auto-post to give you a chance to inspect the message before it is sent to the federation server. To do this, create a file called globals.vm in the <template_dir>/third-party-debug/base directory. In this template, set the $debugRedirect variable to true like this:

#set ($debugRedirect = true)

This will cause an interstitial page to be shown that contains the SAML message (both the encoded and decoded version) as well as the relay state.

../../_images/debugging_saml.png

Fig. 137 SAML Debugging

Tip

This technique of adding a global.vm template to third-party-debug and setting $debugRedirect can be used with any protocol, not just SAML.

Service Provider (App) integration

For a Service Provider (App), that depends on SSO from a Federation Server, integration is kept as simple as possible. The Service Provider is registered with the Identity Server, see the section on configuring Service Providers. Doing so, it is assigned a Service Provider Id.

When making a request to authenticate a user, the Service Provider (App) redirects the user to the Authentication endpoint of the Identity Server, identifying itself with its Service Provider Id as parameter in the request. The authentication process ensures that the Federation Server gets a SAML Assertion with information about the authenticated user, and when this is accepted by the Federation Server, the user is redirected back to the Service Provider (App).

That URL that the authenticated user is redirected to, can be either the target-URL as configured with the Authentication Service (or maybe even a default URL that is configured at the Federation Server), but it can also be established as part of the initial request to the authentication endpoint of the Authentication Service. This means that the RelayState is generated from the request parameters, and provided to the Federation Server. It is then up to the Federation Server whether it understands this though.

Federation Server integration

As the SAML protocol will issue a SAML Assertion and provide that in an unsolicited SAML Response message to the Federation Server, both services need to be introduced to each other. At its minimum, the Authentication Service needs to exchange its EntityId as well as the signing certificate with the Federation Server at the receiving end. The EntityId is defined by the server’s Environment Id.

See also

For information about configuring the Identity Server’s environment or the Crypto facility, refer to the sections Configuration Guide and Cryptography.

What follows, is information how to set up a PingFederate and ADFS Federation Server to be used by the Authentication Service.

PingFederate

The SAML integration protocol can be used with PingFederate from Ping Identity. In particular, the SAML 2.0 IdP-initiated Web SSO profile needs to be setup using a POST binding. The steps to do this are documented in the PingFederate manual, but consist of the following high-level steps:

  1. Create a SAML 2.0 Identity Provider connection in PingFederate and an SP adapter that will integrate your app with PingFederate.

  2. On the general connection information tab of the IdP connection

    1. Use the Entity ID that corresponds to the environment/name as configured in the Identity Server.
    2. Enter the recipient-entity-id that was configured in the Identity Server as the Virtual Server IDs.
  3. In the IdP connection, enabled the IdP-initiated SSO profile but not any of the others.

  4. When configuring browser SSO, enable the POST binding but not the others.

  5. Import and select the certificate that was configured in protocol instance’s saml/signing-key setting when configuring the security credential to be used for the PingFederate connection.

You can verify that the connection works by accessing the Authentication Service’s authenticate endpoint for the profile that is configured with the SAML integration protocol.

AD FS

The SAML integration protocol can be used to use the Curity Identity Server as the authentication server in an AD FS environment. This is made possible by configuring the Curity Identity Server as a Claims Provider for the AD FS server.

Add the Curity Identity Server as a Claims Provider Trust

  1. Enter claims provider trust data manually

    ../../_images/adfs-1.png
  2. Use AD FS profile

    ../../_images/adfs-2.png
  3. Enable support for the Web SSO protocol

  4. Set the Claims provider SAML 2.0 SSO URL to be the authentication endpoint. I.e. https://localhost:8443/authn/authenticate

    ../../_images/adfs-3-4.png
  5. Use a Claims provider trust identifier that corresponds to the environment/name as configured in the Curity Identity Server.

    ../../_images/adfs-5.png
  6. Configure the certificate that corresponds to the signing-key configured in the Curity Identity Server.

    ../../_images/adfs-6.png

Configure Claim Rules to pass through all claims that the Curity Identity Server sends

  1. Create a new Claim Rule and use the template Send Claims Using a Custom Rule.
  2. Set the rule to be c:[] => issue(claim = c);

Tip

Create a Claim Rule to passthrough all claims issued by the Curity Identity Server to a Relying Party

c:[Issuer == "se.curity"]
         => issue(claim = c);

Where se.curity corresponds to the environment/name as configured in the Curity Identity Server.

Tip

Set the default Claims Provider for a Relying Party from powershell

Set-AdfsRelyingPartyTrust
    -TargetIdentifier "rp-entity-id"
    -ClaimsProviderName @("se.curity")

Where se.curity corresponds to the environment/name as configured in the Curity Identity Server and rp-entity-id is the configured identifier for the Relying Party.

RelayState

When using IdP initiated SSO with ADFS, the form parameter RelayState is used. The value of the RelayState is a URL encoded string with the following components.

Parameter name Description
RPID The id of the Relying Party at ADFS. The Curity Identity Server will send the Service Provider ID.
wctx A parameter for WS-Federation Relying Parties. The Curity Identity Server will add this if the query parameter target_url is present in the authentication request. The Curity Identity Server will also add any unknown parameters to the url as the query string.
RelayState A nested RelayState parameter that will be sent to SAML Relying Parties by ADFS. The Curity Identity Server will pass all unknown parameters here. If the target_url is set, the RelayState will be the same as wctx. The full string is url encoded.

Examples

  • Sending an unknown parameter foo

    Authentication request
    https://login.example.com/authn/authenticate?serviceProviderId=app1&foo=bar
    
    Result:
    RelayState=RPID%3Dapp1%26RelayState%3Dfoo%253Dbar
    
    Data sent from ADFS to SAML Relying Party
    RelayState=foo%3Dbar
    
  • Sending both target_url and an unknown parameter foo

    Authentication request
    https://login.example.com/authn/authenticate?serviceProviderId=app1&foo=bar&target_url=https://localhost/ws-fed
    
    Result:
    RPID%3Dapp1%26wctx%3Dhttps%253A%252F%252Flocalhost%252Fws-fed%253Ffoo%253Dbar%26Relaystate%3Dhttps%253A%252F%252Flocalhost%252Fws-fed%253Ffoo%253Dbar
    
    Data sent from ADFS to a WS-Federation Relying Party
    wctx=https%3A%2F%2Flocalhost%2Fws-fed%3Ffoo%3Dbar
    
    Data sent from ADFS to a SAML Relying Party
    wctx=https%3A%2F%2Flocalhost%2Fws-fed%3Ffoo%3Dbar&RelayState=https%3A%2F%2Flocalhost%2Fws-fed%3Ffoo%3Dbar
    

    Note

    It is up to the application to handle the data received. Nor SAML nor ADFS specify the use of the data, but it could be used to for loading a specific endpoint in the RP, or similar.

SAML Logout

When using the SAML integration protocol, the integrating party can send SAML Logout Requests to logout the current authenticated session. The requests needs to conform to the SAML Single Logout Profile of the Profiles for the OASIS Security Assertion Markup Language (SAML) V2.0 (Section 4.4)

Logout Request

The logout is initiated by sending a LogoutRequest to <authentication-endpoint-path>/logout, below is an example request.

<samlp:LogoutRequest ID="_df7af98a-e872-457e-9ab5-9337b3680c1b"
                     Version="2.0"
                     IssueInstant="2020-05-15T05:41:03.269Z"
                     Destination="https://login.example.com/saml/authn/authenticate/logout"
                     Consent="urn:oasis:names:tc:SAML:2.0:consent:unspecified"
                     xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">
    <Issuer xmlns="urn:oasis:names:tc:SAML:2.0:assertion">http://fs.curityio.net/</Issuer>
    <NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
            xmlns="urn:oasis:names:tc:SAML:2.0:assertion">johndoe</NameID>
    <samlp:SessionIndex>_b2d5fe1d-bbb0-4644-a315-32728197fe60</samlp:SessionIndex>
</samlp:LogoutRequest>

Curity Identity Server will validate that the Issuer is the recipient-entity-id of the protocol config, or one of the service-providers defined in the profile. If the request is valid, a LogoutResponse will be sent to the configured logout-service-url.

Note

The SessionIndex and NameID parameters are ignored, all SSO Sessions will be terminated.

Logout Response

The LogoutResponse will contain a status code, and will be signed with the configured signing-key.

<saml2p:LogoutResponse Destination="https://fs.curityio.net/saml"
                       ID="_89a4fa60-209f-47af-ba65-1b2959d02d13"
                       InResponseTo="_df7af98a-e872-457e-9ab5-9337b3680c1b"
                       IssueInstant="2020-05-15T05:41:03.276Z"
                       Version="2.0"
                       xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol">
    <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">se.curity</saml2:Issuer>
    <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
        <ds:SignedInfo>
            <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
            <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
            <ds:Reference URI="#_89a4fa60-209f-47af-ba65-1b2959d02d13">
                <ds:Transforms>
                    <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
                    <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
                </ds:Transforms>
                <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
                <ds:DigestValue>GgDl0PDpNIr/OEex0KMlmZdphDnHFJSHxuxkL5I8GTI=</ds:DigestValue>
            </ds:Reference>
        </ds:SignedInfo>
        <ds:SignatureValue>tfcHN<snip>zS3fqQ==</ds:SignatureValue>
        <ds:KeyInfo>
            <ds:X509Data>
                <ds:X509Certificate>MIIDc<snip>KlQ==</ds:X509Certificate>
            </ds:X509Data>
        </ds:KeyInfo>
    </ds:Signature>
    <saml2p:Status>
        <saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" />
    </saml2p:Status>
</saml2p:LogoutResponse>

Session Index

The SAML SLO profile requires the SessionIndex parameter to be sent in a LogoutRequest. Curity Identity Server will just log out all browser sessions, and not take the sent SessionIndex into account. Curity Identity Server will however echo the sent SessionIndex in the LogoutResponse. Since some SAML Identity Providers might require the SessionIndex, it is recommended to enable the setting include-session-index-in-response.

Logout using serviceProviderId

A registered service-provider can use the simplified logout method by simply issuing a GET request with the query parameter serviceProviderId. This will terminate the session(s) and send an unsolicited LogoutResponse to the configured logout-service-url.

Note

Not all SAML IdP support receiving unsolicited responses.