Search code examples
opensaml

How to add a NameId value to a AttributeValue using OpenSAML2


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>

Solution

  • 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;
    }