Permalink
Browse files

Changes to support retrieving certificates as beans.

  • Loading branch information...
1 parent d1a9e96 commit b0c7e8dab8c3f9ead869055aa460feb0dc5af4f6 @iamthechad iamthechad committed May 10, 2012
Showing with 456 additions and 0 deletions.
  1. +16 −0 src/main/java/com/google/code/springcryptoutils/core/certificate/CertificateChooserByAlias.java
  2. +25 −0 src/main/java/com/google/code/springcryptoutils/core/certificate/CertificateException.java
  3. +56 −0 src/main/java/com/google/code/springcryptoutils/core/certificate/CertificateFactoryBean.java
  4. +23 −0 src/main/java/com/google/code/springcryptoutils/core/certificate/CertificateRegistryByAlias.java
  5. +106 −0 src/main/java/com/google/code/springcryptoutils/core/certificate/CertificateRegistryByAliasImpl.java
  6. +7 −0 src/main/java/com/google/code/springcryptoutils/core/certificate/package-info.java
  7. +6 −0 src/main/java/com/google/code/springcryptoutils/core/spring/SpringCryptoUtilsNamespaceHandler.java
  8. +23 −0 ...va/com/google/code/springcryptoutils/core/spring/certificate/CertificateBeanDefinitionParser.java
  9. +22 −0 ...ode/springcryptoutils/core/spring/certificate/CertificateRegistryByaliasBeanDefinitionParser.java
  10. +23 −0 src/main/resources/com/google/code/springcryptoutils/core/spring/crypt.xsd
  11. +32 −0 .../java/com/google/code/springcryptoutils/core/certificate/CertificateFactoryBeanExceptionTest.java
  12. +26 −0 src/test/java/com/google/code/springcryptoutils/core/certificate/CertificateFactoryBeanTest.java
  13. +54 −0 ...t/java/com/google/code/springcryptoutils/core/certificate/CertificateRegistryByAliasImplTest.java
  14. +8 −0 ...om/google/code/springcryptoutils/core/certificate/CertificateFactoryBeanExceptionTest-context.xml
  15. +10 −0 ...sources/com/google/code/springcryptoutils/core/certificate/CertificateFactoryBeanTest-context.xml
  16. +19 −0 ...com/google/code/springcryptoutils/core/certificate/CertificateRegistryByAliasImplTest-context.xml
@@ -0,0 +1,16 @@
+package com.google.code.springcryptoutils.core.certificate;
+
+/**
+ * An interface for choosing certificates from a keystore.
+ *
+ * @author Chad Johnston (cjohnston@megatome.com)
+ */
+public interface CertificateChooserByAlias {
+
+ /**
+ * Must return the alias the key has in the keystore.
+ *
+ * @return the alias
+ */
+ String getAlias();
+}
@@ -0,0 +1,25 @@
+package com.google.code.springcryptoutils.core.certificate;
+
+/**
+ * @author Chad Johnston (cjohnston@megatome.com)
+ */
+public class CertificateException extends RuntimeException {
+ /**
+ * Creates a new exception instance.
+ *
+ * @param message the exception message
+ */
+ public CertificateException(String message) {
+ super(message);
+ }
+
+ /**
+ * Creates a new exception instance.
+ *
+ * @param message the exception message
+ * @param cause the root cause
+ */
+ public CertificateException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
@@ -0,0 +1,56 @@
+package com.google.code.springcryptoutils.core.certificate;
+
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.beans.factory.InitializingBean;
+
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.cert.Certificate;
+
+public class CertificateFactoryBean implements FactoryBean, InitializingBean {
+ private KeyStore keystore;
+ private String alias;
+
+ private Certificate certificate;
+
+ /**
+ * Sets the keystore holding the public key.
+ *
+ * @param keystore the keystore
+ */
+ public void setKeystore(KeyStore keystore) {
+ this.keystore = keystore;
+ }
+
+ /**
+ * Sets the certificate alias as known in the keystore.
+ *
+ * @param alias the certificate alias
+ */
+ public void setAlias(String alias) {
+ this.alias = alias;
+ }
+
+ public Object getObject() {
+ return certificate;
+ }
+
+ public Class getObjectType() {
+ return Certificate.class;
+ }
+
+ public boolean isSingleton() {
+ return true;
+ }
+
+ public void afterPropertiesSet() throws KeyStoreException {
+ Certificate cert = keystore.getCertificate(alias);
+
+ if (cert == null) {
+ throw new CertificateException("no such certificate with alias: " + alias);
+ }
+
+ certificate = cert;
+ }
+
+}
@@ -0,0 +1,23 @@
+package com.google.code.springcryptoutils.core.certificate;
+
+import com.google.code.springcryptoutils.core.keystore.KeyStoreChooser;
+
+import java.security.cert.Certificate;
+
+/**
+ * An interface for selecting a certificate at runtime from an
+ * underlying certificate registry.
+ *
+ * @author Chad Johnston (cjohnston@megatome.com)
+ */
+public interface CertificateRegistryByAlias {
+
+ /**
+ * Returns the selected certificate or null if not found.
+ *
+ * @param keyStoreChooser the keystore chooser
+ * @param certificateChooserByAlias the certificate chooser by alias
+ * @return the selected certificate or null if not found
+ */
+ Certificate get(KeyStoreChooser keyStoreChooser, CertificateChooserByAlias certificateChooserByAlias);
+}
@@ -0,0 +1,106 @@
+package com.google.code.springcryptoutils.core.certificate;
+
+import com.google.code.springcryptoutils.core.keystore.KeyStoreChooser;
+import com.google.code.springcryptoutils.core.keystore.KeyStoreRegistry;
+
+import java.security.KeyStore;
+import java.security.cert.Certificate;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author Chad Johnston (cjohnston@megatome.com)
+ */
+public class CertificateRegistryByAliasImpl implements CertificateRegistryByAlias {
+ private KeyStoreRegistry keyStoreRegistry;
+
+ private Map<CacheCert, Certificate> cache = new HashMap<CacheCert, Certificate>();
+
+ /**
+ * Sets the keystore registry.
+ *
+ * @param keyStoreRegistry the keystore registry
+ */
+ public void setKeyStoreRegistry(KeyStoreRegistry keyStoreRegistry) {
+ this.keyStoreRegistry = keyStoreRegistry;
+ }
+
+ /**
+ * Returns the selected certificate or null if not found.
+ *
+ * @param keyStoreChooser the keystore chooser
+ * @param certificateChooserByAlias the public key chooser by alias
+ * @return the selected public key or null if not found
+ */
+ public Certificate get(KeyStoreChooser keyStoreChooser, CertificateChooserByAlias certificateChooserByAlias) {
+ CacheCert cacheCert = new CacheCert(keyStoreChooser.getKeyStoreName(), certificateChooserByAlias.getAlias());
+ Certificate retrievedPublicKey = cache.get(cacheCert);
+
+ if (retrievedPublicKey != null) {
+ return retrievedPublicKey;
+ }
+
+ KeyStore keyStore = keyStoreRegistry.get(keyStoreChooser);
+
+ if (keyStore != null) {
+ CertificateFactoryBean factory = new CertificateFactoryBean();
+ factory.setKeystore(keyStore);
+ factory.setAlias(certificateChooserByAlias.getAlias());
+ try {
+ factory.afterPropertiesSet();
+ Certificate certificate = (Certificate) factory.getObject();
+
+ if (certificate != null) {
+ cache.put(cacheCert, certificate);
+ }
+ return certificate;
+ } catch (Exception e) {
+ throw new CertificateException("error initializing the certificate factory bean", e);
+ }
+ }
+
+ return null;
+ }
+
+ private static final class CacheCert {
+
+ private static final int INT_HASHCODE_BASE = 31;
+
+ private String keyStoreName;
+ private String certificateAlias;
+
+ private CacheCert(String keyStoreName, String certificateAlias) {
+ this.keyStoreName = keyStoreName;
+ this.certificateAlias = certificateAlias;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ CacheCert cacheCert = (CacheCert) o;
+ return !(keyStoreName != null ? !keyStoreName.equals(cacheCert.keyStoreName) : cacheCert.keyStoreName != null) && !(certificateAlias != null ? !certificateAlias.equals(cacheCert.certificateAlias) : cacheCert.certificateAlias != null);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = keyStoreName != null ? keyStoreName.hashCode() : 0;
+ result = INT_HASHCODE_BASE * result + (certificateAlias != null ? certificateAlias.hashCode() : 0);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("CacheKey");
+ sb.append("{keyStoreName='").append(keyStoreName).append('\'');
+ sb.append(", certificateAlias='").append(certificateAlias).append('\'');
+ sb.append('}');
+ return sb.toString();
+ }
+ }
+}
@@ -0,0 +1,7 @@
+/**
+ * Interfaces and classes used to load cryptographic certificates
+ * and map references to them.
+ *
+ * @author Chad Johnston (cjohnston@megatome.com)
+ */
+package com.google.code.springcryptoutils.core.certificate;
@@ -1,5 +1,7 @@
package com.google.code.springcryptoutils.core.spring;
+import com.google.code.springcryptoutils.core.spring.certificate.CertificateBeanDefinitionParser;
+import com.google.code.springcryptoutils.core.spring.certificate.CertificateRegistryByAliasBeanDefinitionParser;
import com.google.code.springcryptoutils.core.spring.cipher.asymmetric.AsymmetricCiphererBeanDefinitionParser;
import com.google.code.springcryptoutils.core.spring.cipher.asymmetric.AsymmetricCiphererWithChooserByKeyIdBeanDefinitionParser;
import com.google.code.springcryptoutils.core.spring.cipher.asymmetric.Base64EncodedAsymmetricCiphererBeanDefinitionParser;
@@ -32,6 +34,10 @@ public void init() {
registerBeanDefinitionParser("publicKeyRegistryByAlias", new PublicKeyRegistryByAliasBeanDefinitionParser());
registerBeanDefinitionParser("privateKeyRegistryByAlias", new PrivateKeyRegistryByAliasBeanDefinitionParser());
+ // certificate
+ registerBeanDefinitionParser("certificateRegistryByAlias", new CertificateRegistryByAliasBeanDefinitionParser());
+ registerBeanDefinitionParser("certificate", new CertificateBeanDefinitionParser());
+
// signature
registerBeanDefinitionParser("signer", new SignerBeanDefinitionParser());
registerBeanDefinitionParser("verifier", new VerifierBeanDefinitionParser());
@@ -0,0 +1,23 @@
+package com.google.code.springcryptoutils.core.spring.certificate;
+
+import com.google.code.springcryptoutils.core.certificate.CertificateFactoryBean;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
+import org.w3c.dom.Element;
+
+/**
+ * @author Chad Johnston (cjohnston@megatome.com)
+ */
+public class CertificateBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
+
+ @Override
+ protected Class getBeanClass(Element element) {
+ return CertificateFactoryBean.class;
+ }
+
+ @Override
+ protected void doParse(Element element, BeanDefinitionBuilder bean) {
+ bean.addPropertyReference("keystore", element.getAttribute("keystore-ref"));
+ bean.addPropertyValue("alias", element.getAttribute("alias"));
+ }
+}
@@ -0,0 +1,22 @@
+package com.google.code.springcryptoutils.core.spring.certificate;
+
+import com.google.code.springcryptoutils.core.certificate.CertificateRegistryByAliasImpl;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
+import org.w3c.dom.Element;
+
+/**
+ * @author Chad Johnston (cjohnston@megatome.com)
+ */
+public class CertificateRegistryByAliasBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
+
+ @Override
+ protected Class getBeanClass(Element element) {
+ return CertificateRegistryByAliasImpl.class;
+ }
+
+ @Override
+ protected void doParse(Element element, BeanDefinitionBuilder bean) {
+ bean.addPropertyReference("keyStoreRegistry", element.getAttribute("keystoreRegistry-ref"));
+ }
+}
@@ -111,6 +111,29 @@
</xsd:complexType>
</xsd:element>
+ <!-- CERTIFICATE -->
+
+ <xsd:element name="certificateRegistryByAlias">
+ <xsd:complexType>
+ <xsd:complexContent>
+ <xsd:extension base="beans:identifiedType">
+ <xsd:attribute name="keystoreRegistry-ref" type="xsd:string" use="required"/>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="certificate">
+ <xsd:complexType>
+ <xsd:complexContent>
+ <xsd:extension base="beans:identifiedType">
+ <xsd:attribute name="keystore-ref" type="xsd:string" use="required"/>
+ <xsd:attribute name="alias" type="xsd:string" use="required"/>
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+
<!-- DIGITAL SIGNATURE -->
<xsd:element name="signer">
@@ -0,0 +1,32 @@
+package com.google.code.springcryptoutils.core.certificate;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration
+public class CertificateFactoryBeanExceptionTest {
+
+ @Autowired
+ private KeyStore keyStore;
+
+ @Test(expected = CertificateException.class)
+ public void testInvalidAlias() throws KeyStoreException {
+ assertNotNull(keyStore);
+ assertEquals("keyStoreType", "JKS", keyStore.getType());
+
+ CertificateFactoryBean cfb = new CertificateFactoryBean();
+ cfb.setKeystore(keyStore);
+ cfb.setAlias("*** INVALID ***");
+ cfb.afterPropertiesSet();
+ }
+}
@@ -0,0 +1,26 @@
+package com.google.code.springcryptoutils.core.certificate;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import java.security.cert.Certificate;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration
+public class CertificateFactoryBeanTest {
+
+ @Autowired
+ private Certificate certificate;
+
+ @Test
+ public void testCertificateProperlyLoaded() {
+ assertNotNull(certificate);
+ assertEquals("certificate type", "X.509", certificate.getType());
+ }
+}
Oops, something went wrong.

0 comments on commit b0c7e8d

Please sign in to comment.