Service Providers

Introduction

Service providers are usually applications or relying parties. They depend on the Identity Server for authentication.

A Service provider can have the following properties configured:

Parameter Name Mandatory Description
allowed-authenticators No the authenticators to be used by this Service provider (reference by ID). If not set, all authenticators are allowed.
default-authenticator No one of the allowed-authenticators can be set as the default one.
authenticator-filters No any Authenticator Filters to be used by this Service provider.
template-area No allows specifying The Template Override System to override some (or all) templates being used.
required-claim No a mandatory claim
context-info No a message that can be shown to users during authentication.
application-url No URL used if a request is made to the authentication service without the parameters necessary to initiate an authentication transaction.
target-url Yes URL used to redirect the user to the application after a successful login has taken place.
allowed-origins No list of URIs or URI-patterns that is allowed to embed the rendered pages inside an iframe or be a trusted source. See Framable User Interface for details.

Managing Service Providers in the Admin UI

In the admin Web UI, a service provider is also referred to as an “app”. These are accessible from the Service Provider page under each authentication profile:

../_images/service-providers-in-gui.png

Fig. 133 Managing the service provider apps in the admin GUI

To open this page, select Authentication → $AUTHENTICATION_PROFILE_ID → Service Providers.

Framable User Interface

The Authentication Service offers specific capabilities to allow its user screens to be embedded through IFRAMEs. While the default behaviour of HTML-pages is to not be allowed to be framed (due to security reasons, i.e. clickjacking prevention), it is however possible to allow framing on a per-service-provider base.

Note

Recent browsers add protection mechanisms where first parties and third parties are given different capabilities, which results in default settings that do or do not allow third parties to set cookies. This can have an effect in the way that framing the authenticating user interface can be done, as the pages served by Curity are considered to be coming from a third party when they are hosted from another domain. If you experience unexpected behaviour when integrating Curity through framed pages, please see the section on Third Party Cookies.

The framability settings control both HTTP Response headers as well as the inclusion of a anti-clickjacking JavaScript from the default templates. By default, the following behaviour is effective:

Header Default Value Description
X-Frame-Options header DENY Explicitly disallow this page to be included in a frameset
Content-Security-Policy header frame-ancestors ‘none’ Explicitly disallow anybody to frame this page
Anti Clickjack script script included JavaScript in the default templates that breaks out of a frameset

To configure whether requests to authenticate for a particular Service Provider are framable, you can configure the following options:

...
<profiles>
    <profile>
        <type xmlns:auth="https://curity.se/ns/conf/profile/authentication">
            auth:authentication-service
        </type>
        ...
        <service-providers>
            <service-provider>
                <id>${ID}</id>
                ...
                <allowed-origins>${allowed-origin-value-1}</allowed-origins>
                <allowed-origins>${allowed-origin-value-n}</allowed-origins>
                ...
            </service-provider>
        ...
        </service-providers>
        ...
    </profile>
...
</profiles>
...
Configuration Element Default Value Mandatory Meaning
allowed-origins N/A false An optional list of valid origins (URI patterns) that are may frame the authentication HTML pages. When no entry is configured, framing is not allowed. When there are multiple allowed origins, please read on to understand how to control its behaviour in such cases.

Multiple values for ‘allowed-origins’

When framing is allowed, it is required to define at least one allowed-origins value. This one value is then used as ALLOW-FROM value in the X-Frame-Options response header (if no wildcards are in the pattern!), as well as value for the frame-ancestors list of the Content-Security-Policy response header value.

The X-Frame-Options header only supports one value with its ALLOW-FROM value. This means that

  1. when there is one configured allowed-origins value, but this contains a wildcard, or
  2. when there are multiple configured allowed-origins values

the Service Provider should specify which value to use in the X-Frame-Options header. This value must be provided through the for_origin request parameter. The Curity server will validate whether this for_origin value matches against at least one allowed-origins value before using it as value for the X-Frame-Options ALLOW-FROM response header.

When there are multiple configured allowed-origins values, and there is no for_origin provided to select one value, the server will respond such that framing is allowed by sending the appropriate frame-ancestors list as part of the Content-Security-Policy response header and disable the standard anti-Clickjack script, but since it can not decide which value to use for X-Frame-Options, it will send X-Frame-Options DENY as well.

Parameter name Description
for_origin URL to set with the X-Frame-Options ALLOW-FROM response header.

Note that the Content-Security-Policy’s frame-ancestors response header will be set with all the allowed-origins values.

Origin URI pattern format

The format that can be used to specify a valid origin follows the Source Expression Matching specification of the _Content Security Policy spec. The path part of a origin URI pattern is ignored. Some examples of valid values for allowed-origins, are:

  • https://example.com
  • https://example.com:\*
  • https://\*.example.com:444

Original Query retry integration

The Authentication Service introduces an integration point for a Service Provider to be notified when an unknown request in an existing authentication transaction occurs. This can happen when the regular authentication flow can not be continued when a user ends up in a browser session that no longer has a session with the Authentication Service.

Possible cause of this, could be when the user started an authentication session, and followed through the new account registration procedure. Part of this procedure can involve the user to go to its email-client, and select the account activation link. This link could open up a new browser application, that does not hold the user’s session. It could also be that after activating the account, the session times out before the user chooses to continue by clicking the Login-link.

The Authentication Service will keep a reference to the original query that the Service provider made to start an authentication flow, or that the OAuth Client made to start an authorization flow that took the user to authenticate at the Authentication Service. It does this by passing along an _oq parameter that keeps the original query state in the querystring.

Whenever a session could not be continued, but an _oq-value was available, the user is redirected back to the Application Url that is configured for the Service Provider or the OAuth Client. The redirect back to this URL also contains all the parameters that were in the original request. These parameters are the querystring-parameters from an initial GET-request, or the formbody-parameters from an initial POST-request. Note that if a Service Provider or OAuth Client does not configure an Application Url, then no value for the Original Query parameter will be created.

By providing the Service Provider with all the information that it included in the initial authentication request, it is now up to the Service Provider to re-create a new authentication attempt when it receives the user on the endpoint that is configured as Application Url, and send the user back to the Authentication Service, to start a new authentication attempt. In case of an OAuth Client it works the same, except that the endpoint that is configured as Application Url should restart the authorization attempt at the authorize endpoint of the Authorization Service.

Example

Service Provider sends user to the Authentication Service to request authentication:
  • GET https://curity.example.com/authenticate?serviceProviderId=se.curity&acr=urn:se:curity:authentication:html-form:htmlSql
When the session is lost, the user is redirected to the configured Application Url of the Service Provider:
  • REDIRECT https://example.org/application-url?serviceProviderId=se.curity&acr=urn:se:curity:authentication:html-form:htmlSql
Now the Service Provider has the chance to craft a new authentication request, and redirect the user there:
  • REDIRECT https://curity.example.com/authenticate?serviceProviderId=se.curity&acr=urn:se:curity:authentication:html-form:htmlSql

Example OAuth Client

OAuth Client sends user to the Authorization Service to request an access- or ID-token:
  • GET https://curity.example.com/authorize?client_id=oauth_client&response_type=code&scope=openid&nonce=675765&redirect_uri=https://oauth-client.example.org/cb

The Authorization Service redirects the user to the Authentication Service to authenticate the user.

When the session is lost, the user is redirected to the configured Application Url of the OAuth Client:
  • REDIRECT https://oauth-client.example.org/application-url?client_id=oauth_client&response_type=code&scope=openid&nonce=675765&redirect_uri=https://oauth-client.example.org/cb
Now the OAuth Client has the chance to craft a new authorization request, and redirect the user there:
  • REDIRECT https://curity.example.com/authorize?client_id=oauth_client&response_type=code&scope=openid&nonce=799888&redirect_uri=https://oauth-client.example.org/cb

Important

when the application-url sends the user back to restart the flow, make sure that an external entity can not use the application-url endpoint to control the value of the nonce or state parameters for malicious intent.

Third Party Cookies

Modern browsers distinguish between requests to first parties and to third parties, which is the case when an app (first party) integrates with the authentication services of an authentication provider (third party). So when a user visits a page on the domain of https://example.org, and Curity is integrated through framing and hosted from another domain, let’s say https://curity.example.com, then we are fitting this exact picture.

The consequence could be that cookies from https://curity.example.com are being rejected, and as such, Curity can not keep a cookie-based session with the end user, which would result in a failing authentication attempt.

To prevent this from happening, Curity offers a means to make an attempt to turn Curity into a first party. It does this by preflighting Curity before the app’s website loads, resulting in a preflight-cookie being set from the https://curity.example.com-domain, after which the user is taken back to https://example.org.

Steps to Integrate Preflighting

  1. Add the app’s URL to the whitelisted redirect url’s of the authentication profile.

For example, add https://example.org/* to the whitelist.

2. Establish the URL of the preflight script through the URL of the anonymous endpoint of the authentication service that you’re using.

You can find the path in the Endpoints configuration of the authentication service. Let’s say, it is mapped on the path /anonymous. The base-url is set to https://curity.example.com. Putting everything together, the URL of the preflight script now is https://curity.example.com/anonymous/resources/js/preflight.min.js.

  1. Include the preflight script in the page of the app.

The script will auto-execute the function to find out whether a preflight needs to be done, and execute the actual preflight, ensuring that the user is taken back to the URL of the current page after preflight has completed.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<html>
  <head>
    ...
    <script type="text/javascript" src="https://curity.example.com/anonymous/resources/js/preflight.min.js"></script>
    ...
  </head>
  <body>
    ...
  </body>
</html>

Note that it is only a best effort attempt to raise Curity as first party; different browsers may develop new features that may influence how this attempt will work out.

Advanced Preflight behaviour

The preflight script will ensure that the request is preflighted, and that the preflight result is persisted to optimize the flows. In case custom behaviour is desired, e.g. when a different return-url should be used or other actions are to be taken upon initiating the preflight process, there are extension points to either override the preflight redirect or the preflight return.

To override the preflight request, define a global function onPreflight() before including the script. This function gets the default preflightUrl (i.e. endpoint at Curity that establishes the first party relationship) and the returnUrl provided as parameters.

Listing 116 Example onPreflight() override
1
2
3
4
5
6
7
8
<script type="text/javascript">
function onPreflight(preflightUrl, returnUrl) {
  console.log('Stepping out to ' + preflightUrl + ' to preflight the request to ' + returnUrl);
  window.location(preflightUrl + '?return_url' + encodeURIComponent(returnUrl));
}
</script>

<script type="text/javascript" src="https://curity.example.com/anonymous/resources/js/preflight.min.js"></script>

To override the preflight return, define the global function onPreflightReturn() before including the script. No parameters are provided to this function.

Listing 117 Example onPreflightReturn() override
1
2
3
4
5
6
7
8
<script type="text/javascript">
function onPreflightReturn() {
  console.log('Third party preflighted the request and returned; setting cookie as session cookie');
  document.cookie = "_preflighted=true";
}
</script>

<script type="text/javascript" src="https://curity.example.com/anonymous/resources/js/preflight.min.js"></script>

When the preflight script is included, code will run to ensure preflight is done when needed. It is possible to disable possible redirects by setting data-autoload="false" as a tag on the script-tag that includes the preflight-script:

Listing 118 Disable auto-execute of preflight script
1
    <script type="text/javascript" data-autoload="false" src="https://curity.example.com/anonymous/resources/js/preflight.min.js"></script>

Disabling the Preflight Resource

By default, the preflight resource will be exposed as part of the anonymous endpoint on the authentication service. If you are not using it, you can disable this on the Authentication-service through the enable-preflight configuration setting.