Shibboleth IdPv5 in der Schulungs-VM |
![]() |
su -
Sie installieren in diesem Tutorial die Version 5.1.4 Laden Sie sich die 5.1.4 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.4.tar.gz
wget -P /opt/install https://shibboleth.net/downloads/identity-provider/latest/shibboleth-identity-provider-5.1.4.tar.gz.sha256
wget -P /opt/install https://shibboleth.net/downloads/identity-provider/latest/shibboleth-identity-provider-5.1.4.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.4.tar.gz.asc /opt/install/shibboleth-identity-provider-5.1.4.tar.gz
cd /opt/install && sha256sum -c shibboleth-identity-provider-5.1.4.tar.gz.sha256
tar -xzf /opt/install/shibboleth-identity-provider-5.1.4.tar.gz -C /opt/install/
Führen Sie das interaktive Installerskript aus:
/opt/install/shibboleth-identity-provider-5.1.4/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.4
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"/>
<!-- Metadaten aller SPs der DFN-AAI Produktivföderation -->
<MetadataProvider id="dfn_aai"
xsi:type="FileBackedHTTPMetadataProvider"
backingFile="%{idp.home}/metadata/dfn-aai-sp-metadata.xml"
metadataURL="http://www.aai.dfn.de/metadata/dfn-aai-sp-metadata.xml"
maxRefreshDelay="PT2H">
<MetadataFilter xsi:type="SignatureValidation"
requireSignedRoot="true"
certificateFile="/etc/ssl/aai/dfn-aai.pem"/>
</MetadataProvider>
zur Doku: Konfiguration der Föderationsmetadaten
<!-- Datei: /opt/shibboleth-idp/metadata/idp-metadata.xml -->
zur Doku: Einmalige Verwendung der idp-metadata.xml
ldapsearch -x -W -D cn=admin,dc=nodomain -H ldap://idp.local -b "dc=users,dc=nodomain" '(uid=professorin)'
# 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 root 733 11. Apr 15:18 /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/ldap.properties
idp.attribute.resolver.LDAP.searchFilter = (uid=$resolutionContext.principal)
# Datei: /opt/shibboleth-idp/conf/c14n/subject-c14n.properties
idp.c14n.simple.lowercase = true
<!-- 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
<!-- Datei: /opt/shibboleth-idp/conf/attribute-resolver.xml -->
<DataConnector id="staticAttributes" xsi:type="Static" exportAttributes="schacHomeOrganization">
<Attribute id="schacHomeOrganization">
<Value>%{idp.scope}</Value>
</Attribute>
<Attribute id="affiliation">
<Value>member</Value>
</Attribute>
</DataConnector>
<!-- Datei: /opt/shibboleth-idp/conf/attribute-resolver.xml -->
<DataConnector id="staticAttributes" xsi:type="Static" exportAttributes="schacHomeOrganization">
<Attribute id="schacHomeOrganization">
<Value>%{idp.scope}</Value>
</Attribute>
<Attribute id="o">
<Value>%{idp.scope}</Value>
</Attribute>
</DataConnector>
<!-- 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="uid givenName sn mail displayName">
<FilterTemplate>
<![CDATA[
%{idp.attribute.resolver.LDAP.searchFilter}
]]>
</FilterTemplate>
<ConnectionPool
minPoolSize="%{idp.pool.LDAP.minSize:3}"
maxPoolSize="%{idp.pool.LDAP.maxSize:10}"
blockWaitTime="%{idp.pool.LDAP.blockWaitTime:PT3S}"
validatePeriodically="%{idp.pool.LDAP.validatePeriodically:true}"
validateTimerPeriod="%{idp.pool.LDAP.validatePeriod:PT5M}"
expirationTime="%{idp.pool.LDAP.idleTime:PT10M}" />
</DataConnector>
Bitte beachten Sie im Data Connector "myLDAP" die Zeile "exportAttributes". Sie können 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.
<AttributeDefinition>
zu schreiben.
<AttributeDefinition>
. Gleiches gilt für die Attribute o und schacHomeOrganisation, welche im statischen Data Connector definiert sind.
Bleiben die Attribute eduPersonScopedAffiliation und eduPersonEntitlement:
<!-- Datei: /opt/shibboleth-idp/conf/attribute-resolver.xml -->
<!-- Schema: eduPerson attributes -->
<AttributeDefinition xsi:type="Simple" id="eduPersonAffiliation">
<InputDataConnector ref="myLDAP" attributeNames="eduPersonAffiliation" />
</AttributeDefinition>
<AttributeDefinition xsi:type="Scoped" id="eduPersonScopedAffiliation" scope="%{idp.scope}">
<InputDataConnector ref="myLDAP" attributeNames="eduPersonAffiliation"/>
</AttributeDefinition>
<!-- eduPersonEntitlement je nach eduPersonAffiliation setzen -->
<AttributeDefinition xsi:type="ScriptedAttribute" id="eduPersonEntitlement">
<InputAttributeDefinition ref="eduPersonAffiliation" />
<Script><![CDATA[
if (eduPersonAffiliation.getValues().contains("member")) {
eduPersonEntitlement.getValues().add("urn:mace:dir:entitlement:common-lib-terms");
}
]]></Script>
</AttributeDefinition>
<AttributeDefinition>
für das Attribute eduPersonEntitlement kommt ein scripted Attribute zum Einsatz. Damit der IdP diese ausführen kann, muss das Nashorn-Plugin installiert werden:
/opt/shibboleth-idp/bin/plugin.sh -I net.shibboleth.idp.plugin.nashorn
<!-- Datei: /opt/shibboleth-idp/conf/attribute-filter.xml -->
<!-- Release an additional attribute to an SP. -->
<AttributeFilterPolicy id="SPs_locals">
<PolicyRequirementRule xsi:type="Requester" value="https://sp.example.org" />
<AttributeRule attributeID="uid" permitAny="true" />
</AttributeFilterPolicy>
<!-- Datei: /opt/shibboleth-idp/conf/attribute-filter.xml -->
<!-- Release an additional attribute to an SP. -->
<AttributeFilterPolicy id="SPs_locals">
<PolicyRequirementRule xsi:type="Requester" value="https://sp1.local/shibboleth" />
<AttributeRule attributeID="eduPersonScopedAffiliation" permitAny="true" />
<AttributeRule attributeID="sn" 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
/opt/shibboleth-idp/bin/module.sh -e idp.intercept.Consent
Output:
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:
<!-- Datei: /opt/shibboleth-idp/conf/relying-party.xml -->
<bean id="shibboleth.DefaultRelyingParty" parent="RelyingParty">
<property name="profileConfigurations">
<list>
<!-- SAML 1.1 and SAML 2.0 AttributeQuery are disabled by default. -->
<!--
<ref bean="Shibboleth.SSO" />
<ref bean="SAML1.AttributeQuery" />
<ref bean="SAML1.ArtifactResolution" />
-->
<ref bean="SAML2.SSO" />
<ref bean="SAML2.ECP" />
<ref bean="SAML2.Logout" />
...
</list>
</property>
</bean>
<!-- Datei /opt/shibboleth-idp/conf/relying-party.xml -->
<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/idp-consent-audit.log
zur Doku: Datenbank-Konfiguration
zum Shib-Wiki: JDBCStorageService
Legen Sie eine Datenbank für Shibboleth an. Sie wird zwei Tabellen enthalten:mariadb -uroot
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;
/opt/shibboleth-idp/bin/plugin.sh --truststore /opt/install/PGP_KEYS -I net.shibboleth.plugin.storage.jdbc
Der DB-Zugriff wird über den JDBCStorageService hergestellt. Dieser wird in ./conf/global.xml definiert. Diese Datei ist im Auslieferungszustand leer (bis auf Kommentare).
Fügen Sie für die MariaDB-Konfiguration folgende Zeilen zur Datei 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" />
Die Shibboleth-Entwickler empfehlen nicht mehr das tomcat-pooling zu verwenden, sondern DBCP 2. Die Properties für den Datenbank-Zugriff
werden jetzt noch entsprechend in conf/idp.properties ergänzt:
# Datei /opt/shibboleth-idp/conf/idp.properties
mysql.class = org.apache.commons.dbcp2.BasicDataSource
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 = uid
idp.consent.allowGlobal = 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
Laden Sie das Servlet neu und melden Sie sich erneut für den SP1 an.
touch /opt/shibboleth-idp/war/idp.war
Schauen Sie sich anschließend den Eintrag in der Datenbank an:
mariadb -uroot
MariaDB [(none)]> USE shibboleth;
MariaDB [shibboleth]> SELECT * FROM StorageRecords\G
# Datei: /opt/shibboleth-idp/conf/saml-nameid.properties
idp.persistentId.sourceAttribute = uid
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-->
<DataConnector id="StoredId" xsi:type="StoredId"
generatedAttributeID="persistentId"
salt="%{idp.persistentId.salt}"
encoding="BASE32"
queryTimeout="0">
<InputDataConnector ref="myLDAP" attributeNames="%{idp.persistentId.sourceAttribute}"/>
<BeanManagedConnection>shibboleth.MySQLDataSource</BeanManagedConnection>
</DataConnector>
Im oberen Teil der conf/attribute-resolver.xml bei den Attribute Definitions definieren Sie die samlPairwiseID:
<!-- 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" />
Laden Sie das Servlet neu und melden Sie sich erneut für den SP1 an.
touch /opt/shibboleth-idp/war/idp.war
Werfen Sie einen Blick in die Datenbank und schauen sich die Tabelle shibpid an:
mariadb -uroot
MariaDB [(none)]> USE shibboleth;
MariaDB [shibboleth]> SELECT * FROM shibpid\G
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.
Schauen Sie sich nun die Assertion an. Dazu suchen Sie in der Log-Datei /opt/shibboleth-idp/logs/idp-process.log nach Assertion before encryption.
Hier finden Sie die vom IdP an den SP übertragenen Attribute, sowie die NameID im Format urn:oasis:names:tc:SAML:2.0:nameid-format:transient.
Assertion
<!-- Datei: /opt/shibboleth-idp/logs/idp-process.log -->
2025-05-21 17:55:00,008 - 127.0.0.1 - DEBUG [org.opensaml.saml.saml2.encryption.Encrypter:332] - Assertion before encryption:
<?xml version="1.0" encoding="UTF-8"?>
<!-- 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
Verzeichnis anzeigen lassen:
ls /opt/shibboleth-idp/conf/attributes/
custom default-rules.xml dfnEduPerson.xml eduCourse.xml eduPerson.xml inetOrgPerson.xml samlSubject.xml
Einbinden in:
# /opt/shibboleth-idp/conf/attributes/default-rules.xml
[..]
<import resource="dfnEduPerson.xml" />
[..]
Download der Transcoding Properties für dfnMisc:
wget https://download.aai.dfn.de/schema/dfnMisc.xml -O /opt/shibboleth-idp/conf/attributes/dfnMisc.xml
Verzeichnis anzeigen lassen:
ls /opt/shibboleth-idp/conf/attributes/
custom default-rules.xml dfnEduPerson.xml eduCourse.xml eduPerson.xml inetOrgPerson.xml samlSubject.xml dfnMisc.xml
Einbinden in:
# /opt/shibboleth-idp/conf/attributes/default-rules.xml
[..]
<import resource="dfnMisc.xml" />
[..]
Shibboleth-Instanz neu laden:
# touch /opt/shibboleth-idp/war/idp.war
Etliche Service Provider sind immer noch nicht in der Lage, die SAML samlPairwiseID oder die persistentID zu verarbeiten. Sie erwarten den entsprechenden Wert in Form des veralteten Attributs eduPersonTargetedID.
Passen Sie die Datei attribute-resolver.xml an. Der DataConnector wurde bereits in Übung 3.3 erstellt. Erstellen Sie eine Attribut-Definition mit folgenden Parametern:
<!-- 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="StoredId" attributeNames="persistentId"/>
</AttributeDefinition>
<!-- Datei: /opt/shibboleth-idp/conf/attribute-filter.xml -->
<!-- Release to local SPs -->
<AttributeFilterPolicy id="SPs_locals">
....
<AttributeRule attributeID="eduPersonTargetedID" permitAny="true" />
</AttributeFilterPolicy>
Shibboleth-Instanz neu laden:
# touch /opt/shibboleth-idp/war/idp.war