Die im folgenden dokumentierte Beispielkonfiguration beruht sowohl auf den Vorschlägen der Forschungsstelle Recht im DFN, "Datenschutzrechtliche Analyse das AAI-Verfahrens", 69. BT als auch auf hausinternen Konsultationen mit dem Justiziariat des DFN-Vereins.
Beachten Sie bitte, dass es sich hierbei um unverbindliche Vorschläge handelt! Der DFN-Verein übernimmt keine Verantwortung für etwaige juristische Streitfälle, die sich aus diesen Beispielen oder daraus abgeleiteten Konfigurationen ergeben!
Führen Sie zunächst die unter Aktivierung der Nutzungsbedingungen beschrieben Arbeitsschritte durch.
Die im folgenden vorgestellten Beispiele benötigen die hier verlinkte, angepasste Version der messages.properties. Bitte lesen Sie die Inline-Kommentare und passen die Properties den jeweiligen Erfordernissen und Rahmenbedingungen entsprechend an!
Unabhängig davon, auf welcher Rechtsgrundlage die Übertragung von Attributen an einen Service Provider erfolgt, kann der Terms-of-Use Consent unter anderem dazu verwendet werden, eine Einwilligung in die Generierung und Speicherung der SAML2 Persistent Name ID (Persistent Id) einzuholen. Dies ist insofern sinnvoll, als es sich bei bei der Persistent Id um kein Attribut handelt und Endnutzer beim Zugriff auf einen SP nicht steuern können, ob eine Persistent Id übertragen wird. Die Übertragung der Persistent Id wird per Default zwischen IdP und SP ausgehandelt und kann ggf. seitens des IdP-Admins durch eine entsprechend angepasste Relying Party Konfiguration gesteuert werden. Siehe hierzu unter Weitergabe der Persistent Id.
Unser Beispiel stellt noch eine allgemeine Funktionsbeschreibung des IdP voran. Konkret handelt es sich um die Properties my-service-description
und my-tou.text
. Selbstverständlich kann (und soll) dieser Text durch weitere, für die jeweilige Einrichtung relevante Punkte ergänzt werden.
Hier ein Beispiel für ein Velocity Template, das diese Properties zum Einholen der Einwilligung der EndnutzerInnen anzeigt: terms-of-use.vm sowie für eine statische JSP-Datei, die es EndnutzerInnen erlaubt, auf den aktuellen Wortlaut der Einwilligungserklärung zuzugreifen: tou.jsp. Die letztgenannte Datei muss unter ./edit-webapp
abgelegt werden. Änderungen an dieser Datei erfordern daher eine erneute Generierung des IdP-Servlets via ./bin/build.sh
(bzw. ./bin/build.bat
).
Diese Datei (tou.jsp) kann an beliebiger Stelle verlinkt werden, z.B. im Footer und/oder auf der Login-Seite des IdP:
<div class="column two"> <ul class="list list-help"> <li class="list-help-item"><a href="#springMessageText("idp.url.password.reset", "#")"><span class="item-marker">›</span> #springMessageText("idp.login.forgotPassword", "Forgot your password?")</a></li> <li class="list-help-item"><a href="$request.getContextPath()/tou.jsp" target="_blank"><span class="item-marker">›</span> Wortlaut Einwilligungserklärung</a></li> </ul> <!-- usw. -->
Sofern die Übertragung von Attributen ausschließlich freiwillig, aufgrund einer Einwilligung der EndnutzerInnen erfolgt (DSGVO Art. 6.1 lit a), muss kein separater Flow definiert werden!
Hier ein Beispiel für ein entsprechendes Velocity Template: ./views/intercept/attribute-release.vm (Variante 1).
Wenn die Attributfreigabe fallweise aufgrund anderer Erlaubnisnormen erfolgt, bedarf es entsprechend angepasster Interceptor Flows, die je nach anfragendem SP und ggf. Nutzergruppe aufgerufen werden. Siehe hierzu die Lösungsmodelle aus der Präsentation "Datenschutzrechtliche Analyse das AAI-Verfahrens" von der 69. DFN-Betriebstagung und die Präsentation "Wir basteln einen Interceptor Flow".
Neben der angepassten Datei ./views/intercept/attribute-release.vm (siehe oben) werden hierfür noch die Velocity Templates attribute-info.vm und attribute-must.vm, die von der selben Wiki Seite heruntergeladen werden können (Varianten 2 und 3) und die ebenfalls in ./views/intercept
abgelegt werden.
Weiterhin sind folgende Konfigurationsschritte erforderlich:
1. Flow aus bestehendem Interceptor erstellen:
./system/flows/intercept/attribute-release-beans.xml
und
./system/flows/intercept/attribute-release-flow.xml
jeweils kopieren nach:
./flows/intercept/attribute-info/attribute-info-beans.xml
./flows/intercept/attribute-info/attribute-info-flow.xml
und
./flows/intercept/attribute-must/attribute-must-beans.xml
./flows/intercept/attribute-must/attribute-must-flow.xml
2. In den kopierten Dateien die Pfade anpassen:
In den *-flow.xml Dateien die Referenzen auf die bean-Dateien anpassen:
< <bean-import resource="attribute-release-beans.xml" /> --- > <bean-import resource="attribute-info-beans.xml" />
bzw.
< <bean-import resource="attribute-release-beans.xml" /> --- > <bean-import resource="attribute-must-beans.xml" />
3. Dafür sorgen, dass Bezeichnung des Events im Log dem jeweils aufgerufenen Flow entspricht (–> Nachweispflichten)
<action-state id="ExtractConsent"> <evaluate expression="ExtractConsent" /> <evaluate expression="'AttributeReleaseInfo'" /> <transition on="AttributeReleaseInfo" to="AttributeReleaseInfo" /> </action-state> <!-- Write 'AttributeReleaseInfo' event to consent audit log. --> <action-state id="AttributeReleaseInfo"> <evaluate expression="PopulateConsentAuditContext" /> <evaluate expression="WriteAttributeReleaseConsentAuditLog" /> <evaluate expression="'proceed'" /> <transition on="proceed" to="TestForDoNotRememberConsent" /> </action-state>
und
<action-state id="ExtractConsent"> <evaluate expression="ExtractConsent" /> <evaluate expression="'AttributeReleaseMust'" /> <transition on="AttributeReleaseMust" to="AttributeReleaseMust" /> </action-state> <!-- Write 'AttributeReleaseMust' event to consent audit log. --> <action-state id="AttributeReleaseMust"> <evaluate expression="PopulateConsentAuditContext" /> <evaluate expression="WriteAttributeReleaseConsentAuditLog" /> <evaluate expression="'proceed'" /> <transition on="proceed" to="TestForDoNotRememberConsent" /> </action-state>
4. Neue Flows deklarieren und mit Activation Conditions verknüpfen
Dies geschieht am besten in ./conf/intercept/profile-intercept.xml (Beispiel)
5. Neue Flows in der Relying Party Konfiguration dem SSO-Profil als Post Authentication Flows zuordnen
<bean id="shibboleth.DefaultRelyingParty" parent="RelyingParty"> <property name="profileConfigurations"> <list> <bean parent="SAML2.SSO" p:postAuthenticationFlows="#{{'terms-of-use', 'attribute-release', 'attribute-info', 'attribute-must'}}" /> <ref bean="SAML2.ECP" /> <ref bean="SAML2.Logout" /> <ref bean="SAML2.AttributeQuery" /> <ref bean="SAML2.ArtifactResolution" /> </list> </property> </bean>
Bei Attribute Queries kann die jeweils letzte Entscheidung des Users zur Attributfreigabe berücksichtigt werden. Dies funktioniert natürlich nur, wenn die (virtuellen) Entscheidungen zur Attributfreigabe in einer IdP-seitigen Datenbank abgelegt werden und eine entsprechende Condition gesetzt ist. Siehe hierzu unter Server-Side-Storage - User Consent.
Damit Attribute Queries unter diesen Rahmenbedingungen auch im oben skizzierten Setup funktionieren, sind weitere Konfigurationsschritte erforderlich:
Zunächst die Dateien
./system/flows/intercept/attribute-release-query-beans.xml
und
./system/flows/intercept/attribute-release-query-flow.xml
in ein Verzeichnis namens
./flows/intercept/attribute-release-query
kopieren.
Anschließend müssen diverse Anpassungen vorgenommen werden:
<!-- Use 'intercept/attribute-release' as storage context. --> <bean id="AttributeReleaseStorageContextLookupStrategy" parent="shibboleth.Functions.Constant" c:target="intercept/attribute-release" /> <bean id="ReadAttributeReleaseConsentFromStorage" class="net.shibboleth.idp.consent.flow.storage.impl.ReadConsentFromStorage" scope="prototype" p:storageKeyLookupStrategy-ref="shibboleth.consent.UserAndRelyingPartyStorageKey" p:storageSerializer-ref="shibboleth.consent.ConsentSerializer" p:storageContextLookupStrategy-ref="AttributeReleaseStorageContextLookupStrategy" /> <!-- Use 'intercept/attribute-info' as storage context. --> <bean id="AttributeReleaseInfoStorageContextLookupStrategy" parent="shibboleth.Functions.Constant" c:target="intercept/attribute-info" /> <bean id="ReadAttributeReleaseInfoConsentFromStorage" class="net.shibboleth.idp.consent.flow.storage.impl.ReadConsentFromStorage" scope="prototype" p:storageKeyLookupStrategy-ref="shibboleth.consent.UserAndRelyingPartyStorageKey" p:storageSerializer-ref="shibboleth.consent.ConsentSerializer" p:storageContextLookupStrategy-ref="AttributeReleaseInfoStorageContextLookupStrategy" /> <!-- Use 'intercept/attribute-must' as storage context. --> <bean id="AttributeReleaseMustStorageContextLookupStrategy" parent="shibboleth.Functions.Constant" c:target="intercept/attribute-must" /> <bean id="ReadAttributeReleaseMustConsentFromStorage" class="net.shibboleth.idp.consent.flow.storage.impl.ReadConsentFromStorage" scope="prototype" p:storageKeyLookupStrategy-ref="shibboleth.consent.UserAndRelyingPartyStorageKey" p:storageSerializer-ref="shibboleth.consent.ConsentSerializer" p:storageContextLookupStrategy-ref="AttributeReleaseMustStorageContextLookupStrategy" />
In der Flow-Definition den Block nach <!– Read consent from storage –>
anpassen und erweitern:
<!-- Read consent from storage. --> <action-state id="ReadConsentFromStorage"> <evaluate expression="ReadAttributeReleaseConsentFromStorage" /> <evaluate expression="'proceed'" /> <transition on="proceed" to="ReadInfoConsentFromStorage" /> </action-state> <action-state id="ReadInfoConsentFromStorage"> <evaluate expression="ReadAttributeReleaseInfoConsentFromStorage" /> <evaluate expression="'proceed'" /> <transition on="proceed" to="ReadMustConsentFromStorage" /> </action-state> <action-state id="ReadMustConsentFromStorage"> <evaluate expression="ReadAttributeReleaseMustConsentFromStorage" /> <evaluate expression="'proceed'" /> <transition on="proceed" to="TestForReadGlobalAttributeConsentFromStorage" /> </action-state> <decision-state id="TestForReadGlobalAttributeConsentFromStorage"> <if test="attributeReleaseFlowDescriptor.globalConsentAllowed" then="ReadGlobalAttributeConsentFromStorage" else="CheckPreviousConsents" /> </decision-state> <action-state id="ReadGlobalAttributeConsentFromStorage"> <evaluate expression="ReadAttributeReleaseGlobalConsentFromStorage" /> <evaluate expression="'proceed'" /> <transition on="proceed" to="TestForGlobalAttributeConsent" /> </action-state> <!-- hier noch der angepasste Pfad fürs Import-Statement der Attribute Release Bohne --> <bean-import resource="../../../system/flows/intercept/attribute-release-beans.xml" />
Anschließend noch den flow in ./conf/intercept/profile-intercept.xml
bekannt machen:
<bean id="shibboleth.AvailableInterceptFlows" parent="shibboleth.DefaultInterceptFlows" lazy-init="true"> <property name="sourceList"> <list merge="true"> <!-- ... --> <bean id="intercept/attribute-release-query" parent="shibboleth.consent.AttributeReleaseFlow" /> <!-- ... --> </list> </property> </bean>