Shibboleth IdP als OpenID Connect - Provider

Danke

Der Dank für diese Dokumentation geht an Manuel Haim von der Philipps-Universität Marburg.

Die OIDC-Login-Schnittstelle wird für Webanwendungen benötigt, die ausschließlich das OIDC- bzw. OAuth-2.0-Protokoll unterstützen.

Versionsnummern prüfen!

Prüfen Sie bitte vor dem Download die aktuellen Versionsnummern der Plugins! Die Download-Links ändern sich leider mit den Versionsnummern.
root@idp:~# cd /opt/install/
root@idp:~# curl -O https://shibboleth.net/downloads/identity-provider/plugins/oidc-common/2.1.0/oidc-common-dist-2.1.0.tar.gz
root@idp:~# curl -O https://shibboleth.net/downloads/identity-provider/plugins/oidc-common/2.1.0/oidc-common-dist-2.1.0.tar.gz.asc
root@idp:~# curl -O https://shibboleth.net/downloads/identity-provider/plugins/oidc-op/3.2.1/idp-plugin-oidc-op-distribution-3.2.1.tar.gz
root@idp:~# curl -O https://shibboleth.net/downloads/identity-provider/plugins/oidc-op/3.2.1/idp-plugin-oidc-op-distribution-3.2.1.tar.gz.asc

Bei der Installation prüft der Plugin-Installer online die Kompatibilität der Plugin-Version zur Shibboleth-Version. Falls der Shibboleth-IdP nur über einen HTTP-Proxy Zugriff zum Internet erhält, muss für die Plugin-Installation zunächst ein HTTP-Proxy konfiguriert werden.

Im IdP <= 4.1.2 gibt es einen Bug (vgl. https://issues.shibboleth.net/jira/browse/IDP-1838), hier lässt sich die Kompatibilitäts-Prüfung mittels Parameter --nocheck umgehen:

root@idp:~# /opt/shibboleth-idp/bin/plugin.sh --nocheck -i oidc-common-dist-1.1.0.tar.gz
root@idp:~# /opt/shibboleth-idp/bin/plugin.sh --nocheck -i idp-plugin-oidc-op-distribution-3.0.1.tar.gz

Zur Konfiguration des HTTP-Proxy (IdP >= 4.1.3) müssen wir eine Datei /opt/install/beanfile.xml mit eigenen HttpClient-Parametern anlegen:

/opt/install/beanfile.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:c="http://www.springframework.org/schema/c"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
 
       default-init-method="initialize"
       default-destroy-method="destroy">
 
    <!--
    HttpClient bean for plugin installation.
    Use with /opt/shibboleth-idp/bin/plugin.sh -hc <BeanName> -i <plugin.tar.gz> <this-file.xml>
    -->
    <bean id="myHttpClient" parent="shibboleth.HttpClientFactory"
        p:connectionProxyHost="http-proxy.example.org"
        p:connectionProxyPort="3128" />
 
</beans>

Und dann mit folgenden Parametern installieren:

root@idp:~# /opt/shibboleth-idp/bin/plugin.sh -hc myHttpClient -i oidc-common-dist-1.1.0.tar.gz beanfile.xml
root@idp:~# /opt/shibboleth-idp/bin/plugin.sh -hc myHttpClient -i idp-plugin-oidc-op-distribution-3.0.1.tar.gz beanfile.xml
root@idp:~# /opt/shibboleth-idp/bin/plugin.sh -i oidc-common-dist-1.1.0.tar.gz
2021-07-21 11:07:04,309 - INFO [net.shibboleth.idp.installer.plugin.impl.PluginInstaller:233] - Installing Plugin net.shibboleth.oidc.common version 1.1.0
Installing Plugin net.shibboleth.oidc.common version 1.1.0
2021-07-21 11:07:04,400 - INFO [net.shibboleth.idp.installer.BuildWar:225] - Rebuilding /opt/shibboleth-idp/war/idp.war, Version 4.1.2
Rebuilding /opt/shibboleth-idp/war/idp.war, Version 4.1.2
2021-07-21 11:07:04,445 - INFO [net.shibboleth.idp.installer.BuildWar:225] - Initial populate from /opt/shibboleth-idp/dist/webapp to /opt/shibboleth-idp/webpapp.tmp
Initial populate from /opt/shibboleth-idp/dist/webapp to /opt/shibboleth-idp/webpapp.tmp
2021-07-21 11:07:05,614 - INFO [net.shibboleth.idp.installer.BuildWar:225] - Overlay from /opt/shibboleth-idp/dist/plugin-webapp to /opt/shibboleth-idp/webpapp.tmp
Overlay from /opt/shibboleth-idp/dist/plugin-webapp to /opt/shibboleth-idp/webpapp.tmp
2021-07-21 11:07:05,670 - INFO [net.shibboleth.idp.installer.BuildWar:225] - Overlay from /opt/shibboleth-idp/edit-webapp to /opt/shibboleth-idp/webpapp.tmp
Overlay from /opt/shibboleth-idp/edit-webapp to /opt/shibboleth-idp/webpapp.tmp
2021-07-21 11:07:05,736 - INFO [net.shibboleth.idp.installer.BuildWar:217] - Creating war file /opt/shibboleth-idp/war/idp.war
Creating war file /opt/shibboleth-idp/war/idp.war
root@idp:~# /opt/shibboleth-idp/bin/plugin.sh -i idp-plugin-oidc-op-distribution-3.0.1.tar.gz
Plugin net.shibboleth.idp.plugin.oidc.op: Trust store folder does not exist, creating
Plugin net.shibboleth.idp.plugin.oidc.op: Trust store does not exist, creating
TrustStore does not contain signature 0X26691839355EBCA
Accept this key:
Signature:	0X26691839355EBCA
FingerPrint:	6D18FD63708FCCA079B68CCE026691839355EBCA
Username:	Henri Mikkonen <henri.mikkonen@iki.fi>
 [yN] y
Installing Plugin net.shibboleth.idp.plugin.oidc.op version 3.0.1
Rebuilding /opt/shibboleth-idp/war/idp.war, Version 4.1.2
Initial populate from /opt/shibboleth-idp/dist/webapp to /opt/shibboleth-idp/webpapp.tmp
Overlay from /opt/shibboleth-idp/dist/plugin-webapp to /opt/shibboleth-idp/webpapp.tmp
Overlay from /opt/shibboleth-idp/edit-webapp to /opt/shibboleth-idp/webpapp.tmp
Creating war file /opt/shibboleth-idp/war/idp.war
Module file changes as a result of this install
	conf/oidc-clientinfo-resolvers.xml created
	static/openid-configuration.json created
	bin/lib/json-web-key-generator-0.8.2-jar-with-dependencies.jar created
	conf/oidc-credentials.xml created
	conf/attributes/oidc-claim-rules.xml created
	bin/jwtgen.sh created
	conf/examples/oidc-attribute-filter.xml created
	bin/jwtgen.bat created
	conf/oidc.properties created
	conf/examples/oidc-attribute-resolver.xml created

Datei /opt/shibboleth-idp/conf/credentials.xml anpassen. Folgendes wird z.B. vor dem schließenden </beans>-Tag ganz unten eingesetzt:

/opt/shibboleth-idp/conf/credentials.xml
...
    <!-- OIDC extension default credential definitions -->
    <import resource="oidc-credentials.xml" />
...

Datei /opt/shibboleth-idp/conf/attributes/default-rules.xml anpassen:

/opt/shibboleth-idp/conf/attributes/default-rules.xml
...
    <import resource="oidc-claim-rules.xml" />
...

JSON Web Keys erzeugen:

root@idp:~# /opt/shibboleth-idp/bin/jwtgen.sh -t RSA -s 2048 -u sig -i defaultRSASign | tail -n +2 >/opt/shibboleth-idp/credentials/idp-signing-rs.jwk
root@idp:~# /opt/shibboleth-idp/bin/jwtgen.sh -t EC -c P-256 -u sig -i defaultECSign | tail -n +2 >/opt/shibboleth-idp/credentials/idp-signing-es.jwk
root@idp:~# /opt/shibboleth-idp/bin/jwtgen.sh -t RSA -s 2048 -u enc -i defaultRSAEnc | tail -n +2 >/opt/shibboleth-idp/credentials/idp-encryption-rsa.jwk

Datei /opt/shibboleth-idp/conf/oidc.properties anpassen:

/opt/shibboleth-idp/conf/oidc.properties
...
idp.oidc.issuer = https://idp.example.org
...

Wenn Sie eine veraltete IdP-Konfiguration weiterpflegen, achten Sie bitte darauf, dass die Datei conf/idp.properties oben die folgende Zeile enthält, damit automatisch alle .properties-Dateien unterhalb des conf-Ordners (wie z.B. conf/oidc.properties) eingelesen werden.

idp.searchForProperties=true

Momentan gibt es für OIDC keine signierten Föderationsmetadaten, wie sie für die SAML-Kommunikation existieren. Der Grund für das Fehlen ist, dass OpenID Connect Federation noch nicht fertig spezifiziert ist. Daher kann nur jeder OP (also jeder IdP) seine Metadaten direkt abrufbar machen. Die standardisierte Request-URI dafür lautet /.well-known/openid-configuration.

Um die „Metadaten“, also die Konfigurationsparameter, unter https://idp.example.org/.well-known/openid-configuration bereitzustellen, gehen Sie so vor (vgl. auch OPDiscovery im Shibboleth-Wiki):

  • In der mitgelieferten Datei /opt/shibboleth-idp/static/openid-configuration.json muss jeweils {{ service_name }} durch Ihren Wert für idp.example.org ausgetauscht werden. (Ja, muss es. Das ist kein Jinja-Template.) In derselben Datei sollten Sie nicht unterstützte Scopes aus dem Abschnitt scopes_supported entfernen.
  • Dann müssen Sie für unverifizierte Relying Parties ein Profil freischalten:
    /opt/shibboleth-idp/conf/relying-party.xml
    ...
        <bean id="shibboleth.UnverifiedRelyingParty" parent="RelyingParty">
            <property name="profileConfigurations">
                <list>
                    <bean parent="OIDC.Configuration" />
                    <!-- <bean parent="SAML2.SSO" p:encryptAssertions="false" /> -->
                </list>
            </property>
        </bean>
    ...
  • Wenn Ihr IdP so aufgesetzt ist, wie wir es empfehlen, dann wird alles unter dem URL-Pfad /idp/ vom Tomcat bereitgestellt, der Basispfad / hingegen von Apache (Einrichtung weiter unten). Daher müssen Sie den Redirect für /.well-known/openid-configuration in der Konfiguration des virtuellen Hosts im Apache einrichten:
    ...
      Redirect seeother /.well-known/openid-configuration https://idp.example.org/idp/profile/oidc/configuration
    ...
  • Alternativ können die Konfigurationsparameter statisch bereitgestellt werden (erfordert a2enmod headers):
      Alias /.well-known/openid-configuration /opt/shibboleth-idp/static/openid-configuration.json
      <Location "/.well-known/openid-configuration">
        ForceType application/json
        Header set Access-Control-Allow-Origin *
      </Location>

Schließlich müssen noch die entsprechenden OIDC-Profile in Shibboleth aktiviert werden. Wir wollen OIDC-Clients manuell hinzufügen und lassen das Profil „OIDC-Registration“ daher weg. Außerdem sollen auch beim OIDC-Login dieselben Flows wie beim Shibboleth-Login berücksichtigt werden. Achtung: Wenn Sie weitere Flows unter postAuthenticationFlows eintragen, etwa context-check, dann berücksichtigen Sie dies ggf. beim Debugging! Hier wird nur die Standardkonfiguration beschrieben.

Datei /opt/shibboleth-idp/conf/relying-party.xml bearbeiten:

/opt/shibboleth-idp/conf/relying-party.xml
...
    <bean id="shibboleth.UnverifiedRelyingParty" parent="RelyingParty">
        <property name="profileConfigurations">
            <list>
                <bean parent="OIDC.Configuration" />
                <bean parent="OIDC.Keyset" />
                <!-- <bean parent="SAML2.SSO" p:encryptAssertions="false" /> -->
            </list>
        </property>
    </bean>
...
    <!-- Default configuration, with default settings applied for all profiles. -->
    <bean id="shibboleth.DefaultRelyingParty" parent="RelyingParty">
        <property name="profileConfigurations">
            <list>
...
                <bean parent="OIDC.SSO"
                     p:postAuthenticationFlows="#{ {'terms-of-use', 'attribute-release'} }" />
                <ref bean="OIDC.UserInfo" />
                <ref bean="OAUTH2.Revocation" />
                <ref bean="OAUTH2.Introspection" />
            </list>
        </property>
    </bean>
...

Tomcat und Apache neustarten:

root@idp:~# systemctl restart tomcat9
root@idp:~# systemctl restart apache2

Wenn soweit alles ohne Fehler läuft (vgl. Shibboleth-Logs), können wir die Attribute konfigurieren.

Für OIDC sollten eine globale subject-id und/oder eine anwendungsbezogene pairwise-id definiert werden. Nachfolgend ein Beispiel basierend auf uid und persistentId:

In der Datei /opt/shibboleth-idp/conf/attribute-resolver.xml weitere Attribute analog zu /opt/shibboleth-idp/conf/examples/oidc-attribute-resolver.xml ergänzen:

/opt/shibboleth-idp/conf/attribute-resolver.xml
<?xml version="1.0" encoding="UTF-8"?>
<AttributeResolver
        xmlns="urn:mace:shibboleth:2.0:resolver" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xmlns:oidc="urn:mace:shibboleth:2.0:resolver:oidc"
        xsi:schemaLocation="urn:mace:shibboleth:2.0:resolver http://shibboleth.net/schema/idp/shibboleth-attribute-resolver.xsd
                            urn:mace:shibboleth:2.0:resolver:oidc http://shibboleth.net/schema/oidc/shibboleth-attribute-encoder-oidc.xsd">
...
    <!-- OIDC subjects -->
    <AttributeDefinition id="subject-public" xsi:type="Simple"
            activationConditionRef="shibboleth.oidc.Conditions.PublicRequired">
        <InputDataConnector ref="myLDAP_account" attributeNames="uid" />
        <AttributeEncoder xsi:type="oidc:OIDCString" name="sub" />
    </AttributeDefinition>
 
    <AttributeDefinition id="subject-pairwise" xsi:type="Simple"
            activationConditionRef="shibboleth.oidc.Conditions.PairwiseRequired">
        <InputDataConnector ref="myStoredId" attributeNames="persistentId"/>
        <AttributeEncoder xsi:type="oidc:OIDCString" name="sub" />
    </AttributeDefinition>
 
    <!-- gender -->
    <AttributeDefinition id="gender" xsi:type="Mapped">
        <InputDataConnector ref="myLDAP_people" attributeNames="UniMrAnrede" />
        <DefaultValue></DefaultValue>
        <ValueMap>
            <ReturnValue>male</ReturnValue>
            <SourceValue>Herr</SourceValue>
        </ValueMap>
        <ValueMap>
            <ReturnValue>female</ReturnValue>
            <SourceValue>Frau</SourceValue>
        </ValueMap>
    </AttributeDefinition>
...

In Datei /opt/shibboleth-idp/conf/attribute-filter.xml weitere Attribute analog zu /opt/shibboleth-idp/conf/examples/oidc-attribute-filter.xml ergänzen:

/opt/shibboleth-idp/conf/attribute-filter.xml
...
    <!-- OIDC scopes -->
    <AttributeFilterPolicy id="OPENID_SCOPE">
        <PolicyRequirementRule xsi:type="oidc:OIDCScope" value="openid" />
        <AttributeRule attributeID="subject-public">
            <PermitValueRule xsi:type="ANY" />
        </AttributeRule>
        <AttributeRule attributeID="subject-pairwise">
            <PermitValueRule xsi:type="ANY" />
        </AttributeRule>
    </AttributeFilterPolicy>
 
    <AttributeFilterPolicy id="OPENID_SCOPE_EMAIL">
        <PolicyRequirementRule xsi:type="oidc:OIDCScope" value="email" />
        <AttributeRule attributeID="mail">
            <PermitValueRule xsi:type="ANY" />
        </AttributeRule>
        <AttributeRule attributeID="email_verified">
            <PermitValueRule xsi:type="ANY" />
        </AttributeRule>
    </AttributeFilterPolicy>
 
    <AttributeFilterPolicy id="OPENID_SCOPE_PROFILE">
        <PolicyRequirementRule xsi:type="oidc:OIDCScope" value="profile" />
        <AttributeRule attributeID="displayName">
            <PermitValueRule xsi:type="ANY" />
        </AttributeRule>
        <AttributeRule attributeID="sn">
            <PermitValueRule xsi:type="ANY" />
        </AttributeRule>
        <AttributeRule attributeID="givenName">
            <PermitValueRule xsi:type="ANY" />
        </AttributeRule>
        <AttributeRule attributeID="uid">
            <PermitValueRule xsi:type="ANY" />
        </AttributeRule>
        <AttributeRule attributeID="gender">
            <PermitValueRule xsi:type="ANY" />
        </AttributeRule>
        <AttributeRule attributeID="eduPersonPrincipalName">
            <PermitValueRule xsi:type="ANY" />
        </AttributeRule>
    </AttributeFilterPolicy>
...

OIDC-Clients (Relying Parties, RP) können über XML-Metadaten hinzugefügt werden (vgl. OAuthRPMetadataProfile im Shibboleth-Wiki).

<md:EntityDescriptor
        xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"
        xmlns:oidcmd="urn:mace:shibboleth:metadata:oidc:1.0"
        entityID="rp.example.org">
    <md:SPSSODescriptor protocolSupportEnumeration="http://openid.net/specs/openid-connect-core-1_0.html">
        <md:Extensions>
            <oidcmd:OAuthRPExtensions
                grant_types="authorization_code"
                response_types="code"
                token_endpoint_auth_method="client_secret_basic"
                scopes="openid profile email" />
            <mdui:UIInfo xmlns:mdui="urn:oasis:names:tc:SAML:metadata:ui">
                <mdui:DisplayName xml:lang="de">Beispiel-OIDC-RP</mdui:DisplayName>
                <mdui:DisplayName xml:lang="en">Example OIDC RP</mdui:DisplayName>
                <mdui:Description xml:lang="de">Beispiel-OIDC-RP der Hochschule XY.</mdui:Description>
                <mdui:Description xml:lang="en">Example OIDC RP of University XY.</mdui:Description>
                <mdui:InformationURL xml:lang="de">https://rp.example.org</mdui:InformationURL>
                <mdui:InformationURL xml:lang="en">https://rp.example.org</mdui:InformationURL>
                <mdui:Logo height="93" width="260">https://rp.example.org/logo.png</mdui:Logo>
            </mdui:UIInfo>
        </md:Extensions>
        <md:KeyDescriptor>
            <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                <oidcmd:ClientSecret>HIER-STEHT-EIN-GEHEIMES-SECRET</oidcmd:ClientSecret>
            </ds:KeyInfo>
        </md:KeyDescriptor>
        <md:NameIDFormat>urn:mace:shibboleth:metadata:oidc:1.0:nameid-format:public</md:NameIDFormat>
        <md:AssertionConsumerService
                Binding="https://tools.ietf.org/html/rfc6749#section-3.1.2"
                Location="https://rp.example.org/OIDC-ODER-OAUTH-ENDPOINT"
                index="1"/>
    </md:SPSSODescriptor>
    <md:Organization>
        <md:OrganizationDisplayName xml:lang="de">Hochschule XY</md:OrganizationDisplayName>
        <md:OrganizationDisplayName xml:lang="en">University XY</md:OrganizationDisplayName>
        <md:OrganizationURL xml:lang="de">https://www.example.org</md:OrganizationURL>
        <md:OrganizationURL xml:lang="en">https://www.example.org</md:OrganizationURL>
    </md:Organization>
</md:EntityDescriptor>

Für jeden OIDC-Client muss eine client_id festgelegt werden (z.B. 32 Hex-Zeichen langer Zufallswert oder ein FQDN, aber keine URL) sowie ein client_secret (z.B. per makepasswd --chars=32) und die redirect_uri.

Die für die Client-Konfiguration nötigen Parameter können per https://idp.example.org/.well-known/openid-configuration abgefragt werden.

Die freigegebenen Shibboleth-Attribute werden gemäß /opt/shibboleth-idp/conf/attributes/oidc-claim-rules.xml in OIDC-Attribute übersetzt.

Das OIDC-Plugin unterstützt bislang noch kein Logout, und die OIDC-RPs werden auch nicht auf der Logout-Seite angezeigt: https://issues.shibboleth.net/jira/browse/JOIDC-13

Die OIDC-Attribute werden im Attribute Release bislang nur mit englischen Beschreibungstexten angezeigt. Zur Korrektur müssen die entsprechenden deutschen Beschreibungstexte unter /opt/shibboleth-idp/conf/attributes/oidc-claim-rules.xml ergänzt werden.

Ihren OpenID Provider können Sie mit unseren öffentlichen Relying Parties testen.

  • Zuletzt geändert: vor 12 Tagen