Skip to content

Second factor query protocol

Pieter van der Meulen edited this page Sep 27, 2016 · 8 revisions

RFC - Second factor query protocol

Introduction

This RFC describes an enhancement of the Stepup-Gateway that allows external systems to authenticate only the second factor of a user.

Current authentication process at the Stepup-Gateway

Currently the Stepup-Gateway (GW) allows authentication to SAML 2.0 Service Providers (SPs). To initiate the authentication process the SP sends a SAML AuthnRequest to the Stepup-Gateway. Optionally the SP can request a level of assurance (LoA) identifier in the SAML request by including a RequestedAuthnContext in the request.

The authentication process is orchestrated by the GW:

  1. The GW performs the authentication by first authenticating the user to the "remote IdP" using SAML. This is the Identity Provider (IdP) that authenticates the user. Only after this step is completed GW learns the identity of the user and the institution (organisation) the user belongs to.

  2. When the authentication succeeds the GW decides whether a second authentication factor needs to be queried. Input are the (LoA) requested by the SP and the minimum LoA configured in the GW for the SP and the institution.

  3. When the previous steps succeed, the GW returns a SAML Response with a Assertion to the SP. The Assertion contains the attributes for the user that were received from the remote IdP.

Note that to use the Stepup-Gateway for strong authentication a user must be present with a web browser during the authentication process. This is requirement for using the Stepup-Gateway. It allows us to add additional second factor authentication methods without having to update services or client software.

Use case

The use case is systems where it is unfeasible to completely externalise authentication to the Stepup-Gateway. We have seen several situations in organisations where this is the case:

  • The system needs to receive the password of the user to perform (some of) its functions
  • The system cannot coordinate single-sign on with the identity provider of the organisation, leading to degradation of the user experience by requiring the user to login twice. These systems are application gateways used by the organisation to control access to multiple of their applications, including windows applications.

Solution

As noted above the authentication of the user by the Stepup-Gateway must be performed from a webbrowser. A difference with the authentication process currently offered by the GW is that the service now must communicate the identity of the user to the GW. A similar situation exists for Tiqr authentication between the GW and the Tiqr authentication server. The solution implemented there uses a SAML AuthnRequest with a Subject element.

The Subject[^samlcore-Subject] element is optional in an AuthnRequest. The GW uses it to request authentication for specific user. To allow an external service to the same, we will use the same mechanism. To indicate the type of second factor requested the SP can use the RequestedAuthnContext[^sanmcore-RequestedAuthnContext] element in the AuthnRequest. This means that the service will be a SAML 2.0 Service Provider (SP).

AuthnRequest

To make the second factor authentication request the SP must meet the same SAML requirements as currently in force:

  • AuthnRequests must be sent to the GW using the urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect[^HTTP-Redirect] binding.
  • AuthnRequests must be signed using http://www.w3.org/2001/04/xmldsig-more#rsa-sha256. Note that the HTTP-Redirect does not use XML Signatures.

An additional requirement for the SP that is specific to this use case is that the SP must know the identifier of the user at the stepup gateway. When using OpenConext / SURFconext as the remote IdP this identifier will be generated by OpenConext / SURFconext based on the schacHomeOrganization and uid attributes of the user at his IdP. The identifier takes the form:

urn:collab:person:{{urn:mace:terena.org:attribute-def:schacHomeOrganization}}:{{urn:mace:dir:attribute-def:uid}}

Example SAML AuthnRequest from the SP to the Stepup-Gateway requesting authentication for a user with ID "urn:collab:person:some-organisation.example.org:m1234567890":

<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
                    xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
                    ID="_zQIibz9FKixdlgX8/E7bHqE29wfatcgbsPdVn0NN"
                    Version="2.0"
                    IssueInstant="2016-03-10T15:09:21Z"
                    Destination="https://gw.stepup.example.org/gssp/2nd-factor-only/single-sign-on"
                    AssertionConsumerServiceURL="https://application-gateway.some-organisation.example.org/consume-assertion"
                    ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"

    <saml:Issuer>https://application-gateway.some-organisation.example.org/metadata</saml:Issuer>
    <saml:Subject>
        <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">urn:collab:person:some-organisation.example.org:m1234567890</saml:NameID>
    </saml:Subject>
    <samlp:RequestedAuthnContext>
        <saml:AuthnContextClassRef>http://stepup.example.org/verified-second-factor/level2</saml:AuthnContextClassRef>
    </samlp:RequestedAuthnContext>    
</samlp:AuthnRequest>

SAML Response

The result of a successful authentication is a SAML Response

Example Response:

<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
                xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
                ID="_ECAokbn0lm7lfVT7THQUl+dSbMrpeyAgiTv0+q16"
                Version="2.0"
                IssueInstant="2016-03-10T15:09:25Z"
                Destination="https://application-gateway.some-organisation.example.org/consume-assertion"
                InResponseTo="_zQIibz9FKixdlgX8/E7bHqE29wfatcgbsPdVn0NN"
                >
    <saml:Issuer>https://gw.stepup.example.org/second-factory-only/metadata</saml:Issuer>
    <samlp:Status>
        <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" />
    </samlp:Status>
    <saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                    xmlns:xs="http://www.w3.org/2001/XMLSchema"
                    ID="_zQIibz9FKixdlgX8/E7bHqE29wfatcgbsPdVn0NN"
                    Version="2.0"
                    IssueInstant="2016-03-10T15:09:25Z"
                    >
        <saml:Issuer>https://gw.stepup.example.org/second-factory-only/metadata</saml: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="#_1ROuxGVzJi5bbre6W4woNza82aK41HKjp6aKtw9r">
                    <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>YR5JFfJc1JZIKm7Ao3kXtDupEfeMrhKpD9T1lF1z0Lg=</ds:DigestValue>
                </ds:Reference>
            </ds:SignedInfo>
            <ds:SignatureValue>...</ds:SignatureValue>
            <ds:KeyInfo>
                <ds:X509Data>
                    <ds:X509Certificate>...</ds:X509Certificate>
                </ds:X509Data>
            </ds:KeyInfo>
        </ds:Signature>
        <saml:Subject>
            <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">urn:collab:person:some-organisation.example.org:m1234567890</saml:NameID>
            <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
                <saml:SubjectConfirmationData NotOnOrAfter="2016-03-10T15:14:25Z"
                                              Recipient="https://application-gateway.some-organisation.example.org/consume-assertion"
                                              InResponseTo="_zQIibz9FKixdlgX8/E7bHqE29wfatcgbsPdVn0NN"
                                              />
            </saml:SubjectConfirmation>
        </saml:Subject>
        <saml:Conditions NotBefore="2016-03-10T15:09:25Z"
                         NotOnOrAfter="2016-03-10T15:14:25Z"
                         >
            <saml:AudienceRestriction>
                <saml:Audience>https://application-gateway.some-organisation.example.org/metadata</saml:Audience>
            </saml:AudienceRestriction>
        </saml:Conditions>
        <saml:AuthnStatement AuthnInstant="2016-03-10T15:09:25Z">
            <saml:AuthnContext>
                <saml:AuthnContextClassRef>http://stepup.example.org/verified-second-factor/level2</saml:AuthnContextClassRef>
            </saml:AuthnContext>
        </saml:AuthnStatement>
    </saml:Assertion>
</samlp:Response>

The response contains a Subject of the user for which authentication was requested, this must match what the SP sent in the Request.

Errors

When the GW is unable or unwilling to authenticate the user a SAML Response with a non success status is sent. In other failure scenarios a non 20x HTTP status code may be returned. The downside of using a HTTP status code is that the user is now "stranded" at the GW. This is not a good user experience. Common failure modes should therefore be handled though a SAML error response as this directs the user back to the SP.

Example error response:

<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
                xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
                ID="_ECAokbn0lm7lfVT7THQUl+dSbMrpeyAgiTv0+q16"
                Version="2.0"
                IssueInstant="2016-03-10T15:09:25Z"
                Destination="https://application-gateway.some-organisation.example.org/consume-assertion"
                InResponseTo="_zQIibz9FKixdlgX8/E7bHqE29wfatcgbsPdVn0NN">
                <saml:Issuer>https://gw.stepup.example.org/metadata</saml:Issuer
                >
    <samlp:Status>
        <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Responder">
            <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:AuthnFailed" />
        </samlp:StatusCode>
    </samlp:Status>
</samlp:Response>

SAML status codes are used to refer specific failure modes back to the SP:

  • Responder - AuthnFailed: The authentication was not successful
  • Responder - NoAuthnContext: The user could not be authenticated at the requested level

Security considerations

The SP needs to know the identity of the user in the Stepup-Gateway. This interface allows a SP to test for the existence of an user identifier at the stepup gateway. When used in combination with OpenConext the identifiers organisation+uid. This makes finding user identifiers by guessing feasible. The SP can initiate authentication without a user present. For authentications that incur costs. for SMS authentication that means an SP can trigger the sending of an SMS to the user, for tiqr authentication this means that an SP can trigger sending a push notification to the user. The SP can determine whether a user is able to perform stepup without the user being present. Because of the above it should be possible to enable the ability of the SP to query second factors on a per IdP / institution basis. Additionally, the users for which an SP may query the second factor should be limited. This can be accomplished limiting the users an SP may authenticate on a per organisation basis.

Implementation discussion

  • The example messages introduce a new IdP EnityID and endpoint on the gateway: https://gw.stepup.example.org/second-factory-only/metadata, similar to the gssp. Technically this additional endpoint is not required. We should discuss whether we want this or not. What type of authentication to use (i.e. normal stepup or second factor only) can be decided based on the RequestedAuthentication context and the EntityID of the SP involved. Having to communicate an additional set of metadata to some SPs will make it more complicated. I don't see the value of an SP Entity being able to use both authentications types, so we could limit an SP to only one type (i.e. normal stepup or second factor only)

  • The authentication context identifiers include a "level". E.g.: http://stepup.example.org/verified-second-factor/level2. I'm avoiding the use "loa" here to clearly differentiate them. The actual identifiers should be configurable just like the existing loa ones are now. Each second factor type maps to an level. It makes sense to have the same two levels by default (level2: sms&tiqr; level3: yubikey&u2f) as we have defined for loa. The same mapping behaviour should occur as for loa. I.e. a request for a level2 token authentication can be fulfilled by a level3 token authentication.

  • 2nd factor only authentications must be distinguishable from normal setup authentications in the authentication log.

[^samlcore-Subject]: See the description of the AuthnRequest element in the [https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf](SAML 2.0 Core specification), section 3.4.1, line 2017

[^sanmcore-RequestedAuthnContext]: See the description of the AuthnRequest element in the [https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf](SAML 2.0 Core specification), section 3.4.1, line 2034

[^HTTP-Redirect]: See [https://docs.oasis-open.org/security/saml/v2.0/saml-bindings-2.0-os.pdf](SAML 2.0 Bindings), section 3.4