Using OpenSAML2 how does one create the following XML:
<saml:Attribute Name="urn:mace:dir:attribute-def:eduPersonTargetedID"
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
<saml:AttributeValue>
<saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">c693b1c47a0da7de6518bc30a1bb8d2e44b56980</saml:NameID>
</saml:AttributeValue>
</saml:Attribute>
Extending OpenSAML fixes the issue as it doesn't seem to support NameID values within Attribute Value elements.
The following files are required to implement the AttributeValue.
Builder
package com.blah;
import org.opensaml.common.impl.AbstractSAMLObjectBuilder;
import org.opensaml.common.xml.SAMLConstants;
import org.opensaml.saml2.core.AttributeValue;
public class AttributeValueBuilder extends AbstractSAMLObjectBuilder<AttributeValue>{
public AttributeValueBuilder() {
}
@Override
public AttributeValue buildObject() {
return buildObject(SAMLConstants.SAML20_NS, AttributeValue.DEFAULT_ELEMENT_LOCAL_NAME, SAMLConstants.SAML20_PREFIX);
}
@Override
public AttributeValue buildObject(String namespaceURI, String localName, String namespacePrefix) {
return new AttributeValueImpl(namespaceURI, localName, namespacePrefix);
}
}
Implementation
package com.blah;
import java.util.ArrayList;
import java.util.List;
import org.opensaml.common.impl.AbstractSAMLObject;
import org.opensaml.xml.XMLObject;
public class AttributeValueImpl extends AbstractSAMLObject implements org.opensaml.saml2.core.AttributeValue{
protected AttributeValueImpl(String namespaceURI, String elementLocalName,
String namespacePrefix) {
super(namespaceURI, elementLocalName, namespacePrefix);
}
private List<XMLObject> children = new ArrayList<XMLObject>();
@Override
public List<XMLObject> getOrderedChildren() {
return children;
}
}
Marshaller
package com.blah;
import org.opensaml.common.impl.AbstractSAMLObjectMarshaller;
public class AttributeValueMarshaller extends AbstractSAMLObjectMarshaller {
}
Unmarshaller
package com.blah;
import org.opensaml.common.impl.AbstractSAMLObjectUnmarshaller;
import org.opensaml.xml.XMLObject;
import org.opensaml.xml.io.UnmarshallingException;
public class AttributeValueUnmarshaller extends AbstractSAMLObjectUnmarshaller {
@Override
protected void processChildElement(XMLObject parentSAMLObject, XMLObject childSAMLObject)
throws UnmarshallingException {
AttributeValueImpl attributeValue = (AttributeValueImpl) parentSAMLObject;
attributeValue.getOrderedChildren().add(childSAMLObject);
}
}
Once these files are included they need to be added to the OpenSAML bootstrapping configuration file saml2-assertion-config.xml (I copied it from the OpenSAML jar and placed it into the root of the Java src):
<!-- AttributeValue -->
<ObjectProvider qualifiedName="saml2:AttributeValue">
<BuilderClass className="com.blah.AttributeValueBuilder" />
<MarshallingClass className="com.blah.AttributeValueMarshaller" />
<UnmarshallingClass className="com.blah.AttributeValueUnmarshaller" />
</ObjectProvider>
<ObjectProvider qualifiedName="saml2:AttributeValueType">
<BuilderClass className="com.blah.AttributeValueBuilder" />
<MarshallingClass className="com.blah.AttributeValueMarshaller" />
<UnmarshallingClass className="com.blah.AttributeValueUnmarshaller" />
</ObjectProvider>
It is now possible to add any element to the Attribute Value body.
private static XMLObject createAttributeValueNameId(String value) throws ConfigurationException {
XMLObjectBuilder<AttributeValueImpl> attrBuilder = getSamlBuilder().getBuilder(AttributeValue.DEFAULT_ELEMENT_NAME);
AttributeValueImpl attributeValue = attrBuilder.buildObject(AttributeValue.DEFAULT_ELEMENT_NAME);
XMLObjectBuilder<AttributeValue> builder = getSamlBuilder().getBuilder(NameID.DEFAULT_ELEMENT_NAME);
NameID nameId = (NameID) builder.buildObject(NameID.DEFAULT_ELEMENT_NAME);
nameId.setFormat(NameID.UNSPECIFIED);
nameId.setValue(value);
attributeValue.getOrderedChildren().add(nameId);
return attributeValue;
}