AccessingMetadataTags
Shibboleth makes heavy use of the <mdattr:EntityAttributes>
extension in SAML metadata to attach "tags" to metadata either directly or via metadata filter and use the tags to drive configuration or many other use cases within the software. It is potentially useful to extend this approach to many local use cases that are outside the direct scope of the software. For example, one might wish to use tags to attach other pieces of information to SP metadata in order to perform access control functions or customize the user interface in unexpected ways.
This example deals with how to conveniently access custom tags for more “unanticipated” purposes, rather than any of the usual features of the software that already know how to operate based on tags. Two obvious cases are using them in view templates or in scripts.
Note that all of these examples assume the use of URI-based naming; that is, they assume the underlying SAML <Attribute>
NameFormat
value is set to urn:oasis:names:tc:SAML:2.0:attrname-format:URI
Notably, none of this is strictly required if you can utilize the Attribute Resolver for your use case (and you almost always can do that). There’s an EntityAttributesDataConnectornow that can automate this process.
Foundational Beans
The basis of both use cases is to define a Spring bean (or beans) to pull the tags desired out of the metadata and expose them. There are already classes able to do this as part of the implementation of the MetadataDrivenConfiguration feature and there are parent beans defined to make use of them to insulate the deployer from those classes.
There are different classes defined to handle different data types. By far the most likely need is for String data, or multiple String values in a Set or List. Pick the parent bean needed based on the data type you wish to expose from the tag. The hyperlinks reference the underlying class documentation describing the options supported. These parent beans expose a single String, Boolean, Integer, Long, Double, or Duration:
These two beans expose a type-safe collection (either a List or Set) of a primtive type:
Finally, this special bean allows the value of the tag to actually reference the ID of a Spring Bean in the configuration.
Examples
To access an <Attribute>
tag named https://example.org/tags/custom1
as a single String value, create the following bean definition (in global.xml or some other directly applicable file):
<bean id="my.TagLookup" parent="shibboleth.TagLookupString"
p:propertyName="https://example.org/tags/custom1"
p:explicitPropertyName="true"
p:enableCaching="false" />
The explicitPropertyName
setting is necessary to allow reuse of these classes without triggering their built-in behavior that looks for tags using special prefixes for the MetadataDrivenConfiguration feature. Turning off caching is usually advisable because that feature was designed to optimize multiple lookups of the same tag as would be common when accessing configuration settings. For most one-off use cases, the caching isn’t needed and probably costs more in time than it’s worth, but it could be used.
The same example, but handling multiple <AttributeValue>
elements in the metadata and exposing them all as a Set<String>:
<bean id="my.TagLookup" parent="shibboleth.TagLookupSet"
p:propertyType="java.lang.String"
p:propertyName="https://example.org/tags/custom1"
p:explicitPropertyName="true"
p:enableCaching="false" />
Views
Using these lookup beans in a view template just requires wiring it into the shibboleth.CustomViewContext bean in global.xml:
<util:map id="shibboleth.CustomViewContext">
<entry key="tagLookup" value-ref="my.TagLookup"/>
</util:map>
Obviously you can add this to any existing map content or add multiple lookup beans with appropriate names for clarity.
To call a lookup bean from a Velocity view, just do:
The result of the expression will be the value of the tag or null.
Scripts
Using these lookup beans in a scripted function, condition, etc. just requires injecting the bean via the customObjectRef hook common to such cases:
The above is a pathological example since the script just returns the same thing as directly calling the function but illustrates how to make use of the tag in a more general case.