AMQP-626: Add keystore\truststore type setters

JIRA: https://jira.spring.io/browse/AMQP-626
Fixes GH-436 (https://github.com/spring-projects/spring-amqp/issues/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
This commit is contained in:
Heath Abelson
2016-07-27 15:10:15 -04:00
committed by Artem Bilan
parent 83c499f1cf
commit 208775dd2e
3 changed files with 131 additions and 2 deletions

View File

@@ -57,6 +57,7 @@ import com.rabbitmq.client.SocketConfigurator;
* Override {@link #setUpSSL()} to take complete control over setting up SSL.
*
* @author Gary Russell
* @author Heath Abelson
*
* @since 1.4
*/
@@ -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();
@@ -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;
@@ -225,6 +238,64 @@ public class RabbitConnectionFactoryBean extends AbstractFactoryBean<ConnectionF
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)
@@ -417,18 +488,20 @@ public class RabbitConnectionFactoryBean extends AbstractFactoryBean<ConnectionF
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");

View File

@@ -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;
@@ -35,6 +36,7 @@ import com.rabbitmq.client.ConnectionFactory;
/**
* @author Gary Russell
* @author Heath Abelson
* @since 1.4.4
*
*/
@@ -79,4 +81,56 @@ public class SSLConnectionTests {
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());
}
}
}

View File

@@ -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