Repository: qpid-proton-j Updated Branches: refs/heads/master 31f5fc97b -> 0cb8ca03c
PROTON-1962: update some defaults and related handling Project: http://git-wip-us.apache.org/repos/asf/qpid-proton-j/repo Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton-j/commit/0cb8ca03 Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton-j/tree/0cb8ca03 Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton-j/diff/0cb8ca03 Branch: refs/heads/master Commit: 0cb8ca03cec42120dcfc434561592d89a89a805e Parents: 31f5fc9 Author: Robbie Gemmell <[email protected]> Authored: Tue Nov 6 12:17:09 2018 +0000 Committer: Robbie Gemmell <[email protected]> Committed: Tue Nov 6 12:17:09 2018 +0000 ---------------------------------------------------------------------- .../apache/qpid/proton/engine/SslDomain.java | 15 +- .../apache/qpid/proton/engine/Transport.java | 14 +- .../impl/ssl/SimpleSslTransportWrapper.java | 8 +- .../proton/engine/impl/ssl/SslDomainImpl.java | 12 +- .../engine/impl/ssl/SslEngineFacadeFactory.java | 8 + .../qpid/proton/engine/impl/ssl/SslImpl.java | 9 + .../qpid/proton/reactor/impl/IOHandler.java | 3 +- .../impl/ssl/SimpleSslTransportWrapperTest.java | 13 +- .../engine/impl/ssl/SslDomainImplTest.java | 73 +++++++++ .../qpid/proton/systemtests/engine/SslTest.java | 164 +++++++++++++++++++ tests/python/proton_tests/ssl.py | 31 +++- 11 files changed, 328 insertions(+), 22 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/qpid-proton-j/blob/0cb8ca03/proton-j/src/main/java/org/apache/qpid/proton/engine/SslDomain.java ---------------------------------------------------------------------- diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/SslDomain.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/SslDomain.java index 279d934..06a3517 100644 --- a/proton-j/src/main/java/org/apache/qpid/proton/engine/SslDomain.java +++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/SslDomain.java @@ -49,15 +49,24 @@ public interface SslDomain /** * Determines the level of peer validation. * - * {@link #ANONYMOUS_PEER} is configured by default. + * {@link #VERIFY_PEER_NAME} is used by default in {@link Mode#CLIENT client} + * mode if not configured otherwise, with {@link #ANONYMOUS_PEER} used for + * {@link Mode#SERVER server} mode if not configured otherwise. */ public enum VerifyMode { /** - * will only connect to those peers that provide a valid identifying certificate signed - * by a trusted CA and are using an authenticated cipher + * Requires peers provide a valid identifying certificate signed by + * a trusted certificate. Does not verify hostname details of the + * peer certificate, use {@link #VERIFY_PEER_NAME} for this instead. */ VERIFY_PEER, + /** + * Requires peers provide a valid identifying certificate signed + * by a trusted certificate, including verifying hostname details + * of the certificate using peer details provided when configuring + * TLS via {@link Transport#ssl(SslDomain, SslPeerDetails)}. + */ VERIFY_PEER_NAME, /** * does not require a valid certificate, and permits use of ciphers that http://git-wip-us.apache.org/repos/asf/qpid-proton-j/blob/0cb8ca03/proton-j/src/main/java/org/apache/qpid/proton/engine/Transport.java ---------------------------------------------------------------------- diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/Transport.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/Transport.java index f8de042..66cde84 100644 --- a/proton-j/src/main/java/org/apache/qpid/proton/engine/Transport.java +++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/Transport.java @@ -194,15 +194,21 @@ public interface Transport extends Endpoint * {@link Ssl} object, regardless of the parameters supplied. * * @param sslDomain the SSL settings to use - * @param sslPeerDetails may be null, in which case SSL session resume will not be attempted + * @param sslPeerDetails peer details, used for SNI, hostname verification, etc when connecting. May be null. * @return an {@link Ssl} object representing the SSL session. + * @throws IllegalArgumentException if the sslDomain requests hostname verification but sslPeerDetails are null. + * @throws IllegalStateException if the sslDomain has not been initialised. */ - Ssl ssl(SslDomain sslDomain, SslPeerDetails sslPeerDetails); + Ssl ssl(SslDomain sslDomain, SslPeerDetails sslPeerDetails) throws IllegalArgumentException; /** - * As per {@link #ssl(SslDomain, SslPeerDetails)} but no attempt is made to resume a previous SSL session. + * Equivalent to {@link #ssl(SslDomain, SslPeerDetails)} but passing null for SslPeerDetails, meaning no SNI detail + * is sent, hostname verification isn't supported etc when connecting. + * + * @throws IllegalArgumentException if the sslDomain requests hostname verification. + * @throws IllegalStateException if the sslDomain has not been initialised. */ - Ssl ssl(SslDomain sslDomain); + Ssl ssl(SslDomain sslDomain) throws IllegalArgumentException; /** http://git-wip-us.apache.org/repos/asf/qpid-proton-j/blob/0cb8ca03/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SimpleSslTransportWrapper.java ---------------------------------------------------------------------- diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SimpleSslTransportWrapper.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SimpleSslTransportWrapper.java index a30e88b..f2454b3 100644 --- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SimpleSslTransportWrapper.java +++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SimpleSslTransportWrapper.java @@ -360,9 +360,15 @@ public class SimpleSslTransportWrapper implements SslTransportWrapper try { unwrapInput(); } catch (SSLException e) { - _logger.log(Level.WARNING, e.getMessage()); + if(_logger.isLoggable(Level.FINEST)){ + _logger.log(Level.FINEST, e.getMessage(), e); + } else { + _logger.log(Level.WARNING, e.getMessage()); + } _inputBuffer.position(_inputBuffer.limit()); _tail_closed = true; + + throw new TransportException(e); } finally { _inputBuffer.compact(); } http://git-wip-us.apache.org/repos/asf/qpid-proton-j/blob/0cb8ca03/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslDomainImpl.java ---------------------------------------------------------------------- diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslDomainImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslDomainImpl.java index 3928b05..fddde1a 100644 --- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslDomainImpl.java +++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslDomainImpl.java @@ -19,7 +19,6 @@ package org.apache.qpid.proton.engine.impl.ssl; import javax.net.ssl.SSLContext; -import org.apache.qpid.proton.ProtonUnsupportedOperationException; import org.apache.qpid.proton.engine.ProtonJSslDomain; import org.apache.qpid.proton.engine.SslDomain; import org.apache.qpid.proton.engine.SslPeerDetails; @@ -27,7 +26,7 @@ import org.apache.qpid.proton.engine.SslPeerDetails; public class SslDomainImpl implements SslDomain, ProtonSslEngineProvider, ProtonJSslDomain { private Mode _mode; - private VerifyMode _verifyMode = VerifyMode.ANONYMOUS_PEER; + private VerifyMode _verifyMode; private String _certificateFile; private String _privateKeyFile; private String _privateKeyPassword; @@ -94,10 +93,6 @@ public class SslDomainImpl implements SslDomain, ProtonSslEngineProvider, Proton @Override public void setPeerAuthentication(VerifyMode verifyMode) { - if(verifyMode == VerifyMode.VERIFY_PEER_NAME) - { - throw new ProtonUnsupportedOperationException(); - } _verifyMode = verifyMode; _sslEngineFacadeFactory.resetCache(); } @@ -105,6 +100,11 @@ public class SslDomainImpl implements SslDomain, ProtonSslEngineProvider, Proton @Override public VerifyMode getPeerAuthentication() { + if(_verifyMode == null) + { + return _mode == Mode.SERVER ? VerifyMode.ANONYMOUS_PEER : VerifyMode.VERIFY_PEER_NAME; + } + return _verifyMode; } http://git-wip-us.apache.org/repos/asf/qpid-proton-j/blob/0cb8ca03/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslEngineFacadeFactory.java ---------------------------------------------------------------------- diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslEngineFacadeFactory.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslEngineFacadeFactory.java index 309e0dc..6a730df 100644 --- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslEngineFacadeFactory.java +++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslEngineFacadeFactory.java @@ -53,6 +53,7 @@ import java.util.logging.Logger; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLParameters; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; @@ -232,6 +233,13 @@ public class SslEngineFacadeFactory { sslEngine.setNeedClientAuth(true); } + + if(domain.getPeerAuthentication() == SslDomain.VerifyMode.VERIFY_PEER_NAME) + { + SSLParameters sslParameters = sslEngine.getSSLParameters(); + sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); + sslEngine.setSSLParameters(sslParameters); + } } if(_logger.isLoggable(Level.FINE)) http://git-wip-us.apache.org/repos/asf/qpid-proton-j/blob/0cb8ca03/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslImpl.java ---------------------------------------------------------------------- diff --git a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslImpl.java index de99351..24d7c43 100644 --- a/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslImpl.java +++ b/proton-j/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslImpl.java @@ -25,6 +25,7 @@ import java.nio.ByteBuffer; import org.apache.qpid.proton.ProtonUnsupportedOperationException; import org.apache.qpid.proton.engine.Ssl; import org.apache.qpid.proton.engine.SslDomain; +import org.apache.qpid.proton.engine.SslDomain.VerifyMode; import org.apache.qpid.proton.engine.SslPeerDetails; import org.apache.qpid.proton.engine.Transport; import org.apache.qpid.proton.engine.TransportException; @@ -54,6 +55,14 @@ public class SslImpl implements Ssl, TransportLayer _domain = domain; _protonSslEngineProvider = (ProtonSslEngineProvider)domain; _peerDetails = peerDetails; + + if(_domain.getMode() == null) { + throw new IllegalStateException("Client/server mode must be configured, SslDomain must have init called."); + } + + if(_peerDetails == null && _domain.getPeerAuthentication() == VerifyMode.VERIFY_PEER_NAME) { + throw new IllegalArgumentException("Peer hostname verification is enabled, but no peer details were provided"); + } } public TransportWrapper wrap(TransportInput inputProcessor, TransportOutput outputProcessor) http://git-wip-us.apache.org/repos/asf/qpid-proton-j/blob/0cb8ca03/proton-j/src/main/java/org/apache/qpid/proton/reactor/impl/IOHandler.java ---------------------------------------------------------------------- diff --git a/proton-j/src/main/java/org/apache/qpid/proton/reactor/impl/IOHandler.java b/proton-j/src/main/java/org/apache/qpid/proton/reactor/impl/IOHandler.java index 81b85ff..5d58182 100644 --- a/proton-j/src/main/java/org/apache/qpid/proton/reactor/impl/IOHandler.java +++ b/proton-j/src/main/java/org/apache/qpid/proton/reactor/impl/IOHandler.java @@ -37,6 +37,7 @@ import org.apache.qpid.proton.engine.EndpointState; import org.apache.qpid.proton.engine.Event; import org.apache.qpid.proton.engine.Sasl; import org.apache.qpid.proton.engine.Transport; +import org.apache.qpid.proton.engine.TransportException; import org.apache.qpid.proton.engine.impl.TransportImpl; import org.apache.qpid.proton.engine.Record; import org.apache.qpid.proton.reactor.Reactor; @@ -232,7 +233,7 @@ public class IOHandler extends BaseHandler { } else { transport.process(); } - } catch (IOException e) { + } catch (IOException | TransportException e) { ErrorCondition condition = new ErrorCondition(); condition.setCondition(Symbol.getSymbol("proton:io")); condition.setDescription(e.getMessage()); http://git-wip-us.apache.org/repos/asf/qpid-proton-j/blob/0cb8ca03/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/ssl/SimpleSslTransportWrapperTest.java ---------------------------------------------------------------------- diff --git a/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/ssl/SimpleSslTransportWrapperTest.java b/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/ssl/SimpleSslTransportWrapperTest.java index 6ee1582..605046c 100644 --- a/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/ssl/SimpleSslTransportWrapperTest.java +++ b/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/ssl/SimpleSslTransportWrapperTest.java @@ -347,12 +347,19 @@ public class SimpleSslTransportWrapperTest @Test public void testSslUnwrapThrowsException_returnsErrorResultAndRefusesFurtherInput() throws Exception { - SSLException sslException = new SSLException("unwrap exception"); + String unwrapExceptionMessage = "unwrap exception message"; + SSLException sslException = new SSLException(unwrapExceptionMessage); _dummySslEngine.rejectNextEncodedPacket(sslException); _sslWrapper.tail().put("<-A->".getBytes(StandardCharsets.UTF_8)); - _sslWrapper.process(); - assertEquals(_sslWrapper.capacity(), Transport.END_OF_STREAM); + try { + _sslWrapper.process(); + fail("no exception"); + } catch(TransportException e) { + assertEquals("javax.net.ssl.SSLException: " + unwrapExceptionMessage, e.getMessage()); + } + + assertEquals(Transport.END_OF_STREAM, _sslWrapper.capacity()); } @Test http://git-wip-us.apache.org/repos/asf/qpid-proton-j/blob/0cb8ca03/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/ssl/SslDomainImplTest.java ---------------------------------------------------------------------- diff --git a/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/ssl/SslDomainImplTest.java b/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/ssl/SslDomainImplTest.java new file mode 100644 index 0000000..e0d7a5d --- /dev/null +++ b/proton-j/src/test/java/org/apache/qpid/proton/engine/impl/ssl/SslDomainImplTest.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.qpid.proton.engine.impl.ssl; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNull; + +import org.apache.qpid.proton.engine.SslDomain; +import org.apache.qpid.proton.engine.SslDomain.Mode; +import org.apache.qpid.proton.engine.SslDomain.VerifyMode; +import org.junit.Test; + +public class SslDomainImplTest { + + @Test + public void testInitGetMode() throws Exception + { + SslDomain sslDomain = SslDomain.Factory.create(); + assertNull("Unexpected mode, none was set", sslDomain.getMode()); + + sslDomain.init(Mode.CLIENT); + assertEquals("Unexpected mode", Mode.CLIENT, sslDomain.getMode()); + + sslDomain.init(Mode.SERVER); + assertEquals("Unexpected mode", Mode.SERVER, sslDomain.getMode()); + } + + @Test + public void testVerifyModeDefault() throws Exception + { + SslDomain clientSslDomain = SslDomain.Factory.create(); + assertEquals("Unexpected default verification mode", VerifyMode.VERIFY_PEER_NAME, clientSslDomain.getPeerAuthentication()); + clientSslDomain.init(Mode.CLIENT); + assertEquals("Unexpected default verification mode", VerifyMode.VERIFY_PEER_NAME, clientSslDomain.getPeerAuthentication()); + + SslDomain serverSslDomain = SslDomain.Factory.create(); + serverSslDomain.init(Mode.SERVER); + assertEquals("Unexpected default verification mode", VerifyMode.ANONYMOUS_PEER, serverSslDomain.getPeerAuthentication()); + } + + @Test + public void testVerifyModeSetGet() throws Exception + { + SslDomain clientSslDomain = SslDomain.Factory.create(); + clientSslDomain.init(Mode.CLIENT); + assertNotEquals("Unexpected verification mode", VerifyMode.VERIFY_PEER, clientSslDomain.getPeerAuthentication()); + clientSslDomain.setPeerAuthentication(VerifyMode.VERIFY_PEER); + assertEquals("Unexpected verification mode", VerifyMode.VERIFY_PEER, clientSslDomain.getPeerAuthentication()); + + SslDomain serverSslDomain = SslDomain.Factory.create(); + serverSslDomain.init(Mode.SERVER); + assertNotEquals("Unexpected verification mode", VerifyMode.VERIFY_PEER, serverSslDomain.getPeerAuthentication()); + serverSslDomain.setPeerAuthentication(VerifyMode.VERIFY_PEER); + assertEquals("Unexpected verification mode", VerifyMode.VERIFY_PEER, serverSslDomain.getPeerAuthentication()); + } +} http://git-wip-us.apache.org/repos/asf/qpid-proton-j/blob/0cb8ca03/proton-j/src/test/java/org/apache/qpid/proton/systemtests/engine/SslTest.java ---------------------------------------------------------------------- diff --git a/proton-j/src/test/java/org/apache/qpid/proton/systemtests/engine/SslTest.java b/proton-j/src/test/java/org/apache/qpid/proton/systemtests/engine/SslTest.java index 32ab62d..962bd2b 100644 --- a/proton-j/src/test/java/org/apache/qpid/proton/systemtests/engine/SslTest.java +++ b/proton-j/src/test/java/org/apache/qpid/proton/systemtests/engine/SslTest.java @@ -22,6 +22,8 @@ import static org.apache.qpid.proton.engine.EndpointState.ACTIVE; import static org.apache.qpid.proton.engine.EndpointState.UNINITIALIZED; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.io.File; import java.io.FileInputStream; @@ -31,6 +33,8 @@ import java.security.SecureRandom; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.TrustManagerFactory; import org.apache.qpid.proton.Proton; @@ -41,7 +45,9 @@ import org.apache.qpid.proton.engine.EndpointState; import org.apache.qpid.proton.engine.SslDomain; import org.apache.qpid.proton.engine.SslDomain.Mode; import org.apache.qpid.proton.engine.SslDomain.VerifyMode; +import org.apache.qpid.proton.engine.SslPeerDetails; import org.apache.qpid.proton.engine.Transport; +import org.apache.qpid.proton.engine.TransportException; import org.junit.Test; public class SslTest @@ -67,6 +73,27 @@ public class SslTest private final Connection _serverConnection = Proton.connection(); @Test + public void testFailureToInitSslDomainThrowsISE() throws Exception { + SslDomain sslDomain = SslDomain.Factory.create(); + + try { + _clientTransport.ssl(sslDomain, null); + fail("Expected an exception to be thrown"); + } catch (IllegalStateException ise) { + // Expected + assertTrue(ise.getMessage().contains("Client/server mode must be configured")); + } + + try { + _serverTransport.ssl(sslDomain); + fail("Expected an exception to be thrown"); + } catch (IllegalStateException ise) { + // Expected + assertTrue(ise.getMessage().contains("Client/server mode must be configured")); + } + } + + @Test public void testOpenConnectionsWithProvidedSslContext() throws Exception { SslDomain clientSslDomain = SslDomain.Factory.create(); @@ -125,6 +152,143 @@ public class SslTest assertConditions(_serverTransport); } + @Test + public void testHostnameVerificationSuccess() throws Exception { + doHostnameVerificationTestImpl(true, true); + } + + @Test + public void testHostnameVerificationFailure() throws Exception { + doHostnameVerificationTestImpl(false, true); + } + + @Test + public void testHostnameVerificationSkipped() throws Exception { + doHostnameVerificationTestImpl(false, false); + } + + private void doHostnameVerificationTestImpl(boolean useMatchingServerName, boolean useHostnameVerification) throws Exception { + final String serverPeerName = useMatchingServerName ? "localhost" : "anotherserverhost"; + final VerifyMode clientVerifyMode = useHostnameVerification ? VerifyMode.VERIFY_PEER_NAME : VerifyMode.VERIFY_PEER; + + SslDomain clientSslDomain = SslDomain.Factory.create(); + clientSslDomain.init(Mode.CLIENT); + clientSslDomain.setPeerAuthentication(clientVerifyMode); + + SSLContext clientSslContext = createSslContext(CLIENT_JKS_KEYSTORE, PASSWORD, CLIENT_JKS_TRUSTSTORE, PASSWORD); + clientSslDomain.setSslContext(clientSslContext); + SslPeerDetails sslPeerDetails = SslPeerDetails.Factory.create(serverPeerName, 1234); + _clientTransport.ssl(clientSslDomain, sslPeerDetails); + + SslDomain serverSslDomain = SslDomain.Factory.create(); + serverSslDomain.init(Mode.SERVER); + serverSslDomain.setPeerAuthentication(VerifyMode.VERIFY_PEER_NAME); + SSLContext serverSslContext = createSslContext(SERVER_JKS_KEYSTORE, PASSWORD, SERVER_JKS_TRUSTSTORE, PASSWORD); + serverSslDomain.setSslContext(serverSslContext); + _serverTransport.ssl(serverSslDomain, SslPeerDetails.Factory.create("client", 4567)); + + _clientConnection.setContainer(CLIENT_CONTAINER); + _serverConnection.setContainer(SERVER_CONTAINER); + + _clientTransport.bind(_clientConnection); + _serverTransport.bind(_serverConnection); + + assertConditions(_clientTransport); + assertConditions(_serverTransport); + + _clientConnection.open(); + + assertEndpointState(_clientConnection, ACTIVE, UNINITIALIZED); + assertEndpointState(_serverConnection, UNINITIALIZED, UNINITIALIZED); + + assertConditions(_clientTransport); + assertConditions(_serverTransport); + + if(useHostnameVerification && !useMatchingServerName) { + // Verify the expected failures and resulting transport closures + pumpWithFailingNegotiation(); + + assertEquals(Transport.END_OF_STREAM, _clientTransport.pending()); + assertEquals(Transport.END_OF_STREAM, _clientTransport.capacity()); + + assertEquals(Transport.END_OF_STREAM, _serverTransport.pending()); + assertEquals(Transport.END_OF_STREAM, _serverTransport.capacity()); + return; + } else { + // Verify the connections succeed + _pumper.pumpAll(); + + assertEndpointState(_clientConnection, ACTIVE, UNINITIALIZED); + assertEndpointState(_serverConnection, UNINITIALIZED, ACTIVE); + + assertConditions(_clientTransport); + assertConditions(_serverTransport); + + _serverConnection.open(); + + assertEndpointState(_clientConnection, ACTIVE, UNINITIALIZED); + assertEndpointState(_serverConnection, ACTIVE, ACTIVE); + + assertConditions(_clientTransport); + assertConditions(_serverTransport); + + _pumper.pumpAll(); + + assertEndpointState(_clientConnection, ACTIVE, ACTIVE); + assertEndpointState(_serverConnection, ACTIVE, ACTIVE); + + assertConditions(_clientTransport); + assertConditions(_serverTransport); + } + } + + @Test + public void testOmittingPeerDetailsThrowsIAEWhenRequired() throws Exception { + doOmitPeerDetailsThrowsIAEWhenRequiredTestImpl(true); + doOmitPeerDetailsThrowsIAEWhenRequiredTestImpl(false); + } + + private void doOmitPeerDetailsThrowsIAEWhenRequiredTestImpl(boolean explicitlySetVerifyMode) { + SslDomain clientSslDomain = SslDomain.Factory.create(); + clientSslDomain.init(Mode.CLIENT); + + if (explicitlySetVerifyMode) { + clientSslDomain.setPeerAuthentication(VerifyMode.VERIFY_PEER_NAME); + } + + try { + _clientTransport.ssl(clientSslDomain, null); + fail("Expected an exception to be thrown"); + } catch (IllegalArgumentException ise) { + // Expected + } + + try { + _clientTransport.ssl(clientSslDomain); + fail("Expected an exception to be thrown"); + } catch (IllegalArgumentException ise) { + // Expected + } + } + + private void pumpWithFailingNegotiation() throws Exception { + try { + _pumper.pumpAll(); + fail("Expected an exception"); + } catch (TransportException te) { + assertTrue(te.getCause().getCause() instanceof SSLHandshakeException); + } + + try { + _pumper.pumpAll(); + fail("Expected an exception"); + } catch (TransportException te) { + assertTrue(te.getCause().getCause() instanceof SSLException); + } + + _pumper.pumpAll(); + } + private void assertConditions(Transport transport) { ErrorCondition remoteCondition = transport.getRemoteCondition(); http://git-wip-us.apache.org/repos/asf/qpid-proton-j/blob/0cb8ca03/tests/python/proton_tests/ssl.py ---------------------------------------------------------------------- diff --git a/tests/python/proton_tests/ssl.py b/tests/python/proton_tests/ssl.py index 1a05780..518ef4d 100644 --- a/tests/python/proton_tests/ssl.py +++ b/tests/python/proton_tests/ssl.py @@ -25,6 +25,7 @@ import string import subprocess import sys from proton import * +from org.apache.qpid.proton.engine import TransportException from .common import Skipped, pump @@ -82,6 +83,25 @@ class SslTest(common.Test): def _pump(self, ssl_client, ssl_server, buffer_size=1024): pump(ssl_client.transport, ssl_server.transport, buffer_size) + def _pump_with_failing_negotiation(self, client, server, onesided = False): + # Exception once for client/server transport + try: + self._pump( client, server ) + assert False, "Expected exception did not occur!" + except TransportException: + pass + + if(onesided != True): + # Exception once for server/client transport + try: + self._pump( client, server ) + assert False, "Expected exception did not occur!" + except TransportException: + pass + + # Ensure both are processed to completion + self._pump( client, server ) + def _do_handshake(self, client, server): """ Attempt to connect client to server. Will throw a TransportException if the SSL handshake fails. @@ -154,6 +174,8 @@ class SslTest(common.Test): self._testpath("server-private-key.pem"), "server-password") server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER ) + + self.client_domain.set_peer_authentication( SSLDomain.ANONYMOUS_PEER ) client = SslTest.SslTestConnection( self.client_domain ) client.connection.open() @@ -235,7 +257,7 @@ class SslTest(common.Test): client.connection.open() server.connection.open() - self._pump( client, server ) + self._pump_with_failing_negotiation(client, server) assert client.transport.closed assert server.transport.closed assert client.connection.state & Endpoint.REMOTE_UNINIT @@ -260,7 +282,7 @@ class SslTest(common.Test): client.connection.open() server.connection.open() - self._pump( client, server ) + self._pump_with_failing_negotiation(client, server) assert client.transport.closed assert server.transport.closed assert client.connection.state & Endpoint.REMOTE_UNINIT @@ -335,7 +357,7 @@ class SslTest(common.Test): client.connection.open() server.connection.open() - self._pump( client, server ) + self._pump_with_failing_negotiation(client, server) assert client.transport.closed assert server.transport.closed assert client.connection.state & Endpoint.REMOTE_UNINIT @@ -430,7 +452,7 @@ class SslTest(common.Test): client.connection.open() server.connection.open() - self._pump( client, server ) + self._pump_with_failing_negotiation(client, server, onesided = True) assert client.transport.closed assert server.transport.closed assert client.connection.state & Endpoint.REMOTE_UNINIT @@ -479,6 +501,7 @@ class SslTest(common.Test): def test_singleton(self): """Verify that only a single instance of SSL can exist per Transport""" transport = Transport() + self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER ) ssl1 = SSL(transport, self.client_domain) ssl2 = transport.ssl(self.client_domain) ssl3 = transport.ssl(self.client_domain) --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
