Push SAML Attribute namespace configuration into the resolver. (Needed for proper...
[java-idp.git] / src / edu / internet2 / middleware / shibboleth / aa / attrresolv / provider / SAML2PersistentID.java
index 0f65d20..4682f09 100644 (file)
@@ -34,15 +34,19 @@ import java.security.Principal;
 import java.security.UnrecoverableKeyException;
 import java.security.cert.CertificateException;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Iterator;
 
 import javax.crypto.SecretKey;
 import javax.naming.NamingException;
 import javax.naming.directory.Attribute;
 import javax.naming.directory.Attributes;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
 
 import org.apache.log4j.Logger;
 import org.bouncycastle.util.encoders.Base64;
+import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
@@ -53,6 +57,8 @@ import edu.internet2.middleware.shibboleth.aa.attrresolv.Dependencies;
 import edu.internet2.middleware.shibboleth.aa.attrresolv.ResolutionPlugInException;
 import edu.internet2.middleware.shibboleth.aa.attrresolv.ResolverAttribute;
 import edu.internet2.middleware.shibboleth.common.ShibResource;
+import edu.internet2.middleware.shibboleth.common.XML;
+import edu.internet2.middleware.shibboleth.xml.Parser;
 
 /**
  * <code>AttributeDefinition</code> implementation that provides a persistent, but pseudonymous, identifier for
@@ -235,9 +241,7 @@ public class SAML2PersistentID extends BaseAttributeDefinition implements Attrib
                        return;
                }
 
-               if (lifeTime != -1) {
-                       attribute.setLifetime(lifeTime);
-               }
+               standardProcessing(attribute);
 
                // Hash the data together to produce the persistent ID.
                try {
@@ -248,18 +252,26 @@ public class SAML2PersistentID extends BaseAttributeDefinition implements Attrib
                        md.update((byte) '!');
                        String result = new String(Base64.encode(md.digest(salt)));
 
-                       // :-/ String-ified SAML2 persistent NameId format
-                       StringBuffer id = new StringBuffer();
-                       id.append("<saml2:NameID Format=\"urn:oasis:names:tc:SAML:2.0:nameid-format:persistent\" NameQualifier=\"");
-                       id.append(responder);
-                       id.append("\" SPNameQualifier=\"");
-                       id.append(requester);
-                       id.append("\" >");
-                       id.append(result.replaceAll(System.getProperty("line.separator"), ""));
-                       id.append("</saml2:NameID>");
-
-                       attribute.addValue(id.toString());
-                       attribute.setResolved();
+                       // SAML2 persistent NameId format
+                       try {
+                               DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
+                               docFactory.setNamespaceAware(true);
+                               Document placeHolder = docFactory.newDocumentBuilder().newDocument();
+                               Element nameIDNode = placeHolder.createElementNS(XML.SAML2ASSERT_NS, "NameID");
+                               nameIDNode.setAttribute("xmlns", XML.SAML2ASSERT_NS);
+                               nameIDNode.setAttribute("Format", "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent");
+                               nameIDNode.setAttribute("NameQualifier", responder);
+                               nameIDNode.setAttribute("SPNameQualifier", requester);
+                               nameIDNode.appendChild(placeHolder.createTextNode(result.replaceAll(System
+                                               .getProperty("line.separator"), "")));
+
+                               attribute.addValue(nameIDNode);
+                               attribute.registerValueHandler(new DOMValueHandler());
+                               attribute.setResolved();
+                       } catch (ParserConfigurationException pce) {
+                               log.error("Unable to create DOM for persistent ID: " + pce);
+                               throw new ResolutionPlugInException("Error generating persistent ID.");
+                       }
 
                } catch (NoSuchAlgorithmException e) {
                        log.error("Unable to load SHA-1 hash algorithm.");
@@ -275,4 +287,49 @@ public class SAML2PersistentID extends BaseAttributeDefinition implements Attrib
                                (byte) 0x61, (byte) 0xEF};
                return Arrays.equals(defaultKey, salt);
        }
-}
+
+       class DOMValueHandler implements ValueHandler {
+
+               public void toDOM(Element valueElement, Object value, Document document) {
+
+                       valueElement.appendChild(document.importNode((Node) value, true));
+               }
+
+               public Iterator getValues(Collection internalValues) {
+
+                       return new SerializationIterator(internalValues.iterator());
+               }
+
+               public boolean equals(Object object) {
+
+                       if (object instanceof DOMValueHandler) { return true; }
+                       return false;
+               }
+
+               private class SerializationIterator implements Iterator {
+
+                       Iterator wrapped;
+
+                       SerializationIterator(Iterator i) {
+
+                               wrapped = i;
+                       }
+
+                       public boolean hasNext() {
+
+                               return wrapped.hasNext();
+                       }
+
+                       public Object next() {
+
+                               return Parser.serialize(((Element) wrapped.next()));
+                       }
+
+                       public void remove() {
+
+                               wrapped.remove();
+                       }
+
+               }
+       }
+}
\ No newline at end of file