/*
* Copyright 2001-2005 Internet2
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package gov.nih.nci.cagrid.opensaml;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.util.Hashtable;
import org.apache.log4j.Category;
import org.w3c.dom.*;
import org.xml.sax.SAXException;
/**
* Represents a SAML Subject
*
* @author Scott Cantor
* @created March 25, 2002
*/
public class SAMLNameIdentifier extends SAMLObject implements Cloneable
{
protected String name = null;
protected String nameQualifier = null;
protected String format = null;
/** Maps formats to Java class implementations */
protected static Hashtable /*<String,String>*/ formatMap = new Hashtable();
/** Unspecified Format Identifier */
public final static String FORMAT_UNSPECIFIED = "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified";
/** Email Format Identifier */
public final static String FORMAT_EMAIL = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress";
/** X.509 Subject Format Identifier */
public final static String FORMAT_X509 = "urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName";
/** Windows Domain Format Identifier */
public final static String FORMAT_WINDOWS = "urn:oasis:names:tc:SAML:1.1:nameid-format:WindowsDomainQualifiedName";
/**
* Registers a class to handle a specific NameID format when parsing XML
*
* @param format The format URI to register
* @param className The Java class that handles this format
*/
public static void regFactory(String format, String className)
{
formatMap.put(format, className);
}
/**
* Unregisters a class to handle a specific NameID format when parsing XML
*
* @param type The format URI to unregister
*/
public static void unregFactory(String format)
{
formatMap.remove(format);
}
/**
* Locates an implementation class for a NameIdentifier based on Format and constructs it based
* on the DOM provided.
*
* @param e The root of a DOM containing the SAML condition
* @return SAMLNameIdentifier A constructed NameIdentifier object
*
* @throws SAMLException Thrown if an error occurs while constructing the object
*/
public static SAMLNameIdentifier getInstance(Element e)
throws SAMLException
{
if (e == null)
throw new MalformedException("SAMLNameIdentifier.getInstance() given an empty DOM");
try {
String className = (String)formatMap.get(e.getAttributeNS(null,"Format"));
if (className == null)
return new SAMLNameIdentifier(e);
Class implementation = Class.forName(className);
Class[] paramtypes = {Element.class};
Object[] params = {e};
Constructor ctor = implementation.getDeclaredConstructor(paramtypes);
return (SAMLNameIdentifier)ctor.newInstance(params);
}
catch (ClassNotFoundException ex) {
throw new SAMLException(SAMLException.REQUESTER, "SAMLNameIdentifier.getInstance() unable to locate implementation class for NameIdentifier", ex);
}
catch (NoSuchMethodException ex) {
throw new SAMLException(SAMLException.REQUESTER, "SAMLNameIdentifier.getInstance() unable to bind to constructor for NameIdentifier", ex);
}
catch (InstantiationException ex) {
throw new SAMLException(SAMLException.REQUESTER, "SAMLNameIdentifier.getInstance() unable to build implementation object for NameIdentifier", ex);
}
catch (IllegalAccessException ex) {
throw new SAMLException(SAMLException.REQUESTER, "SAMLNameIdentifier.getInstance() unable to access implementation of NameIdentifier", ex);
}
catch (java.lang.reflect.InvocationTargetException ex) {
ex.printStackTrace();
Throwable e2 = ex.getTargetException();
if (e2 instanceof SAMLException)
throw (SAMLException)e2;
else
throw new SAMLException(SAMLException.REQUESTER, "SAMLNameIdentifier.getInstance() caught unknown exception while building NameIdentifier object: " + e2.getMessage());
}
}
/**
* Locates an implementation class for a NameIdentifier based on Format and constructs it based
* on the stream provided.
*
* @param in The stream to deserialize from
* @return SAMLNameIdentifier A constructed NameIdentifier object
*
* @throws SAMLException Thrown if an error occurs while constructing the object
*/
public static SAMLNameIdentifier getInstance(InputStream in)
throws SAMLException
{
try {
Document doc = XML.parserPool.parse(in);
return getInstance(doc.getDocumentElement());
}
catch (SAXException e) {
Category.getInstance("SAMLNameIdentifier").error("caught an exception while parsing a stream:\n" + e.getMessage());
throw new MalformedException("SAMLNameIdentifier.getInstance() caught exception while parsing a stream",e);
}
catch (java.io.IOException e) {
Category.getInstance("SAMLNameIdentifier").error("caught an exception while parsing a stream:\n" + e.getMessage());
throw new MalformedException("SAMLNameIdentifier.getInstance() caught exception while parsing a stream",e);
}
}
/**
* Locates an implementation class for a NameIdentifier based on Format and constructs an empty instance.
*
* @param format The format, indicating which implementation class to use
* @return SAMLNameIdentifier A constructed NameIdentifier object
*
* @throws SAMLException Thrown if an error occurs while constructing the object
*/
public static SAMLNameIdentifier getInstance(String format)
throws SAMLException
{
try {
if (format == null)
return new SAMLNameIdentifier();
String className = (String)formatMap.get(format);
if (className == null)
return new SAMLNameIdentifier(null, null, format);
Class implementation = Class.forName(className);
Class[] paramtypes = {String.class, String.class, String.class};
Object[] params = {null, null, format};
Constructor ctor = implementation.getDeclaredConstructor(paramtypes);
return (SAMLNameIdentifier)ctor.newInstance(params);
}
catch (ClassNotFoundException ex) {
throw new SAMLException(SAMLException.REQUESTER, "SAMLNameIdentifier.getInstance() unable to locate implementation class for NameIdentifier", ex);
}
catch (NoSuchMethodException ex) {
throw new SAMLException(SAMLException.REQUESTER, "SAMLNameIdentifier.getInstance() unable to bind to constructor for NameIdentifier", ex);
}
catch (InstantiationException ex) {
throw new SAMLException(SAMLException.REQUESTER, "SAMLNameIdentifier.getInstance() unable to build implementation object for NameIdentifier", ex);
}
catch (IllegalAccessException ex) {
throw new SAMLException(SAMLException.REQUESTER, "SAMLNameIdentifier.getInstance() unable to access implementation of NameIdentifier", ex);
}
catch (java.lang.reflect.InvocationTargetException ex) {
ex.printStackTrace();
Throwable e2 = ex.getTargetException();
if (e2 instanceof SAMLException)
throw (SAMLException)e2;
else
throw new SAMLException(SAMLException.REQUESTER, "SAMLNameIdentifier.getInstance() caught unknown exception while building NameIdentifier object: " + e2.getMessage());
}
}
/**
* Default constructor
*/
public SAMLNameIdentifier() {
}
/**
* Builds a name identifier out of its component parts
*
* @param name Name of subject (optional)
* @param nameQualifier Federates or qualifies subject name (optional)
* @param format URI describing name semantics and format (optional)
* @exception SAMLException Raised if a name cannot be constructed
* from the supplied information
*/
public SAMLNameIdentifier(String name, String nameQualifier, String format) throws SAMLException {
this.name = XML.assign(name);
this.nameQualifier = XML.assign(nameQualifier);
this.format = XML.assign(format);
}
/**
* Reconstructs a name identifier from a DOM tree
*
* @param e The root of a DOM tree
* @exception SAMLException Thrown if the object cannot be constructed
*/
public SAMLNameIdentifier(Element e) throws SAMLException {
fromDOM(e);
}
/**
* Reconstructs a name identifier from a stream
*
* @param in A stream containing XML
* @exception SAMLException Raised if an exception occurs while constructing
* the object.
*/
public SAMLNameIdentifier(InputStream in) throws SAMLException {
fromDOM(fromStream(in));
}
/**
* @see gov.nih.nci.cagrid.opensaml.SAMLObject#fromDOM(org.w3c.dom.Element)
*/
public void fromDOM(Element e) throws SAMLException {
super.fromDOM(e);
if (config.getBooleanProperty("gov.nih.nci.cagrid.opensaml.strict-dom-checking") && !XML.isElementNamed(e,XML.SAML_NS,"NameIdentifier"))
throw new MalformedException("SAMLNameIdentifier.fromDOM() requires saml:NameIdentifier at root");
nameQualifier = XML.assign(e.getAttributeNS(null,"NameQualifier"));
format = XML.assign(e.getAttributeNS(null,"Format"));
name = XML.assign(e.getFirstChild().getNodeValue());
checkValidity();
}
/**
* Gets the name of the Subject
*
* @return The Subject name
*/
public String getName() {
return name;
}
/**
* Sets the name of the Subject
*
* @param name The name
*/
public void setName(String name) {
if (XML.isEmpty(name))
throw new IllegalArgumentException("name cannot be empty");
this.name = name;
setDirty(true);
}
/**
* Gets the name qualifier
*
* @return The name qualifier
*/
public String getNameQualifier() {
return nameQualifier;
}
/**
* Sets the name qualifier
*
* @param nameQualifier The name qualifier
*/
public void setNameQualifier(String nameQualifier) {
this.nameQualifier = XML.assign(nameQualifier);
setDirty(true);
}
/**
* Gets the format of the name
*
* @return The name format URI
*/
public String getFormat() {
return format;
}
/**
* Sets the format of the name
*
* @param format The name format URI
*/
public void setFormat(String format) {
this.format = XML.assign(format);
setDirty(true);
}
/**
* @see gov.nih.nci.cagrid.opensaml.SAMLObject#buildRoot(org.w3c.dom.Document,boolean)
*/
protected Element buildRoot(Document doc, boolean xmlns) {
Element e = doc.createElementNS(XML.SAML_NS, "NameIdentifier");
if (xmlns)
e.setAttributeNS(XML.XMLNS_NS, "xmlns", XML.SAML_NS);
return e;
}
/**
* @see gov.nih.nci.cagrid.opensaml.SAMLObject#toDOM(org.w3c.dom.Document,boolean)
*/
public Node toDOM(Document doc, boolean xmlns) throws SAMLException {
// Let the base build/verify the DOM root.
super.toDOM(doc, xmlns);
Element nameid = (Element)root;
if (dirty) {
if (!XML.isEmpty(nameQualifier))
nameid.setAttributeNS(null,"NameQualifier", nameQualifier);
if (!XML.isEmpty(format))
nameid.setAttributeNS(null,"Format", format);
nameid.appendChild(doc.createTextNode(name));
setDirty(false);
}
else if (xmlns) {
nameid.setAttributeNS(XML.XMLNS_NS, "xmlns", XML.SAML_NS);
}
return root;
}
/**
* @see gov.nih.nci.cagrid.opensaml.SAMLObject#checkValidity()
*/
public void checkValidity() throws SAMLException {
if (XML.isEmpty(name))
throw new MalformedException("NameIdentifier is invalid, requires name");
}
/**
* Copies a SAML object such that no dependencies exist between the original
* and the copy
*
* @return The new object
* @see java.lang.Object#clone()
*/
public Object clone() throws CloneNotSupportedException {
return (SAMLNameIdentifier)super.clone();
}
}