--- /dev/null
+/*
+ * The Shibboleth License, Version 1. Copyright (c) 2002 University Corporation for Advanced Internet Development, Inc.
+ * All rights reserved
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+ * following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the distribution, if any, must include the
+ * following acknowledgment: "This product includes software developed by the University Corporation for Advanced
+ * Internet Development <http://www.ucaid.edu> Internet2 Project. Alternately, this acknowledegement may appear in the
+ * software itself, if and wherever such third-party acknowledgments normally appear.
+ *
+ * Neither the name of Shibboleth nor the names of its contributors, nor Internet2, nor the University Corporation for
+ * Advanced Internet Development, Inc., nor UCAID may be used to endorse or promote products derived from this software
+ * without specific prior written permission. For written permission, please contact shibboleth@shibboleth.org
+ *
+ * Products derived from this software may not be called Shibboleth, Internet2, UCAID, or the University Corporation
+ * for Advanced Internet Development, nor may Shibboleth appear in their name, without prior written permission of the
+ * University Corporation for Advanced Internet Development.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND WITH ALL FAULTS. ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK OF SATISFACTORY QUALITY, PERFORMANCE,
+ * ACCURACY, AND EFFORT IS WITH LICENSEE. IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY
+ * CORPORATION FOR ADVANCED INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package edu.internet2.middleware.shibboleth.common;
+
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.cert.X509Certificate;
+
+/**
+ * @author Walter Hoehn
+ *
+ */
+public class Credential {
+
+ public static int X509 = 0;
+
+ private int type;
+ private Key key;
+ private X509Certificate[] certs;
+
+ public Credential(X509Certificate[] certChain, PrivateKey key) {
+ type = X509;
+ certs = certChain;
+ this.key = key;
+ }
+
+ public int getCredentialType() {
+ return type;
+ }
+
+ public String getKeyAlgorithm() {
+ return key.getAlgorithm();
+ }
+
+ public PrivateKey getPrivateKey() {
+ if (key instanceof PrivateKey) {
+ return (PrivateKey) key;
+ }
+ return null;
+ }
+
+ public X509Certificate getX509Certificate() {
+ return certs[0];
+ }
+
+ public X509Certificate[] getX509CertificateChain() {
+ return certs;
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * The Shibboleth License, Version 1. Copyright (c) 2002 University Corporation for Advanced Internet Development, Inc.
+ * All rights reserved
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+ * following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the distribution, if any, must include the
+ * following acknowledgment: "This product includes software developed by the University Corporation for Advanced
+ * Internet Development <http://www.ucaid.edu> Internet2 Project. Alternately, this acknowledegement may appear in the
+ * software itself, if and wherever such third-party acknowledgments normally appear.
+ *
+ * Neither the name of Shibboleth nor the names of its contributors, nor Internet2, nor the University Corporation for
+ * Advanced Internet Development, Inc., nor UCAID may be used to endorse or promote products derived from this software
+ * without specific prior written permission. For written permission, please contact shibboleth@shibboleth.org
+ *
+ * Products derived from this software may not be called Shibboleth, Internet2, UCAID, or the University Corporation
+ * for Advanced Internet Development, nor may Shibboleth appear in their name, without prior written permission of the
+ * University Corporation for Advanced Internet Development.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND WITH ALL FAULTS. ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK OF SATISFACTORY QUALITY, PERFORMANCE,
+ * ACCURACY, AND EFFORT IS WITH LICENSEE. IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY
+ * CORPORATION FOR ADVANCED INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package edu.internet2.middleware.shibboleth.common;
+
+import org.w3c.dom.Element;
+
+/**
+ * @author Walter Hoehn
+ *
+ */
+public interface CredentialResolver {
+ Credential loadCredential(Element e) throws CredentialFactoryException;
+}
\ No newline at end of file
--- /dev/null
+/*
+ * The Shibboleth License, Version 1. Copyright (c) 2002 University Corporation for Advanced Internet Development, Inc.
+ * All rights reserved
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+ * following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the distribution, if any, must include the
+ * following acknowledgment: "This product includes software developed by the University Corporation for Advanced
+ * Internet Development <http://www.ucaid.edu> Internet2 Project. Alternately, this acknowledegement may appear in the
+ * software itself, if and wherever such third-party acknowledgments normally appear.
+ *
+ * Neither the name of Shibboleth nor the names of its contributors, nor Internet2, nor the University Corporation for
+ * Advanced Internet Development, Inc., nor UCAID may be used to endorse or promote products derived from this software
+ * without specific prior written permission. For written permission, please contact shibboleth@shibboleth.org
+ *
+ * Products derived from this software may not be called Shibboleth, Internet2, UCAID, or the University Corporation
+ * for Advanced Internet Development, nor may Shibboleth appear in their name, without prior written permission of the
+ * University Corporation for Advanced Internet Development.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND WITH ALL FAULTS. ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK OF SATISFACTORY QUALITY, PERFORMANCE,
+ * ACCURACY, AND EFFORT IS WITH LICENSEE. IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY
+ * CORPORATION FOR ADVANCED INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package edu.internet2.middleware.shibboleth.common;
+
+import java.io.IOException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.UnrecoverableKeyException;
+import java.util.Hashtable;
+
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+import org.apache.log4j.Logger;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * @author Walter Hoehn
+ *
+ */
+public class Credentials {
+
+ public static final String credentialsNamespace = "urn:mace:shibboleth:credentials";
+
+ private static Logger log = Logger.getLogger(Credentials.class.getName());
+ private Hashtable data = new Hashtable();
+
+ public Credentials(Element e) {
+
+ //TODO talk to Scott about the possibility of changing "resolver" to "loader", to avoid confusion with the AR
+
+ if (!e.getTagName().equals("Credentials")) {
+ throw new IllegalArgumentException();
+ }
+
+ NodeList resolverNodes = e.getChildNodes();
+ if (resolverNodes.getLength() <= 0) {
+ log.error("Credentials configuration inclues no Credential Resolver definitions.");
+ throw new IllegalArgumentException("Cannot load credentials.");
+ }
+
+ for (int i = 0; resolverNodes.getLength() > i; i++) {
+ if (resolverNodes.item(i).getNodeType() == Node.ELEMENT_NODE) {
+ try {
+
+ String credentialId = ((Element) resolverNodes.item(i)).getAttribute("id");
+ if (credentialId == null || credentialId.equals("")) {
+ log.error("Found credential that was not labeled with a unique \"id\" attribute. Skipping.");
+ }
+
+ if (data.containsKey(credentialId)) {
+ log.error("Duplicate credential id (" + credentialId + ") found. Skipping");
+ }
+
+ log.info("Found credential (" + credentialId + "). Loading...");
+ data.put(credentialId, CredentialFactory.loadCredential((Element) resolverNodes.item(i)));
+
+ } catch (CredentialFactoryException cfe) {
+ log.error("Could not load credential, skipping: " + cfe.getMessage());
+ } catch (ClassCastException cce) {
+ log.error("Problem realizing credential configuration" + cce.getMessage());
+ }
+ }
+ }
+ }
+
+ public boolean containsCredential(String identifier) {
+ return data.containsKey(identifier);
+ }
+
+ public Credential getCredential(String identifier) {
+ return (Credential) data.get(identifier);
+ }
+
+ static class CredentialFactory {
+
+ private static Logger log = Logger.getLogger(CredentialFactory.class.getName());
+
+ public static Credential loadCredential(Element e) throws CredentialFactoryException {
+ if (e.getTagName().equals("KeyInfo")) {
+ return new KeyInfoCredentialResolver().loadCredential(e);
+ }
+
+ if (e.getTagName().equals("FileCredResolver")) {
+ return new FileCredentialResolver().loadCredential(e);
+ }
+
+ if (e.getTagName().equals("KeyStoreResolver")) {
+ return new KeystoreCredentialResolver().loadCredential(e);
+ }
+
+ if (e.getTagName().equals("CustomCredResolver")) {
+ return new CustomCredentialResolver().loadCredential(e);
+ }
+
+ log.error("Unrecognized Credential Resolver type: " + e.getTagName());
+ throw new CredentialFactoryException("Failed to load credential.");
+ }
+
+ }
+
+}
+
+class KeyInfoCredentialResolver implements CredentialResolver {
+ private static Logger log = Logger.getLogger(KeyInfoCredentialResolver.class.getName());
+ KeyInfoCredentialResolver() throws CredentialFactoryException {
+ log.error("Credential Resolver (KeyInfoCredentialResolver) not implemented");
+ throw new CredentialFactoryException("Failed to load credential.");
+ }
+
+ public Credential loadCredential(Element e) {
+ return null;
+ }
+}
+
+class FileCredentialResolver implements CredentialResolver {
+ private static Logger log = Logger.getLogger(FileCredentialResolver.class.getName());
+ FileCredentialResolver() throws CredentialFactoryException {
+ log.error("Credential Resolver (FileCredentialResolver) not implemented");
+ throw new CredentialFactoryException("Failed to load credential.");
+ }
+ public Credential loadCredential(Element e) {
+ return null;
+ }
+}
+
+class KeystoreCredentialResolver implements CredentialResolver {
+
+ private static Logger log = Logger.getLogger(KeystoreCredentialResolver.class.getName());
+
+ public Credential loadCredential(Element e) throws CredentialFactoryException {
+
+ if (!e.getTagName().equals("KeyStoreResolver")) {
+ log.error("Invalid Credential Resolver configuration: expected <KeyStoreResolver> .");
+ throw new CredentialFactoryException("Failed to initialize Credential Resolver.");
+ }
+
+ String id = e.getAttribute("id");
+ if (id == null || id.equals("")) {
+ log.error("Credential Resolvers require specification of the attribute \"id\".");
+ throw new CredentialFactoryException("Failed to initialize Credential Resolver.");
+ }
+
+ String keyStoreType = e.getAttribute("keyStoreType");
+ if (keyStoreType == null || keyStoreType.equals("")) {
+ log.debug("Using default store type for credential.");
+ keyStoreType = "JKS";
+ }
+
+ String path = loadPath(e);
+ String alias = loadAlias(e);
+ String keyPassword = loadKeyPassword(e);
+ String keyStorePassword = loadKeyStorePassword(e);
+
+ try {
+ KeyStore keyStore = KeyStore.getInstance(keyStoreType);
+
+ keyStore.load(new ShibResource(path, this.getClass()).getInputStream(), keyStorePassword.toCharArray());
+
+ PrivateKey privateKey = (PrivateKey) keyStore.getKey(alias, keyPassword.toCharArray());
+
+ if (privateKey == null) {
+ throw new CredentialFactoryException("No key entry was found with an alias of (" + alias + ").");
+ }
+
+ Certificate[] certificates = keyStore.getCertificateChain(alias);
+ if (certificates == null) {
+ throw new CredentialFactoryException(
+ "An error occurred while reading the java keystore: No certificate found with the specified alias ("
+ + alias
+ + ").");
+ }
+
+ X509Certificate[] x509Certs = new X509Certificate[certificates.length];
+ for (int i = 0; i < certificates.length; i++) {
+ if (certificates[i] instanceof X509Certificate) {
+ x509Certs[i] = (X509Certificate) certificates[i];
+ } else {
+ throw new CredentialFactoryException(
+ "The KeyStore Credential Resolver can only load X509 certificates. Found an unsupported certificate of type ("
+ + certificates[i]
+ + ").");
+ }
+ }
+
+ return new Credential(x509Certs, privateKey);
+
+ } catch (KeyStoreException kse) {
+ throw new CredentialFactoryException("An error occurred while accessing the java keystore: " + kse);
+ } catch (NoSuchAlgorithmException nsae) {
+ throw new CredentialFactoryException("Appropriate JCE provider not found in the java environment: " + nsae);
+ } catch (CertificateException ce) {
+ throw new CredentialFactoryException(
+ "The java keystore contained a certificate that could not be loaded: " + ce);
+ } catch (IOException ioe) {
+ throw new CredentialFactoryException("An error occurred while reading the java keystore: " + ioe);
+ } catch (UnrecoverableKeyException uke) {
+ throw new CredentialFactoryException(
+ "An error occurred while attempting to load the key from the java keystore: " + uke);
+ }
+
+ }
+
+ private String loadPath(Element e) throws CredentialFactoryException {
+
+ NodeList pathElements = e.getElementsByTagNameNS(Credentials.credentialsNamespace, "Path");
+ if (pathElements.getLength() < 1) {
+ log.error("KeyStore path not specified.");
+ throw new CredentialFactoryException("KeyStore Credential Resolver requires a <Path> specification.");
+ }
+ if (pathElements.getLength() > 1) {
+ log.error("Multiple KeyStore path specifications, using first.");
+ }
+ Node tnode = pathElements.item(0).getFirstChild();
+ String path = null;
+ if (tnode != null && tnode.getNodeType() == Node.TEXT_NODE) {
+ path = tnode.getNodeValue();
+ }
+ if (path == null || path.equals("")) {
+ log.error("KeyStore path not specified.");
+ throw new CredentialFactoryException("KeyStore Credential Resolver requires a <Path> specification.");
+ }
+ return path;
+ }
+
+ private String loadAlias(Element e) throws CredentialFactoryException {
+
+ NodeList aliasElements = e.getElementsByTagNameNS(Credentials.credentialsNamespace, "Alias");
+ if (aliasElements.getLength() < 1) {
+ log.error("KeyStore key alias not specified.");
+ throw new CredentialFactoryException("KeyStore Credential Resolver requires an <Alias> specification.");
+ }
+ if (aliasElements.getLength() > 1) {
+ log.error("Multiple KeyStore alias specifications, using first.");
+ }
+ Node tnode = aliasElements.item(0).getFirstChild();
+ String alias = null;
+ if (tnode != null && tnode.getNodeType() == Node.TEXT_NODE) {
+ alias = tnode.getNodeValue();
+ }
+ if (alias == null || alias.equals("")) {
+ log.error("KeyStore key alias not specified.");
+ throw new CredentialFactoryException("KeyStore Credential Resolver requires an <Alias> specification.");
+ }
+ return alias;
+ }
+
+ private String loadKeyStorePassword(Element e) throws CredentialFactoryException {
+
+ NodeList passwordElements = e.getElementsByTagNameNS(Credentials.credentialsNamespace, "KeyStorePassword");
+ if (passwordElements.getLength() < 1) {
+ log.error("KeyStore password not specified.");
+ throw new CredentialFactoryException("KeyStore Credential Resolver requires an <KeyStorePassword> specification.");
+ }
+ if (passwordElements.getLength() > 1) {
+ log.error("Multiple KeyStore password specifications, using first.");
+ }
+ Node tnode = passwordElements.item(0).getFirstChild();
+ String password = null;
+ if (tnode != null && tnode.getNodeType() == Node.TEXT_NODE) {
+ password = tnode.getNodeValue();
+ }
+ if (password == null || password.equals("")) {
+ log.error("KeyStore password not specified.");
+ throw new CredentialFactoryException("KeyStore Credential Resolver requires an <KeyStorePassword> specification.");
+ }
+ return password;
+ }
+
+ private String loadKeyPassword(Element e) throws CredentialFactoryException {
+
+ NodeList passwords = e.getElementsByTagNameNS(Credentials.credentialsNamespace, "KeyPassword");
+ if (passwords.getLength() < 1) {
+ log.error("KeyStore key password not specified.");
+ throw new CredentialFactoryException("KeyStore Credential Resolver requires an <KeyPassword> specification.");
+ }
+ if (passwords.getLength() > 1) {
+ log.error("Multiple KeyStore key password specifications, using first.");
+ }
+ Node tnode = passwords.item(0).getFirstChild();
+ String password = null;
+ if (tnode != null && tnode.getNodeType() == Node.TEXT_NODE) {
+ password = tnode.getNodeValue();
+ }
+ if (password == null || password.equals("")) {
+ log.error("KeyStore key password not specified.");
+ throw new CredentialFactoryException("KeyStore Credential Resolver requires an <KeyPassword> specification.");
+ }
+ return password;
+ }
+}
+
+class CustomCredentialResolver implements CredentialResolver {
+
+ private static Logger log = Logger.getLogger(CustomCredentialResolver.class.getName());
+ private CredentialResolver resolver;
+
+ public Credential loadCredential(Element e) throws CredentialFactoryException {
+
+ if (!e.getTagName().equals("CustomCredResolver")) {
+ log.error("Invalid Credential Resolver configuration: expected <CustomCredResolver> .");
+ throw new CredentialFactoryException("Failed to initialize Credential Resolver.");
+ }
+
+ String id = e.getAttribute("id");
+ if (id == null || id.equals("")) {
+ log.error("Credential Resolvers require specification of the attribute \"id\".");
+ throw new CredentialFactoryException("Failed to initialize Credential Resolver.");
+ }
+
+ String className = e.getAttribute("Class");
+ if (className == null || className.equals("")) {
+ log.error("Custom Credential Resolver requires specification of the attribute \"Class\".");
+ throw new CredentialFactoryException("Failed to initialize Credential Resolver.");
+ }
+
+ try {
+ return ((CredentialResolver) Class.forName(className).newInstance()).loadCredential(e);
+
+ } catch (Exception loaderException) {
+ log.error(
+ "Failed to load Custom Credential Resolver implementation class: " + loaderException.getMessage());
+ throw new CredentialFactoryException("Failed to initialize Credential Resolver.");
+ }
+
+ }
+
+}
+
+class CredentialFactoryException extends Exception {
+
+ CredentialFactoryException(String message) {
+ super(message);
+ }
+}
--- /dev/null
+/*
+ * The Shibboleth License, Version 1. Copyright (c) 2002 University Corporation for Advanced Internet Development, Inc.
+ * All rights reserved
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+ * following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the distribution, if any, must include the
+ * following acknowledgment: "This product includes software developed by the University Corporation for Advanced
+ * Internet Development <http://www.ucaid.edu> Internet2 Project. Alternately, this acknowledegement may appear in the
+ * software itself, if and wherever such third-party acknowledgments normally appear.
+ *
+ * Neither the name of Shibboleth nor the names of its contributors, nor Internet2, nor the University Corporation for
+ * Advanced Internet Development, Inc., nor UCAID may be used to endorse or promote products derived from this software
+ * without specific prior written permission. For written permission, please contact shibboleth@shibboleth.org
+ *
+ * Products derived from this software may not be called Shibboleth, Internet2, UCAID, or the University Corporation
+ * for Advanced Internet Development, nor may Shibboleth appear in their name, without prior written permission of the
+ * University Corporation for Advanced Internet Development.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND WITH ALL FAULTS. ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK OF SATISFACTORY QUALITY, PERFORMANCE,
+ * ACCURACY, AND EFFORT IS WITH LICENSEE. IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY
+ * CORPORATION FOR ADVANCED INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package edu.internet2.middleware.shibboleth.common;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+
+import junit.framework.TestCase;
+
+import org.apache.log4j.BasicConfigurator;
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.apache.xerces.parsers.DOMParser;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+/**
+ * Validation suite for the <code>Credentials</code> interface.
+ *
+ * @author Walter Hoehn
+ */
+
+public class CredentialsTests extends TestCase {
+
+ private DOMParser parser = new DOMParser();
+
+ public CredentialsTests(String name) {
+ super(name);
+ BasicConfigurator.resetConfiguration();
+ BasicConfigurator.configure();
+ //TODO turn this off later
+ Logger.getRootLogger().setLevel(Level.DEBUG);
+ }
+
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(CredentialsTests.class);
+ BasicConfigurator.configure();
+ //TODO turn this off later
+ Logger.getRootLogger().setLevel(Level.DEBUG);
+ }
+
+ /**
+ * @see junit.framework.TestCase#setUp()
+ */
+ protected void setUp() throws Exception {
+ super.setUp();
+ try {
+ //TODO turn this back on when you get the schema worked out
+ parser.setFeature("http://xml.org/sax/features/validation", false);
+ parser.setFeature("http://apache.org/xml/features/validation/schema", false);
+ parser.setEntityResolver(new EntityResolver() {
+ public InputSource resolveEntity(String publicId, String systemId) throws SAXException {
+
+ if (systemId.endsWith("shibboleth-credentials.xsd")) {
+ InputStream stream;
+ try {
+ stream = new FileInputStream("src/schemas/shibboleth-credentials.xsd");
+ if (stream != null) {
+ return new InputSource(stream);
+ }
+ throw new SAXException("Could not load entity: Null input stream");
+ } catch (FileNotFoundException e) {
+ throw new SAXException("Could not load entity: " + e);
+ }
+ } else {
+ return null;
+ }
+ }
+ });
+
+ parser.setErrorHandler(new ErrorHandler() {
+ public void error(SAXParseException arg0) throws SAXException {
+ throw new SAXException("Error parsing xml file: " + arg0);
+ }
+ public void fatalError(SAXParseException arg0) throws SAXException {
+ throw new SAXException("Error parsing xml file: " + arg0);
+ }
+ public void warning(SAXParseException arg0) throws SAXException {
+ throw new SAXException("Error parsing xml file: " + arg0);
+ }
+ });
+ } catch (Exception e) {
+ fail("Failed to setup xml parser: " + e);
+ }
+
+ }
+
+ public void testKeyStoreX509() {
+
+ try {
+ InputStream inStream = new FileInputStream("data/credentials1.xml");
+ parser.parse(new InputSource(inStream));
+ Credentials credentials = new Credentials(parser.getDocument().getDocumentElement());
+
+ assertTrue("Credential could not be found.", credentials.containsCredential("test"));
+ Credential credential = credentials.getCredential("test");
+
+ assertTrue(
+ "Credential was loaded with an incorrect type.",
+ credential.getCredentialType() == Credential.X509);
+ assertNotNull("Private key was not loaded correctly.", credential.getPrivateKey());
+ assertEquals(
+ "Unexpected X509 certificate found.",
+ credential.getX509Certificate().getSubjectDN().getName(),
+ "CN=shib2.internet2.edu, OU=Unknown, O=Unknown, ST=Unknown, C=Unknown");
+ assertEquals(
+ "Unexpected certificate chain length.",
+ new Integer(credential.getX509CertificateChain().length),
+ new Integer(3));
+ assertEquals(
+ "Unexpected X509 certificate found.",
+ credential.getX509CertificateChain()[2].getSubjectDN().getName(),
+ "CN=HEPKI Master CA -- 20020701A, OU=Division of Information Technology, O=University of Wisconsin, L=Madison, ST=Wisconsin, C=US");
+ } catch (Exception e) {
+ fail("Failed to load credentials: " + e);
+ }
+ }
+
+}