Skip to content

Commit

Permalink
AMQP-626: Add keystore\truststore type setters
Browse files Browse the repository at this point in the history
JIRA: https://jira.spring.io/browse/AMQP-626
Fixes GH-436 (#436)

Currently the `RabbitConnectionFactoryBean` has hard-coded keystore/truststore types.

* Add setters for keystore/truststore types and leave previously-hardcoded as default values.
* Add `keyStore.type` and `trustStore.type` properties for the `ssl.properties` resource
  • Loading branch information
Heath Abelson authored and artembilan committed Jul 27, 2016
1 parent 83c499f commit 208775d
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 2 deletions.
Expand Up @@ -57,6 +57,7 @@
* Override {@link #setUpSSL()} to take complete control over setting up SSL.
*
* @author Gary Russell
* @author Heath Abelson
*
* @since 1.4
*/
Expand All @@ -70,8 +71,16 @@ public class RabbitConnectionFactoryBean extends AbstractFactoryBean<ConnectionF

private static final String TRUST_STORE_PASS_PHRASE = "trustStore.passPhrase";

private static final String KEY_STORE_TYPE = "keyStore.type";

private static final String TRUST_STORE_TYPE = "trustStore.type";

private static final String TLS_V1_1 = "TLSv1.1";

private static final String KEY_STORE_DEFAULT_TYPE = "PKCS12";

private static final String TRUST_STORE_DEFAULT_TYPE = "JKS";

protected final ConnectionFactory connectionFactory = new ConnectionFactory();

private final Properties sslProperties = new Properties();
Expand All @@ -88,6 +97,10 @@ public class RabbitConnectionFactoryBean extends AbstractFactoryBean<ConnectionF

private volatile String trustStorePassphrase;

private volatile String keyStoreType;

private volatile String trustStoreType;

private volatile String sslAlgorithm = TLS_V1_1;

private volatile boolean sslAlgorithmSet;
Expand Down Expand Up @@ -225,6 +238,64 @@ public void setTrustStorePassphrase(String trustStorePassphrase) {
this.trustStorePassphrase = trustStorePassphrase;
}

/**
* Get the key store type - this defaults to PKCS12 if not overridden by
* {@link #setSslPropertiesLocation(Resource)} or {@link #setKeyStoreType}
* @return the key store type.
* @since 1.6.2
*/
protected String getKeyStoreType() {
if (this.keyStoreType == null && this.sslProperties.getProperty(KEY_STORE_TYPE) == null) {
return KEY_STORE_DEFAULT_TYPE;
}
else if (this.keyStoreType != null) {
return this.keyStoreType;
}
else {
return this.sslProperties.getProperty(KEY_STORE_TYPE);
}
}

/**
* Set the key store type - overrides
* the property in {@link #setSslPropertiesLocation(Resource)}.
* @param keyStoreType the key store type.
* @see java.security.KeyStore#getInstance(String)
* @since 1.6.2
*/
public void setKeyStoreType(String keyStoreType) {
this.keyStoreType = keyStoreType;
}

/**
* Get the trust store type - this defaults to JKS if not overridden by
* {@link #setSslPropertiesLocation(Resource)} or {@link #setTrustStoreType}
* @return the trust store type.
* @since 1.6.2
*/
protected String getTrustStoreType() {
if (this.trustStoreType == null && this.sslProperties.getProperty(TRUST_STORE_TYPE) == null) {
return TRUST_STORE_DEFAULT_TYPE;
}
else if (this.trustStoreType != null) {
return this.trustStoreType;
}
else {
return this.sslProperties.getProperty(TRUST_STORE_TYPE);
}
}

/**
* Set the trust store type - overrides
* the property in {@link #setSslPropertiesLocation(Resource)}.
* @param trustStoreType the trust store type.
* @see java.security.KeyStore#getInstance(String)
* @since 1.6.2
*/
public void setTrustStoreType(String trustStoreType) {
this.trustStoreType = trustStoreType;
}

/**
* @param host the host.
* @see com.rabbitmq.client.ConnectionFactory#setHost(java.lang.String)
Expand Down Expand Up @@ -417,18 +488,20 @@ protected void setUpSSL() throws Exception {
Assert.state(StringUtils.hasText(keyStorePassword), KEY_STORE_PASS_PHRASE + " property required");
String trustStorePassword = getTrustStorePassphrase();
Assert.state(StringUtils.hasText(trustStorePassword), TRUST_STORE_PASS_PHRASE + " property required");
String keyStoreType = getKeyStoreType();
String trustStoreType = getTrustStoreType();
Resource keyStore = resolver.getResource(keyStoreName);
Resource trustStore = resolver.getResource(trustStoreName);
char[] keyPassphrase = keyStorePassword.toCharArray();
char[] trustPassphrase = trustStorePassword.toCharArray();

KeyStore ks = KeyStore.getInstance("PKCS12");
KeyStore ks = KeyStore.getInstance(keyStoreType);
ks.load(keyStore.getInputStream(), keyPassphrase);

KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, keyPassphrase);

KeyStore tks = KeyStore.getInstance("JKS");
KeyStore tks = KeyStore.getInstance(trustStoreType);
tks.load(trustStore.getInputStream(), trustPassphrase);

TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
Expand Down
Expand Up @@ -17,6 +17,7 @@
package org.springframework.amqp.rabbit.connection;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;

Expand All @@ -35,6 +36,7 @@

/**
* @author Gary Russell
* @author Heath Abelson
* @since 1.4.4
*
*/
Expand Down Expand Up @@ -79,4 +81,56 @@ public void testNoAlgNoProps() throws Exception {
verify(rabbitCf).useSslProtocol();
}

@Test
public void testTypeDefault() throws Exception {
RabbitConnectionFactoryBean fb = new RabbitConnectionFactoryBean();
assertEquals("PKCS12", fb.getKeyStoreType());
assertEquals("JKS", fb.getTrustStoreType());
}

@Test
public void testTypeProps() throws Exception {
RabbitConnectionFactoryBean fb = new RabbitConnectionFactoryBean();
fb.setSslPropertiesLocation(new ClassPathResource("ssl.properties"));
fb.afterPropertiesSet();
try {
fb.setUpSSL();
//Here we make sure the exception is thrown because setUpSSL() will fail.
// But we only care about having it load the props
fail("setupSSL should fail");
}
catch (Exception e) {
assertEquals("foo", fb.getKeyStoreType());
assertEquals("bar", fb.getTrustStoreType());
}
}

@Test
public void testTypeSettersNoProps() throws Exception {
RabbitConnectionFactoryBean fb = new RabbitConnectionFactoryBean();
fb.setKeyStoreType("alice");
fb.setTrustStoreType("bob");
assertEquals("alice", fb.getKeyStoreType());
assertEquals("bob", fb.getTrustStoreType());
}

@Test
public void testTypeSettersOverrideProps() throws Exception {
RabbitConnectionFactoryBean fb = new RabbitConnectionFactoryBean();
fb.setSslPropertiesLocation(new ClassPathResource("ssl.properties"));
fb.afterPropertiesSet();
fb.setKeyStoreType("alice");
fb.setTrustStoreType("bob");
try {
fb.setUpSSL();
// Here we make sure the exception is thrown because setUpSSL() will fail.
//But we only care about having it load the props
fail("setupSSL should fail");
}
catch (Exception e) {
assertEquals("alice", fb.getKeyStoreType());
assertEquals("bob", fb.getTrustStoreType());
}
}

}
2 changes: 2 additions & 0 deletions spring-rabbit/src/test/resources/ssl.properties
Expand Up @@ -2,3 +2,5 @@ keyStore=file:/path/to/client/keycert.p12
trustStore=file:/path/to/client/truststore
keyStore.passPhrase=secret
trustStore.passPhrase=secret
keyStore.type=foo
trustStore.type=bar

0 comments on commit 208775d

Please sign in to comment.