Per Attribute Consent für vom SP nicht 'required' Attribute
In den allgemeinen Properties (conf/idp.properties
) des IdP kann man einen per Attrbute Consent einstellen (idp.consent.allowPerAttribute = true
). D.h. der Nutzer kann für jedes Attribut über eine Checkbox entscheiden, ob der Wert an den SP übertragen wird oder nicht. Das macht im Sinne des Prozesses aber nur Sinn, für die Attribute, die vom SP nicht explizit über die Metadaten (mit dem Tag required=„True“
versehen) angefordert werden.
Um das auf der Attribute-Release Seite zu berücksichtigen sind folgende zwei kleine Anpassungen vorzunehmen:
- Eine schon vorhandene IdP-Class in das Velocity Template propagieren. Dazu ist die Datei
system/flows/intercept/attribute_release_flow.xml
wie folgt zu ergänzen:
- system/flows/intercept/attribute-release_flow.xml
... 111 <!-- Display attribute release page. --> 112 113 <view-state id="DisplayAttributeReleasePage" view="#{flowRequestContext.activeFlow.id}"> 114 <on-render> 115 <evaluate expression="environment" result="viewScope.environment" /> 116 <evaluate expression="T(net.shibboleth.utilities.java.support.codec.HTMLEncoder)" result="viewScope.encoder" /> 117 <evaluate expression="flowRequestContext.getExternalContext().getNativeRequest()" result="viewScope.request" /> 118 <evaluate expression="flowRequestContext.getExternalContext().getNativeResponse()" result="viewScope.response" /> 119 <evaluate expression="opensamlProfileRequestContext" result="viewScope.profileRequestContext" /> 120 <evaluate expression="new net.shibboleth.idp.consent.logic.impl.AttributeDisplayNameFunction(flowRequestContext.getExternalContext().getNativeRequest(), FallbackLanguages)" 121 result="viewScope.attributeDisplayNameFunction" /> 122 <evaluate expression="new net.shibboleth.idp.consent.logic.impl.AttributeDisplayDescriptionFunction(flowRequestContext.getExternalContext().getNativeRequest(), FallbackLanguages)" 123 result="viewScope.attributeDisplayDescriptionFunction" /> 124 <!-- Get RequiredPredicate object as $attributeRequired in velocity template --> 125 <evaluate expression="new net.shibboleth.idp.consent.logic.impl.IsAttributeRequiredPredicate(flowRequestContext.getExternalContext().getNativeRequest())" 126 result="viewScope.attributeRequired" /> ...
- Im Velocity Template die Checkbox nur für non-required Attribute anzeigen. Dazu die Datei
views/intercept/attribute-release.vm
anpassen:
- views/intercept/attribute-release.vm
... <!-- Attribute Liste - Tabelle Start --> <table class="listing"> <thead> <tr> <th colspan="2"> #springMessageText("idp.attribute-release.attributesHeader", "Information to be Provided to Service") </th> <th> <!-- check / uncheck all --> #if ($attributeReleaseFlowDescriptor.perAttributeConsentEnabled ) <script language="JavaScript"> function toggle(source) { checkboxes = document.getElementsByName('_shib_idp_consentIds'); for(var i=0, n=checkboxes.length;i<n;i++) { if(checkboxes[i].type != "hidden"){ checkboxes[i].checked = source.checked; } } } </script> <input type="checkbox" onClick="toggle(this)" checked />#springMessageText("idp.attribute-release.ToggleAll", "Alle")<br/> #end </th> </tr> </thead> <tbody> #foreach ($attribute in $attributeReleaseContext.getConsentableAttributes().values()) <tr> <td> $encoder.encodeForHTML($attributeDisplayNameFunction.apply($attribute)) </td> <td> #foreach ($value in $attribute.values) <strong>$encoder.encodeForHTML($value.getDisplayValue())</strong> <br /> #end </td> <td> #if ($attributeReleaseFlowDescriptor.perAttributeConsentEnabled ) <!-- $attributeRequired.apply($attribute)) return "true" for required attributes --> #if (!$attributeRequired.apply($attribute)) <!-- not required, allow to check separably --> #set ($inputType = "checkbox") #else <!-- required, don't allow to check separably --> #set ($inputType = "hidden") <!-- inform the user, that is a required attribute --> <strong>#springMessageText("idp.attribute-release.requiredLabel", "notwendig")</strong> #end #else #set ($inputType = "hidden") #end <input id="$attribute.id" type="$inputType" name="_shib_idp_consentIds" value="$encoder.encodeForHTML($attribute.id)" checked \> </td> </tr> #end </tbody> ...
- Damit auch die Internationalisierung klappt, müssen die Message Properties noch ergänzt werden.
- messages/messages.properties
... idp.attribute-release.ToggleAll = Alle idp.attribute-release.requiredLabel = notwendig ...
Wird der AttributeQuery benutzt, muss auch hier der letzte Consent vom Nutzer beachtet werden. Dazu ist in conf/intercept/consent-intercept-config.xml
für die Bean shibboleth.consent.AttributeQuery.Condition
der parent Parameter auf den Wert shibboleth.Conditions.TRUE
zu setzen, siehe hierzu unter Server-Side-Storage, Sessions, User Consent und Persistent Identifier. Damit werden auch AttributeQueries gegen die zuletzt gespeicherte Nutzereinwilligung gefiltert. Hat der Nutzer nur einmal zugestimmt, werden keine Attribute übertragen.
Für das Propagieren des zusätzlichen Objektes in den Attribute-Release-Flow ist leider ein Neustart des IdP nötig.
Wer sich davor scheut, den System Flow zu editieren, kann die Referenz auch direkt im Velocity Template holen. Das ist nicht unbedingt schön, aber funktional getestet mit dem IDP4. Das Instanziieren eines neuen Objekts ist in Velocity nicht vorgesehen, deswegen sieht der Code etwas abenteuerlich aus. Die Änderungen beschränken sich dann auf die Datei views/intercept/attribute-release.vm:
... #set ($requestClass = $attributeReleaseContext.getClass().forName("javax.servlet.http.HttpServletRequest")) #set ($isAttributeRequired = $attributeReleaseContext.getClass().forName("net.shibboleth.idp.consent.logic.impl.IsAttributeRequiredPredicate").getDeclaredConstructor($requestClass).newInstance($request)) ...
... <td style="vertical-align: top"> #if ($attributeReleaseFlowDescriptor.perAttributeConsentEnabled && !($isAttributeRequired.apply($attribute))) #set ($inputType = "checkbox") #else #set ($inputType = "hidden") #end <input id="$attribute.id" type="$inputType" name="_shib_idp_consentIds" value="$encoder.encodeForHTML($attribute.id)" checked> ...