Skip to content

Commit

Permalink
Merging changes from master to dev, upto release 1.2.10 (Azure#323)
Browse files Browse the repository at this point in the history
* Making host name verification optional (Azure#317)

* Making ssl host name verification optional based on a system property. This will help with some proxy scenarios.

* adding code comments


# Conflicts:
#	azure-servicebus/src/main/java/com/microsoft/azure/servicebus/amqp/ConnectionHandler.java
#	azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/ClientConstants.java
#	pom.xml

* Fixing a bug in certonly verification path. (Azure#318)

Fixing a bug in certificate only verification path.

* Fixing a regression caused by upgrading to proton-j version 1.31. Fix addresses the case where a property value is null. (Azure#321)


# Conflicts:
#	azure-servicebus/src/main/java/com/microsoft/azure/servicebus/MessageConverter.java
  • Loading branch information
yvgopal authored Jan 9, 2019
1 parent 2edad13 commit 2e04188
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,27 @@
// amqp_connection/transport related events from reactor
public class ConnectionHandler extends BaseHandler
{
private static final SslDomain.VerifyMode VERIFY_MODE;
private static final Logger TRACE_LOGGER = LoggerFactory.getLogger(ConnectionHandler.class);
protected final IAmqpConnection messagingFactory;

static
{
String verifyModePropValue = System.getProperty(ClientConstants.SSL_VERIFY_MODE_PROPERTY_NAME);
if(ClientConstants.SSL_VERIFY_MODE_ANONYMOUS.equalsIgnoreCase(verifyModePropValue))
{
VERIFY_MODE = SslDomain.VerifyMode.ANONYMOUS_PEER;
}
else if(ClientConstants.SSL_VERIFY_MODE_CERTONLY.equalsIgnoreCase(verifyModePropValue))
{
VERIFY_MODE = SslDomain.VerifyMode.VERIFY_PEER;
}
else
{
VERIFY_MODE = SslDomain.VerifyMode.VERIFY_PEER_NAME;
}
}

protected ConnectionHandler(final IAmqpConnection messagingFactory)
{
add(new Handshaker());
Expand Down Expand Up @@ -90,19 +108,42 @@ public void addTransportLayers(final Event event, final TransportInternal transp
SslDomain domain = Proton.sslDomain();
domain.init(SslDomain.Mode.CLIENT);

try {
// Default SSL context will have the root certificate from azure in truststore anyway
SSLContext defaultContext = SSLContext.getDefault();
StrictTLSContextSpi strictTlsContextSpi = new StrictTLSContextSpi(defaultContext);
SSLContext strictTlsContext = new StrictTLSContext(strictTlsContextSpi, defaultContext.getProvider(), defaultContext.getProtocol());
domain.setSslContext(strictTlsContext);
domain.setPeerAuthentication(SslDomain.VerifyMode.VERIFY_PEER_NAME);
if(VERIFY_MODE == SslDomain.VerifyMode.VERIFY_PEER_NAME)
{
try {
// Default SSL context will have the root certificate from azure in truststore anyway
SSLContext defaultContext = SSLContext.getDefault();
StrictTLSContextSpi strictTlsContextSpi = new StrictTLSContextSpi(defaultContext);
SSLContext strictTlsContext = new StrictTLSContext(strictTlsContextSpi, defaultContext.getProvider(), defaultContext.getProtocol());
domain.setSslContext(strictTlsContext);
domain.setPeerAuthentication(SslDomain.VerifyMode.VERIFY_PEER_NAME);
SslPeerDetails peerDetails = Proton.sslPeerDetails(this.getOutboundSocketHostName(), this.getOutboundSocketPort());
transport.ssl(domain, peerDetails);
} catch (NoSuchAlgorithmException e) {
// Should never happen
TRACE_LOGGER.error("Default SSL algorithm not found in JRE. Please check your JRE setup.", e);
// this.messagingFactory.onConnectionError(new ErrorCondition(AmqpErrorCode.InternalError, e.getMessage()));
transport.ssl(domain, peerDetails);
} catch (NoSuchAlgorithmException e) {
// Should never happen
TRACE_LOGGER.error("Default SSL algorithm not found in JRE. Please check your JRE setup.", e);
// this.messagingFactory.onConnectionError(new ErrorCondition(AmqpErrorCode.InternalError, e.getMessage()));
}
}
else if (VERIFY_MODE == SslDomain.VerifyMode.VERIFY_PEER)
{
// Default SSL context will have the root certificate from azure in truststore anyway
try {
SSLContext defaultContext = SSLContext.getDefault();
domain.setSslContext(defaultContext);
domain.setPeerAuthentication(SslDomain.VerifyMode.VERIFY_PEER);
transport.ssl(domain);
} catch (NoSuchAlgorithmException e) {
// Should never happen
TRACE_LOGGER.error("Default SSL algorithm not found in JRE. Please check your JRE setup.", e);
// this.messagingFactory.onConnectionError(new ErrorCondition(AmqpErrorCode.InternalError, e.getMessage()));
}

}
else
{
domain.setPeerAuthentication(SslDomain.VerifyMode.ANONYMOUS_PEER);
transport.ssl(domain);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,11 @@ private ClientConstants() { }

public static final String HTTPS_URI_FORMAT = "https://%s:%s";

public static final String SSL_VERIFY_MODE_PROPERTY_NAME = "com.microsoft.azure.servicebus.ssl.verifymode";
public static final String SSL_VERIFY_MODE_ANONYMOUS = "anonymous"; // Accepts any certificate
public static final String SSL_VERIFY_MODE_CERTONLY = "verifyCertificateOnly"; // Accepts only certificates issued by trusted authorities
public static final String SSL_VERIFY_MODE_CERT_AND_HOSTNAME = "verifyCertificateAndHostName"; // Accepts only certificates issued by trusted authorities and having same subject name as the host address

static final int DEFAULT_SAS_TOKEN_SEND_RETRY_INTERVAL_IN_SECONDS = 5;
static final String SAS_TOKEN_AUDIENCE_FORMAT = "amqp://%s/%s";
static final Duration SAS_TOKEN_SEND_TIMEOUT = Duration.ofSeconds(10);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,13 @@ public void testBasicReceiveAndComplete() throws InterruptedException, ServiceBu
TestCommons.testBasicReceiveAndComplete(this.sender, this.sessionId, this.receiver);
}

@Test
public void testBasicReceiveAndCompleteMessageWithProperties() throws InterruptedException, ServiceBusException, ExecutionException
{
this.receiver = ClientFactory.createMessageReceiverFromEntityPath(factory, this.receiveEntityPath, ReceiveMode.PEEKLOCK);
TestCommons.testBasicReceiveAndCompleteMessageWithProperties(this.sender, this.sessionId, this.receiver);
}

@Test
public void testBasicReceiveAndAbandon() throws InterruptedException, ServiceBusException, ExecutionException
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,14 @@ public void testBasicReceiveAndComplete() throws InterruptedException, ServiceBu
TestCommons.testBasicReceiveAndComplete(this.sender, sessionId, this.session);
}

@Test
public void testBasicReceiveAndCompleteMessageWithProperties() throws InterruptedException, ServiceBusException, ExecutionException
{
String sessionId = TestUtils.getRandomString();
this.session = ClientFactory.acceptSessionFromEntityPath(this.factory, this.receiveEntityPath, sessionId, ReceiveMode.PEEKLOCK);
TestCommons.testBasicReceiveAndCompleteMessageWithProperties(this.sender, sessionId, this.session);
}

@Test
public void testBasicReceiveAndAbandon() throws InterruptedException, ServiceBusException, ExecutionException
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,32 @@ public static void testBasicReceiveAndComplete(IMessageSender sender, String ses
Assert.assertNull("Message was not properly completed", receivedMessage);
}

public static void testBasicReceiveAndCompleteMessageWithProperties(IMessageSender sender, String sessionId, IMessageReceiver receiver) throws InterruptedException, ServiceBusException, ExecutionException
{
String messageId = UUID.randomUUID().toString();
Message message = new Message("AMQP message");
message.setMessageId(messageId);
if(sessionId != null)
{
message.setSessionId(sessionId);
}
HashMap<String, String> messageProps = new HashMap<>();
messageProps.put("key1", "value1");
messageProps.put("key2", null); // Some customers are using it this way
message.setProperties(messageProps);
sender.send(message);

IMessage receivedMessage = receiver.receive();
Assert.assertNotNull("Message not received", receivedMessage);
Assert.assertEquals("Message Id did not match", messageId, receivedMessage.getMessageId());
Map<String, String> receivedProps = receivedMessage.getProperties();
Assert.assertEquals("All sent properties not recieved", "value1", receivedProps.get("key1"));
Assert.assertNull("Property with null value not received", receivedProps.get("key2"));
receiver.complete(receivedMessage.getLockToken());
receivedMessage = receiver.receive(SHORT_WAIT_TIME);
Assert.assertNull("Message was not properly completed", receivedMessage);
}

public static void testBasicReceiveAndAbandon(IMessageSender sender, String sessionId, IMessageReceiver receiver) throws InterruptedException, ServiceBusException, ExecutionException
{
String messageId = UUID.randomUUID().toString();
Expand Down

0 comments on commit 2e04188

Please sign in to comment.