/*
* Copyright 2014-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.amqp.rabbit.connection;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import java.security.SecureRandom;
import java.util.Collections;
import javax.net.ssl.SSLContext;
import org.apache.commons.logging.Log;
import org.junit.Ignore;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import org.springframework.amqp.utils.test.TestUtils;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.core.io.ClassPathResource;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
/**
* @author Gary Russell
* @author Heath Abelson
* @author Hareendran
*
* @since 1.4.4
*
*/
public class SSLConnectionTests {
@Test
@Ignore
public void test() throws Exception {
RabbitConnectionFactoryBean fb = new RabbitConnectionFactoryBean();
fb.setUseSSL(true);
fb.setSslPropertiesLocation(new ClassPathResource("ssl.properties"));
fb.setClientProperties(Collections.<String, Object>singletonMap("foo", "bar"));
fb.afterPropertiesSet();
ConnectionFactory cf = fb.getObject();
assertEquals("bar", cf.getClientProperties().get("foo"));
Connection conn = cf.newConnection();
Channel chan = conn.createChannel();
chan.close();
conn.close();
}
@Test
public void testAlgNoProps() throws Exception {
RabbitConnectionFactoryBean fb = new RabbitConnectionFactoryBean();
ConnectionFactory rabbitCf = spy(TestUtils.getPropertyValue(fb, "connectionFactory", ConnectionFactory.class));
new DirectFieldAccessor(fb).setPropertyValue("connectionFactory", rabbitCf);
fb.setUseSSL(true);
fb.setSslAlgorithm("TLSv1.2");
fb.afterPropertiesSet();
fb.getObject();
verify(rabbitCf).useSslProtocol(Mockito.any(SSLContext.class));
}
@Test
public void testNoAlgNoProps() throws Exception {
RabbitConnectionFactoryBean fb = new RabbitConnectionFactoryBean();
ConnectionFactory rabbitCf = spy(TestUtils.getPropertyValue(fb, "connectionFactory", ConnectionFactory.class));
new DirectFieldAccessor(fb).setPropertyValue("connectionFactory", rabbitCf);
fb.setUseSSL(true);
fb.afterPropertiesSet();
fb.getObject();
verify(rabbitCf).useSslProtocol(Mockito.any(SSLContext.class));
}
@Test
public void testUseSslProtocolShouldNotBeCalled() throws Exception {
RabbitConnectionFactoryBean fb = new RabbitConnectionFactoryBean();
ConnectionFactory rabbitCf = spy(TestUtils.getPropertyValue(fb, "connectionFactory", ConnectionFactory.class));
new DirectFieldAccessor(fb).setPropertyValue("connectionFactory", rabbitCf);
fb.setUseSSL(true);
fb.afterPropertiesSet();
fb.getObject();
verify(rabbitCf, never()).useSslProtocol();
}
@Test
public void testSkipServerCertificate() throws Exception {
RabbitConnectionFactoryBean fb = new RabbitConnectionFactoryBean();
ConnectionFactory rabbitCf = spy(TestUtils.getPropertyValue(fb, "connectionFactory", ConnectionFactory.class));
new DirectFieldAccessor(fb).setPropertyValue("connectionFactory", rabbitCf);
fb.setUseSSL(true);
fb.setSkipServerCertificateValidation(true);
fb.afterPropertiesSet();
fb.getObject();
verify(rabbitCf).useSslProtocol();
verify(rabbitCf).useSslProtocol("TLSv1.2");
}
@Test
public void testSkipServerCertificateWithAlgorithm() throws Exception {
RabbitConnectionFactoryBean fb = new RabbitConnectionFactoryBean();
ConnectionFactory rabbitCf = spy(TestUtils.getPropertyValue(fb, "connectionFactory", ConnectionFactory.class));
new DirectFieldAccessor(fb).setPropertyValue("connectionFactory", rabbitCf);
fb.setUseSSL(true);
fb.setSslAlgorithm("TLSv1.2");
fb.setSkipServerCertificateValidation(true);
fb.afterPropertiesSet();
fb.getObject();
verify(rabbitCf).useSslProtocol("TLSv1.2");
}
@Test
public void testUseSslProtocolWithProtocolShouldNotBeCalled() throws Exception {
RabbitConnectionFactoryBean fb = new RabbitConnectionFactoryBean();
ConnectionFactory rabbitCf = spy(TestUtils.getPropertyValue(fb, "connectionFactory", ConnectionFactory.class));
new DirectFieldAccessor(fb).setPropertyValue("connectionFactory", rabbitCf);
fb.setUseSSL(true);
fb.setSslAlgorithm("TLSv1.2");
fb.afterPropertiesSet();
fb.getObject();
verify(rabbitCf, never()).useSslProtocol("TLSv1.2");
}
@Test
public void testKSTS() throws Exception {
RabbitConnectionFactoryBean fb = new RabbitConnectionFactoryBean();
Log logger = spy(TestUtils.getPropertyValue(fb, "logger", Log.class));
given(logger.isDebugEnabled()).willReturn(true);
new DirectFieldAccessor(fb).setPropertyValue("logger", logger);
fb.setUseSSL(true);
fb.setKeyStoreType("JKS");
fb.setKeyStoreResource(new ClassPathResource("test.ks"));
fb.setKeyStorePassphrase("secret");
fb.setTrustStoreResource(new ClassPathResource("test.truststore.ks"));
fb.setKeyStorePassphrase("secret");
fb.setSecureRandom(SecureRandom.getInstanceStrong());
fb.afterPropertiesSet();
fb.getObject();
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
verify(logger).debug(captor.capture());
final String log = captor.getValue();
assertThat(log, allOf(containsString("KM: ["), containsString("TM: ["), containsString("random: java.")));
}
@Test
public void testNullTS() throws Exception {
RabbitConnectionFactoryBean fb = new RabbitConnectionFactoryBean();
Log logger = spy(TestUtils.getPropertyValue(fb, "logger", Log.class));
given(logger.isDebugEnabled()).willReturn(true);
new DirectFieldAccessor(fb).setPropertyValue("logger", logger);
fb.setUseSSL(true);
fb.setKeyStoreType("JKS");
fb.setKeyStoreResource(new ClassPathResource("test.ks"));
fb.setKeyStorePassphrase("secret");
fb.afterPropertiesSet();
fb.getObject();
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
verify(logger).debug(captor.capture());
final String log = captor.getValue();
assertThat(log, allOf(containsString("KM: ["), containsString("TM: null"), containsString("random: null")));
}
@Test
public void testNullKS() throws Exception {
RabbitConnectionFactoryBean fb = new RabbitConnectionFactoryBean();
Log logger = spy(TestUtils.getPropertyValue(fb, "logger", Log.class));
given(logger.isDebugEnabled()).willReturn(true);
new DirectFieldAccessor(fb).setPropertyValue("logger", logger);
fb.setUseSSL(true);
fb.setKeyStoreType("JKS");
fb.setTrustStoreResource(new ClassPathResource("test.truststore.ks"));
fb.setKeyStorePassphrase("secret");
fb.afterPropertiesSet();
fb.getObject();
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
verify(logger).debug(captor.capture());
final String log = captor.getValue();
assertThat(log, allOf(containsString("KM: null"), containsString("TM: ["), containsString("random: null")));
}
@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());
}
}
}