Skip to content

DiscoveryAndOPConfiguration

Scott Cantor edited this page Feb 18, 2021 · 8 revisions

Current File(s): conf/idp.properties, jetty-config

Overview

Together with the correct servlet container settings, the OIDC plugin offers building blocks for supporting some of the features defined at OpenID Connect Disovery 1.0 specification. This page describes one example configuration with Jetty.

WebFinger (OP Issuer Discovery)

The flows/oidc/webfinger -directory contains a simplified flow for WebFinger. It does not have any input validation features: it responds with a reference to the OIDC issuer for all the valid requests with rel -parameter corresponding to http://openid.net/specs/connect/1.0/issuer. The resource -paramater in the request is not currently verified or exploited in any way.

Servlet Container Configuration

The servlet container must be configured to route /.well-known/webfinger -requests to the /idp/profile/oidc/webfinger endpoint.

In Jetty, this can be achieved for instance by enabling the rewrite handler and configuring jetty-rewrite.xml in the following way:

<Configure id="Server" class="org.eclipse.jetty.server.Server">
    <Get id="oldhandler" name="handler"/>
    <Set name="handler">
     <New id="Rewrite" class="org.eclipse.jetty.rewrite.handler.RewriteHandler">
      <Set name="handler"><Ref id="oldhandler"/></Set>
      <Set name="rewriteRequestURI">true</Set>
      <Set name="rewritePathInfo">false</Set>
      <Set name="originalPathAttribute">requestedPath</Set>
      <Call name="addRule">
        <Arg>
          <New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
            <Set name="pattern">/.well-known/webfinger</Set>
            <Set name="replacement">/idp/profile/oidc/webfinger</Set>
          </New>
        </Arg>
      </Call>
     </New>
    </Set>
</Configure>

Example sequence

The request:

https://192.168.0.150/.well-known/webfinger?resource=acct%3Ajoe%40192.168.0.150&rel=http%3A%2F%2Fopenid.net%2Fspecs%2Fconnect%2F1.0%2Fissuer

The response

HTTP/1.1 200 OK
Set-Cookie: JSESSIONID=node0qfvgrby0j9le95rb2319m6mg1.node0;Path=/idp;Secure
Cache-Control: no-store
Content-Type: application/jrd+json;charset=utf-8
Content-Length: 130
Server: Jetty(9.4.2.v20170220)

{"subject":"acct:joe@192.168.0.150","links":[{"rel":"http://openid.net/specs/connect/1.0/issuer","href":"https://192.168.0.150"}]

OpenID Provider Metadata

The default installation includes a template openid-configuration -file in the static/.well-known directory. That should be configured to exists in the endpoint consisting of the OP issuer and /.well-known/openid-configuration -postfix (e.g. https://192.168.0.150/.well-known/openid-configuration).

Currently the file must be manually updated to correspond to the configuration in other files (conf/idp.properties, conf/attribute-resolver.xml, etc..). The standard contents of the metadata file is specified here.

There are two ways to publish the OP metadata. Either statically from the file (default), or partially dynamically using the discovery flow.

Static OP configuration response

The servlet container should add Content-Type: application/json -header when responding with the openid-configuration. In Jetty, this can be achieved for instance by enabling rewrite handler and configuring jetty-rewrite.xml in the following way:

<Configure id="Server" class="org.eclipse.jetty.server.Server">
    <Get id="oldhandler" name="handler"/>
    <Set name="handler">
     <New id="Rewrite" class="org.eclipse.jetty.rewrite.handler.RewriteHandler">
      <Set name="handler"><Ref id="oldhandler"/></Set>
      <Set name="rewriteRequestURI">true</Set>
      <Set name="rewritePathInfo">false</Set>
      <Set name="originalPathAttribute">requestedPath</Set>
      <Call name="addRule">
        <Arg>
          <New class="org.eclipse.jetty.rewrite.handler.HeaderPatternRule">
            <Set name="pattern">/.well-known/openid-configuration</Set>
            <Set name="name">Content-Type</Set>
            <Set name="value">application/json</Set>
          </New>
        </Arg>
      </Call>
     </New>
    </Set>
</Configure>

Dynamic OP configuration response

The servlet container must be configured to route /.well-known/openid-configuration -requests to the /idp/profile/oidc/discovery endpoint.

In Jetty, this can be achieved for instance by enabling the rewrite handler and configuring jetty-rewrite.xml in the following way:

<Configure id="Server" class="org.eclipse.jetty.server.Server">
    <Get id="oldhandler" name="handler"/>
    <Set name="handler">
     <New id="Rewrite" class="org.eclipse.jetty.rewrite.handler.RewriteHandler">
      <Set name="handler"><Ref id="oldhandler"/></Set>
      <Set name="rewriteRequestURI">true</Set>
      <Set name="rewritePathInfo">false</Set>
      <Set name="originalPathAttribute">requestedPath</Set>
      <Call name="addRule">
        <Arg>
          <New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
            <Set name="pattern">/.well-known/openid-configuration</Set>
            <Set name="replacement">/idp/profile/oidc/discovery</Set>
          </New>
        </Arg>
      </Call>
     </New>
    </Set>
</Configure>

The discovery-flow configuration

After the servlet container has been configured to route the openid-configuration traffic to the discovery flow, the dynamic response claims can be configured in the following way:

The discovery-flow configuration in v1.x

In the /opt/shibboleth-idp/flows/oidc/discovery/discovery-beans.xml file:

The bean called shibboleth.oidc.OpenIdConfigurationResolver is the main configuration bean. For it's constructor, a file that will be used as a skeleton for the openid-configuration must be provided. The property called dynamicValueResolvers contains a map of dynamic configuration claims. The map contains 1..n entries, key referring to the name of the claim, and value to the MetadataValueResolver.

See the next subsections for the available MetadataValueResolver implementations.

The discovery-flow configuration in v2.x

The global bean set with the idp.oidc.discovery.resolver property is the main configuration bean. By default, its value is shibboleth.oidc.DefaultOpenIdConfigurationResolver, which is defined in the bean declarations inside JAR.

When the property is set to a different value, matching bean definition must implement org.geant.idpextension.oidc.metadata.resolver.ProviderMetadataResolver.

See the next subsections for the available MetadataValueResolver implementations and an example of custom resolver bean (with id=shibboleth.oidc.OpenIdConfigurationResolver).

ArrayMetadataValueResolver

class: org.geant.idpextension.oidc.metadata.impl.ArrayMetadataValueResolver

Contains an array of other _MetadataValueResolver_s set in a property called embeddedResolvers. The claim name can also be optionally defined in a property called objectName.

CredentialMetadataValueResolver

class: org.geant.idpextension.oidc.metadata.impl.CredentialMetadataValueResolver

Publishes the public key information from the given Shibboleth IdP credential. It is set with a property called credential.

FilesystemMetadataValueResolver

class: org.geant.idpextension.oidc.metadata.impl.FilesystemMetadataValueResolver

Publishes the contents of the JSON file given in the constructor of the class. Optionally a Timer can also be given in the constructor for timing the refresh of the contents of the file.

Example configuration

The example configuration below uses a file from /opt/shibboleth-idp/static/.well-known/openid-configuration as a skeleton for the OP configuration and adds a claim called signing-keys with a value from a single credential in an array.

<bean id="shibboleth.oidc.OpenIdConfigurationResolver" class="org.geant.idpextension.oidc.metadata.impl.DynamicFilesystemProviderMetadataResolver">
    <property name="dynamicValueResolvers">
        <map value-type="org.geant.idpextension.oidc.metadata.resolver.MetadataValueResolver">
            <entry key="signing-keys" value-ref="ArrayResolverExample" />
        </map>
    </property>
    <constructor-arg type="java.io.File"
        value="/opt/shibboleth-idp/static/.well-known/openid-configuration" />
</bean>

<bean id="shibboleth.oidc.DefaultSigningCredential"
    class="org.geant.idpextension.oidc.profile.spring.factory.BasicJWKCredentialFactoryBean">
    <property name="jWKResource">
        <bean class="org.springframework.core.io.FileSystemResource">
            <constructor-arg type="java.lang.String"
                value="%{idp.signing.oidc.key}" />
        </bean>
    </property>
</bean>

<bean id="ArrayResolverExample"
    class="org.geant.idpextension.oidc.metadata.impl.ArrayMetadataValueResolver"
    p:objectName="keys">
    <property name="embeddedResolvers">
        <list
            value-type="org.geant.idpextension.oidc.metadata.resolver.MetadataValueResolver">
            <ref bean="CredentialResolver" />
        </list>
    </property>
</bean>

<bean id="CredentialResolver"
    class="org.geant.idpextension.oidc.metadata.impl.CredentialMetadataValueResolver"
    p:credential-ref="shibboleth.oidc.DefaultSigningCredential" />

Example openid-configuration

{
 "issuer": "https://192.168.0.150",
 "authorization_endpoint": "https://192.168.0.150/idp/profile/oidc/authorize",
 "registration_endpoint": "https://192.168.0.150/idp/profile/oidc/register",
 "token_endpoint": "https://192.168.0.150/idp/profile/oidc/token",
 "userinfo_endpoint": "https://192.168.0.150/idp/profile/oidc/userinfo",
 "jwks_uri": "https://192.168.0.150/oidc/keyset.jwk",
 "response_types_supported": [
  "code",
  "id_token",
  "token id_token",
  "code id_token",
  "code token",
  "code token id_token"
 ],
 "subject_types_supported": [
  "public",
  "pairwise"
 ],
 "grant_types_supported": [
  "authorization_code",
  "implicit"
 ],
 "id_token_signing_alg_values_supported": [
  "RS256"
 ],
 "token_endpoint_auth_methods_supported": [
  "client_secret_basic",
  "client_secret_post",
  "client_secret_jwt",
  "private_key_jwt"
 ],
 "request_parameter_supported": false,
 "request_uri_parameter_supported": false,
 "require_request_uri_registration": false,
 "request_uri_parameter_supported": false,
 "scopes_supported": [
  "openid",
  "profile",
  "email",
  "address",
  "phone",
  "info"
 ],
 "claims_supported": [
  "aud",
  "acr",
  "exp",
  "iat",
  "iss",
  "sub",
  "eduPersonPrincipalName",
  "eduPersonAffiliation",
  "mail"
 ]
}

(Migrated)