OPFederationWIP

OPFederationWIP

This page describes a feature that is still work in progress and should only be used for experimental testing at this point.

This page currently describes only the most common basic/common configuration options. The more advanced options will be added later.

Introduction

The OpenID Federation 1.0 (currently draft) specification defines components used to build multilateral federations and describes how to apply them on top of the OAuth2/OIDC stack.

The main Jira ticket to follow is https://shibboleth.atlassian.net/browse/JOIDC-222 . This is subject to change once a new Jira project is populated for the new OpenID Federation plugin to the OP plugin.

Source code access

The development is now being done on java-idp-plugin-oidc-op-oidfed repository.

The development was previously done on branch dev/JOIDC-222 in the java-idp-oidc repository, but the current approach is to provide the OpenID Federation features as a plugin/extension to the OP plugin.

See https://shibboleth.atlassian.net/wiki/spaces/DEV/pages/1137344525 for instructions on detailed instructions on how to access the source code.

Plugin (binary) snapshots

In order to deploy the current state of the work for federation feature, one needs to install (1) the latest snapshot of the OP plugin and (2) the latest snapshot of the OpenID Federation plugin for OP. The links to the latest snapshots can be found from the following endpoints:

  • OP: https://build.shibboleth.net/maven/snapshots/net/shibboleth/idp/plugin/oidc/idp-plugin-oidc-op-distribution/4.4.0-SNAPSHOT/

  • Federation plugin: https://build.shibboleth.net/nexus-proxy/content/repositories/snapshots/net/shibboleth/idp/plugin/oidfed/idp-plugin-oidfed-op-dist/1.0.0-SNAPSHOT/

The tar.gz packages with the latest timestamps should be used.

The snapshot distribution package is signed with the Shibboleth Jenkins' key. To use that key as the truststore, download it from https://shibboleth.net/downloads/SHIBBOLETH_SNAPSHOT_PGP_KEYS.

Installation example

Make sure that the latest release versions of these plugins are installed (see https://shibboleth.atlassian.net/wiki/spaces/IDPPLUGINS/pages/1376878882 ):

  • net.shibboleth.oidc.common (3.0.0 or later)

  • net.shibboleth.idp.plugin.oidc.config (3.0.0 or later)

cd /opt/shibboleth-idp sh bin/plugin.sh -I net.shibboleth.oidc.common sh bin/plugin.sh -I net.shibboleth.idp.plugin.oidc.config wget https://shibboleth.net/downloads/SHIBBOLETH_SNAPSHOT_PGP_KEYS sh bin/plugin.sh --noCheck --truststore SHIBBOLETH_SNAPSHOT_PGP_KEYS -i https://build.shibboleth.net/maven/snapshots/net/shibboleth/idp/plugin/oidc/idp-plugin-oidc-op-distribution/4.4.0-SNAPSHOT/idp-plugin-oidc-op-distribution-4.4.0-20250911.012902-9.tar.gz sh bin/plugin.sh --noCheck --truststore SHIBBOLETH_SNAPSHOT_PGP_KEYS -i https://build.shibboleth.net/nexus-proxy/content/repositories/snapshots/net/shibboleth/idp/plugin/oidfed/idp-plugin-oidfed-op-dist/1.0.0-SNAPSHOT/idp-plugin-oidfed-op-dist-1.0.0-20250911.102501-2.tar.gz

Configuration

First configure the standard OIDC/OAuth2 feature as described here: https://shibboleth.atlassian.net/wiki/spaces/IDPPLUGINS/pages/1376878976/OIDC+OP#Initial-Setup . Also note that ES384 and ES512 credentials are not included in the basic example, but the section https://shibboleth.atlassian.net/wiki/spaces/IDPPLUGINS/pages/1376878976/OIDC+OP#Key-Generation-for-ES384-and-ES512 describes how to generate and enable them.

Regarding the publication of OP’s own configuration, follow the instructions for dynamic publication: https://shibboleth.atlassian.net/wiki/spaces/IDPPLUGINS/pages/1376879256/OPDiscovery#Configuration . As documented on the page, this part contains editing of static/openid-configuration.json file and configuring servlet container to redirect /.well-known/openid-configuration requests into the oidc/configuration flow.

Federation configuration

Trust anchors

The locally trusted trust anchors need to be configured in conf/oidfed/oidfed-trust-anchors.json (NOTE! In earlier versions the file was located in conf-directory, not in its oidfed-subfolder). The file is a JSON file, containing a map of trust anchor identifiers to their locally trusted JWK sets. The contents below is just an example and not up-to-date keyset for the example trust anchor: fetch the current keyset by other means,

{ "https://ta.oidf-pilot.edugain.org": { "keys": [ { "alg": "ES512", "crv": "P-521", "kid": "vwOKov9Lo5z4cPqVpgcTsFtbaryfv8Lb_UhT2sMACuc", "kty": "EC", "use": "sig", "x": "ARl3Tch9N0dYO7El-UBFss3_dsGvm1ehj4i_z7c26TXYJ9LxFYcqVDa1Dla5QUBpAp1bs2NOLFz_txwmFz4z9wJB", "y": "Ac5wwr2RPrDE7R0mk691iC1k31KQRxlgacKsNAnEJ2auYdMn3p1kIKfxSHsALBmVyt-NTjzihvtL9JvnPjOLOgDY" } ] } }

Entity configuration

  1. Generate a new key pair for the federation entity (ES512 in this example)

    1. cd /opt/shibboleth-idp bin/jwtgen.sh -t EC -c P-521 -u sig -i defaultECFedSign | tail -n +2 > credentials/fed-signing-es521.jwk
  2. Refer to the new key in conf/oidc-credentials.xml

    1. ... <bean id="shibboleth.oidfed.DefaultES521SigningCredential" parent="shibboleth.JWKCredential" p:resource="/opt/shibboleth-idp/credentials/fed-signing-es521.jwk" /> <util:list id="shibboleth.oidfed.SigningCredentials"> <ref bean="shibboleth.oidfed.DefaultES521SigningCredential" /> </util:list> ...
  3. Define a signing algorithm that is compatible with the key (conf/oidc.properties)

    1. idp.oidfed.entity.sigalg = ES512
  4. Enable OIDFED.Configuration for shibboleth.UnverifiedRelyingParty in conf/relying-party.xml

    1. ... <bean id="shibboleth.UnverifiedRelyingParty" parent="RelyingParty"> <property name="profileConfigurations"> <list> <ref bean="OIDC.Keyset" /> <ref bean="OIDC.Configuration" /> <ref bean="OIDFED.Configuration" /> </list> </property> </bean> ...
  5. Register your OP with a federation authority

    1. This is obviously out of scope of the plugin itself, but in the end the authority should be included in the authority_hints in your entity configuration. In the example above, the OP is registered to https://ia1.oidf-pilot.edugain.org intermediate authority.

    2. idp.oidfed.entity.authorityHints = https://ia1.oidf-pilot.edugain.org

Finally, the servlet container needs to be configured to redirect /.well-known/openid-federation requests into the oidfed/entity-configuration flow.

After changes have been applied, the endpoint should be responding with the entity configuration.

curl -v https://op1.oidf-pilot.edugain.org/.well-known/openid-federation * Request completely sent off < HTTP/2 200 < alt-svc: h3=":443"; ma=2592000 < cache-control: no-store < content-type: application/entity-statement+jwt;charset=UTF-8 < date: Wed, 25 Jun 2025 11:48:07 GMT < set-cookie: __Host-JSESSIONID=6677368AD3E3F2C833A7FF6635D55A5B; Path=/; Secure; HttpOnly < via: 1.1 Caddy < eyJraWQiOiJkZWZhdWx0RUNGZWRTaWduIiwidHlwIjoiZW50aXR5LXN0YXRlbWVudCtqd3QiLCJhbGciOiJFUzUxMiJ9.eyJzdWIiOiJodHRwczovL29wMS5vaWRmLXBpbG90LmVkdWdhaW4ub3JnIiwibWV0YWRhdGEiOnsib3BlbmlkX3Byb3ZpZGVyIjp7ImF1dGhvcml6YXRpb25fZW5kcG9pbnQiOiJodHRwczovL29wMS5vaWRmLXBpbG90LmVkdWdhaW4ub3JnL2lkcC9wcm9maWxlL29pZGMvYXV0aG9yaXplIiwidG9rZW5fZW5kcG9pbnQiOiJodHRwczovL29wMS5vaWRmLXBpbG90LmVkdWdhaW4ub3JnL2lkcC9wcm9maWxlL29pZGMvdG9rZW4iLCJyZWdpc3RyYXRpb25fZW5kcG9pbnQiOiJodHRwczovL29wMS5vaWRmLXBpbG90LmVkdWdhaW4ub3JnL2lkcC9wcm9maWxlL29pZGMvcmVnaXN0ZXIiLCJpbnRyb3NwZWN0aW9uX2VuZHBvaW50IjoiaHR0cHM6Ly9vcDEub2lkZi1waWxvdC5lZHVnYWluLm9yZy9pZHAvcHJvZmlsZS9vYXV0aDIvaW50cm9zcGVjdGlvbiIsInJldm9jYXRpb25fZW5kcG9pbnQiOiJodHRwczovL29wMS5vaWRmLXBpbG90LmVkdWdhaW4ub3JnL2lkcC9wcm9maWxlL29hdXRoMi9yZXZvY2F0aW9uIiwicHVzaGVkX2F1dGhvcml6YXRpb25fcmVxdWVzdF9lbmRwb2ludCI6Imh0dHBzOi8vb3AxLm9pZGYtcGlsb3QuZWR1Z2Fpbi5vcmcvaWRwL3Byb2ZpbGUvb2F1dGgyL3B1c2hlZC1hdXRob3JpemF0aW9uIiwiZmVkZXJhdGlvbl9yZWdpc3RyYXRpb25fZW5kcG9pbnQiOiJodHRwczovL29wMS5vaWRmLXBpbG90LmVkdWdhaW4ub3JnL2lkcC9wcm9maWxlL29pZGZlZC9yZWdpc3RlciIsImlzc3VlciI6Imh0dHBzOi8vb3AxLm9pZGYtcGlsb3QuZWR1Z2Fpbi5vcmciLCJqd2tzX3VyaSI6Imh0dHBzOi8vb3AxLm9pZGYtcGlsb3QuZWR1Z2Fpbi5vcmcvaWRwL3Byb2ZpbGUvb2lkYy9rZXlzZXQiLCJzY29wZXNfc3VwcG9ydGVkIjpbIm9wZW5pZCIsInByb2ZpbGUiLCJlbWFpbCIsImFkZHJlc3MiLCJwaG9uZSIsIm9mZmxpbmVfYWNjZXNzIl0sInJlc3BvbnNlX3R5cGVzX3N1cHBvcnRlZCI6WyJjb2RlIiwiaWRfdG9rZW4iLCJpZF90b2tlbiB0b2tlbiIsImNvZGUgaWRfdG9rZW4iLCJjb2RlIHRva2VuIiwiY29kZSBpZF90b2tlbiB0b2tlbiJdLCJyZXNwb25zZV9tb2Rlc19zdXBwb3J0ZWQiOlsicXVlcnkiLCJmcmFnbWVudCIsImZvcm1fcG9zdCJdLCJncmFudF90eXBlc19zdXBwb3J0ZWQiOlsiYXV0aG9yaXphdGlvbl9jb2RlIiwiaW1wbGljaXQiLCJyZWZyZXNoX3Rva2VuIl0sInRva2VuX2VuZHBvaW50X2F1dGhfbWV0aG9kc19zdXBwb3J0ZWQiOlsiY2xpZW50X3NlY3JldF9iYXNpYyIsImNsaWVudF9zZWNyZXRfcG9zdCIsImNsaWVudF9zZWNyZXRfand0IiwicHJpdmF0ZV9rZXlfand0Il0sInJlcXVlc3Rfb2JqZWN0X3NpZ25pbmdfYWxnX3ZhbHVlc19zdXBwb3J0ZWQiOlsibm9uZSIsIlJTMjU2IiwiUlMzODQiLCJSUzUxMiIsIkhTMjU2IiwiSFMzODQiLCJIUzUxMiIsIkVTMjU2IiwiRVMzODQiLCJFUzUxMiJdLCJyZXF1ZXN0X3BhcmFtZXRlcl9zdXBwb3J0ZWQiOnRydWUsInJlcXVlc3RfdXJpX3BhcmFtZXRlcl9zdXBwb3J0ZWQiOnRydWUsInJlcXVpcmVfcmVxdWVzdF91cmlfcmVnaXN0cmF0aW9uIjp0cnVlLCJkcG9wX3NpZ25pbmdfYWxnX3ZhbHVlc19zdXBwb3J0ZWQiOlsiUlMyNTYiLCJSUzM4NCIsIlJTNTEyIiwiRVMyNTYiLCJFUzM4NCIsIkVTNTEyIl0sImNsaWVudF9yZWdpc3RyYXRpb25fdHlwZXNfc3VwcG9ydGVkIjpbImF1dG9tYXRpYyIsImV4cGxpY2l0Il0sInN1YmplY3RfdHlwZXNfc3VwcG9ydGVkIjpbInB1YmxpYyIsInBhaXJ3aXNlIl0sInVzZXJpbmZvX2VuZHBvaW50IjoiaHR0cHM6Ly9vcDEub2lkZi1waWxvdC5lZHVnYWluLm9yZy9pZHAvcHJvZmlsZS9vaWRjL3VzZXJpbmZvIiwiZW5kX3Nlc3Npb25fZW5kcG9pbnQiOiJodHRwczovL29wMS5vaWRmLXBpbG90LmVkdWdhaW4ub3JnL2lkcC9wcm9maWxlL29pZGMvZW5kLXNlc3Npb24iLCJpZF90b2tlbl9zaWduaW5nX2FsZ192YWx1ZXNfc3VwcG9ydGVkIjpbIlJTMjU2IiwiUlMzODQiLCJSUzUxMiIsIkhTMjU2IiwiSFMzODQiLCJIUzUxMiIsIkVTMjU2IiwiRVMzODQiLCJFUzUxMiIsIlBTMjU2IiwiUFMzODQiLCJQUzUxMiJdLCJpZF90b2tlbl9lbmNyeXB0aW9uX2FsZ192YWx1ZXNfc3VwcG9ydGVkIjpbIlJTQTFfNSIsIlJTQS1PQUVQIiwiUlNBLU9BRVAtMjU2IiwiUlNBLU9BRVAtMzg0IiwiUlNBLU9BRVAtNTEyIiwiQTEyOEtXIiwiQTE5MktXIiwiQTI1NktXIiwiQTEyOEdDTUtXIiwiQTE5MkdDTUtXIiwiQTI1NkdDTUtXIiwiRUNESC1FUyIsIkVDREgtRVMrQTEyOEtXIiwiRUNESC1FUytBMTkyS1ciLCJFQ0RILUVTK0EyNTZLVyJdLCJpZF90b2tlbl9lbmNyeXB0aW9uX2VuY192YWx1ZXNfc3VwcG9ydGVkIjpbIkExMjhDQkMtSFMyNTYiLCJBMTkyQ0JDLUhTMzg0IiwiQTI1NkNCQy1IUzUxMiIsIkExMjhHQ00iLCJBMTkyR0NNIiwiQTI1NkdDTSJdLCJ1c2VyaW5mb19zaWduaW5nX2FsZ192YWx1ZXNfc3VwcG9ydGVkIjpbIlJTMjU2IiwiUlMzODQiLCJSUzUxMiIsIkhTMjU2IiwiSFMzODQiLCJIUzUxMiIsIkVTMjU2IiwiRVMzODQiLCJFUzUxMiIsIlBTMjU2IiwiUFMzODQiLCJQUzUxMiJdLCJ1c2VyaW5mb19lbmNyeXB0aW9uX2FsZ192YWx1ZXNfc3VwcG9ydGVkIjpbIlJTQTFfNSIsIlJTQS1PQUVQIiwiUlNBLU9BRVAtMjU2IiwiUlNBLU9BRVAtMzg0IiwiUlNBLU9BRVAtNTEyIiwiQTEyOEtXIiwiQTE5MktXIiwiQTI1NktXIiwiQTEyOEdDTUtXIiwiQTE5MkdDTUtXIiwiQTI1NkdDTUtXIiwiRUNESC1FUyIsIkVDREgtRVMrQTEyOEtXIiwiRUNESC1FUytBMTkyS1ciLCJFQ0RILUVTK0EyNTZLVyJdLCJ1c2VyaW5mb19lbmNyeXB0aW9uX2VuY192YWx1ZXNfc3VwcG9ydGVkIjpbIkExMjhDQkMtSFMyNTYiLCJBMTkyQ0JDLUhTMzg0IiwiQTI1NkNCQy1IUzUxMiIsIkExMjhHQ00iLCJBMTkyR0NNIiwiQTI1NkdDTSJdLCJkaXNwbGF5X3ZhbHVlc19zdXBwb3J0ZWQiOlsicGFnZSJdLCJjbGFpbXNfc3VwcG9ydGVkIjpbImF1ZCIsImlzcyIsInN1YiIsImlhdCIsImV4cCIsImFjciIsImF1dGhfdGl* Connection #0 to host op1.oidf-pilot.edugain.org left intact tZSIsImVtYWlsIiwiZW1haWxfdmVyaWZpZWQiLCJhZGRyZXNzIiwicGhvbmUiLCJwaG9uZV9udW1iZXJfdmVyaWZpZWQiLCJuYW1lIiwiZmFtaWx5X25hbWUiLCJnaXZlbl9uYW1lIiwibWlkZGxlX25hbWUiLCJuaWNrbmFtZSIsInByZWZlcnJlZF91c2VybmFtZSIsInByb2ZpbGUiLCJwaWN0dXJlIiwid2Vic2l0ZSIsImdlbmRlciIsImJpcnRoZGF0ZSIsInpvbmVpbmZvIiwibG9jYWxlIiwidXBkYXRlZF9hdCJdLCJjbGFpbXNfcGFyYW1ldGVyX3N1cHBvcnRlZCI6dHJ1ZSwiZnJvbnRjaGFubmVsX2xvZ291dF9zdXBwb3J0ZWQiOnRydWUsImZyb250Y2hhbm5lbF9sb2dvdXRfc2Vzc2lvbl9zdXBwb3J0ZWQiOnRydWUsImJhY2tjaGFubmVsX2xvZ291dF9zdXBwb3J0ZWQiOnRydWUsImJhY2tjaGFubmVsX2xvZ291dF9zZXNzaW9uX3N1cHBvcnRlZCI6dHJ1ZX19LCJqd2tzIjp7ImtleXMiOlt7Imt0eSI6IkVDIiwidXNlIjoic2lnIiwiY3J2IjoiUC01MjEiLCJraWQiOiJkZWZhdWx0RUNGZWRTaWduIiwieCI6IkFNSURkazBXR0NaQ2xkZDlIMW82Z0FFYjJhSEE0bVY2bXJab05ZX1YtT1ZCZ1gtU0txMnZydWFXeW5nQjJyWVZGbVJyR3VjMW02V0N5cW9icXFmUTZRSkIiLCJ5IjoiQVZjNkVkUlVkLWk0T2NEdGtJZ3NDc2Jsc1ZOS1ZFYU9ZTWxfOU9iRlZFc0loYWFuY3AwY2FSeXN3bEItQ0RQWDhyaUN4NFNCdWxEOEg1WjhlbVl4WHlaaCJ9XX0sImlzcyI6Imh0dHBzOi8vb3AxLm9pZGYtcGlsb3QuZWR1Z2Fpbi5vcmciLCJhdXRob3JpdHlfaGludHMiOlsiaHR0cHM6Ly9pYTEub2lkZi1waWxvdC5lZHVnYWluLm9yZyJdLCJleHAiOjE3NTA5Mzg0ODcsImlhdCI6MTc1MDg1MjA4N30.ALrbgqQaeRI8OPEZURDjnKpaRsYVgiZMVTywlrB45OcHBxuNVfKffkAWHLaGHWNTHPaBldqXOuNLqdzMuIVIQ2zNAUuVAXOFpo6gyz9FVfGQmbAsRAQVvxLlihEbPfJg1HZxBEZ0aqVV65Ano5usPv4Qx66qiRnPq4ZHqaNg2GuNvSDj

Automatic registration

  1. Enable OIDFED.AutomaticRegistration for shibboleth.DefaultRelyingParty in conf/relying-party.xml

    1. ... <bean id="shibboleth.DefaultRelyingParty" parent="RelyingParty"> <property name="profileConfigurations"> <list> <ref bean="OIDC.SSO" /> <ref bean="OIDC.UserInfo"/> <ref bean="OAUTH2.Token"/> <ref bean="OAUTH2.Revocation"/> <ref bean="OAUTH2.Introspection" /> <ref bean="OAUTH2.PAR" /> <bean parent="OIDFED.AutomaticRegistration" /> </list> </property> </bean> ...
  2. Enable automatically registered RPs access per flow/endpoint (conf/oidc.properties):

    1. idp.oidfed.authorize.automaticRegistrationCondition = shibboleth.Conditions.TRUE idp.oidfed.token.automaticRegistrationCondition = shibboleth.Conditions.TRUE idp.oidfed.userinfo.automaticRegistrationCondition = shibboleth.Conditions.TRUE
Trust Chain Resolution method

By default, all the valid trust chains for the incoming RP are resolved locally. The valid trust anchors are configured as described in sectionhttps://shibboleth.atlassian.net/wiki/spaces/IDPPLUGINS/pages/4500914216/OPFederationWIP#Trust-anchors.

The property idp.oidfed.trustchain.resolver.useResolverApiCondition may be used for defining a condition when a remote resolve entity API would be used instead of the local resolution. By default, its value is shibboleth.Conditions.FALSE. A value shibboleth.Conditions.TRUE would mean that remote resolution is always attempted.

Another property idp.oidfed.trustchain.resolver.fallbackToLocalCondition may be used for controlling whether or not to fall back into local resolution if the remote resolution fails. By default its value is shibboleth.Conditions.TRUE.

Remote Trust Chain resolution endpoints

If the condition for using remote resolver entity API returns true for the incoming client, by default the configuration in the conf/oidfed/oidfed-trustchain-resolver.xml -file is exploited.

... <bean id="shibboleth.oidfed.DefaultTrustedRemoteResolverEntitiesLookupStrategy" parent="shibboleth.Functions.Constant"> <constructor-arg name="target"> <util:list value-type="net.shibboleth.idp.plugin.oidc.op.oidfed.profile.TrustedRemoteResolverEntity"> <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.profile.TrustedRemoteResolverEntity" c:entity="https://trust-anchor.federation.local" c:anchors="https://trust-anchor.federation.local,https://another.federation.local" /> </util:list> </constructor-arg> </bean> ...

The example above configures an entity https://trust-anchor.federation.local to be trusted for remote resolution. Its federation_resolve_endpointis automatically fetched and used as the endpoint together with the two trust_anchors parameters as specified by the c:anchors value. It could also contain a single value. Multiple values are separated by commas. Only the trust anchors that are locally trusted (see https://shibboleth.atlassian.net/wiki/spaces/IDPPLUGINS/pages/4500914216/OPFederationWIP#Trust-anchors ) are used: others are filtered out.

Resolve Entity API

Enable OIDFED.ResolveEntity for shibboleth.DefaultRelyingParty in conf/relying-party.xml

... <bean id="shibboleth.DefaultRelyingParty" parent="RelyingParty"> <property name="profileConfigurations"> <list> <ref bean="OIDC.SSO" /> <ref bean="OIDC.UserInfo"/> <ref bean="OAUTH2.Token"/> <ref bean="OAUTH2.Revocation"/> <ref bean="OAUTH2.Introspection" /> <ref bean="OAUTH2.PAR" /> <bean parent="OIDFED.AutomaticRegistration" /> <bean parent="OIDFED.ResolveEntity" /> </list> </property> </bean> ...
  1.  

Remarks:

  • Currently the Resolve Entity API doesn’t support client authentication

  • The Resolve Entity API exploits the same trust anchor configuration as automatic registration (via conf/oidfed/oidfed-trust-anchors.json).