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 |
---|---|---|---|---|---|
OpenID Connect Relying Party Proxy | net.shibboleth.idp.plugin.authn.oidc.rp.OIDCRPPlugin | idp.authn.oidc.RP | authn/OIDCRelyingParty | not-released |
For a detailed guide on how to install plugins, see here.
In summary, use the plugin
command that ships with the IdP to install the plugin from either a local file pre-downloaded, from a URL or by pluginId 4.2
Installation
C:>\opt\shibboleth-idp\bin\plugin.bat -I net.shibboleth.idp.plugin.oidc.whatever
or
$ /opt/shibboleth-idp/bin/plugin.sh -i http://shibboleth.net/downloads/identity-provider/plugins/pluginName/version/URL
or
$ /opt/shibboleth-idp/bin/plugin.sh -i <plugin.tar.gz>
If installing from a local file, you need to ensure the GPG detached signature (e.g. the .asc file) is placed alongside the main plugin archive on disk.
Listing Installed Plugins
$ /opt/shibboleth-idp/bin/plugin.sh -l
or
C:>\opt\shibboleth-idp\bin\plugin.bat -l
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-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:
The Issuer Identifier of the upstream OpenID Provider must be known somehow.
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:
Create a client with your OpenID Provider.
Note your client_id and client_secret.
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.
Add your client_id to the property
idp.authn.oidc.rp.client.clientId
.Add your client_secret to the property
idp.authn.oidc.rp.client.clientSecret
.Establish the Proxy Issuer.
Configure a Redirect URL.
Configure the attributer filter to expose claims to the rest of the system.
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 |
---|---|
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
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:
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
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
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
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
<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:
<!-- 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
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
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.
<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
<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 thesub
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
<!-- 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 SimplePostLoginC14NConfiguration. 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
## 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
<!-- Remove comment tags to enable Attribute-based c14n --> <bean id="c14n/attribute" parent="shibboleth.PostLoginSubjectCanonicalizationFlow" />
conf/c14n/subject-c14n.properties
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 |
---|---|
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
## 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
Advanced Request Object signature signing operations and ID Token and UserInfo response encryption, 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 ‘query’ response_mode
is used by the RP — as it is also the default mode for the ‘code’ response_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
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
<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.
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.
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
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_enc
client 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
idp.authn.oidc.rp.client.enc.key=%{idp.home}/credentials/example-enc-key.jwk.jwk
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:
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:
Sanatizes the UserInfo and
id_token
claims.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.
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:
If one of UserInfo or
id_token
claims are null, the other is returned.If both input claims are
null
, an empty claims set is returned.Merges the
id_token
claims into the UserInfo claims, the value of a claim from theid_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
idp.security.authn.oidc.rp.config = CustomSecurityConfig
global.xml
## 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)