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)

Authentication Flow ID

Latest Version

Bug Reporting

Plugin

Plugin ID

Module(s)

Authentication Flow ID

Latest Version

Bug Reporting

OpenID Connect Relying Party Proxy

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

idp.authn.oidc.RP

authn/OIDCRelyingParty

not-released

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
1 2 3 4 /%{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
1 /%{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
1 2 3 4 5 jar:oidc-providermetadata-resolvers.xml -> conf/authn/oidc-providermetadata-resolvers.xml jar:oidc-rp-credentials.xml -> conf/authn/oidc-rp-credentials.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 behavior 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. Establish the Proxy Issuer.

  5. Configure a Redirect URL.

  6. Configure the attributer filter to expose claims to the rest of the system.

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

For finer control, see the Advanced Configuration topics. Adjust your Auditing requirements as appropriate.

Basic Configuration

This section describes the basic configuration options needed to set up a functioning OpenID Reyling 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.

Establish Proxy Issuer (OpenID Provider)

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

oidc-rp.properties

1 idp.authn.oidc.rp.provider.proxyIssuer = <issuer identifier of upstream OP>

Setting up the RP as an OAuth 2.0 Client

For a basic setup, where only one upstream OpenID Provider (OP) is used, once you’ve registered with the OP set the following properties:

1 2 idp.authn.oidc.rp.client.clientId = <client_id received from the OP> idp.authn.oidc.rp.client.clientSecret = <client_secret received from the OP>

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 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

1 idp.authn.oidc.rp.client.redirectURI=https://<hostname>:<port>/idp/profile/Authn/OIDC/RP/callback

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 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 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-seperated 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

1 idp.authn.oidc.rp.client.redirecturl.allowedOrigins = https://prod.example.com, https://dev.example.com:8443

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 where 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

1 idp.authn.oidc.rp.client.scopes = profile,email

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

relying-party.xml

1 2 3 4 5 6 7 <bean id="ExampleOP" parent="RelyingPartyByName" c:relyingPartyIds="https://upstream.op.example.com/"> <property name="profileConfigurations"> <list> <bean parent="OIDC.SSO" p:scopes="profile,email"/> </list> </property> </bean>

Forced Authentication

The RP’s default behavior 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. This forces the OP to prompt the End-User for reauthentication, and return an error if unsuccessful.

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 suitable space-separated string values to the acr_values authentication request parameter.

To add ACR values to the request parameter, 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 can be defined in the conf/authn/authn-comparison.xml file:

1 2 3 4 5 6 7 8 9 10 11 12 <!-- Mappings from Requested Principals to OIDC ACRs --> <util:map id="shibboleth.authn.oidc.rp.PrincipalProxyRequestMappings"> <entry> <key> <bean parent="shibboleth.SAML2AuthnContextClassRef" c:classRef="http://example.org/ac/classes/mfa" /> </key> <list> <bean class="net.shibboleth.oidc.authn.principal.AuthenticationContextClassReferencePrincipal" c:classRef="https://proxy.example.org/context2" /> </list> </entry> </util:map>

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.

Authentication Methods References

The Authentication Methods References (amr) describes 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 return it, it can be extracted and mapped into a Principal object, see Subject Population.

Authentication Response

Obtaining an ID Token

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 a 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

1 idp.authn.oidc.rp.client.userinfo.enabled = false

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

To avoid UserInfo response format confusion in the decoder e.g. from an unlikely HTTP header injection attack, you can require that only JWT UserInfo response types will be accepted — and not a plain JSON object — by setting the following property:

oidc-rp.propeties

1 idp.authn.oidc.rp.client.userinfo.requireJWTResponse = true

This is false by default, to allow either type. It is debatable how helpful this will be. If a JWT response is sent alongside the application/json Content-Type header, the decoder might (although certainly not under normal tested operations) set take the JWT as a JSON Object response, and skip signature validation. However, the claims are not in a valid state, and they should fail JSON Object validation later on in the flow.

Note, you also need to configure JWT UserInfo response objects on the OP for this to then not fail.

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.

1 <import resource="oidc-claim-rules.xml" />

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

1 2 3 4 5 6 <AttributeFilterPolicy id="alwaysReleaseFromProxy"> <PolicyRequirementRule xsi:type="Issuer" value="https://proxy.example.org" /> <AttributeRule attributeID="displayName" permitAny="true" /> <AttributeRule attributeID="mail" permitAny="true" /> <AttributeRule attributeID="sn" permitAny="true" /> </AttributeFilterPolicy>

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

1 2 3 4 5 6 7 8 9 10 11 12 <!-- Mappings from Authentication Methods References and Authentication Context Class References in the claims of the id_token to Java principals about the subject. --> <util:map id="shibboleth.authn.oidc.rp.PrincipalProxyResponseMappings"> <entry key="pwd"> <list> <bean parent="shibboleth.SAML2AuthnContextClassRef" c:classRef="urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport" /> </list> </entry> </util:map>

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 IdP attributes. In most cases, extracting the Subject Identifier and exposing it as a canonical principal name makes sense. Although 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 and exposes it as a canonical principal name for the subject. This is identical in function to the https://shibboleth.atlassian.net/wiki/spaces/IDP4/pages/1265631621. If that is sufficient, no configuration is necessary, although several properties can tweak its behavior including configuration of name transformers (see Reference).

Attribute-Sourced C14N Example

Before you can enable attribute-sourced C14N, you need to ensure the claims are mapped into IdP Attributes using appropriate attribute transcoders (which should be the case by default if you have followed the installation, see Attribute Extraction), and, importantly, you have an attribute filter policy which permits the passthrough of the attribute you are basing the C14N on (see Attribute Filtering).

If you want to extract one of the End-User claims as the canonical principal name, you need to disable the inbuilt C14N flow:

oidc-properties.properties

1 2 ## Uncomment and set this to true idp.authn.oidc.rp.c14n.subjectidentifier.disabled = true

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

1 2 <!-- Remove comment tags to enable Attribute-based c14n --> <bean id="c14n/attribute" parent="shibboleth.PostLoginSubjectCanonicalizationFlow" />

conf/c14n/subject-c14n.properties

1 2 3 4 idp.c14n.attribute.attributeSourceIds = mail # Allows direct use of attributes via SAML proxy authn, bypasses resolver idp.c14n.attribute.resolveFromSubject = true idp.c14n.attribute.resolutionCondition = shibboleth.Conditions.FALSE

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


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/authn/oidc-rp-credentials.xml

Configuration of keys for signing and encryption

conf/authn/oidc-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 set the AuthenticatingAuthority of the AuthenticationContext to the Issuer Identifier of the OP to use. To enable discovery, set the following properties:

oidc-rp.properties

1 2 3 4 ## Comment this property out # idp.authn.oidc.rp.provider.proxyIssuer = <something> ## Set this property to true idp.authn.oidc.rp.provider.discoveryRequired = true

JSON Web Key Set Document

Asymmetric Request Object signature signing, and ID Token / UserInfo response encryption, both require the RP to publish signing and encryption public keys in its 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

There is a single, global, keyset profile. If multiple downstream OPs are used there is no way to present different keys to different OPs. This is unlikely to occur for the time being as discovery is not implemented by default. It will be revised in future versions.

Advanced Authentication Request Options

Response Mode

The response_mode authentication request parameter (technically 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 also the default mode for the ‘coderesponse_type the RP supports. 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.responseMode property e.g.:

oidc-rp.properties

1 idp.authn.oidc.rp.client.responseMode = query|form_post

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

relying-party.xml

1 2 3 4 5 6 7 <bean id="ExampleOP" parent="RelyingPartyByName" c:relyingPartyIds="https://downstream.op.example.com/"> <property name="profileConfigurations"> <list> <bean parent="OIDC.SSO" p:responseMode="form_post"/> </list> </property> </bean>

Only the ‘query’ and ‘form_post’ response modes are supported (see OAuth 2.0 Response Types, and OAuth 2.0 Form Post).

Requested Claims Hook

The RP can request individual claims to be returned in either the ID Token or UserInfo response. See https://openid.net/specs/openid-connect-core-1_0.html#ClaimsParameter. 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 is shown below.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 <bean id="shibboleth.oidc.rp.RequestedClaimsHook" parent="shibboleth.Functions.Scripted" factory-method="inlineScript" p:inputType="org.opensaml.profile.context.ProfileRequestContext" p:outputType="com.nimbusds.openid.connect.sdk.OIDCClaimsRequest"> <constructor-arg> <value> <![CDATA[ var requestedClaims = new com.nimbusds.openid.connect.sdk.OIDCClaimsRequest() .withIDTokenClaimsRequest(new com.nimbusds.openid.connect.sdk.assurance.claims.VerifiedClaimsSetRequest().add("given_name")) .withUserInfoClaimsRequest(new com.nimbusds.openid.connect.sdk.assurance.claims.VerifiedClaimsSetRequest().add("family_name")) requestedClaims; ]]> </value> </constructor-arg>

Request Object

Authentication request parameters can be signed and encrypted (as a JWT) and passed via the request authorization parameter. Authorization Request parameter support is disabled by default, but can be enabled globally by setting the property idp.authn.oidc.rp.client.requestobject.supported 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 (e.g. using the request_parameter_supported value), otherwise the RP will fall back to plain OAuth 2.0 request parameters.

The RP does not currently support the request_uri parameter to pass the request object by reference as opposed to by value.

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. In fact, the RP currently sends the same parameters in both formats/locations if enabled — although this will be reviewed.

Signing

Request object signing is enabled by default but can be disabled globally by setting the idp.authn.oidc.rp.client.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. 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.authn.oidc.rp.client.sig.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 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’.

1 2 3 4 5 6 7 8 9 10 11 12 13 {   "p": "value",   "kty": "RSA",   "q": "value",   "d": "value",   "e": "AQAB",   "use": "sig",   "kid": "defaultRSASig",   "qi": "value",   "dp": "value",   "dq": "value",   "n": "modulus-value" }

You must register the public key components of this signing key with the OP, otherwise it will have no way to validate the JWT.

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/authn/oidc-rp-credentials.xml using the bean shibboleth.authn.oidc.rp.DefaultSigningCredentials. 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 security configuration, see Custom Security Configuration.

Encryption

Request object encryption is disabled by default but can be enabled globally by setting the idp.authn.oidc.rp.client.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 in the security configuration that the OP supports and there is a resolvable credential for. If the OP does not describe any supported JWE encryption algorithms, the first algorithm from the configuration that supports a resolvable credential is used.

The usable credentials are taken from the OP’s published JWK Set document, and the client_secret. The default configuration specifies RSA encryption first, followed by AES Key Wrapping, followed by Elliptic Curve Diffie Hellman Key Agreement. Note, AES Key Wrapping generates a key wrapping key derived from the client_secret. While Direct Encryption using a key derived from the client_secret is supported internally, it is disabled by default.

For OPs that support Request Objects, it is likely the JWT will be encrypted using RSA Key Encryption e.g. RSA-OAEP.

More advanced customisation of Request Object encryption would require a RelyingParty override with a new security configuration, see Custom Security Configuration.

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 serializing 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

1 idp.authn.oidc.rp.httpRequestMethod = GET|POST

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

Advanced Authentication 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, see Custom 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 following property, and register its public key components with the OP:

oidc-rp.properties

1 idp.authn.oidc.rp.client.enc.key=%{idp.home}/credentials/example-enc-key.jwk.jwk
1 2 3 4 5 6 7 8 9 10 11 12 13 { "p": "value", "kty": "RSA|EC", "q": "value", "d": "value", "e": "AQAB", "use": "enc", "kid": "defaultRSAEnc", "qi": "value", "dp": "value", "dq": "value", "n": "modulus" }

More advanced customisation of ID Token decryption would require a RelyingParty override with a new security configuration, see Custom Security Configuration.

The RP does not currently host the contents of a JWK Set, and hence does not support the jwks_uri parameter. Consequently automated key rotation is not support.

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.

How these settings are configured may different per OpenID Provider

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 behavior, the configuration for the default metadata resolver could be found in /conf/authn/oidc-providermetadata-resolvers.xml. Note, 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:

1 2 3 4 5 6 7 8 9 10 11 12 <bean id="ProviderHTTPResolver" parent="shibboleth.authn.oidc.rp.OIDCProviderMetadataResolver">         <constructor-arg>             <bean parent="shibboleth.authn.oidc.rp.CacheBuilder">                 <constructor-arg>                     <bean p:cacheId="ProviderHTTPDynamicResolver" parent="shibboleth.authn.oidc.rp.BaseProviderDynamicCacheBuilderSpec"                      p:minCacheDuration="PT1M"                     p:maxCacheDuration="PT2M"                     p:cleanupTaskInterval="PT30S"/>                 </constructor-arg>             </bean>         </constructor-arg>   </bean>

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 sanatization strategy removes any ‘validation’ claims, and leaves ‘identity', ‘authorization’, and ‘misc’ claims. That prevents exposure of validation claims to the attribute translation and filtering stages — although are still available to various internal functions. See the table below to show which gets removed by default.

Claim Name

Claim

Claim Name

Claim

azp

Authorized Party, already validated while accepting a token.

nonce

Nonce to prevent reply-attacks, already validated while accepting a token.

auth_time

The authentication time

acr

Authentication Context Class. These are translated into Principal objects by Subject Population

amr

Authentication Method Reference. These are translated into Principal objects by Subject Population

iss

Issuer, already validated while accepting a token.

iat

Issued At, already validated while accepting a token.

aud

Audience, already validated while accepting a token.

exp

Expiry, already validated while accepting a token.

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.

Custom Security Configuration

The RP uses a profile default security configuration for JWT encryption, decryption, signing, and signature validation. The bean used to implement the default can be changed by specifying a new bean name in the idp.security.authn.oidc.rp.config property. The new bean can inherit from the default configuration — to make configuration easier — and override settings where appropriate, for example:

oidc-rp.properties

1 idp.security.authn.oidc.rp.config = CustomSecurityConfig

global.xml

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ## In global.xml ### These are all the configurations you can override, you can omit those where the defaults are sufficient. <bean id="CustomSecurityConfig" parent="shibboleth.authn.oidc.rp.DefaultSecurityConfiguration"> <property name="jwtDecryptionConfiguration"> <ref bean="decryptionBeanName" /> </property> <property name="jwtSignatureValidationConfiguration"> <ref bean="signatureValidationBeanName" /> </property> <property name="jwtSignatureSigningConfiguration"> <ref bean="signatureSigningBeanName" /> </property> <property name="jwtEncryptionConfiguration"> <ref bean="encryptionBeanName" /> </property> </bean>

As with other IdP security configurations, you can also override this on a per-profile, per-relying-party basis by adding a p:securityConfiguration-ref attribute to a profile bean. For more on this topic, see SecurityConfiguration.

Auditing

There are some new audit fields (in review)

Field

Description

Field

Description

RESPT

The outgoing authentication request’s response_type

RESPM

The outgoing authentication request’s response_mode

ACRS

The outgoing authentication request’s Authentication Context Class References

RDURI

The outgoing authentication request’s redirect_uri

AUTHNR

The authentication result status of ‘success’, or the error code if the response was indicative of an error

AUTHNFS

The authentication flow steps that have run by the time this audit statement has been written. By default, these are: AuthenticationRequest, AuthenticationResponse, TokenResponse, UserInfoPlainResponse | UserInfoJWTResponse

Reference

Name

Type

Default

Description

Name

Type

Default

Description

idp.authn.oidc.rp.provider.proxyIssuer

String

 

Statically-defined Issuer ID of upstream OP to use for authentication.

idp.authn.oidc.rp.client.clientId

String

 

OAuth 2.0 Client Identifier valid at the Authorization Server.

idp.authn.oidc.rp.client.redirecturl.allowedOrigins

String list

 

A list of allowed origins the RP can use when dynamically creating a redirect URI to use. Can be overriden to a fixed redirect URI using the property idp.authn.oidc.rp.client.redirectURL

idp.authn.oidc.rp.client.redirectURI

String

 

The redirect URI to supply to the Authorization Server during an Authentication Request. Is where the Authentication Response is sent. Will override the dynamically computed redirect computed using the idp.authn.oidc.rp.client.redirecturl.allowedOrigins

idp.authn.oidc.rp.client.clientSecret

String

 

OAuth 2.0 secret know only to the IdP and the Authorization Server. Used to authenticate the RP to the Authorization Server and to potentially secure JSON Web Tokens.

idp.authn.oidc.rp.provider.keyfetch.interval

Duration

30 minutes

The time duration for which an OpenID Provider’s key set document is cached.

idp.authn.oidc.rp.client.enc.key

Resource path

 

Resource containing a JWK private key for decryption, typically a file in the credentials directory. For example, for decryption id_tokens or UserInfo tokens.

idp.authn.oidc.rp.client.sig.key

Resource path

 

Resource containing private key for signing, typically a file in the credentials directory. For example, to sign the Request Object (if used) sent to the Authorization Server.

idp.authn.oidc.rp.provider.discoveryRequired

Boolean

false

Whether to invoke OP-discovery prior to running flow. Defualt is false as there is currently no OP discovery mechanism to use.

idp.authn.oidc.rp.client.requestobject.supported

Boolean

false

Should the authentication request to the Authorization Server be passed inside a Request Object (by value).

idp.authn.oidc.rp.client.requestobject.encrypted

Boolean

false

If supported, should the Request Object be encrypted.

idp.authn.oidc.rp.client.requestobject.signed

Boolean

true

If supported, should the Request Object be signed. Defaults to true otherwise the advantage of using a Request Object is limited to certain caching functions.

idp.authn.oidc.rp.client.userinfo.enabled

Boolean

true

Should the RP request claims from the UserInfo Endpoint.

idp.authn.oidc.rp.client.userinfo.requireJWTResponse

Boolean

false

If true, the UserInfo response must use the application/jwt format i.e. be returned as a JWT.

idp.authn.oidc.rp.client.responseMode

String

query

The mechanism the OP uses to response to an Authentication Request from the Authorization Endpoint. Only supports one-of; ‘query’ or ‘form_post’.

idp.authn.oidc.rp.client.scopes

String list

openid

Define which scopes to request authorization for. By default ‘openid’ is required and always supplied. A comma separated list of additional scopes can be request e.g. ` profile,email`

dp.authn.oidc.rp.supportedPrincipals

String list

 

Comma-delimited list of protocol-specific Principal strings associated with flow. The flow must support principals requested by the SP. By default, the usual password-centric are used. These can be overridden by this property. Remeber that by default these are not added to the authentication result (see idp.authn.oidc.rp.addDefaultPrincipal), instead taking any AMRs or ACRs mapped from the upstream OP.

idp.authn.oidc.rp.addDefaultPrincipal

Boolean

false

Whether to auto-attach the preceding set of Principal objects to each Subject produced by this flow.

idp.authn.oidc.rp.client.authenticationMethod

String

client_secret_basic

The mechanism by which the client authenticates to the Authorization Server when using the Token endpoint. Supports client_secret_basic and client_secret_post.

idp.authn.oidc.rp.client.idtoken.tlsServerValidationOnly

Boolean

false

If true and the ID Token was retrieved using TLS with server validation, JWS signature checking will be skipped

The general properties configuring this flow via authn/authn.properties are:

Name

Type

Default

Description

Name

Type

Default

Description

idp.authn.oidc.rp.c14n.subjectidentifier.lowercase

Boolean

false

Whether to lowercase the incoming NameID value prior to applying any transforms

idp.authn.oidc.rp.c14n.subjectidentifier.uppercase

Boolean

false

Whether to upcase the incoming NameID value prior to applying any transforms

idp.authn.oidc.rp.c14n.subjectidentifier.trim

Boolean

true

Whether to trim leading and trailing whitespace from the username

idp.authn.oidc.rp.c14n.subjectidentifier.disabled

Boolean

false

Disable the inbuilt C14N flow, and fall back to system wide C14N flows

The following beans if needed may be defined in oidc-rp-config.xml

Bean ID / Type

Default

Description

Bean ID / Type

Default

Description

shibboleth.authn.oidc.rp.TokenRequestEncoder

Function<HttpResponse, T>

shibboleth.authn.oidc.rp.DefaultAuthCodeTokenResponseEncoder

A function bean to create a Token Request to the OP. Must consider the authorization grant and client authentication.

shibboleth.authn.oidc.rp.TokenResponseDecoder

Function<HttpResponse, T>

shibboleth.authn.oidc.rp.DefaultTokenResponseDecoder

A function bean to decode the token response from the OP. The default decoder just converts the JSON response into a simple JSON map.