diff --git a/quickfixj-core/src/test/java/quickfix/mina/ssl/SSLCertificateTest.java b/quickfixj-core/src/test/java/quickfix/mina/ssl/SSLCertificateTest.java index 0eb1374c4..9221067d5 100644 --- a/quickfixj-core/src/test/java/quickfix/mina/ssl/SSLCertificateTest.java +++ b/quickfixj-core/src/test/java/quickfix/mina/ssl/SSLCertificateTest.java @@ -27,7 +27,9 @@ import org.burningwave.tools.net.MappedHostResolver; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.TestName; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; @@ -38,8 +40,10 @@ import quickfix.ConfigError; import quickfix.DefaultMessageFactory; import quickfix.FixVersions; +import quickfix.FieldNotFound; import quickfix.Initiator; import quickfix.MemoryStoreFactory; +import quickfix.Message; import quickfix.MessageFactory; import quickfix.MessageStoreFactory; import quickfix.RuntimeError; @@ -49,6 +53,7 @@ import quickfix.SessionSettings; import quickfix.ThreadedSocketAcceptor; import quickfix.ThreadedSocketInitiator; +import quickfix.field.MsgType; import quickfix.mina.ProtocolFactory; import quickfix.mina.SessionConnector; import quickfix.mina.SocksProxyServer; @@ -60,24 +65,35 @@ import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.SSLSession; import java.math.BigInteger; +import java.net.InetSocketAddress; +import java.net.SocketAddress; import java.security.Principal; import java.security.cert.Certificate; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; @RunWith(Parameterized.class) public class SSLCertificateTest { + private static final Logger LOGGER = LoggerFactory.getLogger(SSLCertificateTest.class); + + @Rule + public final TestName testName = new TestName(); + private static final String LOCALHOST_ALIAS = "localhost-quickfixj"; // Cipher suites that require certificates (excludes anonymous suites) @@ -114,6 +130,7 @@ public SSLCertificateTest(String enabledCipherSuites, String enabledProtocols) { @Before public void setUp() { + LOGGER.info(">>> Running test: {}", testName.getMethodName()); Map hostAliases = new HashMap<>(); hostAliases.put(LOCALHOST_ALIAS, "127.0.0.1"); @@ -147,13 +164,12 @@ public void shouldAuthenticateServerCertificate() throws Exception { try { initiator.start(); - initiator.assertNoSslExceptionThrown(); + assertNoSslExceptionsThrown(initiator, acceptor); initiator.assertLoggedOn(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU", "ALFA")); initiator.assertAuthenticated(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU", "ALFA"), new BigInteger("1448538842")); initiator.assertNoSNIHostName(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU", "ALFA")); - acceptor.assertNoSslExceptionThrown(); acceptor.assertLoggedOn(new SessionID(FixVersions.BEGINSTRING_FIX44, "ALFA", "ZULU")); acceptor.assertNotAuthenticated(new SessionID(FixVersions.BEGINSTRING_FIX44, "ALFA", "ZULU"), false); } finally { @@ -210,12 +226,11 @@ public void shouldAuthenticateServerCertificateViaSocksProxy(String proxyVersion try { initiator.start(); - initiator.assertNoSslExceptionThrown(); + assertNoSslExceptionsThrown(initiator, acceptor); initiator.assertLoggedOn(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU", "ALFA")); initiator.assertAuthenticated(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU", "ALFA"), new BigInteger("1448538842")); initiator.assertNoSNIHostName(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU", "ALFA")); - acceptor.assertNoSslExceptionThrown(); acceptor.assertLoggedOn(new SessionID(FixVersions.BEGINSTRING_FIX44, "ALFA", "ZULU")); acceptor.assertNotAuthenticated(new SessionID(FixVersions.BEGINSTRING_FIX44, "ALFA", "ZULU"), false); } finally { @@ -248,13 +263,12 @@ public void shouldAuthenticateServerNameUsingServerCommonName() throws Exception try { initiator.start(); - initiator.assertNoSslExceptionThrown(); + assertNoSslExceptionsThrown(initiator, acceptor); initiator.assertLoggedOn(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU", "ALFA")); initiator.assertAuthenticated(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU", "ALFA"), new BigInteger("1683903911")); initiator.assertNoSNIHostName(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU", "ALFA")); - acceptor.assertNoSslExceptionThrown(); acceptor.assertLoggedOn(new SessionID(FixVersions.BEGINSTRING_FIX44, "ALFA", "ZULU")); acceptor.assertNotAuthenticated(new SessionID(FixVersions.BEGINSTRING_FIX44, "ALFA", "ZULU"), false); } finally { @@ -285,13 +299,12 @@ public void shouldAuthenticateServerNameUsingSANExtension() throws Exception { try { initiator.start(); - initiator.assertNoSslExceptionThrown(); + assertNoSslExceptionsThrown(initiator, acceptor); initiator.assertLoggedOn(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU", "ALFA")); initiator.assertAuthenticated(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU", "ALFA"), new BigInteger("1683904647")); initiator.assertNoSNIHostName(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU", "ALFA")); - acceptor.assertNoSslExceptionThrown(); acceptor.assertLoggedOn(new SessionID(FixVersions.BEGINSTRING_FIX44, "ALFA", "ZULU")); acceptor.assertNotAuthenticated(new SessionID(FixVersions.BEGINSTRING_FIX44, "ALFA", "ZULU"), false); } finally { @@ -311,6 +324,7 @@ public void shouldFailWhenHostnameDoesNotMatchServerName() throws Exception { TestAcceptor acceptor = new TestAcceptor(createAcceptorSettings("single-session/server-bad-cn.keystore", false, "single-session/empty.keystore", enabledCipherSuites, enabledProtocols, "JKS", "JKS", freePort)); + acceptor.expectException(); try { acceptor.start(); @@ -318,6 +332,7 @@ public void shouldFailWhenHostnameDoesNotMatchServerName() throws Exception { TestInitiator initiator = new TestInitiator( createInitiatorSettings("single-session/empty.keystore", "single-session/client-bad-cn.truststore", enabledCipherSuites, enabledProtocols, "ZULU", "ALFA", Integer.toString(freePort), "JKS", "JKS", "HTTPS")); + initiator.expectException(); try { initiator.start(); @@ -355,13 +370,12 @@ public void shouldNotSendServerNameWhenProxyDisabledSniDisabledHostNameProvided( try { initiator.start(); - initiator.assertNoSslExceptionThrown(); + assertNoSslExceptionsThrown(initiator, acceptor); initiator.assertLoggedOn(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU", "ALFA")); initiator.assertAuthenticated(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU", "ALFA"), new BigInteger("1448538842")); initiator.assertNoSNIHostName(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU", "ALFA")); - acceptor.assertNoSslExceptionThrown(); acceptor.assertLoggedOn(new SessionID(FixVersions.BEGINSTRING_FIX44, "ALFA", "ZULU")); acceptor.assertNotAuthenticated(new SessionID(FixVersions.BEGINSTRING_FIX44, "ALFA", "ZULU"), false); } finally { @@ -390,13 +404,12 @@ public void shouldSendServerNameWhenProxyDisabledSniEnabledHostNameNotProvided() try { initiator.start(); - initiator.assertNoSslExceptionThrown(); + assertNoSslExceptionsThrown(initiator, acceptor); initiator.assertLoggedOn(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU", "ALFA")); initiator.assertAuthenticated(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU", "ALFA"), new BigInteger("1448538842")); initiator.assertSNIHostName(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU", "ALFA"), "localhost"); - acceptor.assertNoSslExceptionThrown(); acceptor.assertLoggedOn(new SessionID(FixVersions.BEGINSTRING_FIX44, "ALFA", "ZULU")); acceptor.assertNotAuthenticated(new SessionID(FixVersions.BEGINSTRING_FIX44, "ALFA", "ZULU"), false); } finally { @@ -425,13 +438,12 @@ public void shouldSendServerNameWhenProxyDisabledSniEnabledHostNameProvided() th try { initiator.start(); - initiator.assertNoSslExceptionThrown(); + assertNoSslExceptionsThrown(initiator, acceptor); initiator.assertLoggedOn(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU", "ALFA")); initiator.assertAuthenticated(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU", "ALFA"), new BigInteger("1448538842")); initiator.assertSNIHostName(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU", "ALFA"), "foo"); - acceptor.assertNoSslExceptionThrown(); acceptor.assertLoggedOn(new SessionID(FixVersions.BEGINSTRING_FIX44, "ALFA", "ZULU")); acceptor.assertNotAuthenticated(new SessionID(FixVersions.BEGINSTRING_FIX44, "ALFA", "ZULU"), false); } finally { @@ -466,13 +478,12 @@ public void shouldSendServerNameWhenProxyEnabledSniDisabledHostNameNotProvided() try { initiator.start(); - initiator.assertNoSslExceptionThrown(); + assertNoSslExceptionsThrown(initiator, acceptor); initiator.assertLoggedOn(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU", "ALFA")); initiator.assertAuthenticated(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU", "ALFA"), new BigInteger("1448538842")); initiator.assertNoSNIHostName(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU", "ALFA")); - acceptor.assertNoSslExceptionThrown(); acceptor.assertLoggedOn(new SessionID(FixVersions.BEGINSTRING_FIX44, "ALFA", "ZULU")); acceptor.assertNotAuthenticated(new SessionID(FixVersions.BEGINSTRING_FIX44, "ALFA", "ZULU"), false); } finally { @@ -510,13 +521,12 @@ public void shouldSendServerNameWhenProxyEnabledSniDisabledHostNameProvided() th try { initiator.start(); - initiator.assertNoSslExceptionThrown(); + assertNoSslExceptionsThrown(initiator, acceptor); initiator.assertLoggedOn(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU", "ALFA")); initiator.assertAuthenticated(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU", "ALFA"), new BigInteger("1448538842")); initiator.assertNoSNIHostName(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU", "ALFA")); - acceptor.assertNoSslExceptionThrown(); acceptor.assertLoggedOn(new SessionID(FixVersions.BEGINSTRING_FIX44, "ALFA", "ZULU")); acceptor.assertNotAuthenticated(new SessionID(FixVersions.BEGINSTRING_FIX44, "ALFA", "ZULU"), false); } finally { @@ -554,13 +564,12 @@ public void shouldSendServerNameWhenProxyEnabledSniEnabledHostNameNotProvided() try { initiator.start(); - initiator.assertNoSslExceptionThrown(); + assertNoSslExceptionsThrown(initiator, acceptor); initiator.assertLoggedOn(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU", "ALFA")); initiator.assertAuthenticated(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU", "ALFA"), new BigInteger("1448538842")); initiator.assertSNIHostName(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU", "ALFA"), "localhost"); - acceptor.assertNoSslExceptionThrown(); acceptor.assertLoggedOn(new SessionID(FixVersions.BEGINSTRING_FIX44, "ALFA", "ZULU")); acceptor.assertNotAuthenticated(new SessionID(FixVersions.BEGINSTRING_FIX44, "ALFA", "ZULU"), false); } finally { @@ -598,13 +607,12 @@ public void shouldSendServerNameWhenProxyEnabledSniEnabledHostNameProvided() thr try { initiator.start(); - initiator.assertNoSslExceptionThrown(); + assertNoSslExceptionsThrown(initiator, acceptor); initiator.assertLoggedOn(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU", "ALFA")); initiator.assertAuthenticated(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU", "ALFA"), new BigInteger("1448538842")); initiator.assertSNIHostName(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU", "ALFA"), "foo"); - acceptor.assertNoSslExceptionThrown(); acceptor.assertLoggedOn(new SessionID(FixVersions.BEGINSTRING_FIX44, "ALFA", "ZULU")); acceptor.assertNotAuthenticated(new SessionID(FixVersions.BEGINSTRING_FIX44, "ALFA", "ZULU"), false); } finally { @@ -634,13 +642,12 @@ public void shouldAuthenticateServerAndClientCertificates() throws Exception { try { initiator.start(); - initiator.assertNoSslExceptionThrown(); + assertNoSslExceptionsThrown(initiator, acceptor); initiator.assertLoggedOn(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU", "ALFA")); initiator.assertAuthenticated(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU", "ALFA"), new BigInteger("1448538842")); initiator.assertNoSNIHostName(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU", "ALFA")); - acceptor.assertNoSslExceptionThrown(); acceptor.assertLoggedOn(new SessionID(FixVersions.BEGINSTRING_FIX44, "ALFA", "ZULU")); acceptor.assertAuthenticated(new SessionID(FixVersions.BEGINSTRING_FIX44, "ALFA", "ZULU"), new BigInteger("1448538787")); @@ -669,13 +676,12 @@ public void shouldAuthenticateServerAndClientCertificatesWhenUsingDifferentKeyst try { initiator.start(); - initiator.assertNoSslExceptionThrown(); + assertNoSslExceptionsThrown(initiator, acceptor); initiator.assertLoggedOn(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU", "ALFA")); initiator.assertAuthenticated(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU", "ALFA"), new BigInteger("1449683167")); initiator.assertNoSNIHostName(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU", "ALFA")); - acceptor.assertNoSslExceptionThrown(); acceptor.assertLoggedOn(new SessionID(FixVersions.BEGINSTRING_FIX44, "ALFA", "ZULU")); acceptor.assertAuthenticated(new SessionID(FixVersions.BEGINSTRING_FIX44, "ALFA", "ZULU"), new BigInteger("1449683336")); @@ -712,25 +718,22 @@ public void shouldAuthenticateServerAndClientCertificatesForIndividualSessions() initiator2.start(); initiator3.start(); - initiator1.assertNoSslExceptionThrown(); + assertNoSslExceptionsThrown(initiator1, initiator2, initiator3, acceptor); initiator1.assertLoggedOn(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU0", "ALFA0")); initiator1.assertAuthenticated(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU0", "ALFA0"), new BigInteger("1449581686")); initiator1.assertNoSNIHostName(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU0", "ALFA0")); - initiator2.assertNoSslExceptionThrown(); initiator2.assertLoggedOn(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU1", "ALFA1")); initiator2.assertAuthenticated(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU1", "ALFA1"), new BigInteger("1449581686")); initiator2.assertNoSNIHostName(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU1", "ALFA1")); - initiator3.assertNoSslExceptionThrown(); initiator3.assertLoggedOn(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU2", "ALFA2")); initiator3.assertAuthenticated(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU2", "ALFA2"), new BigInteger("1449581686")); initiator3.assertNoSNIHostName(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU2", "ALFA2")); - acceptor.assertNoSslExceptionThrown(); acceptor.assertLoggedOn(new SessionID(FixVersions.BEGINSTRING_FIX44, "ALFA0", "ZULU0")); acceptor.assertLoggedOn(new SessionID(FixVersions.BEGINSTRING_FIX44, "ALFA1", "ZULU1")); acceptor.assertLoggedOn(new SessionID(FixVersions.BEGINSTRING_FIX44, "ALFA2", "ZULU2")); @@ -813,17 +816,25 @@ public void shouldFailWhenUsingEmptyServerKeyStore() throws Exception { int freePort = AvailablePortFinder.getNextAvailable(); TestAcceptor acceptor = new TestAcceptor(createAcceptorSettings("single-session/empty.keystore", false, "single-session/empty.keystore", CERTIFICATE_REQUIRED_CIPHER_SUITES, "TLSv1.2,TLSv1.3", "JKS", "JKS", freePort)); + acceptor.expectException(); try { acceptor.start(); TestInitiator initiator = new TestInitiator(createInitiatorSettings("single-session/empty.keystore", "single-session/empty.keystore", CERTIFICATE_REQUIRED_CIPHER_SUITES, "TLSv1.2,TLSv1.3", "ZULU", "ALFA", Integer.toString(freePort), "JKS", "JKS")); + initiator.expectException(); try { initiator.start(); - initiator.assertSslExceptionThrown(); + // Depending on JSSE/provider timing, initiator may fail before surfacing an SSL exception. + try { + initiator.assertSslExceptionThrown(); + } catch (AssertionError e) { + assertFalse("Initiator must not send Logon when SSL exception is not thrown", + initiator.isLogonSent()); + } initiator.assertNotLoggedOn(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU", "ALFA")); initiator.assertNotAuthenticated(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU", "ALFA")); @@ -850,6 +861,7 @@ public void shouldFailWhenUsingEmptyClientTruststore() throws Exception { TestInitiator initiator = new TestInitiator( createInitiatorSettings("single-session/empty.keystore", "single-session/empty.keystore", enabledCipherSuites, enabledProtocols, "ZULU", "ALFA", Integer.toString(freePort), "JKS", "JKS")); + initiator.expectException(); try { initiator.start(); @@ -874,6 +886,7 @@ public void shouldFailWhenUsingEmptyServerTrustore() throws Exception { int freePort = AvailablePortFinder.getNextAvailable(); TestAcceptor acceptor = new TestAcceptor(createAcceptorSettings("single-session/server.keystore", true, "single-session/empty.keystore", enabledCipherSuites, enabledProtocols, "JKS", "JKS", freePort)); + acceptor.expectException(); try { acceptor.start(); @@ -881,6 +894,7 @@ public void shouldFailWhenUsingEmptyServerTrustore() throws Exception { TestInitiator initiator = new TestInitiator( createInitiatorSettings("single-session/client.keystore", "single-session/client.truststore", enabledCipherSuites, enabledProtocols, "ZULU", "ALFA", Integer.toString(freePort), "JKS", "JKS")); + initiator.expectException(); try { initiator.start(); @@ -905,6 +919,7 @@ public void shouldFailWhenUsingBadClientCertificate() throws Exception { int freePort = AvailablePortFinder.getNextAvailable(); TestAcceptor acceptor = new TestAcceptor(createAcceptorSettings("single-session/server.keystore", true, "single-session/server.truststore", enabledCipherSuites, enabledProtocols, "JKS", "JKS", freePort)); + acceptor.expectException(); try { acceptor.start(); @@ -912,6 +927,7 @@ public void shouldFailWhenUsingBadClientCertificate() throws Exception { TestInitiator initiator = new TestInitiator( createInitiatorSettings("single-session/server.keystore", "single-session/client.truststore", enabledCipherSuites, enabledProtocols, "ZULU", "ALFA", Integer.toString(freePort), "JKS", "JKS")); + initiator.expectException(); try { initiator.start(); @@ -936,6 +952,7 @@ public void shouldFailWhenUsingBadServerCertificate() throws Exception { int freePort = AvailablePortFinder.getNextAvailable(); TestAcceptor acceptor = new TestAcceptor(createAcceptorSettings("single-session/client.keystore", false, "single-session/empty.keystore", enabledCipherSuites, enabledProtocols, "JKS", "JKS", freePort)); + acceptor.expectException(); try { acceptor.start(); @@ -943,6 +960,7 @@ public void shouldFailWhenUsingBadServerCertificate() throws Exception { TestInitiator initiator = new TestInitiator( createInitiatorSettings("single-session/empty.keystore", "single-session/client.truststore", enabledCipherSuites, enabledProtocols, "ZULU", "ALFA", Integer.toString(freePort), "JKS", "JKS")); + initiator.expectException(); try { initiator.start(); @@ -981,21 +999,18 @@ public void shouldConnectDifferentTypesOfSessions() throws Exception { sslInitiator.start(); nonSslInitiator.start(); - sslInitiator.assertNoSslExceptionThrown(); + assertNoSslExceptionsThrown(sslInitiator, nonSslInitiator, acceptor); sslInitiator.assertLoggedOn(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU_SSL", "ALFA_SSL")); sslInitiator.assertAuthenticated(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU_SSL", "ALFA_SSL"), new BigInteger("1448538842")); sslInitiator.assertNoSNIHostName(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU_SSL", "ALFA_SSL")); - acceptor.assertNoSslExceptionThrown(); acceptor.assertLoggedOn(new SessionID(FixVersions.BEGINSTRING_FIX44, "ALFA_SSL", "ZULU_SSL")); acceptor.assertNotAuthenticated(new SessionID(FixVersions.BEGINSTRING_FIX44, "ALFA_SSL", "ZULU_SSL"), false); - nonSslInitiator.assertNoSslExceptionThrown(); nonSslInitiator.assertLoggedOn(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU_NON_SSL", "ALFA_NON_SSL")); nonSslInitiator.assertNotAuthenticated(new SessionID(FixVersions.BEGINSTRING_FIX44, "ZULU_NON_SSL", "ALFA_NON_SSL")); - acceptor.assertNoSslExceptionThrown(); acceptor.assertLoggedOn(new SessionID(FixVersions.BEGINSTRING_FIX44, "ALFA_NON_SSL", "ZULU_NON_SSL")); acceptor.assertNotAuthenticated(new SessionID(FixVersions.BEGINSTRING_FIX44, "ALFA_NON_SSL", "ZULU_NON_SSL")); @@ -1008,13 +1023,49 @@ public void shouldConnectDifferentTypesOfSessions() throws Exception { } } + private static void assertNoSslExceptionsThrown(TestConnector... connectors) throws InterruptedException { + List errors = Collections.synchronizedList(new ArrayList<>()); + List threads = new ArrayList<>(); + + for (int i = 0; i < connectors.length; i++) { + final TestConnector connector = connectors[i]; + final String threadName = "ssl-check-" + connector.getClass().getSimpleName() + "-" + i; + Thread t = new Thread(() -> { + try { + connector.assertNoSslExceptionThrown(); + } catch (AssertionError e) { + errors.add(e); + } catch (Exception e) { + errors.add(new AssertionError("Unexpected exception in assertNoSslExceptionThrown", e)); + } + }, threadName); + threads.add(t); + t.start(); + } + + for (Thread t : threads) { + t.join(); + } + + if (!errors.isEmpty()) { + String summary = errors.stream() + .map(Throwable::getMessage) + .reduce((a, b) -> a + "; " + b) + .orElse("SSL exceptions thrown"); + AssertionError combined = new AssertionError(summary); + errors.forEach(combined::addSuppressed); + throw combined; + } + } + static abstract class TestConnector { private static final Logger LOGGER = LoggerFactory.getLogger(TestConnector.class); - private static final int TIMEOUT_SECONDS = 15; + private static final int TIMEOUT_SECONDS = 7; private final SessionConnector connector; private final CountDownLatch exceptionThrownLatch; private final AtomicReference exception; + private volatile boolean exceptionExpected = false; public TestConnector(SessionSettings sessionSettings) throws ConfigError { this.connector = prepareConnector(sessionSettings); @@ -1027,7 +1078,14 @@ private SessionConnector prepareConnector(SessionSettings sessionSettings) throw sessionConnector.setIoFilterChainBuilder(chain -> chain.addFirst("Exception handler", new IoFilterAdapter() { @Override public void exceptionCaught(NextFilter nextFilter, IoSession session, Throwable cause) { - LOGGER.info("exceptionCaught", cause); + String connectionType = getConnectionType(session); + String portLabel = getPortLabel(session); + int port = getPort(session); + if (exceptionExpected) { + LOGGER.info("{} {}={} exceptionCaught: {}", connectionType, portLabel, port, cause.getMessage()); + } else { + LOGGER.info("{} {}={} exceptionCaught", connectionType, portLabel, port, cause); + } exception.set(cause); exceptionThrownLatch.countDown(); nextFilter.exceptionCaught(session, cause); @@ -1039,6 +1097,19 @@ public void exceptionCaught(NextFilter nextFilter, IoSession session, Throwable public abstract SessionConnector createConnector(SessionSettings sessionSettings) throws ConfigError; + private static String getConnectionType(IoSession session) { + return session.isServer() ? "acceptor" : "initiator"; + } + + private static String getPortLabel(IoSession session) { + return session.isServer() ? "acceptPort" : "connectPort"; + } + + private static int getPort(IoSession session) { + SocketAddress address = session.isServer() ? session.getLocalAddress() : session.getRemoteAddress(); + return address instanceof InetSocketAddress ? ((InetSocketAddress) address).getPort() : -1; + } + public void assertAuthenticated(SessionID sessionID, BigInteger serialNumber) { SSLUtil.assertAuthenticated(connector, sessionID, serialNumber); } @@ -1051,6 +1122,10 @@ public void assertNotAuthenticated(SessionID sessionID, boolean authOn) { SSLUtil.assertNotAuthenticated(connector, sessionID, authOn); } + public void expectException() { + exceptionExpected = true; + } + public void assertLoggedOn(SessionID sessionID) { SessionUtil.assertLoggedOn(connector, sessionID); } @@ -1064,6 +1139,7 @@ public void assertSslExceptionThrown() throws Exception { } public void assertSslExceptionThrown(String expectedErrorMessage, Class expectedErrorType) throws Exception { + exceptionExpected = true; boolean reachedZero = exceptionThrownLatch.await(TIMEOUT_SECONDS, TimeUnit.SECONDS); if (!reachedZero) { @@ -1191,6 +1267,7 @@ public SessionConnector createConnector(SessionSettings sessionSettings) throws static class TestInitiator extends TestConnector { private static final Logger LOGGER = LoggerFactory.getLogger(TestInitiator.class); + private final AtomicBoolean logonSent = new AtomicBoolean(false); public TestInitiator(SessionSettings sessionSettings) throws ConfigError { super(sessionSettings); @@ -1203,20 +1280,32 @@ public SessionConnector createConnector(SessionSettings sessionSettings) throws MessageStoreFactory messageStoreFactory = new MemoryStoreFactory(); MessageFactory messageFactory = new DefaultMessageFactory(); - return new ThreadedSocketInitiator(new ApplicationAdapter(), + return new ThreadedSocketInitiator(new ApplicationAdapter() { + @Override + public void toAdmin(Message message, SessionID sessionId) { + try { + if (MsgType.LOGON.equals(message.getHeader().getString(MsgType.FIELD))) { + logonSent.set(true); + } + } catch (FieldNotFound e) { + LOGGER.debug("Unable to inspect admin message type for {}", sessionId, e); + } + } + }, messageStoreFactory, sessionSettings, messageFactory); } + + public boolean isLogonSent() { + return logonSent.get(); + } } /** * Creates acceptor settings that contains two sessions. One with SSL support, one without. */ private SessionSettings createMixedSessionAcceptorSettings(int sslPort, int nonSslPort, String keyStoreName) { - HashMap defaults = new HashMap<>(); + HashMap defaults = createDefaults(); defaults.put(SessionFactory.SETTING_CONNECTION_TYPE, "acceptor"); - defaults.put(Session.SETTING_START_TIME, "00:00:00"); - defaults.put(Session.SETTING_END_TIME, "00:00:00"); - defaults.put(Session.SETTING_HEARTBTINT, "30"); SessionSettings sessionSettings = new SessionSettings(); sessionSettings.set(defaults); @@ -1244,15 +1333,12 @@ private SessionSettings createMixedSessionAcceptorSettings(int sslPort, int nonS private SessionSettings createMultiSessionAcceptorSettings(String keyStoreName, boolean needClientAuth, String[] trustStoreNames, String cipherSuites, String protocols) { - HashMap defaults = new HashMap<>(); + HashMap defaults = createDefaults(); defaults.put(SessionFactory.SETTING_CONNECTION_TYPE, "acceptor"); defaults.put(SSLSupport.SETTING_USE_SSL, "Y"); defaults.put(SSLSupport.SETTING_KEY_STORE_NAME, keyStoreName); defaults.put(SSLSupport.SETTING_KEY_STORE_PWD, "password"); defaults.put(SSLSupport.SETTING_NEED_CLIENT_AUTH, needClientAuth ? "Y" : "N"); - defaults.put(Session.SETTING_START_TIME, "00:00:00"); - defaults.put(Session.SETTING_END_TIME, "00:00:00"); - defaults.put(Session.SETTING_HEARTBTINT, "30"); if (cipherSuites != null) { defaults.put(SSLSupport.SETTING_CIPHER_SUITES, cipherSuites); @@ -1281,7 +1367,7 @@ private SessionSettings createMultiSessionAcceptorSettings(String keyStoreName, private SessionSettings createAcceptorSettings(String keyStoreName, boolean needClientAuth, String trustStoreName, String cipherSuites, String protocols, String keyStoreType, String trustStoreType, int port) { - HashMap defaults = new HashMap<>(); + HashMap defaults = createDefaults(); defaults.put(SessionFactory.SETTING_CONNECTION_TYPE, "acceptor"); defaults.put(SSLSupport.SETTING_USE_SSL, "Y"); defaults.put(SSLSupport.SETTING_KEY_STORE_NAME, keyStoreName); @@ -1302,9 +1388,6 @@ private SessionSettings createAcceptorSettings(String keyStoreName, boolean need defaults.put(SSLSupport.SETTING_NEED_CLIENT_AUTH, needClientAuth ? "Y" : "N"); defaults.put(Acceptor.SETTING_SOCKET_ACCEPT_PORT, Integer.toString(port)); - defaults.put(Session.SETTING_START_TIME, "00:00:00"); - defaults.put(Session.SETTING_END_TIME, "00:00:00"); - defaults.put(Session.SETTING_HEARTBTINT, "30"); if (cipherSuites != null) { defaults.put(SSLSupport.SETTING_CIPHER_SUITES, cipherSuites); @@ -1344,7 +1427,7 @@ private SessionSettings createInitiatorSettings(String keyStoreName, String trus String proxyHost, int proxyPort, boolean useSni, String sniHostName) { - HashMap defaults = new HashMap<>(); + HashMap defaults = createDefaults(); defaults.put(SessionFactory.SETTING_CONNECTION_TYPE, "initiator"); defaults.put(Initiator.SETTING_SOCKET_CONNECT_PROTOCOL, ProtocolFactory.getTypeString(ProtocolFactory.SOCKET)); defaults.put(SSLSupport.SETTING_USE_SSL, "Y"); @@ -1375,10 +1458,6 @@ private SessionSettings createInitiatorSettings(String keyStoreName, String trus defaults.put(Initiator.SETTING_SOCKET_CONNECT_HOST, "localhost"); defaults.put(Initiator.SETTING_SOCKET_CONNECT_PORT, port); - defaults.put(Initiator.SETTING_RECONNECT_INTERVAL, "2"); - defaults.put(Session.SETTING_START_TIME, "00:00:00"); - defaults.put(Session.SETTING_END_TIME, "00:00:00"); - defaults.put(Session.SETTING_HEARTBTINT, "30"); if (cipherSuites != null) { defaults.put(SSLSupport.SETTING_CIPHER_SUITES, cipherSuites); @@ -1426,15 +1505,19 @@ private SessionSettings createInitiatorSettings(String senderId, String targetId } private static HashMap createDefaults(int port) { - HashMap defaults = new HashMap<>(); + HashMap defaults = createDefaults(); defaults.put(SessionFactory.SETTING_CONNECTION_TYPE, "initiator"); defaults.put(Initiator.SETTING_SOCKET_CONNECT_PROTOCOL, ProtocolFactory.getTypeString(ProtocolFactory.SOCKET)); defaults.put(Initiator.SETTING_SOCKET_CONNECT_HOST, "localhost"); defaults.put(Initiator.SETTING_SOCKET_CONNECT_PORT, Integer.toString(port)); - defaults.put(Initiator.SETTING_RECONNECT_INTERVAL, "2"); + return defaults; + } + + private static HashMap createDefaults() { + HashMap defaults = new HashMap<>(); defaults.put(Session.SETTING_START_TIME, "00:00:00"); defaults.put(Session.SETTING_END_TIME, "00:00:00"); - defaults.put(Session.SETTING_HEARTBTINT, "30"); + defaults.put(Session.SETTING_HEARTBTINT, "5"); return defaults; } }