OIDCRelyingPartyAuthnConfiguration

Overview

The authn/OIDCRelyingParty login flow supports the use of a separate OpenID Provider (OP) to authenticate the subject, with the IdP acting as an OIDC Relying Party (RP) proxy (OAuth 2.0 Client). This is similar in concept to the SAML Proxy, but for OpenID Connect.

The Authorization Code Flow is the only supported OIDC authentication flow. Both Implicit and Hybrid flows, by default, use the fragment response mode which would require additional User-Agent processing (e.g. JavaScript in the browser) to extract the parameters from the fragment and post them back to the IdP’s callback endpoint.

Dynamic client registration is not supported at this stage.

Plugin Installation

Plugin

Plugin ID

Module(s)

Depends On

Authentication Flow ID

Bug Reporting

Plugin

Plugin ID

Module(s)

Depends On

Authentication Flow ID

Bug Reporting

OpenID Connect Relying Party Proxy

net.shibboleth.idp.plugin.authn.oidc.rp

idp.authn.oidc.RP

idp.oidc.config.3

authn/OIDCRelyingParty

JOIDCRP

Enabling the Module

For a detailed guide on configuring modules, see the ModuleConfiguration topic. Once the plugin has been installed, its module should be enabled automatically for you:

Check Module Is Enabled
/%{idp.home}/bin$ ./module.sh -l ... Module: idp.authn.oidc.RP [ENABLED]

However, if you need to enable it you can using the module command:

Enable the module
/%{idp.home}/bin$ ./module.sh -e idp.authn.oidc.RP

Either manual or automatic module enablement will copy across the following configuration files from the jar:

Configuration files
jar:oidc-providermetadata-resolvers.xml -> conf/authn/oidc-rp-providermetadata-resolvers.xml jar:oidc-rp-credentials.xml -> conf/authn/oidc-credentials.xml jar:oidc-rp-client-secret-credential.xml -> conf/authn/oidc-rp-client-secret-credential.xml jar:oidc-claim-rules.xml -> conf/attributes/oidc-claim-rules.xml jar:oidc-rp-config.xml -> conf/authn/oidc-rp-config.xml jar:oidc-rp.properties -> conf/authn/oidc-rp.properties

Configuration Overview

The following requirements exist for this flow to operate:

  1. The Issuer Identifier of the upstream OpenID Provider must be known somehow.

  2. The OP must make available its configuration document at the well-known location - although this behaviour can be customized.

The following steps must be followed to enable the RP to communicate with an upstream OpenID Provider:

  1. Create a client with your OpenID Provider.

    1. Note your client_id and client_secret.

    2. If you want to enable asymmetric (public key) Request Object signature signing and or ID Token or UserInfo token encryption, register any public digital signature and encryption keys with the OP.

  2. Add your client_id to the property idp.authn.oidc.rp.client.clientId.

  3. Add your client_secret to the property idp.authn.oidc.rp.client.clientSecret.

  4. Add conf/authn/oidc-rp-client-secret-credential.xml to the IdP’s credentials.xml file.

  5. Add conf/oidc-credentials.xml to the IdP’s credentials.xml file.

  6. Establish the Proxy Issuer.

  7. Configure a Redirect URL.

  8. Configure the attribute filter to expose claims to the rest of the system.

  9. Change the login flow to OIDCRelyingParty in authn.properties.

    1. Note, if you want to use the RP inside an MFA flow, you will need to consider which c14n flow to run to produce a suitable principalName, see here.

  10. Add the OIDC.SSO profile to relying-party.xml

For finer control, see the Advanced Configuration topics. Make sure to adjust your Auditing requirements as appropriate.

Basic Configuration

This section describes the basic configuration options needed to set up a functioning OpenID Relying Party. Options in this section are limited to the following configuration file:

Configuration File

Description

Configuration File

Description

conf/authn/oidc-rp.properties

The properties file where most standard configuration options are found.

conf/authn/oidc-rp-client-secret-credential.xml

A credential used to hold the client_secret set in the properties file

conf/oidc-credentials.xml

Assymetric key credentails used by both RP and OP plugins

To enable the most basic functionality of the RP, the client_secret (set in the properties file) must get transformed into an internal Credential suitable for signing, authentication to the token endpoint, and possibly encryption. To do so, simply import the oidc-rp-client-secret-credentials.xml into conf/credentials.xml:

You also need to include the configuration for asymmetric keys, namely the oidc-credentials.xml configuration file. This is shared between the OP and the RP and is described in more detail in the Advanced Topics section.

Establish Proxy Issuer (OpenID Provider)

In the simplest case, the RP will be used with a single upstream OpenID Provider (OP) and you must set the issuer identifier (OP identifier) in the properties file:

oidc-rp.properties

If you wanted to configure more than one upstream OpenID Provider, see the advanced topic.

Setting up the RP as an OAuth 2.0 Client

Once you’ve registered with the OP, obtain the client identifier and client secret and set the following properties:

oidc-rp.properties

Note, it is possible the OP uses ‘certificate-based' authentication and will not give you a client secret by default. As of plugin version 1.1.0 the RP supports the use of client_secret_jwt and private_key_jwt client authentication methods.

Authentication Request

Redirection URI

You will need to specify a redirection URI as per the OAuth2.0 specification (RFC6749). This is the endpoint the OP will redirect the authentication response to via the end-users user-agent (browser). The redirection URI must exactly match the one that is registered with the OP. If only a single OP is configured (i.e. no discovery), the following property can be explicitly set:

oidc-rp.properties

Where <hostname> and <port> match that of your running IdP — the port can be omitted if your IdP uses the standard HTTP/HTTPS port e.g. 80 and 443 respectively. The endpoint itself needs only to be accessible by the end-user’s user-agent (browser).

Dynamic Redirect URI

Alternatively, you can let the RP plugin determine the redirect URI from the Host header sent from the client that issues the original (e.g. SAML) authentication request. To do so, comment out the idp.authn.oidc.rp.client.redirectURI property and then, in order to prevent HTTP Host header injection attacks (and possibly leaking your authorization code to a malicious actor), declare one or more comma-separated allowed 'origins' [RFC6454] in the property idp.authn.oidc.rp.client.redirecturl.allowedOrigins. Each origin is a combination of scheme, host, and port. For schemes where the default port is used e.g. HTTPS on port 443, the port can be omitted. For example, assuming a production IdP has a hostname of prod.example.com using the HTTPS scheme over the default port, and a matching development IdP has a hostname of dev.example.com running on a custom port 8443, the following origins would be sufficient:

oidc-rp.properties

This can be useful if you want to keep a single generic configuration between development, staging, and production servers, etc. Also, if a single IdP instance is serving requests from more than one virtual-host, each authentication request will need to be redirected back to the originating Hostname in order to successfully complete the request.

Scopes

In OIDC, scopes request that certain sets of information are made available as claim values (see Scope Claims) and returned in the UserInfo response (although it is technically possible it could return them in the id_token if other response_types were allowed).

The openid scope is always applied to authentication requests, but further scopes can be added. In the simplest case where there is only one upstream OP, a comma-separated list of scopes can be added to the property idp.authn.oidc.rp.client.scopes, for example:

oidc-rp.properties

When dealing with more than one upstream OP, a RelyingParty scopes override would be required for each, for example:

relying-party.xml

Forced Authentication

The RP’s default behaviour is to respect the forceAuthn requirement of the downstream SAML SP. However, this can be overridden per OP by setting the forceAuthn property of a suitable RelyingParty override.

In the OIDC world, requiring forced authentication amounts to setting the prompt authentication request parameter to login and the max_age parameter to 0 seconds. This forces the OP to prompt the End-User for reauthentication and return an error if unsuccessful. It also includes the auth_time claim in the ID Token response which the RP uses to determine if the authentication happened after the authentication request was issued.

Authentication Context Class Reference

The Authentication Context Class Reference (acr) is similar to the SAML <AuthnContextClassRef> construct and defines the level of authentication performed. The RP can request ACRs by adding them as an essential acr claim inside the Requested Claims object, or as a voluntary claim inside the acr_values request parameter.

By default, the RP tries to add ACR values as essential claims inside the Requested Claims object — whether that be inside the Request Object or as standard URL request parameters. If the OP does not support the claims parameter, the RP reverts to using the acr_values request parameter. Note, in doing so, this changes the requirement semantics from essential to voluntary.

To add ACR values, the RP looks at the defaultAuthenticationMethods RelyingParty configuration option. The global policy (which you could override per OP) either passes through or maps the original SP’s requirements into ACR values. If passed through, it is likely the upstream OP will not understand their semantics, hence a mapping list (bean) can be defined that translates between SAML-requested principals and OIDC ACR values. This bean should already be defined in the conf/authn/authn-comparison.xml file so you can uncomment it, for example:

Of course, if you specified a RelyingParty override for defaultAuthenticationMethods, you could provide any logic you want, for example, always requesting a particular ACR value.

At this time, the RP does not take into consideration the acr_values_supported of the upstream OP. Hence, you could blindly request an ACR that is not supported. This could change in future versions.

Similarly, the response from the OP may contain the acrclaim which might need mapping back into a suitable value for the requesting SP. A mapping list (bean) can be defined that translates between OIDC ACR string values and SAML-requested principals. This bean should already be defined in the conf/authn/authn-comparison.xml file so you can uncomment it, for example:

Authentication Methods References

The Authentication Methods References (amr) describe the family of authentication methods used by the OpenID Provider to authenticate a subject. For example, multi-factor or username and password etc. You can not request which amr is used in the authentication request, but the OP can optionally return it in the id_token. If it does, it can be extracted and mapped into a Principal object, see “Subject Population” below.

Obtaining an ID Token From the Token Endpoint

Upon successful authentication, the OP returns an OAuth 2.0 Authorization Response containing, importantly, an authorization code in the query parameters (unless a different response_mode was configured). The RP will immediately exchange (back-channel) the authorization code for an Access Token and ID Token. The HTTP Client, its security parameters, and the encoder and decoder can all be customised, but these are very much advanced configuration options, which shouldn’t need changing.

UserInfo Endpoint Request

The UserInfo Endpoint returns additional claims about an authenticated End-User. An HTTP GET or HTTP POST request is sent (using the access_token received in the authentication response) to the UserInfo endpoint, and either a plain JSON object is returned, or a signed and or encrypted JWT. Either contain the UserInfo claims about the authenticated end-user — including any specifically requested in the authentication request. The response is validated and the claims are merged with those in the id_token using a replaceable ‘merging strategy’ (see End-User Claims Merging). The merged claims are exposed to the rest of the flow for later translation, filtering, and extraction.

Requests to the UserInfo endpoints are enabled by default. To disable globally, set the following property:

oidc-rp.propeties

Or disabled per OP by providing a RelyingParty override with the property p:retrieveUserInfoEndpointClaims="true|false" set.

relying-party.xml

Post-Processing

Attribute Extraction and Filtering

Currently, IdPAttribute extraction is possible using the AttributeRegistryConfiguration. The plugin installation process will copy a file named oidc-claim-rules.xml to the conf/attributes/ directory. This file contains a default set of OIDC claims to IdPAttribute transcoding rules. To enable it, you must add an import to conf/attributes/default-rules.xml:

If you have already installed the OIDC OP plugin, it is possible you have already enabled the OIDC claim mapping rules below, and you can skip this step.

Once the results have been produced, the AttributeFilterConfiguration is applied. This is a reversal of the usual filtering process of outbound data and operates with the proxying IdP itself as the "requester" and the proxied OP as the "issuer". An example policy to allow through displayName, mail, and sn is shown below.

attribute-filter.xml

Note, attribute resolution and filtering rules are shared with the IdP. Take care not to overlap these rules in confusing ways.

Subject Population

As with any other login flow, the product will be an AuthenticationResult containing a Java Subject with some number of Principal objects. The content of the Subject produced automatically comprises:

  • If the incoming id_token contains the sub claim (it should always), then an OIDCSubjectIdentifierPrincipal is included that wraps the subject claim as is.

  • A ProxyAuthenticationPrincipal is included that will contain the issuer of the id_token as the proxied authorities i.e. the OpenID Provider. Note, this is far less complete than the SAML variant, as it does not contain a ‘chain' of proxied authorities i.e. if the request was proxied further.

  • Any IdPAttribute objects resulting from the initial extraction and filtering stage are wrapped in IdPAttributePrincipals.

What is not automatic is the mapping of OIDC Authentication Context Class References (acr) and Authentication Method References (amr) from the id_token into Principals that can, for example, be matched against requested principals sent by the downstream SAML SP. Internally, both are passed through translation functions that map the Method References and Context Class References into Principal objects. However, by default, the mapping list (bean) does not exist, and the default behaviour does nothing. To provide mappings you need to add the following list bean to conf/authn/authn-comparison.xml. The key is the OIDC AMR or ACR string value, the value is the Principal to populate for the Subject.

conf/authn/authn-comparison.xml

Storing Off Context Information In Private Credentials

The RP is capable of storing custom Principals into the Subject’s private credentials set after authentication using a strategy bean named shibboleth.authn.oidc.rp.ContextToPrivateCredentialsMappingStrategy. This allows, for example, saving off the OIDC access_token and refresh_token from the Token Endpoint for later use by the rest of the system.

A strategy that can map an access_token and refresh_tokeninto an OAuth2AccessTokenPrincipal and OAuth2RefreshTokenPrincipal is included by the RP but is not enabled by default. If you want that functionality, you can include the following bean in the oidc-rp-config.xml file:

Subject Canonicalization

The AuthenticationResult needs to be processed into a normalized principal name to expose to the rest of the system — or subsequent authentication flows. The result of authentication is an OIDC Subject Identifier alongside various claims wrapped inside IdPAttributes. In most cases, extracting the Subject Identifier claim and exposing it as a canonical principal name makes sense. In more advanced cases it is possible to extract one of the End-User claims returned from either the id_token or UserInfo response.

The default behavior provides the former: An inbuilt C14N flow takes the Subject Identifier out of the OIDCSubjectIdentifierPrincipal (populated from the “sub” claim from the OP) and exposes it as a canonical principal name for the subject. This is identical in function to the SimplePostLoginC14NConfiguration. If that is sufficient, no further configuration is necessary, although several properties can tweak the behavior including the configuration of name transformers (see Reference).

If you don’t want that behavior, then read on.

Attribute-Sourced C14N Example

If you want to extract one of the End-User claims as the canonical principal name instead of the “sub” claim value, you need to disable the inbuilt C14N flow:

oidc-properties.properties

Then, as with a similar example in the SAML Proxy authentication flow, you need to configure the attribute post-login c14n flow via properties by pointing it at "<claimName>" as a source. The properties to enable this are commented out in conf/c14n/subject-c14n.properties and are noted below.

conf/c14n/subject-c14n.xml

conf/c14n/subject-c14n.properties

This should result in the mail attribute being presented as the canonical principal name of the subject.

Subject Canonicalization When Using the MFA Flow

If you are using the RP inside an MFA flow, the ‘inbuilt’ subject canonicalization flow above is not responsible for producing the final principal name (although the attribute-sourced flow would be if you use that). Inside the MFA flow, you need to decide which flow you want to produce the final principal name and configure it appropriately within the shibboleth.PostLoginSubjectCanonicalizationFlow list. By default the IdP will use the c14n/simple flow and base the result on any UsernamePrincipal it finds—for example, this would be the result of the Password flow if that was used as the first factor. If you wanted the same behavior described earlier, that is to use the 'sub' claim that comes back inside the ID Token, you’ll need to add the ‘inbuilt' flow to the shibboleth.PostLoginSubjectCanonicalizationFlow. For example:

conf/c14n/subject-c14n.xml


Advanced Configuration

This section described advanced configuration options which can be skipped if a basic configuration is sufficient for your needs. Options in this section relate to the following configuration files:

Configuration File

Description

Configuration File

Description

conf/authn/oidc-rp.properties

The properties file where most standard configuration options are found.

conf/authn/oidc-rp-config.xml

Additional flow configure to modify flow behaviour e.g. a place to add custom beans.

conf/oidc-credentials.xml

Configuration of asymmetric keys for signing and encryption

conf/authn/oidc-rp-providermetadata-resolvers.xml

Configuration of the OpenID Provider metadata resolvers

OpenID Provider Discovery

In addition to setting the upstream OP to use via static configuration taken from the properties file, you can also supply a lookup function to determine the issuer, using the bean shibboleth.authn.oidc.rp.discoveryFunction.

Alternatively, a new discovery service flow that runs prior to this flow could be developed, for example, based on WebFinger Discovery. Such a mechanism would likely need to follow the OpenID Discovery specification and produce an Issuer Identifier that can be set as the AuthenticatingAuthority on the AuthenticationContext. To enable discovery, set the following properties:

oidc-rp.properties

Each upstream OP's settings must be configured individually in the RelyingParty configuration. For example:

relying-party.xml

JSON Web Key Set Document

Asymmetric Request Object signature signing and ID Token / UserInfo response encryption, both require the RP to publicly publish signing and encryption public keys in a Key Set Document. This is presented to the OP as the jwks_uri. To enable the profile endpoint, the following profile bean must be added to the shibboleth.UnverifiedRelyingParty bean:

  • OIDC.Keyset

The profile URI: /idp/profile/oidc/rp/keyset

Advanced Authentication Request Options

Response Mode

The response_mode authentication request parameter (an OAuth 2.0 authorization parameter) defines how the authentication response parameters are returned to the RP (e.g. in the query string, or HTML form parameters). By default, the ‘queryresponse_mode is used by the RP — as it is the default mode for the ‘coderesponse_type the RP supports by default. You can, however, alter this by setting the responseMode profile configuration option. In cases where there is only a single upstream OP, we can achieve this by setting the idp.authn.oidc.rp.client.responseMode property e.g.:

oidc-rp.properties

Alternatively, this can be set per upstream OP using a relying party override:

relying-party.xml

Login_hint

A login_hint request parameter can be set per OP using a Relying Party override. The override can either take a static value or a function that derives a login_hint from the Profile Request Context at runtime.

relying-party.xml

Display 2.1.0

The ‘display’ request parameter can be added to the authorization request by defining a relying-party override either with the static property value p:display or by using a lookup strategy bean (of type Function<ProfileRequestContext, String>) referenced with p:displayLookupStrategy-ref.

relying-party.xml

Requested Claims Hook

The RP can request individual claims to be returned in either the ID Token or UserInfo response, see Claims Parameter. Currently, there is no default mechanism for adding requested claims for an inbound SAML authentication request i.e. from requested attributes. There is however a hook that allows you to build requested claims dynamically per request. The hook is a simple Java Function that takes the entire authentication request context tree (the ProfileRequestContext) and returns a Nimbus OIDCClaimsRequest object. An example scripted function that requests the given_name in the ID Token and family_name in the UserInfo response is shown below.

Requesting The ACR Claim

The requested claims hook can be used to request specific Authentication Context Class References by setting the acr claim with suitable values. Note, however, if the downstream SP requested certain authentication contexts, these will be added to the acr claim alongside those in the requested claims hook before being forwarded to the upstream OP (see ACR).

Request Object

Authentication request parameters can be signed and encrypted (as a JWT) and passed via the request authorization parameter. Authorization Request Object parameter support is disabled by default, but can be enabled globally by setting the property idp.oidc.requestobject.used to 'true', or per RelyingParty override using p:useRequestObject="true". Note, even if enabled, the downstream OP must support the use of the request parameter and advertise that fact in its metadata document using the request_parameter_supported value, otherwise, the RP will fall back to plain OAuth 2.0 request parameters.

Request parameters that are contained in the Request Object JWT supersede those passed by OAuth2.0 request syntax (e.g. the query string parameters, see OIDC Core). The RP does not currently support caching the Request Object, so there is no real benefit of sending variable (dynamic) request parameters as URI parameters and fixed parameters in the Request Object.

Signing

Request object signing is enabled by default but can be disabled globally by setting the idp.oidc.requestobject.signed property to ‘false’, or per relying-party override using p:signRequestObject="false". There seems little point in disabling request object signing, as that forms one of the main benefits of using the request object — to ensure the parameters of the request object have not been tampered with, and the authenticity of the object can be determined.

(Default) Symmetric Key MAC

The default configuration for signing the request object computes an authentication tag using the HS256 MAC algorithm (the only required JWS algorithm - see RFC7518). The symmetric key used is a derivative of the client_secret shared between the OP and RP. In most circumstances, that will be sufficient.

Asymmetric Key Digital Signature

If you did want to alter this behaviour you can. The simplest way is to uncomment the idp.signing.oidc.rs.key property and point it to a suitable asymmetric JSON Web Key credential (see the example below). The potential algorithms to use are defined by the order they appear in the default security configuration. The actual algorithm to use is the first of those that are also supported by the OP (as described in its metadata; request_object_signing_alg_values_supported) and the credential you defined in the JSON Web Key file. If none are compatible, an error will be returned.

The key use is sig for ‘signature’.

If you wanted to support one OP that used RSA signatures, and another that supported EC signatures, further keys can be added to the conf/oidc-credentials.xml using the bean shibboleth.oidc.SigningCredentials. The first key that supports the chosen algorithm with a given upstream OP will then be used.

More advanced customisation of Request Object signing would require a RelyingParty override with a new OIDC Security Configuration. Below is a simple example of how that might be accomplished.

Only support the HS256 signature signing algorithm. In the RP, this would restrict the Request Object JWS to using MAC-based validation.

Encryption

Request object encryption is disabled by default but can be enabled globally by setting the idp.oidc.requestobject.encrypted property to ‘true’, or per relying-party override using p:encryptRequestObject="true".

Asymmetric and Symmetric Key Encryption

There are no required JWE encryption algorithms the OP must support, hence the algorithm to use is chosen by selecting the first algorithm from the Security Configuration that the OP supports and that there is a resolvable credential for. If the OP does not describe any supported request object JWE encryption algorithms, the first algorithm from the security configuration that supports a resolvable credential is used.

Usable credentials are taken from the OP’s published JWK Set document and the configured client_secret. The default configuration specifies RSA encryption first, followed by AES Key Wrapping, and then Elliptic Curve Diffie Hellman Key Agreement.

More advanced customisation of Request Object encryption would require a RelyingParty override with a new Security Configuration.

Adding Arbitrary Claims2.1.0

To include additional, arbitrary, claims in the Request Object to send to the authorization server, you can provide a custom BiConsumer that adds claims to a ClaimSet derived from information pulled out of the ProfileRequestObject. This can be achieved by defining and implementing a new bean (of type BiConsumer<ProfileRequestObject, ClaimsSet>) named shibboleth.authn.oidc.rp.CustomRequestObjectClaimsStrategy. Once defined, the bean will be automatically injected into the Request Object building step of the RP.

The ClaimsSet that is provided to the BiConsumer is actually the set of Request Object claims that are currently being built by the RP. While it is technically possible to modify the claims that have already been added, such as scope or redirect_uri, we do not advise doing so if you want to ensure that the authorization request sent to the Authorization Server is compatible.

Note, that this is not to be confused with adding claims to the ‘claims’ request parameter, which is shown in Requested Claims Hook section. This feature allows complete control over the set of Request Object claims.

Authentication Request Message Encoders

The default message encoder used by the RP encodes the OIDC authentication request (an OAuth 2.0 authorization request) using the HTTP GET method. This defaults to constructing the authentication request parameters using URI Query String Serialization. If you would rather use HTTP POST Form Serialization you can, by setting the following property:

oidc-rp.properties

Or again, this could be achieved per OP using a Relying Party override and the p:httpRequestMethod="POST|GET" property.

Proof Key for Code Exchange (PKCE)2.1.0

The RP supports the Proof Key for Code Exchange (PKCE) OAuth 2.0 extension (rfc7636) to help mitigate various authorization code interception and injection attacks. Despite these types of attacks being hard for confidential clients (which the RP is), it is still recommended. To enable PKCE support in the RP, set the property idp.oidc.forcePKCE to true. As this is a shared property between the OP and the RP, if you wanted to isolate this configuration change to just the RP you can specify it in a relying-party override:

What does it do?

In summary, to ensure that the client requesting the Token Response from the Token Endpoint is the same as the one that performed the initial authorization, a code_verifier is created. This code_verifier is transformed into a code_challenge and added to the initial authorization request. The Token Request is then required to include the original code_verifier which the OpenID Provider can transform and correlate with the code_challenge it received and stored from the authorization request. If they match, it proves that the client requesting the Token Response is the same as the client that performed the initial authorization.

Advanced Token Request Options

Client Authentication

By default, the RP uses the client_secret_basic authentication method when authenticating itself to the Token Endpoint of the Authorization Server. This can be changed using the idp.authn.oidc.rp.client.authenticationMethod property. The following methods are supported:

Client Authentication Method

Description

Client Authentication Method

Description

client_secret_basic

Send the client_id and shared client_secret using the HTTP Basic Authentication scheme.

client_secret_post

Send the client_id and shared client_secret in the request body.

client_secret_jwt1.1.0

Create a JWT using a HMAC SHA algorithm. Use the client_secret credential and the first compatible algorithm (a HMAC one) listed in the active security configuration e.g. the default shibboleth.oidc.SigningConfiguration config.

private_key_jwt1.1.0

Create a JWT and sign it using a suitable private key that corresponds to a public key registered with the OpenID Provider. Uses the configured signing credentials and the first compatible algorithm listed in the active security configuration e.g. the default shibboleth.oidc.SigningConfiguration config, and the list of credentials in shibboleth.oidc.SigningCredentials.

Advanced Token Response Options

ID Token Decryption and Signature Validation

Signature Validation

ID Tokens are always signed (by default using RS256), but the algorithm used can be changed using the id_token_signed_response_alg client metadata/registration value on the OP. Signature validation is performed by a configured TrustEngine. By default, the set of ‘trusted’ validation keys comes from the OP’s hosted JSON Web Key Set document and the client_secret inside the ReylingParty configuration (e.g. the one supplied in the properties files). If one exists, an ‘untrusted’ validation key is extracted from the JOSE header of the JWT. If the ‘untrusted’ key is used to verify the JWS, it must be verified by one of the ‘trusted’ keys. If an ‘untrusted’ key is not supplied, the ‘trusted’ keys will be used for validation instead.

More advanced customisation of signature validation would require a RelyingParty override with a new Security Configuration.

Encryption/Decryption

To enable ID Token encryption on the OP, the RP must register the encryption algorithm to use by setting the id_token_encrypted_response_alg and id_token_encrypted_response_encclient metadata/registration values on the OP (or any other way the OP supports its registration).

If the OP is configured to use a symmetric key encryption algorithm, it uses a key derived from the client_secret to either wrap a content encryption key (key wrapping) or directly as the content-encryption key (direct encryption). The RP can then use the client_secret to decrypt the ID Token.

To enable asymmetric public key encryption management modes, you must first create a suitable JSON Web Key credential (see the example below), reference it with the property idp.signing.oidc.rsa.enc.key, and register its public key components with the OP. For example:

oidc-rp.properties

More advanced customisation of ID Token decryption would require a RelyingParty override with a new Security Configuration.

UserInfo Token Decryption and Signature Validation

Typically, UserInfo response signing must be enabled on the OP before it is used. This involves setting the UserInfo signed response algorithm on the OP, for example, the userinfo_signed_response_alg client metadata/registration value. Once enabled, the OP will return the UserInfo claims inside a signed JWT. The same TrustEngine mechanism used to validate ID Tokens is used to validate the UserInfo claims JWT.

Similarly, UserInfo response encryption must also be enabled on the OP before use. This involves setting the UserInfo encrypted response algorithm and the UserInfo encrypted response encryption algorithm on the OP, for example, the userinfo_encrypted_response_alg and userinfo_encrypted_response_enc client metadata/registration value. The same ID Tokens encryption/decryption mechanisms as used to decrypt the UserInfo claims JWT.

Provider Metadata Lookup

Metadata for the upstream OP is fetched dynamically by an HTTP metadata resolver based on the Issuer location derived from the Issuer Identifier. More specifically by default, appending the well-known path /.well-known/openid-configuration to a normalised Issuer Identifier. This should all work without requiring any further modification.

If you do need to modify its behaviour, the configuration for the default metadata resolver can be found in /conf/authn/oidc-rp-providermetadata-resolvers.xml. Note, that the resolver configuration here differs from that for normal SAML Metadata resolvers. The maxCacheDuration defines how long the metadata remains valid before it expires and is re-fetched. Unlike SAML Metadata, the OIDC Provider metadata does not explicitly define cacheDuration or validUntil settings. An example config is given below:

If required, a well-known location composition strategy can be set for the resolver by defining a BiFunction bean named shibboleth.authn.oidc.rp.WellKnownLocationCompositionStrategy which accepts a Nimbus Issuer and a string well-known path, and returns the Issuer location.

End-User Claims Merging And Sanitization

To construct the final set of End-User claims to translate and filter, the system performs two important operations:

  1. Sanatizes the UserInfo and id_token claims.

  2. Merges the sanatized UserInfo claims with those in the id_token.

The default claim sanitization strategy removes any ‘validation’ claims, and leaves ‘identity', ‘authorization’, and ‘misc’ claims. This prevents exposure of validation claims to the attribute translation and filtering stages — although these are still available to various internal functions. See the table below to show which gets removed by default.

The default merging strategy combines claims in the UserInfo response with those from the id_token to produce a new claims set using the following logic:

  1. If one of UserInfo or id_token claims are null, the other is returned.

  2. If both input claims are null, an empty claims set is returned.

  3. Merges the id_token claims into the UserInfo claims, the value of a claim from the id_token
    is favoured over that from the UserInfo response if the claim names clash.

Both strategies can be customised by supplying beans named shibboleth.authn.oidc.rp.ClaimMergingStrategy and shibboleth.authn.oidc.rp.ClaimSanitizationStrategy. See the Reference section below.

Auditing

There are some new audit fields (in review)

Reference

Vendor Integration Pitfalls

Microsoft

  • Issuer Identifier: If you are unable to determine the issuer to use for the idp.authn.oidc.rp.provider.proxyIssuer property, it can be taken from the OpenID Connect metadata document. The location of the metadata document can be found in the Endpoints tab on the App Registrations page.

  • Issued At (iat) claim: Microsoft(Azure AD) sets the Issued At (iat) claim 5 minutes before the time at which the JWT was actually issued. To the best of our understanding, this is the way they add clockSkew to deal with clock synchronization issues. The default allowable clockSkew for the ID Token is dictated by the idp.policy.clockSkew property: this will need to be set to a value > 5 minutes so IssuedAt validation does not fail.

    • For V1.0.0 of the RP, If you do not want to set the IdP wide clockSkew property to adjust the ‘iat’ claim validation for Azure, you can override the validation bean as shown below:

Google

  • Google does not support the auth_time claim in ID Token responses. This prevents the RP from proxying a forced authentication request as it expects to evaluate the auth_time claim on its return in the ID Token (i.e. the auth_time was after the authentication request was sent). The only information we can find on this subject is recorded in this thread.