<?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
<?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
--- /dev/null
+<?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
*/
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();
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)) {
return new KeyInfoCredentialResolver().loadCredential(e);
}
- if (e.getTagName().equals("FileCredResolver")) {
+ if (e.getTagName().equals("FileResolver")) {
return new FileCredentialResolver().loadCredential(e);
}
return new KeystoreCredentialResolver().loadCredential(e);
}
- if (e.getTagName().equals("CustomCredResolver")) {
+ if (e.getTagName().equals("CustomResolver")) {
return new CustomCredentialResolver().loadCredential(e);
}
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.");
}
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";
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";
String path = loadPath(e);
String alias = loadAlias(e);
+ String certAlias = loadCertAlias(e, alias);
String keyPassword = loadKeyPassword(e);
String keyStorePassword = loadKeyStorePassword(e);
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
+ ").");
}
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;
}
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.");
}
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;
}
--- /dev/null
+<?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>
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);
}
} 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;
}
}
}
}
+ 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 {