Skip to content

Commit fc4bce1

Browse files
committed
Add opt-in to enable server hostname verification
Hostname verification isn't performed by default in the TLS handshake, this commit makes it easier to enable server hostname verification for both blocking and non-blocking IO modes. References #394 (cherry picked from commit fcc3dbb) Conflicts: src/main/java/com/rabbitmq/client/ConnectionFactory.java src/test/java/com/rabbitmq/client/test/ChannelRpcTimeoutIntegrationTest.java
1 parent b2f5cf5 commit fc4bce1

17 files changed

+705
-18
lines changed

src/main/java/com/rabbitmq/client/ConnectionFactory.java

+51-7
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@
1515

1616
package com.rabbitmq.client;
1717

18-
import static java.util.concurrent.TimeUnit.*;
19-
2018
import com.rabbitmq.client.impl.AMQConnection;
2119
import com.rabbitmq.client.impl.ConnectionParams;
2220
import com.rabbitmq.client.impl.CredentialsProvider;
@@ -32,6 +30,10 @@
3230
import com.rabbitmq.client.impl.recovery.RetryHandler;
3331
import com.rabbitmq.client.impl.recovery.TopologyRecoveryFilter;
3432

33+
import javax.net.SocketFactory;
34+
import javax.net.ssl.SSLContext;
35+
import javax.net.ssl.SSLSocketFactory;
36+
import javax.net.ssl.TrustManager;
3537
import java.io.IOException;
3638
import java.net.URI;
3739
import java.net.URISyntaxException;
@@ -49,10 +51,8 @@
4951
import java.util.concurrent.ScheduledExecutorService;
5052
import java.util.concurrent.ThreadFactory;
5153
import java.util.concurrent.TimeoutException;
52-
import javax.net.SocketFactory;
53-
import javax.net.ssl.SSLContext;
54-
import javax.net.ssl.SSLSocketFactory;
55-
import javax.net.ssl.TrustManager;
54+
55+
import static java.util.concurrent.TimeUnit.MINUTES;
5656

5757
/**
5858
* Convenience "factory" class to facilitate opening a {@link Connection} to an AMQP broker.
@@ -126,7 +126,7 @@ public class ConnectionFactory implements Cloneable {
126126
// connections uses, see rabbitmq/rabbitmq-java-client#86
127127
private ExecutorService shutdownExecutor;
128128
private ScheduledExecutorService heartbeatExecutor;
129-
private SocketConfigurator socketConf = new DefaultSocketConfigurator();
129+
private SocketConfigurator socketConf = SocketConfigurators.defaultConfigurator();
130130
private ExceptionHandler exceptionHandler = new DefaultExceptionHandler();
131131
private CredentialsProvider credentialsProvider = new DefaultCredentialsProvider(DEFAULT_USER, DEFAULT_PASS);
132132

@@ -708,6 +708,50 @@ public void useSslProtocol(SSLContext context) {
708708
this.sslContext = context;
709709
}
710710

711+
/**
712+
* Enable server hostname verification for TLS connections.
713+
* <p>
714+
* This enables hostname verification regardless of the IO mode
715+
* used (blocking or non-blocking IO).
716+
* <p>
717+
* This can be called typically after setting the {@link SSLContext}
718+
* with one of the <code>useSslProtocol</code> methods.
719+
*
720+
* @see NioParams#enableHostnameVerification()
721+
* @see NioParams#setSslEngineConfigurator(SslEngineConfigurator)
722+
* @see SslEngineConfigurators#ENABLE_HOSTNAME_VERIFICATION
723+
* @see SocketConfigurators#ENABLE_HOSTNAME_VERIFICATION
724+
* @see ConnectionFactory#useSslProtocol(String)
725+
* @see ConnectionFactory#useSslProtocol(SSLContext)
726+
* @see ConnectionFactory#useSslProtocol()
727+
* @see ConnectionFactory#useSslProtocol(String, TrustManager)
728+
*/
729+
public void enableHostnameVerification() {
730+
enableHostnameVerificationForNio();
731+
enableHostnameVerificationForBlockingIo();
732+
}
733+
734+
protected void enableHostnameVerificationForNio() {
735+
if (this.nioParams == null) {
736+
this.nioParams = new NioParams();
737+
}
738+
this.nioParams = this.nioParams.enableHostnameVerification();
739+
}
740+
741+
protected void enableHostnameVerificationForBlockingIo() {
742+
if (this.socketConf == null) {
743+
this.socketConf = SocketConfigurators.builder()
744+
.defaultConfigurator()
745+
.enableHostnameVerification()
746+
.build();
747+
} else {
748+
this.socketConf = SocketConfigurators.builder()
749+
.add(this.socketConf)
750+
.enableHostnameVerification()
751+
.build();
752+
}
753+
}
754+
711755
public static String computeDefaultTlsProcotol(String[] supportedProtocols) {
712756
if(supportedProtocols != null) {
713757
for (String supportedProtocol : supportedProtocols) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
// Copyright (c) 2018 Pivotal Software, Inc. All rights reserved.
2+
//
3+
// This software, the RabbitMQ Java client library, is triple-licensed under the
4+
// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2
5+
// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see
6+
// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL,
7+
// please see LICENSE-APACHE2.
8+
//
9+
// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND,
10+
// either express or implied. See the LICENSE file for specific language governing
11+
// rights and limitations of this software.
12+
//
13+
// If you have any questions regarding licensing, please contact us at
14+
15+
16+
package com.rabbitmq.client;
17+
18+
import java.io.IOException;
19+
import java.nio.channels.SocketChannel;
20+
21+
/**
22+
* Ready-to-use instances and builder for {@link SocketChannelConfigurator}.
23+
* <p>
24+
* Note {@link SocketChannelConfigurator}s can be combined with
25+
* {@link AbstractSocketChannelConfigurator#andThen(SocketChannelConfigurator)}.
26+
*
27+
* @since 4.8.0
28+
*/
29+
public abstract class SocketChannelConfigurators {
30+
31+
/**
32+
* Disable Nagle's algorithm.
33+
*/
34+
public static final AbstractSocketChannelConfigurator DISABLE_NAGLE_ALGORITHM =
35+
new AbstractSocketChannelConfigurator() {
36+
37+
@Override
38+
public void configure(SocketChannel socketChannel) throws IOException {
39+
SocketConfigurators.DISABLE_NAGLE_ALGORITHM.configure(socketChannel.socket());
40+
}
41+
};
42+
43+
/**
44+
* Default {@link SocketChannelConfigurator} that disables Nagle's algorithm.
45+
*/
46+
public static final AbstractSocketChannelConfigurator DEFAULT = DISABLE_NAGLE_ALGORITHM;
47+
48+
/**
49+
* The default {@link SocketChannelConfigurator} that disables Nagle's algorithm.
50+
*
51+
* @return
52+
*/
53+
public static AbstractSocketChannelConfigurator defaultConfigurator() {
54+
return DEFAULT;
55+
}
56+
57+
/**
58+
* {@link SocketChannelConfigurator} that disables Nagle's algorithm.
59+
*
60+
* @return
61+
*/
62+
public static AbstractSocketChannelConfigurator disableNagleAlgorithm() {
63+
return DISABLE_NAGLE_ALGORITHM;
64+
}
65+
66+
/**
67+
* Builder to configure and creates a {@link SocketChannelConfigurator} instance.
68+
*
69+
* @return
70+
*/
71+
public static SocketChannelConfigurators.Builder builder() {
72+
return new SocketChannelConfigurators.Builder();
73+
}
74+
75+
public static abstract class AbstractSocketChannelConfigurator implements SocketChannelConfigurator {
76+
77+
/**
78+
* Returns a composed configurator that performs, in sequence, this
79+
* operation followed by the {@code after} operation.
80+
*
81+
* @param after the operation to perform after this operation
82+
* @return a composed configurator that performs in sequence this
83+
* operation followed by the {@code after} operation
84+
* @throws NullPointerException if {@code after} is null
85+
*/
86+
public AbstractSocketChannelConfigurator andThen(final SocketChannelConfigurator after) {
87+
if (after == null) {
88+
throw new NullPointerException();
89+
}
90+
return new AbstractSocketChannelConfigurator() {
91+
92+
@Override
93+
public void configure(SocketChannel socketChannel) throws IOException {
94+
AbstractSocketChannelConfigurator.this.configure(socketChannel);
95+
after.configure(socketChannel);
96+
}
97+
};
98+
}
99+
}
100+
101+
public static class Builder {
102+
103+
private AbstractSocketChannelConfigurator configurator = new AbstractSocketChannelConfigurator() {
104+
105+
@Override
106+
public void configure(SocketChannel channel) {
107+
}
108+
};
109+
110+
/**
111+
* Set default configuration.
112+
*
113+
* @return
114+
*/
115+
public Builder defaultConfigurator() {
116+
configurator = configurator.andThen(DEFAULT);
117+
return this;
118+
}
119+
120+
/**
121+
* Disable Nagle's Algorithm.
122+
*
123+
* @return
124+
*/
125+
public Builder disableNagleAlgorithm() {
126+
configurator = configurator.andThen(DISABLE_NAGLE_ALGORITHM);
127+
return this;
128+
}
129+
130+
/**
131+
* Add an extra configuration step.
132+
*
133+
* @param extraConfiguration
134+
* @return
135+
*/
136+
public Builder add(SocketChannelConfigurator extraConfiguration) {
137+
configurator = configurator.andThen(extraConfiguration);
138+
return this;
139+
}
140+
141+
/**
142+
* Return the configured {@link SocketConfigurator}.
143+
*
144+
* @return
145+
*/
146+
public SocketChannelConfigurator build() {
147+
return configurator;
148+
}
149+
}
150+
}

src/main/java/com/rabbitmq/client/SocketConfigurator.java

+2
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@
1919
import java.net.Socket;
2020

2121
public interface SocketConfigurator {
22+
2223
/**
2324
* Provides a hook to insert custom configuration of the sockets
2425
* used to connect to an AMQP server before they connect.
2526
*/
2627
void configure(Socket socket) throws IOException;
28+
2729
}

0 commit comments

Comments
 (0)