Updated credentials schema.
authorwassa <wassa@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Tue, 2 Dec 2003 21:10:37 +0000 (21:10 +0000)
committerwassa <wassa@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Tue, 2 Dec 2003 21:10:37 +0000 (21:10 +0000)
git-svn-id: https://subversion.switch.ch/svn/shibboleth/java-idp/trunk@796 ab3bd59b-922f-494d-bb5f-6f0a3c29deca

data/credentials1.xml
data/credentials2.xml
data/credentials3.xml [new file with mode: 0644]
src/edu/internet2/middleware/shibboleth/common/Credentials.java
src/schemas/credentials.xsd [new file with mode: 0644]
tests/edu/internet2/middleware/shibboleth/common/CredentialsTests.java

index e30c8ca..eda120f 100644 (file)
@@ -1,12 +1,13 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<Credentials xmlns="urn:mace:shibboleth:credentials" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" 
+<Credentials xmlns="urn:mace:shibboleth:credentials:1.0" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
-       xsi:schemaLocation="urn:mace:shibboleth:credentials shibboleth.xsd">
+       xsi:schemaLocation="urn:mace:shibboleth:credentials:1.0 credentials.xsd">
        
-       <KeyStoreResolver id="test" keyStoreType="JKS">
+       <KeyStoreResolver Id="test" storeType="JKS">
                <Path>/conf/keystore.jks</Path>
-               <Alias>shibhs</Alias>
-               <KeyStorePassword>shibhs</KeyStorePassword>
+               <KeyAlias>shibhs</KeyAlias>
+               <CertAlias>shibhs</CertAlias>
+               <StorePassword>shibhs</StorePassword>
                <KeyPassword>shibhs</KeyPassword>
        </KeyStoreResolver>
 </Credentials>
\ No newline at end of file
index b58dadc..02a5563 100644 (file)
@@ -1,14 +1,14 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<Credentials xmlns="urn:mace:shibboleth:credentials" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" 
+<Credentials xmlns="urn:mace:shibboleth:credentials:1.0" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
-       xsi:schemaLocation="urn:mace:shibboleth:credentials shibboleth.xsd">
+       xsi:schemaLocation="urn:mace:shibboleth:credentials:1.0 credentials.xsd">
        
-       <FileCredResolver id="test">
+       <FileResolver Id="test">
                <Certificate format="PEM">
                        <Path>/conf/test.pemcrt</Path>
                </Certificate>
                <Key format="PEM">
                        <Path>/conf/test.pemkey</Path>
                </Key>
-       </FileCredResolver>
+       </FileResolver>
 </Credentials>
\ No newline at end of file
diff --git a/data/credentials3.xml b/data/credentials3.xml
new file mode 100644 (file)
index 0000000..e77d5bb
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Credentials xmlns="urn:mace:shibboleth:credentials:1.0" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" 
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
+       xsi:schemaLocation="urn:mace:shibboleth:credentials:1.0 credentials.xsd">
+       
+       <KeyStoreResolver Id="test" storeType="JKS">
+               <Path>/conf/keystore.jks</Path>
+               <KeyAlias>shibhs</KeyAlias>
+               <StorePassword>shibhs</StorePassword>
+               <KeyPassword>shibhs</KeyPassword>
+       </KeyStoreResolver>
+</Credentials>
\ No newline at end of file
index 3542bef..2bee890 100644 (file)
@@ -66,7 +66,7 @@ import org.w3c.dom.NodeList;
  */
 public class Credentials {
 
-       public static final String credentialsNamespace = "urn:mace:shibboleth:credentials";
+       public static final String credentialsNamespace = "urn:mace:shibboleth:credentials:1.0";
 
        private static Logger log = Logger.getLogger(Credentials.class.getName());
        private Hashtable data = new Hashtable();
@@ -89,9 +89,9 @@ public class Credentials {
                        if (resolverNodes.item(i).getNodeType() == Node.ELEMENT_NODE) {
                                try {
 
-                                       String credentialId = ((Element) resolverNodes.item(i)).getAttribute("id");
+                                       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.");
+                                               log.error("Found credential that was not labeled with a unique \"Id\" attribute. Skipping.");
                                        }
 
                                        if (data.containsKey(credentialId)) {
@@ -127,7 +127,7 @@ public class Credentials {
                                return new KeyInfoCredentialResolver().loadCredential(e);
                        }
 
-                       if (e.getTagName().equals("FileCredResolver")) {
+                       if (e.getTagName().equals("FileResolver")) {
                                return new FileCredentialResolver().loadCredential(e);
                        }
 
@@ -135,7 +135,7 @@ public class Credentials {
                                return new KeystoreCredentialResolver().loadCredential(e);
                        }
 
-                       if (e.getTagName().equals("CustomCredResolver")) {
+                       if (e.getTagName().equals("CustomResolver")) {
                                return new CustomCredentialResolver().loadCredential(e);
                        }
 
@@ -164,14 +164,14 @@ class FileCredentialResolver implements CredentialResolver {
 
        public Credential loadCredential(Element e) throws CredentialFactoryException {
 
-               if (!e.getTagName().equals("FileCredResolver")) {
-                       log.error("Invalid Credential Resolver configuration: expected <FileCredResolver> .");
+               if (!e.getTagName().equals("FileResolver")) {
+                       log.error("Invalid Credential Resolver configuration: expected <FileResolver> .");
                        throw new CredentialFactoryException("Failed to initialize Credential Resolver.");
                }
 
-               String id = e.getAttribute("id");
+               String id = e.getAttribute("Id");
                if (id == null || id.equals("")) {
-                       log.error("Credential Resolvers require specification of the attribute \"id\".");
+                       log.error("Credential Resolvers require specification of the attribute \"Id\".");
                        throw new CredentialFactoryException("Failed to initialize Credential Resolver.");
                }
 
@@ -241,7 +241,7 @@ class FileCredentialResolver implements CredentialResolver {
                        log.error("Multiple Certificate path specifications, using first.");
                }
                
-               String format = ((Element)certificateElements.item(0)).getAttribute("id");
+               String format = ((Element)certificateElements.item(0)).getAttribute("format");
                if (format == null || format.equals("")) {
                        log.debug("No format specified for certificate, using default (PEM) format.");
                        format = "PEM";
@@ -358,13 +358,13 @@ class KeystoreCredentialResolver implements CredentialResolver {
                        throw new CredentialFactoryException("Failed to initialize Credential Resolver.");
                }
 
-               String id = e.getAttribute("id");
+               String id = e.getAttribute("Id");
                if (id == null || id.equals("")) {
-                       log.error("Credential Resolvers require specification of the attribute \"id\".");
+                       log.error("Credential Resolvers require specification of the attribute \"Id\".");
                        throw new CredentialFactoryException("Failed to initialize Credential Resolver.");
                }
 
-               String keyStoreType = e.getAttribute("keyStoreType");
+               String keyStoreType = e.getAttribute("storeType");
                if (keyStoreType == null || keyStoreType.equals("")) {
                        log.debug("Using default store type for credential.");
                        keyStoreType = "JKS";
@@ -372,6 +372,7 @@ class KeystoreCredentialResolver implements CredentialResolver {
 
                String path = loadPath(e);
                String alias = loadAlias(e);
+               String certAlias = loadCertAlias(e, alias);
                String keyPassword = loadKeyPassword(e);
                String keyStorePassword = loadKeyStorePassword(e);
 
@@ -386,11 +387,11 @@ class KeystoreCredentialResolver implements CredentialResolver {
                                throw new CredentialFactoryException("No key entry was found with an alias of (" + alias + ").");
                        }
 
-                       Certificate[] certificates = keyStore.getCertificateChain(alias);
+                       Certificate[] certificates = keyStore.getCertificateChain(certAlias);
                        if (certificates == null) {
                                throw new CredentialFactoryException(
                                        "An error occurred while reading the java keystore: No certificate found with the specified alias ("
-                                               + alias
+                                               + certAlias
                                                + ").");
                        }
 
@@ -448,13 +449,13 @@ class KeystoreCredentialResolver implements CredentialResolver {
 
        private String loadAlias(Element e) throws CredentialFactoryException {
 
-               NodeList aliasElements = e.getElementsByTagNameNS(Credentials.credentialsNamespace, "Alias");
+               NodeList aliasElements = e.getElementsByTagNameNS(Credentials.credentialsNamespace, "KeyAlias");
                if (aliasElements.getLength() < 1) {
                        log.error("KeyStore key alias not specified.");
-                       throw new CredentialFactoryException("KeyStore Credential Resolver requires an <Alias> specification.");
+                       throw new CredentialFactoryException("KeyStore Credential Resolver requires an <KeyAlias> specification.");
                }
                if (aliasElements.getLength() > 1) {
-                       log.error("Multiple KeyStore alias specifications, using first.");
+                       log.error("Multiple key alias specifications, using first.");
                }
                Node tnode = aliasElements.item(0).getFirstChild();
                String alias = null;
@@ -463,17 +464,41 @@ class KeystoreCredentialResolver implements CredentialResolver {
                }
                if (alias == null || alias.equals("")) {
                        log.error("KeyStore key alias not specified.");
-                       throw new CredentialFactoryException("KeyStore Credential Resolver requires an <Alias> specification.");
+                       throw new CredentialFactoryException("KeyStore Credential Resolver requires an <KeyAlias> specification.");
+               }
+               return alias;
+       }
+
+       private String loadCertAlias(Element e, String defaultAlias) throws CredentialFactoryException {
+
+               NodeList aliasElements = e.getElementsByTagNameNS(Credentials.credentialsNamespace, "CertAlias");
+               if (aliasElements.getLength() < 1) {
+                       log.debug("KeyStore cert alias not specified, defaulting to key alias.");
+                       return defaultAlias;
+               }
+
+               if (aliasElements.getLength() > 1) {
+                       log.error("Multiple cert 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.debug("KeyStore cert alias not specified, defaulting to key alias.");
+                       return defaultAlias;
                }
                return alias;
        }
 
        private String loadKeyStorePassword(Element e) throws CredentialFactoryException {
 
-               NodeList passwordElements = e.getElementsByTagNameNS(Credentials.credentialsNamespace, "KeyStorePassword");
+               NodeList passwordElements = e.getElementsByTagNameNS(Credentials.credentialsNamespace, "StorePassword");
                if (passwordElements.getLength() < 1) {
                        log.error("KeyStore password not specified.");
-                       throw new CredentialFactoryException("KeyStore Credential Resolver requires an <KeyStorePassword> specification.");
+                       throw new CredentialFactoryException("KeyStore Credential Resolver requires an <StorePassword> specification.");
                }
                if (passwordElements.getLength() > 1) {
                        log.error("Multiple KeyStore password specifications, using first.");
@@ -485,7 +510,7 @@ class KeystoreCredentialResolver implements CredentialResolver {
                }
                if (password == null || password.equals("")) {
                        log.error("KeyStore password not specified.");
-                       throw new CredentialFactoryException("KeyStore Credential Resolver requires an <KeyStorePassword> specification.");
+                       throw new CredentialFactoryException("KeyStore Credential Resolver requires an <StorePassword> specification.");
                }
                return password;
        }
diff --git a/src/schemas/credentials.xsd b/src/schemas/credentials.xsd
new file mode 100644 (file)
index 0000000..35d06fe
--- /dev/null
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- edited with XMLSPY v2004 rel. 2 U (http://www.xmlspy.com) by Walter F Hoehn, Jr (Columbia University in the City of New York) -->
+<xs:schema targetNamespace="urn:mace:shibboleth:credentials:1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:credentials="urn:mace:shibboleth:credentials:1.0" elementFormDefault="qualified" attributeFormDefault="unqualified">
+       
+       <xs:import namespace="http://www.w3.org/2000/09/xmldsig#" schemaLocation="xmldsig-core-schema.xsd" />
+       
+       <xs:element name="Credentials">
+               <xs:complexType>
+                       <xs:choice maxOccurs="unbounded">
+                               <xs:element ref="ds:KeyInfo"/>
+                               <xs:element name="KeyStoreResolver">
+                                       <xs:annotation>
+                                               <xs:documentation>Pulls credentials from a Java keystore.</xs:documentation>
+                                       </xs:annotation>
+                                       <xs:complexType>
+                                               <xs:complexContent>
+                                                       <xs:extension base="credentials:BaseCredentialFinder">
+                                                               <xs:sequence>
+                                                                       <xs:element name="Path" type="xs:string"/>
+                                                                       <xs:element name="KeyAlias" type="xs:string"/>
+                                                                       <xs:element name="CertAlias" type="xs:string" minOccurs="0"/>
+                                                                       <xs:element name="StorePassword" type="xs:string"/>
+                                                                       <xs:element name="KeyPassword" type="xs:string" minOccurs="0"/>
+                                                               </xs:sequence>
+                                                               <xs:attribute name="storeType" type="xs:string" use="optional" default="JKS"/>
+                                                       </xs:extension>
+                                               </xs:complexContent>
+                                       </xs:complexType>
+                               </xs:element>
+                               <xs:element name="FileResolver">
+                                       <xs:annotation>
+                                               <xs:documentation>Pulls credentials from files.</xs:documentation>
+                                       </xs:annotation>
+                                       <xs:complexType>
+                                               <xs:complexContent>
+                                                       <xs:extension base="credentials:BaseCredentialFinder">
+                                                               <xs:sequence>
+                                                                       <xs:element name="Certificate">
+                                                                               <xs:complexType>
+                                                                                       <xs:sequence>
+                                                                                               <xs:element name="Path" type="xs:string"/>
+                                                                                       </xs:sequence>
+                                                                                       <xs:attribute name="format" type="xs:string" use="optional" default="PEM"/>
+                                                                               </xs:complexType>
+                                                                       </xs:element>
+                                                                       <xs:element name="Key">
+                                                                               <xs:complexType>
+                                                                                       <xs:sequence>
+                                                                                               <xs:element name="Path" type="xs:string"/>
+                                                                                       </xs:sequence>
+                                                                                       <xs:attribute name="format" type="xs:string" use="optional" default="PEM"/>
+                                                                                       <xs:attribute name="password" type="xs:string" use="optional"/>
+                                                                               </xs:complexType>
+                                                                       </xs:element>
+                                                               </xs:sequence>
+                                                       </xs:extension>
+                                               </xs:complexContent>
+                                       </xs:complexType>
+                               </xs:element>
+                               <xs:element name="CustomResolver">
+                                       <xs:annotation>
+                                               <xs:documentation>Allows for specification of a Java class that loads credentials from a custom storage mechanism. </xs:documentation>
+                                       </xs:annotation>
+                                       <xs:complexType>
+                                               <xs:complexContent>
+                                                       <xs:extension base="credentials:BaseCredentialFinder">
+                                                               <xs:sequence>
+                                                                       <xs:any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+                                                               </xs:sequence>
+                                                               <xs:attribute name="class" type="xs:string" use="required"/>
+                                                               <xs:anyAttribute namespace="##any"/>
+                                                       </xs:extension>
+                                               </xs:complexContent>
+                                       </xs:complexType>
+                               </xs:element>
+                       </xs:choice>
+               </xs:complexType>
+       </xs:element>
+       <xs:complexType name="BaseCredentialFinder">
+               <xs:attribute name="Id" type="xs:string" use="required"/>
+       </xs:complexType>
+</xs:schema>
index a6fa10f..a6cbab2 100644 (file)
@@ -85,15 +85,15 @@ public class CredentialsTests extends TestCase {
                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.setFeature("http://xml.org/sax/features/validation", true);
+                       parser.setFeature("http://apache.org/xml/features/validation/schema", true);
                        parser.setEntityResolver(new EntityResolver() {
                                public InputSource resolveEntity(String publicId, String systemId) throws SAXException {
 
-                                       if (systemId.endsWith("shibboleth-credentials.xsd")) {
+                                       if (systemId.endsWith("credentials.xsd")) {
                                                InputStream stream;
                                                try {
-                                                       stream = new FileInputStream("src/schemas/shibboleth-credentials.xsd");
+                                                       stream = new FileInputStream("src/schemas/credentials.xsd");
                                                        if (stream != null) {
                                                                return new InputSource(stream);
                                                        }
@@ -101,7 +101,18 @@ public class CredentialsTests extends TestCase {
                                                } catch (FileNotFoundException e) {
                                                        throw new SAXException("Could not load entity: " + e);
                                                }
-                                       } else {
+                                       } else if (systemId.endsWith("xmldsig-core-schema.xsd")) {
+                                       InputStream stream;
+                                       try {
+                                               stream = new FileInputStream("src/schemas/xmldsig-core-schema.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;
                                        }
                                }
@@ -155,6 +166,37 @@ public class CredentialsTests extends TestCase {
                }
        }
        
+       public void testKeyStoreX509AliasDefaulting() {
+
+               try {
+                       InputStream inStream = new FileInputStream("data/credentials3.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);
+               }
+       }
+       
        public void testFileX509NoPassword() {
 
                try {