Dealing with
any
Types
A couple of elements within the SAML schema are defined with a special, wildcard, type known as an
anyType
. These elements can take any valid XML as content which translates to the SAMLObjects representing those element allowing any XMLObject as a child. Specifically these are, in SAML 1.X:
Advice
,
SubjectConfirmationData
,
AttributeValue
, and
StatusDetail
and in SAML 2.0:
SubjectConfirmationData
,
Advice
,
AuthnContextDecl
,
AttributeValue
,
Extensions
,
StatusDetail
,
StatusResponse
, and all the metadata endpoint elements.
Adding Content to
any
Types
Every SAMLObject representing an XML element of type
anyType
extends
org.opensaml.xml.ElementExtensibleXMLObject
which defines the method
getUnknownXMLObjects()
. XMLObjects representing the content to be added to the SAMLObject should be added to the list returned by this method. These child objects will then be marshalled as any other children object.
Building XMLObjects for use as content works a bit differently than the normal method for building objects, because some child elements are expected to have a specific name (e.g. AttributeValue) but can still contain any valid XML. To build the XMLObject in this case get the builder for the XMLObject as you normally would, but instead of invoking
buildObject()
you need to use either
buildObject(String, String, String)
or
builidObject(QName)
to override the default element name. It's also good practice to explicitly state the schema type of this object as it makes it easier for the receiver of the message to parse it. To do this pass in a
QName
that represents the schema type in as an additional, final, argument to the methods just discussed. All the objects in the OpenSAML library, on their interface, define a static
QName
called TYPE_NAME that can be used as this argument.
Reading Content of
any
Types
The method
getUnknownXMLObjects()
provides access to the unknown content of SAMLObjects defined with the
any
type. Reading information from this list can be problematic if you're not exactly sure what is in the returned list. If, during the unmarshalling process, the library encountered an element whose xsi:type or element name was not recognized (i.e. was not explicitly listed in the OpenSAML configuration files) the library will unmarshall the element into the
org.opensaml.xml.ElementProxy
XMLObject. No information is lost, but if you were expecting to cast the object to a specific SAMLObject interface you'll receive a class cast exception when you try. If the library understands the element or element type, though, it is safe to cast it to the respecting interface.
AttributeValues
Probably the most commonly encountered example of this is the
AttributeValue
element. There is an AttributeValue interface but nothing implements it, which means you can't cast classes to it. It exists simply to hold name constants which may be used when building other XMLObjects via the
XMLObjectBuilder#buildObject(String, String, String)
or
XMLObjectBuilder#buildObject(QName)
methods.
Here's an example of an
AttributeValue
that carries string content. The
AttributeValue
element will express an
xsi:type
of
xs:string
.
Here's an example of an
AttributeValue
that carries element content. An
XSAny
object is used to represent the
AttributeValue
, in order to allow the addition of element children. The
Role
child element in the example is also represented by an
XSAny
. Another and more correct approach would be to implement XML object provider support for the
Role
element.
When marshalled and serialized, this produces the following XML:
<saml2:Attribute xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Name="UserRole" NameFormat="http://www.hhs.gov/healthit/nhin"> <saml2:AttributeValue> <nhin:Role xmlns:nhin="http://www.hhs.gov/healthit/nhin" code="112247003" codeSystem="2.16.840.1.113883.6.96" codeSystemName="SNOMED CT" displayName="Medical doctor"/> </saml2:AttributeValue> </saml2:Attribute>