Shibboleth IdPv5 in der Schulungs-VM |
![]() |
su -
Sie installieren in diesem Tutorial die Version 5.1.3 Laden Sie sich die 5.1.3 als tar-Archiv in das Verzeichnis /opt/install herunter. Die Dateien finden Sie im
Download-Verzeichnis von Shibboleth.
wget -P /opt/install https://shibboleth.net/downloads/identity-provider/latest/shibboleth-identity-provider-5.1.3.tar.gz
wget -P /opt/install https://shibboleth.net/downloads/identity-provider/latest/shibboleth-identity-provider-5.1.3.tar.gz.sha256
wget -P /opt/install https://shibboleth.net/downloads/identity-provider/latest/shibboleth-identity-provider-5.1.3.tar.gz.asc
wget -P /opt/install https://shibboleth.net/downloads/PGP_KEYS
gpg --import /opt/install/PGP_KEYS
gpg --verify /opt/install/shibboleth-identity-provider-5.1.3.tar.gz.asc /opt/install/shibboleth-identity-provider-5.1.3.tar.gz
cd /opt/install && sha256sum -c shibboleth-identity-provider-5.1.3.tar.gz.sha256
tar -xzf /opt/install/shibboleth-identity-provider-5.1.3.tar.gz -C /opt/install/
Führen Sie das interaktive Installerskript aus:
/opt/install/shibboleth-identity-provider-5.1.3/bin/install.sh
Achtung, bei "Hostname" müssen Sie die Standardvorgabe zu idp.local ändern.Bei den anderen Feldern können Sie einfach mit der ENTER-Taste bestätigen.
Installation Directory: [/opt/shibboleth-idp] ?
INFO - New Install. Version: 5.1.3
Host Name: [192.168.137.138] ?
idp.local
INFO - Creating idp-signing, CN = idp.local URI = https://idp.local/idp/shibboleth, keySize=3072
INFO - Creating idp-encryption, CN = idp.local URI = https://idp.local/idp/shibboleth, keySize=3072
INFO - Creating backchannel keystore, CN = idp.local URI = https://idp.local/idp/shibboleth, keySize=3072
INFO - Creating Sealer KeyStore
INFO - No existing versioning property, initializing...
SAML EntityID: [https://idp.local/idp/shibboleth] ?
Attribute Scope: [local] ?
wget --no-check-certificate https://sp1.local/Shibboleth.sso/Metadata -O /opt/shibboleth-idp/metadata/sp1-metadata.xml
Konfigurieren Sie diese Metadatensätze im IdP: Die Zeile gehört vor das schließende MetadataProvider-Tag in der Datei. Ja: Die Datei hat dann ein MetadataProvider-Tag im MetadataProvider-Tag.
<!-- Datei: /opt/shibboleth-idp/conf/metadata-providers.xml -->
<MetadataProvider id="SP1-Metadata" xsi:type="FilesystemMetadataProvider" metadataFile="/opt/shibboleth-idp/metadata/sp1-metadata.xml"/>
Bei der Installation wurde eine Datei mit den IdP-Metadaten automatisch erstellt. In der VM verwenden wir sie, um dem lokalen SP die IdP-Metadaten bekannt zu machen. (Im Produktivbetrieb werden stattdessen die Föderationsmetadaten verwendet.)
In der IdP-Version 5.1.3 gibt es aktuell einen Fehler in diesen automatisch erstellte Metadaten. Korrigieren Sie das fehlende Leerzeichen in Zeile 7:
<!-- Datei: /opt/shibboleth-idp/metadata/idp-metadata.xml -->
<md:EntityDescriptorentityID="https://idp.local/idp/shibboleth"...>
<!-- wird zu -->
<md:EntityDescriptor entityID="https://idp.local/idp/shibboleth"...>
zur Präsentation: Metadaten
# Datei: /opt/shibboleth-idp/conf/ldap.properties
idp.authn.LDAP.authenticator = bindSearchAuthenticator
idp.authn.LDAP.ldapURL = ldap://idp.local:389
idp.authn.LDAP.useStartTLS = false
# idp.authn.LDAP.trustCertificates = %{idp.home}/credentials/ldap-server.crt
idp.authn.LDAP.baseDN = dc=users,dc=nodomain
idp.authn.LDAP.bindDN = cn=admin,dc=nodomain
Das Bind-Passwort wird - zusammen mit anderen Credentials - in einer separaten Datei abgelegt. Sie hat eingeschränkte Zugriffsrechte. Sie enthält auch die bei der Installation gesetzten Passwörter:
shibboleth@debian:~$ ls -la /opt/shibboleth-idp/credentials/secrets.properties
-rw------- 1 root tomcat 733 18. Dez 16:57 /opt/shibboleth-idp/credentials/secrets.properties
Passen Sie das Muster-Passwort aus der mitgelieferten Datei an. Achtung: Es darf kein Leerzeichen am Ende des Passwortes stehen!
# Datei: /opt/shibboleth-idp/credentials/secrets.properties
idp.authn.LDAP.bindDNCredential = shibboleth
<!-- Datei: /opt/shibboleth-idp/conf/access-control.xml -->
<util:map id="shibboleth.AccessControlPolicies">
<entry key="AccessByIPAddress">
<bean id="AccessByIPAddress" parent="shibboleth.IPRangeAccessControl"
p:allowedRanges="#{ {'127.0.0.0/8', '::1/128'} }" />
</entry>
Zur Darstellung der Status-Seite muss eine aktuelle Version der Jakarta JSTL eingebunden werden.
wget -P /opt/shibboleth-idp/edit-webapp/WEB-INF/lib/ https://repo.maven.apache.org/maven2/org/glassfish/web/jakarta.servlet.jsp.jstl/3.0.1/jakarta.servlet.jsp.jstl-3.0.1.jar
wget -P /opt/shibboleth-idp/edit-webapp/WEB-INF/lib/ https://repo.maven.apache.org/maven2/jakarta/servlet/jsp/jstl/jakarta.servlet.jsp.jstl-api/3.0.2/jakarta.servlet.jsp.jstl-api-3.0.2.jar
build erneut ausführen und Tomcat neustarten
/opt/shibboleth-idp/bin/build.sh
systemctl restart tomcat10.service
wget https://download.aai.dfn.de/ws/idp2025/idpv5-attribute-resolver.xml -O /opt/shibboleth-idp/conf/attribute-resolver.xml
Diese xml-Datei enthält u.a. Javascript-Code, der ausgeführt werden soll, damit bestimmte Attribute IdP-seitig generiert werden. Unter OpenJDK 17 benötigt der IdP dafür ein Plugin, das bei früheren Java-Versionen nicht nötig war. So installieren Sie das Nashorn-Plugin:
/opt/shibboleth-idp/bin/plugin.sh --truststore /opt/install/PGP_KEYS -I net.shibboleth.idp.plugin.nashorn
<!-- Datei: /opt/shibboleth-idp/conf/attribute-resolver.xml -->
<AttributeDefinition xsi:type="Simple" id="ou">
<InputDataConnector ref="myLDAP" attributeNames="ou"/>
</AttributeDefinition>
<!-- Datei: /opt/shibboleth-idp/conf/attribute-resolver.xml -->
<DataConnector id="staticAttributes" xsi:type="Static">
<Attribute id="o">
<Value>Beispiel-Hochschule</Value>
</Attribute>
</DataConnector>
Bitte beachten Sie im Data Connector "myLDAP" die Zeile "exportAttributes". Ab Shibboleth IdP 4.x können Sie so Attribute aus dem Identity Management direkt verwenden, wenn sie im IdM genau so heißen, wie in der IdP-internen Attribute Registry (dazu später mehr). Diese Attribute müssen nicht mehr als einzelne AttributeDefinitions oben aufgelistet werden.
opt/shibboleth-idp/conf/attribute-resolver.xml -->
<DataConnector id="myLDAP" xsi:type="LDAPDirectory"
...
exportAttributes="uid givenName sn mail displayName">
...
</DataConnector>
<!-- Datei: /opt/shibboleth-idp/conf/attributes/inetOrgPerson.xml (gekürzt!) -->
<bean parent="shibboleth.TranscodingProperties">
<property name="properties">
<props merge="true">
<prop key="id">mail</prop>
<prop key="transcoder">SAML2StringTranscoder SAML1StringTranscoder</prop>
<prop key="saml2.name">urn:oid:0.9.2342.19200300.100.1.3</prop>
<prop key="saml1.name">urn:mace:dir:attribute-def:mail</prop>
<prop key="displayName.en">E-mail</prop>
<prop key="displayName.de">E-Mail</prop>
<prop key="description.en">E-Mail: Preferred address for e-mail to be sent to this person</prop>
<prop key="description.de">E-Mail-Adresse</prop>
</props>
</property>
</bean>
Jedes Attribut, das im Attribute Resolver verwendet wird - in einer Attribute Definition oder über exportAttributes - muss dem IdP über die Registry bekannt sein (dazu später mehr).
zur Doku: Datenbank-Konfiguration
Nun legen Sie eine Datenbank für Shibboleth an. Sie wird zwei Tabellen enthalten:mariadb -uroot -pshibboleth
SET NAMES 'utf8';
SET CHARACTER SET utf8;
CHARSET utf8;
CREATE DATABASE IF NOT EXISTS shibboleth CHARACTER SET=utf8;
USE shibboleth;
CREATE TABLE IF NOT EXISTS StorageRecords (
context varchar(255) NOT NULL,
id varchar(255) NOT NULL,
expires bigint(20) DEFAULT NULL,
value longtext NOT NULL,
version bigint(20) NOT NULL,
PRIMARY KEY (context, id)
) COLLATE utf8_bin;
CREATE TABLE IF NOT EXISTS shibpid (
localEntity VARCHAR(255) NOT NULL,
peerEntity VARCHAR(255) NOT NULL,
persistentId VARCHAR(50) NOT NULL,
principalName VARCHAR(50) NOT NULL,
localId VARCHAR(50) NOT NULL,
peerProvidedId VARCHAR(50) NULL,
creationDate TIMESTAMP NOT NULL,
deactivationDate TIMESTAMP NULL,
PRIMARY KEY (localEntity, peerEntity, persistentId)
);
CREATE USER 'shibboleth'@'localhost' IDENTIFIED BY 'shibboleth';
GRANT ALL PRIVILEGES ON shibboleth.* TO 'shibboleth'@'localhost';
FLUSH PRIVILEGES;
exit;
# Datei: /opt/shibboleth-idp/conf/saml-nameid.properties
idp.persistentId.sourceAttribute = uid
idp.persistentId.encoding = BASE32
idp.persistentId.generator = shibboleth.StoredPersistentIdGenerator
idp.persistentId.dataSource = shibboleth.MySQLDataSource
Der Hash wird aus Sicherheitsgründen in der zugriffsbeschränkten Passwortdatei abgelegt. In einer produktiven Installation sollte dieser Salt-Hash möglichst beliebig, also zufällig generiert, und lang sein und mit niemandem geteilt werden.
# Datei: /opt/shibboleth-idp/credentials/secrets.properties
idp.persistentId.salt = my-very-very-long-hash
<!-- Datei /opt/shibboleth-idp/conf/saml-nameid.xml -->
<!-- Uncommenting this bean requires configuration in saml-nameid.properties. -->
<ref bean="shibboleth.SAML2PersistentGenerator" />
<!-- Datei /opt/shibboleth-idp/conf/attribute-resolver.xml-->
<!-- Für samlPairwiseID wird die persistentId mit Scope übertragen -->
<AttributeDefinition xsi:type="Scoped" id="samlPairwiseID" scope="%{idp.scope}">
<InputDataConnector ref="StoredId" attributeNames="persistentID"/>
</AttributeDefinition>
<!-- Datei: /opt/shibboleth-idp/conf/c14n/subject-c14n.xml -->
<ref bean="c14n/SAML2Persistent" />
/opt/shibboleth-idp/bin/plugin.sh --truststore /opt/install/PGP_KEYS -I net.shibboleth.plugin.storage.jdbc
Fügen Sie dann für die MariaDB-Konfiguration folgende Zeilen zur Datei conf/global.xml hinzu, z.B. ganz unten vor das schließende </beans>-Tag:
<!-- Datei /opt/shibboleth-idp/conf/global.xml -->
<bean id="shibboleth.MySQLDataSource"
class="%{mysql.class}"
p:driverClassName="org.mariadb.jdbc.Driver"
p:url="%{mysql.url}"
p:username="%{mysql.username}"
p:password="%{mysql.password}"
p:maxWait="15000"
p:testOnBorrow="true"
p:maxActive="100"
p:maxIdle="100"
p:validationQuery="select 1"
p:validationQueryTimeout="5" />
<bean id="JDBCStorageService"
parent="shibboleth.JDBCStorageService"
p:cleanupInterval="%{idp.storage.cleanupInterval:PT10M}"
p:dataSource-ref="shibboleth.MySQLDataSource" />
Speichern Sie die Datenbank-Credentials, indem Sie diese Zeilen an die conf/idp.properties anhängen:
# Datei /opt/shibboleth-idp/conf/idp.properties
mysql.class = org.apache.tomcat.jdbc.pool.DataSource
mysql.url = jdbc:mysql://localhost:3306/shibboleth
mysql.username = shibboleth
An derselben Stelle geben Sie an, dass Sie die Sessions und den User Consent in der MySQL-Datenbank speichern möchten:
# Datei /opt/shibboleth-idp/conf/idp.properties
idp.session.StorageService = JDBCStorageService
idp.consent.StorageService = JDBCStorageService
idp.consent.attribute-release.userStorageKey = shibboleth.consent.PrincipalConsentStorageKey
idp.consent.attribute-release.userStorageKeyAttribute = %{idp.persistentId.sourceAttribute}
idp.consent.terms-of-use.userStorageKey = shibboleth.consent.PrincipalConsentStorageKey
idp.consent.terms-of-use.userStorageKeyAttribute = %{idp.persistentId.sourceAttribute}
idp.consent.allowGlobal = false
idp.consent.compareValues = true
Fehlt nur noch das Datenbank-Passwort des Datenbank-Users "shibboleth". Es gehört ebenfalls in die credentials/secrets.properties:
# Datei: /opt/shibboleth-idp/credentials/secrets.properties
mysql.password = shibboleth
<!-- Datei: /opt/shibboleth-idp/conf/attribute-filter.xml -->
<!-- Release to local SPs -->
<AttributeFilterPolicy id="SPs_locals">
<PolicyRequirementRule xsi:type="OR">
<Rule xsi:type="Requester" value="https://sp1.local/shibboleth" />
</PolicyRequirementRule>
<AttributeRule attributeID="eduPersonScopedAffiliation" permitAny="true" />
<AttributeRule attributeID="surname" permitAny="true" />
<AttributeRule attributeID="givenName" permitAny="true" />
<AttributeRule attributeID="mail" permitAny="true" />
<AttributeRule attributeID="uid" permitAny="true" />
</AttributeFilterPolicy>
# chown -R tomcat:tomcat /opt/shibboleth-idp/
# tail -f /var/log/tomcat10/catalina.DATUM.log
# systemctl restart tomcat10.service
In der Schulungs-VM müssen Sie auch den lokalen Shibboleth-SP hier einmal neustarten, weil er die neu hinzugekommenen IdP-Metadaten einlesen muss. shibd ist der SP, nicht der IdP!
# systemctl restart shibd.service
# /opt/shibboleth-idp/bin/plugin.sh -l
# /opt/shibboleth-idp/bin/module.sh -l
Wenn Ihr IdP noch nicht erreichbar ist, können Sie sich schon selbst auf die Fehlersuche begeben. Die relevanten Logdateien:
username: professorin
password: shibboleth
Bei Erfolg: Auf dem SP1 sollten Sie jetzt eine phpinfo-Seite sehen, auf der oben steht, dass dies der SP1 ist.
# touch /opt/shibboleth-idp/war/idp.war
Sie können das war file neu bauen lassen. Dies ist nötig, wenn Sie im Ordner edit-webapp Veränderungen vorgenommen haben.
# /opt/shibboleth-idp/bin/build.sh
Sie können die Intervalle für automatisches Neuladen der Konfiguration anpassen. Standardwerte:
# Datei: /opt/shibboleth-idp/conf/services.properties
# Beispiele:
idp.service.logging.checkInterval = PT5M
idp.service.relyingparty.checkInterval = PT15M
idp.service.attribute.resolver.checkInterval = PT15M
idp.service.attribute.filter.checkInterval = PT15M
Sie können so genannte Reload-URLs benutzen, um das Neuladen der Konfiguration über eine URL zu triggern.
# Beispiele:
# attribute-resolver.xml neu laden
curl https://idp.local/idp/profile/admin/reload-service?id=shibboleth.AttributeResolverService
# attribute-filter.xml neu laden
curl https://idp.local/idp/profile/admin/reload-service?id=shibboleth.AttributeFilterService
zur Präsentation: Plugins und Module
Bei einer Standardinstallation des IdP 5.1.x fehlt ein wichtiger Schritt: Die Nutzer*innen sollen vor der Freigabe Ihrer Daten an einen SP die Attribute aufgelistet bekommen und der Übertragung zustimmen können. Danach werden sie nur bei Änderungen am Attributset wieder gefragt. Seit Version 4.1.0 muss dafür ein Modul aktiviert werden (Hintergrundinformationen zu IdP-Modulen). Die IdP-Module werden über das Skript /opt/shibboleth-idp/bin/module.sh verwaltet. Mit der Option --help schauen Sie sich die möglichen Parameter an, mit --list die Übersicht der aktivierten und nicht aktivierten installierten Module. Nach der Installation sind neben den drei Kern-Modulen nur das "Admin Hello"-Modul und das Password Authentication-Modul aktiv. Aktivieren Sie das Consent Intercept-Modul:/opt/shibboleth-idp/bin/module.sh -e idp.intercept.Consent
Enabling idp.intercept.Consent...
conf/intercept/consent-intercept-config.xml created
views/intercept/attribute-release.vm created
views/intercept/terms-of-use.vm created
[OK]
Die Terms of Use lassen wir hier weg, siehe dazu unsere oben verlinkte Dokumentation. Wir möchten jetzt lediglich die freizugebenden Attribute einblenden und abnicken lassen:
<ref bean="SAML2.SSO" />
und ersetzen diese wie folgt, damit beim Profil SAML2.SSO die Zustimmung eingeholt wird:
<bean parent="SAML2.SSO" p:postAuthenticationFlows="#{{'attribute-release'}}" />
2025-01-03T13:45:06.198552916Z|https://sp1.local/shibboleth|AttributeReleaseConsent|polstudi|mail,uid|xnB2I0Q/wqQOWzOai552lf6FyiXHjUoOebd685aEHTg=,mEGdTHQZG2ABnCRBMi4n/7TJVPEKANWMVJ//v3p5dOc=|true
/opt/shibboleth-idp/bin/module.sh -i idp.intercept.Consent
less /opt/shibboleth-idp/logs/audit.log
Was benötigt der Service Provider? Werfen wir einen Blick in die Metadaten: Föderationsmetadaten
Metadaten easyroam
<EntityDescriptor entityID="https://get.eduroam.de/shibboleth">
<Extensions>
<mdrpi:RegistrationInfo registrationAuthority="https://www.aai.dfn.de" registrationInstant="2021-08-18T11:46:48Z">
<mdrpi:RegistrationPolicy xml:lang="en">
https://www.aai.dfn.de/fileadmin/documents/mrps_dfn-aai_1.0.pdf
</mdrpi:RegistrationPolicy>
</mdrpi:RegistrationInfo>
<mdattr:EntityAttributes>
<saml:Attribute Name="urn:oasis:names:tc:SAML:profiles:subject-id:req" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
<saml:AttributeValue>pairwise-id</saml:AttributeValue>
</saml:Attribute>
</mdattr:EntityAttributes>
</Extensions>
<SPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<Extensions>
<init:RequestInitiator Binding="urn:oasis:names:tc:SAML:profiles:SSO:request-init" Location="https://get.eduroam.de/Auth/Login"/>
<init:RequestInitiator Binding="urn:oasis:names:tc:SAML:profiles:SSO:request-init" Location="https://www.easyroam.de/Auth/Login"/>
<idpdisc:DiscoveryResponse Binding="urn:oasis:names:tc:SAML:profiles:SSO:idp-discovery-protocol" Location="https://get.eduroam.de/Auth/Login" index="1"/>
<idpdisc:DiscoveryResponse Binding="urn:oasis:names:tc:SAML:profiles:SSO:idp-discovery-protocol" Location="https://www.easyroam.de/Auth/Login" index="2"/>
<mdui:UIInfo>
<mdui:DisplayName xml:lang="de">DFN easyroam</mdui:DisplayName>
<mdui:DisplayName xml:lang="en">DFN easyroam</mdui:DisplayName>
<mdui:Description xml:lang="de">DFN easyroam</mdui:Description>
<mdui:Description xml:lang="en">DFN easyroam</mdui:Description>
<mdui:Logo height="180" width="182">
https://mdv.aai.dfn.de/media/logos/e15/Logo_easyroam_nur_Logo.png
</mdui:Logo>
<mdui:PrivacyStatementURL xml:lang="de">https://get.eduroam.de/Home/Privacy</mdui:PrivacyStatementURL>
</mdui:UIInfo>
</Extensions>
<KeyDescriptor>
<ds:KeyInfo>
<ds:KeyName>get.eduroam.de</ds:KeyName>
<ds:X509Data>
<ds:X509SubjectName>
CN=get.eduroam.de,OU=easyroam,O=Verein zur Förderung eines Deutschen Forschungsnetzes e. V.,ST=Berlin,C=DE
</ds:X509SubjectName>
<ds:X509Certificate>
MIIGLDCCBBSgAwIBAgIURUgPxJMAvZ+IoxP0j98BkUacOGcwDQYJKoZIhvcNAQEL BQAwgZExCzAJBgNVBAYTAkRFMQ8wDQYDVQQIDAZCZXJsaW4xRTBDBgNVBAoMPFZl cmVpbiB6dXIgRsO2cmRlcnVuZyBlaW5lcyBEZXV0c2NoZW4gRm9yc2NodW5nc25l dHplcyBlLiBWLjERMA8GA1UECwwIZWFzeXJvYW0xFzAVBgNVBAMMDmdldC5lZHVy b2FtLmRlMB4XDTI0MDgxMjEyNDIwOFoXDTI3MDgxMjEyNDIwOFowgZExCzAJBgNV BAYTAkRFMQ8wDQYDVQQIDAZCZXJsaW4xRTBDBgNVBAoMPFZlcmVpbiB6dXIgRsO2 cmRlcnVuZyBlaW5lcyBEZXV0c2NoZW4gRm9yc2NodW5nc25ldHplcyBlLiBWLjER MA8GA1UECwwIZWFzeXJvYW0xFzAVBgNVBAMMDmdldC5lZHVyb2FtLmRlMIICIjAN BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA+iNKmXEOFXxbjy00Xyw2PAOGhWuY Z4T4pYux5juM8kQN9jRb1hynfkAxIJnG9fZyEH2saPzvIHf7dsM4FLljVyseuVVg 9K4I1gzdlrWjta5JbSvzPJm9Mi2uVXgtqvNnCof6Ez7JxfP2SDWSVDv8ewW+p2Je 6aXcnakRIf2CvzrX0GoWyNYRRjejQt/2x/iX8Tkq+4KAXLPEgcfbFDofrSAX9rh6 qUkAQ9xuGZZ30BbJ5S2mFeRrmd26SwkpY6r3w9MrMulAbWz0j0cMHBPfajgCj0WW XlyN+koVPj2uAzuHMZuoTJ6iRGEvXvyznTHx0l6hoaT8+chBEsAAqFmQ3lcwiptw TlIws13tr4BsITWgkV5DGYKqZI+TI84rvcQc6I31cVV+Xv1XVr5mzqgyZkFDYAez uo+r2ljOS4xtAG3PsoV3m6U/ZGrB6Aq1FUsOtxkuwdarQCmmI51FIxYWbztl/IyP HWgX2dgedjGZIxJN/4p6VYJsg/61xpBQLSd40kx/JTo3qCXzNEe0v15LxUl/88QC 5/COgdmOyzcLJLcGkFGBJaqHY5FV5P9TmI0uYc3aYvdQ2M7oX3fWLZuzjHWZwdC3 guKBPJIn45f7gPX65F+yoPWlVi0O6swFoC2yjpW0y//qf2dju+DW0NgqAS/j1h9a 1ws5ApXMiyDRyAsCAwEAAaN6MHgwDAYDVR0TAQH/BAIwADBJBgNVHREEQjBAghBh dXRoLmVhc3lyb2FtLmRlggtlYXN5cm9hbS5kZYIOZ2V0LmVkdXJvYW0uZGWCD3d3 dy5lYXN5cm9hbS5kZTAdBgNVHQ4EFgQU+TleYVuQeNEHCNG0JX/gUUPO6SYwDQYJ KoZIhvcNAQELBQADggIBAA8/O+oRbs7Gbt245Jvdmf9Jfy42rQ+VKqL0/ZHo6+vk rB87gN6GnHq5aUprjcreZSg6sMYRX+khwoezQd2V+Oh0wMTQ4bfKk248Z3qd8hbS e0VGmIrcaULJXWsUJc7cGy8AAw2f37rGbe74rkC5qGz8FN1UY/iQec8iSF/wVLu3 JvN5qVyf/9+isgB/aKNxuVHnfYkbc8GoZAYxogz3AYqvAQ6Lq9DEIS4qgsp3Q2Bl Tz/q1aZL5QjQQ6S+FbiAywTI4/3hvH8Z/k/FFf+/asOS5DBnJNw+3tmqqPVLcjv6 ATsbC5M0Ar6mawgncVDw8YYPZzuXVLIypz2lIGuu/Okvk8YgpS/NFsWPTFFYBTCK TF1+mu1SIcHVz/GonU4qYLIbbdHXdIp57R7PSwK+/R7MA1rzJsAYHJHBgWiP8XuL Ki1frtlBmurQMWfonLk/dcDIviwQsSVlimvfQLcikaTO3vAO2QWWci+dSZ0ATliW 7p8qY+Qh4AQBnkZd3GndsaFDK6zBoYu+lJh7RkQs/RqhiDHd/b5uKGwXPOIDFofw AZd0imUj7nTK25w6Rv2jsYmeMqyM7T9pY+c4KRPPNTCTjQiZXkRo8nNxb7C1Xk6G A+MKd/zpbb2BKk6MSwDuVDFcaxfpvIt6PrcYJDFlCmJ6nlpcC9MwnqJHkx7r++Fs
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</KeyDescriptor>
<ArtifactResolutionService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://get.eduroam.de/Auth/Artifact/SOAP" index="1"/>
<ArtifactResolutionService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://www.easyroam.de/Auth/Artifact/SOAP" index="2"/>
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" Location="https://www.easyroam.de/Auth/SLO_ARTIFACT"/>
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" Location="https://get.eduroam.de/Auth/SLO_ARTIFACT"/>
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://www.easyroam.de/Auth/SLO_POST"/>
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://get.eduroam.de/Auth/SLO_POST"/>
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://get.eduroam.de/Auth/SLO_REDIRECT"/>
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://www.easyroam.de/Auth/SLO_REDIRECT"/>
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://www.easyroam.de/Auth/SLO_SOAP"/>
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://get.eduroam.de/Auth/SLO_SOAP"/>
<NameIDFormat>
urn:oasis:names:tc:SAML:2.0:nameid-format:transient
</NameIDFormat>
<AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://get.eduroam.de/Auth/ACS_POST" index="1"/>
<AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign" Location="https://get.eduroam.de/Auth/ACS_SIGN" index="2"/>
<AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" Location="https://get.eduroam.de/Auth/ACS_ARTIFACT" index="3"/>
<AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:PAOS" Location="https://get.eduroam.de/Auth/ACS_ECP" index="4"/>
<AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://www.easyroam.de/Auth/ACS_POST" index="5"/>
<AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign" Location="https://www.easyroam.de/Auth/ACS_SIGN" index="6"/>
<AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" Location="https://www.easyroam.de/Auth/ACS_ARTIFACT" index="7"/>
<AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:PAOS" Location="https://www.easyroam.de/Auth/ACS_ECP" index="8"/>
<AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://auth.easyroam.de/Auth/ACS_POST" index="9"/>
<AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign" Location="https://auth.easyroam.de/Auth/ACS_SIGN" index="10"/>
<AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" Location="https://auth.easyroam.de/Auth/ACS_ARTIFACT" index="11"/>
<AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:PAOS" Location="https://auth.easyroam.de/Auth/ACS_ECP" index="12"/>
<AttributeConsumingService index="1">
<ServiceName xml:lang="de">DFN easyroam</ServiceName>
<ServiceName xml:lang="en">DFN easyroam</ServiceName>
<ServiceDescription xml:lang="de">DFN easyroam</ServiceDescription>
<ServiceDescription xml:lang="en">DFN easyroam</ServiceDescription>
<RequestedAttribute FriendlyName="eduPersonEntitlement" Name="urn:oid:1.3.6.1.4.1.5923.1.1.1.7" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="true"/>
<RequestedAttribute FriendlyName="eduPersonScopedAffiliation" Name="urn:oid:1.3.6.1.4.1.5923.1.1.1.9" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="true"/>
</AttributeConsumingService>
</SPSSODescriptor>
<Organization>
<OrganizationName xml:lang="de">e15</OrganizationName>
<OrganizationName xml:lang="en">e15</OrganizationName>
<OrganizationDisplayName xml:lang="de">DFN-Verein - Deutsches Forschungsnetz</OrganizationDisplayName>
<OrganizationDisplayName xml:lang="en">
German National Research and Education Network, DFN
</OrganizationDisplayName>
<OrganizationURL xml:lang="de">http://www.dfn.de</OrganizationURL>
<OrganizationURL xml:lang="en">http://www.dfn.de/en/</OrganizationURL>
</Organization>
<ContactPerson contactType="other" remd:contactType="http://refeds.org/metadata/contactType/security">
<GivenName>EasyRoam4Edu Support</GivenName>
<EmailAddress>mailto:eduroam@dfn.de</EmailAddress>
</ContactPerson>
<ContactPerson contactType="support">
<GivenName>EasyRoam4Edu Support</GivenName>
<EmailAddress>mailto:easyroam4edu@dfn.de</EmailAddress>
</ContactPerson>
<ContactPerson contactType="technical">
<GivenName>Ralf</GivenName>
<SurName>Paffrath</SurName>
<EmailAddress>mailto:eduroam@dfn.de</EmailAddress>
</ContactPerson>
</EntityDescriptor>
Folgende Attribute werden für die Teilnahme an easyroam benötigt:
<!-- Datei: /opt/shibboleth-idp/conf/attribute-resolver.xml -->
<AttributeDefinition xsi:type="ScriptedAttribute" id="eduPersonEntitlement">
<InputAttributeDefinition ref="uid" />
<Script><![CDATA[
if (uid.getValues().get(0) == "professorin") {
eduPersonEntitlement.getValues().add("https://www.dfn.de/entitlement/geteduroam/admin");
}
eduPersonEntitlement.getValues().add("https://www.dfn.de/entitlement/geteduroam/optin");
]]>
</Script>
</AttributeDefinition>
<!-- Datei: /opt/shibboleth-idp/conf/attribute-filter.xml -->
<AttributeFilterPolicy id="get_eduroam">
<PolicyRequirementRule xsi:type="Requester" value="https://sp1.local/shibboleth" />
<AttributeRule attributeID="eduPersonEntitlement">
<PermitValueRule xsi:type="ValueRegex" regex="^https://www\.dfn\.de/entitlement/geteduroam/.*$" />
</AttributeRule>
<AttributeRule attributeID="eduPersonScopedAffiliation" permitAny="true"/>
<AttributeRule attributeID="samlPairwiseID" permitAny="true"/>
</AttributeFilterPolicy>
Um Fehler in den Logfiles zu sehen, erhöhen wir das Loglevel:
<!-- Datei: /opt/shibboleth-idp/conf/logback.xml -->
<variable name="idp.loglevel.idp" value="DEBUG" />
<variable name="idp.loglevel.ldap" value="INFO" />
<variable name="idp.loglevel.messages" value="DEBUG" />
<variable name="idp.loglevel.encryption" value="DEBUG" />
<variable name="idp.loglevel.opensaml" value="INFO" />
<variable name="idp.loglevel.props" value="INFO" />
<variable name="idp.loglevel.httpclient" value="INFO" />
Stoßen Sie das Neuladen des Servlets manuell an:
touch /opt/shibboleth-idp/war/idp.war
Dann schauen wir uns die Logfiles an:
tail -f /opt/shibboleth-idp/logs/idp-process.log
Anschließend öffnen wir den Webbrowser und loggen uns mit dem User professorin beim SP1 ein.
Auszug Logfile
Im Logfile finden wir eine Warnung und einen Fehler:
Wenn wir das Loglevel nicht erhöhen ist die Fehlermeldung nicht sehr hilfreich: WARN [net.shibboleth.shared.spring.custom.AbstractCustomBeanDefinitionParser:60] - Duplicate Definition 'eduPersonEntitlement' of type 'net.shibboleth.idp.attribute.resolver.ad.impl.ScriptedAttributeDefinition'
ERROR [net.shibboleth.shared.service.AbstractReloadableService:179] - Service 'shibboleth.AttributeResolverService': Initial load failed
net.shibboleth.shared.service.ServiceException: Failed to load [file [/opt/shibboleth-idp/conf/attribute-resolver.xml], class path resource [net/shibboleth/idp/conf/attribute-resolver-syste
m.xml]]
at net.shibboleth.shared.spring.service.ReloadableSpringService.doReload(ReloadableSpringService.java:385)
Caused by: net.shibboleth.shared.service.ServiceException: Unable to initialize attribute resolver for ApplicationContext:shibboleth.AttributeResolverService
at net.shibboleth.idp.attribute.resolver.spring.impl.AttributeResolverServiceStrategy.apply(AttributeResolverServiceStrategy.java:96)
Caused by: net.shibboleth.shared.component.ComponentInitializationException: Attribute Resolver 'ShibbolethAttributeResolver': Plugin 'eduPersonEntitlement' has a dependency on attribute de
finition 'uid' which doesn't exist
at net.shibboleth.idp.attribute.resolver.impl.AttributeResolverImpl.checkPlugInDependencies(AttributeResolverImpl.java:704)
ERROR [net.shibboleth.idp.profile.impl.ResolveAttributes:289] - Profile Action ResolveAttributes: Invalid AttributeResolver configuration
net.shibboleth.shared.service.ServiceException: Service component shibboleth.AttributeResolverService is unavailable
at net.shibboleth.shared.spring.service.ReloadableSpringService.getServiceableComponent(ReloadableSpringService.java:458)
'uid' which doesn't exist
beheben, indem die Attribute Definition für uid hinzugefügt wird und im Data Connector uid aus der Liste der zu exportierenden Attributen entfernt wird.
<!-- Datei: /opt/shibboleth-idp/conf/attribute-resolver.xml -->
<AttributeDefinition xsi:type="Simple" id="uid">
<InputDataConnector ref="myLDAP" attributeNames="uid"/>
</AttributeDefinition>
<!-- Datei: /opt/shibboleth-idp/conf/attribute-resolver.xml -->
<DataConnector id="myLDAP" xsi:type="LDAPDirectory"
ldapURL="%{idp.attribute.resolver.LDAP.ldapURL}"
baseDN="%{idp.attribute.resolver.LDAP.baseDN}"
principal="%{idp.attribute.resolver.LDAP.bindDN}"
principalCredential="%{idp.attribute.resolver.LDAP.bindDNCredential}"
useStartTLS="%{idp.attribute.resolver.LDAP.useStartTLS:true}"
connectTimeout="%{idp.attribute.resolver.LDAP.connectTimeout}"
responseTimeout="%{idp.attribute.resolver.LDAP.responseTimeout}"
exportAttributes="givenName sn mail displayName">
Bleibt noch die Warnung mit der doppelten Definition für eduPersonEntitlement. Die beiden Definitionen werden zu einer zusammen gefasst:
<!-- Datei: /opt/shibboleth-idp/conf/attribute-resolver.xml -->
<AttributeDefinition xsi:type="ScriptedAttribute" id="eduPersonEntitlement">
<InputAttributeDefinition ref="eduPersonAffiliation" />
<InputAttributeDefinition ref="uid" />
<Script><![CDATA[
eduPersonEntitlement.getValues().add("https://www.dfn.de/entitlement/geteduroam/optin");
if (eduPersonAffiliation.getValues().contains("member")) {
eduPersonEntitlement.getValues().add("urn:mace:dir:entitlement:common-lib-terms");
}
if (uid.getValues().get(0) == "professorin") {
eduPersonEntitlement.getValues().add("https://www.dfn.de/entitlement/geteduroam/admin");
}
]]></Script>
</AttributeDefinition>
Stoßen Sie erneut das Neuladen des Servlets manuell an:
touch /opt/shibboleth-idp/war/idp.war
Dann schauen wir uns die Logfiles an:
tail -f /opt/shibboleth-idp/logs/idp-process.log
Anschließend öffnen wir den Webbrowser und loggen uns mit dem User professorin beim SP1 ein.
<!-- Datei: /opt/shibboleth-idp/conf/logback.xml -->
<variable name="idp.loglevel.idp" value="DEBUG" />
<variable name="idp.loglevel.ldap" value="INFO" />
<variable name="idp.loglevel.messages" value="DEBUG" />
<variable name="idp.loglevel.encryption" value="DEBUG" />
<variable name="idp.loglevel.opensaml" value="INFO" />
<variable name="idp.loglevel.props" value="INFO" />
<variable name="idp.loglevel.httpclient" value="INFO" />
Stoßen Sie das Neuladen des Servlets manuell an:
touch /opt/shibboleth-idp/war/idp.war
Als erstes prüfen wir idp-process.log mit welchem Algorithmus die Assertion verschlüsselt wurde. Ab Shibboleth IdP 3.4 wurde eine Einstellung aufgenommen, mit der der Algorithmus eingestellt werden kann, mit dem die Assertions verschlüsselt werden.
Der alte Standard-Algorithmus AES-CBC gilt nicht mehr als sicher, daher ist bei neu installierten IdPs ab Version 4.x die Voreinstellung AES-GCM. Einige Nicht-Shibboleth-Service Provider können mit dem aktuell als sicher betrachteten Algorithmus AES-GCM noch nicht umgehen.
Eine Liste der uns bekannten SPs mit diesem Problem finden Sie auf folgender Seite im Wiki:
https://doku.tid.dfn.de/de:shibidp:config-encryption#konfiguration_des_verschluesselungsalgorithmusDort finden Sie ebenfalls Lösungsvorschläge.
INFO [Shibboleth-Audit.SSO:333] - 127.0.0.1|2025-02-05T10:23:49.890217440Z|2025-02-05T10:24:07.963174270Z|extern|https://sp1.local/shibboleth|_c01dc0b5c564afedad1dd|password|2025-02-05T10:24:01.652597568Z|eduPersonEntitlement,uid,samlPairwiseID,mail,givenName|eVIQHtaTn2vBt6bbxWexuYw+D/87vOYyvoaRomKPmkhwGvYg==|transient|false|false|AES128-GCM|Redirect|POST||Success||1291d44|Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0
Suchen Sie nun nach Assertion before encryption. Hier finden Sie die vom IdP an den SP übertragenen Attribute.
Assertion
<!-- Datei: /opt/shibboleth-idp/logs/idp-process.log -->
2025-02-05 11:24:07,874 - 127.0.0.1 - DEBUG [org.opensaml.saml.saml2.encryption.Encrypter:332] - Assertion before encryption:
<?xml version="1.0" encoding="UTF-8"?><saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" ID="_c01dc0b5c564af29d378db6eeedad1dd" IssueInstant="2025-02-05T10:24:07.697Z" Version="2.0">
<saml2:Issuer>https://idp.local/idp/shibboleth</saml2:Issuer>
<saml2:Subject>
<saml2:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient" NameQualifier="https://idp.local/idp/shibboleth" SPNameQualifier="https://sp1.local/shibboleth" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">AAdzZWNyZXQxVY9g+piuV1rz6NzqpxxCJbueMqErv/HtVmXkzQz1CTCfs2VRFHb7XaqSb3iWm8nn3AUGOSMeqK/K39+v1peVIQHtaTn2vBt6bbxWexuYw+D/87vOYyvoaRomKPmkhwGvYg==
<saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml2:SubjectConfirmationData Address="127.0.0.1" InResponseTo="_38ae57a85200d167d971742ef2af5d56" NotOnOrAfter="2025-02-05T10:29:07.804Z" Recipient="https://sp1.local/Shibboleth.sso/SAML2/POST"/>
</saml2:SubjectConfirmation>
</saml2:Subject>
<saml2:Conditions NotBefore="2025-02-05T10:24:07.697Z" NotOnOrAfter="2025-02-05T10:29:07.697Z">
<saml2:AudienceRestriction>
<saml2:Audience>https://sp1.local/shibboleth</saml2:Audience>
</saml2:AudienceRestriction>
</saml2:Conditions>
<saml2:AuthnStatement AuthnInstant="2025-02-05T10:24:01.652Z" SessionIndex="_3fc69447bf5408f41d919b9c4b7b4d38">
<saml2:SubjectLocality Address="127.0.0.1"/>
<saml2:AuthnContext>
<saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef>
</saml2:AuthnContext>
</saml2:AuthnStatement>
<saml2:AttributeStatement>
<saml2:Attribute FriendlyName="mail" Name="urn:oid:0.9.2342.19200300.100.1.3" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
<saml2:AttributeValue>hans.nichts@external.nodomain.local</saml2:AttributeValue>
</saml2:Attribute>
<saml2:Attribute FriendlyName="uid" Name="urn:oid:0.9.2342.19200300.100.1.1" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
<saml2:AttributeValue>extern</saml2:AttributeValue>
</saml2:Attribute>
<saml2:Attribute FriendlyName="eduPersonEntitlement" Name="urn:oid:1.3.6.1.4.1.5923.1.1.1.7" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
<saml2:AttributeValue>https://www.dfn.de/entitlement/geteduroam/optin</saml2:AttributeValue>
</saml2:Attribute>
<saml2:Attribute FriendlyName="samlPairwiseID" Name="urn:oasis:names:tc:SAML:attribute:pairwise-id" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
<saml2:AttributeValue>EJZ54S4NWQ6HJVARSKXPHC7NP5MTKPHI@local</saml2:AttributeValue>
</saml2:Attribute>
<saml2:Attribute FriendlyName="givenName" Name="urn:oid:2.5.4.42" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
<saml2:AttributeValue>Hans</saml2:AttributeValue>
</saml2:Attribute>
</saml2:AttributeStatement>
</saml2:Assertion>
<!-- Datei: /opt/shibboleth-idp/conf/relying-party.xml-->
<bean parent="SAML2.SSO" p:postAuthenticationFlows="#{{'attribute-release'}}" p:nameIDFormatPrecedence="#{{'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent', 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient'}}" />
# Download der Transcoding Properties für dfnEduPerson:
wget https://download.aai.dfn.de/schema/dfnEduPerson.xml -O /opt/shibboleth-idp/conf/attributes/dfnEduPerson.xml
ls /opt/shibboleth-idp/conf/attributes/
custom default-rules.xml dfnEduPerson.xml eduCourse.xml eduPerson.xml inetOrgPerson.xml samlSubject.xml
# Einbinden in default-rules.xml
[...]
<import resource="dfnEduPerson.xml" />
[...]
# Download der Transcoding Properties für dfnEduPerson:
wget https://download.aai.dfn.de/schema/dfnMisc.xml -O /opt/shibboleth-idp/conf/attributes/dfnMisc.xml
ls /opt/shibboleth-idp/conf/attributes/
custom default-rules.xml dfnEduPerson.xml eduCourse.xml eduPerson.xml inetOrgPerson.xml samlSubject.xml dfnMisc.xml
# Einbinden in default-rules.xml
[...]
<import resource="dfnMisc.xml" />
[...]
Etliche Service Provider sind immer noch nicht in der Lage, die SAML pairwise-id oder die persistentID zu verarbeiten. Sie erwarten den entsprechenden Wert in Form des veralteten Attributs eduPersonTargetedID.
So konfigurieren Sie den IdP, dass er die persistentId aus der Datenbank holt und als eduPersonTargetedID herausgibt. Die Freigabe erfolgt analog zu allen anderen Attributen in ./conf/attribute-filter.xml
<!-- Datei: /opt/shibboleth-idp/conf/attribute-resolver.xml -->
<AttributeDefinition id="eduPersonTargetedID" xsi:type="SAML2NameID" nameIdFormat="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">
<InputDataConnector ref="myStoredId" attributeNames="persistentId"/>
<AttributeDefinition>
<!-- ========================================== -->
<!-- Data Connectors -->
<!-- ========================================== -->
<DataConnector id="myStoredId"
xsi:type="StoredId"
generatedAttributeID="persistentId"
salt="%{idp.persistentId.salt}">
<InputAttributeDefinition ref="%{idp.persistentId.sourceAttribute}" />
<BeanManagedConnection>shibboleth.MySQLDataSource</BeanManagedConnection>
</DataConnector>