Skip to content

Commit

Permalink
Test blocking IO and NIO in hostname verification test
Browse files Browse the repository at this point in the history
Not costly to test both IO modes and makes iterating easier.

References #394
  • Loading branch information
acogoluegnes committed Aug 22, 2018
1 parent fcc3dbb commit 7da0fd3
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 78 deletions.
14 changes: 1 addition & 13 deletions src/test/java/com/rabbitmq/client/test/BrokerTestCase.java
Original file line number Diff line number Diff line change
Expand Up @@ -352,18 +352,6 @@ protected String generateExchangeName() {
}

protected SSLContext getSSLContext() throws NoSuchAlgorithmException {
SSLContext c = null;

// pick the first protocol available, preferring TLSv1.2, then TLSv1,
// falling back to SSLv3 if running on an ancient/crippled JDK
for(String proto : Arrays.asList("TLSv1.2", "TLSv1", "SSLv3")) {
try {
c = SSLContext.getInstance(proto);
return c;
} catch (NoSuchAlgorithmException x) {
// keep trying
}
}
throw new NoSuchAlgorithmException();
return TestUtils.getSSLContext();
}
}
19 changes: 19 additions & 0 deletions src/test/java/com/rabbitmq/client/test/TestUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@
import com.rabbitmq.tools.Host;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.Callable;
Expand Down Expand Up @@ -64,6 +67,22 @@ public static void close(Connection connection) {
}
}

public static SSLContext getSSLContext() throws NoSuchAlgorithmException {
SSLContext c = null;

// pick the first protocol available, preferring TLSv1.2, then TLSv1,
// falling back to SSLv3 if running on an ancient/crippled JDK
for(String proto : Arrays.asList("TLSv1.2", "TLSv1", "SSLv3")) {
try {
c = SSLContext.getInstance(proto);
return c;
} catch (NoSuchAlgorithmException x) {
// keep trying
}
}
throw new NoSuchAlgorithmException();
}

public static boolean isVersion37orLater(Connection connection) {
String currentVersion = null;
try {
Expand Down
136 changes: 71 additions & 65 deletions src/test/java/com/rabbitmq/client/test/ssl/HostnameVerification.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,87 +18,93 @@
import com.rabbitmq.client.Address;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.test.TestUtils;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.TrustManagerFactory;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.concurrent.TimeoutException;
import java.util.function.Consumer;

import static com.rabbitmq.client.test.TestUtils.getSSLContext;
import static java.util.Collections.singletonList;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;

public class HostnameVerification extends UnverifiedConnection {

public void openConnection()
throws IOException, TimeoutException {
try {
String keystorePath = System.getProperty("test-keystore.ca");
assertNotNull(keystorePath);
String keystorePasswd = System.getProperty("test-keystore.password");
assertNotNull(keystorePasswd);
char[] keystorePassword = keystorePasswd.toCharArray();

KeyStore tks = KeyStore.getInstance("JKS");
tks.load(new FileInputStream(keystorePath), keystorePassword);

TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(tks);

String p12Path = System.getProperty("test-client-cert.path");
assertNotNull(p12Path);
String p12Passwd = System.getProperty("test-client-cert.password");
assertNotNull(p12Passwd);
KeyStore ks = KeyStore.getInstance("PKCS12");
char[] p12Password = p12Passwd.toCharArray();
ks.load(new FileInputStream(p12Path), p12Password);

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

SSLContext c = getSSLContext();
c.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
c.init(null, tmf.getTrustManagers(), null);

connectionFactory = TestUtils.connectionFactory();
connectionFactory.useSslProtocol(c);
connectionFactory.enableHostnameVerification();
} catch (NoSuchAlgorithmException ex) {
throw new IOException(ex.toString());
} catch (KeyManagementException ex) {
throw new IOException(ex.toString());
} catch (KeyStoreException ex) {
throw new IOException(ex.toString());
} catch (CertificateException ex) {
throw new IOException(ex.toString());
} catch (UnrecoverableKeyException ex) {
throw new IOException(ex.toString());
}

try {
connection = connectionFactory.newConnection(
() -> singletonList(new Address("127.0.0.1", ConnectionFactory.DEFAULT_AMQP_OVER_SSL_PORT)));
fail("The server certificate isn't issued for 127.0.0.1, the TLS handshake should have failed");
} catch (SSLHandshakeException ignored) {
} catch (IOException e) {
fail();
}
@RunWith(Parameterized.class)
public class HostnameVerification {

static SSLContext sslContext;
@Parameterized.Parameter
public Consumer<ConnectionFactory> customizer;

@Parameterized.Parameters
public static Object[] data() {
return new Object[] {
blockingIo(enableHostnameVerification()),
nio(enableHostnameVerification()),
};
}

private static Consumer<ConnectionFactory> blockingIo(final Consumer<ConnectionFactory> customizer) {
return connectionFactory -> {
connectionFactory.useBlockingIo();
customizer.accept(connectionFactory);
};
}

public void openChannel() {
private static Consumer<ConnectionFactory> nio(final Consumer<ConnectionFactory> customizer) {
return connectionFactory -> {
connectionFactory.useNio();
customizer.accept(connectionFactory);
};
}

private static Consumer<ConnectionFactory> enableHostnameVerification() {
return connectionFactory -> connectionFactory.enableHostnameVerification();
}

@BeforeClass
public static void initCrypto() throws Exception {
String keystorePath = System.getProperty("test-keystore.ca");
assertNotNull(keystorePath);
String keystorePasswd = System.getProperty("test-keystore.password");
assertNotNull(keystorePasswd);
char[] keystorePassword = keystorePasswd.toCharArray();

KeyStore tks = KeyStore.getInstance("JKS");
tks.load(new FileInputStream(keystorePath), keystorePassword);

TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(tks);

String p12Path = System.getProperty("test-client-cert.path");
assertNotNull(p12Path);
String p12Passwd = System.getProperty("test-client-cert.password");
assertNotNull(p12Passwd);
KeyStore ks = KeyStore.getInstance("PKCS12");
char[] p12Password = p12Passwd.toCharArray();
ks.load(new FileInputStream(p12Path), p12Password);

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

sslContext = getSSLContext();
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
}

@Test
public void sSL() {
@Test(expected = SSLHandshakeException.class)
public void hostnameVerificationFailsBecauseCertificateNotIssuedForLoopbackInterface() throws Exception {
ConnectionFactory connectionFactory = TestUtils.connectionFactory();
connectionFactory.useSslProtocol(sslContext);
customizer.accept(connectionFactory);
connectionFactory.newConnection(
() -> singletonList(new Address("127.0.0.1", ConnectionFactory.DEFAULT_AMQP_OVER_SSL_PORT)));
fail("The server certificate isn't issued for 127.0.0.1, the TLS handshake should have failed");
}
}

0 comments on commit 7da0fd3

Please sign in to comment.