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:
allowed-authenticators
default-authenticator
authenticator-filters
template-area
required-claim
context-info
application-url
target-url
allowed-origins
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:
Fig. 138 Managing the service provider apps in the admin GUI
To open this page, select Authentication → $AUTHENTICATION_PROFILE_ID → Service Providers.
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:
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> ...
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
when there is one configured allowed-origins value, but this contains a wildcard, or 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.
for_origin
Note that the Content-Security-Policy’s frame-ancestors response header will be set with all the allowed-origins values.
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
https://example.com
https://example.com:\*
https://\*.example.com:444
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.
_oq
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.
https://curity.example.com/authenticate?serviceProviderId=se.curity&acr=urn:se:curity:authentication:html-form:htmlSql
https://example.org/application-url?serviceProviderId=se.curity&acr=urn:se:curity:authentication:html-form:htmlSql
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.
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
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.
nonce
state
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.
https://example.org
https://curity.example.com
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.
For example, add https://example.org/* to the whitelist.
https://example.org/*
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.
/anonymous
base-url
https://curity.example.com/anonymous/resources/js/preflight.min.js
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.
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.
onPreflight()
preflightUrl
returnUrl
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.
onPreflightReturn()
<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:
data-autoload="false"
1
<script type="text/javascript" data-autoload="false" src="https://curity.example.com/anonymous/resources/js/preflight.min.js"></script>
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.
enable-preflight