8000 JAVA-1364: Enable creation of SslHandler with remote address information · kecmu/java-driver@3c96548 · GitHub
[go: up one dir, main page]

Skip to content

Commit 3c96548

Browse files
author
Alexandre Dutra
committed
JAVA-1364: Enable creation of SslHandler with remote address information
Motivation: SSLOptions do not currently allow to create SslHandler instances with remote address information. This is needed to instantiate SSLEngine/SslHandler with remote address information set, which enables doing hostname verification (for example through a custom TrustManager). We cannot take this information from SocketChannel since it is not connected yet at the time Connection.Initializer creates the SslHandler. Modifications: Create a child interface to SSLOptions, RemoteEndpointAwareSSLOptions, that exposes a new method to create SslHandler instances with remote address information. Modify Connection class so that it detects instances of RemoteEndpointAwareSSLOptions and calls the new method instead of the old one. Create subclasses for JdkSSLOptions and NettySSLOptions that implement RemoteEndpointAwareSSLOptions: RemoteEndpointAwareJdkSSLOptions and RemoteEndpointAwareNettySSLOptions. Deprecate SSLOptions and direct implementations. Result: Remote endpoint information is now available to implementors of RemoteEndpointAwareSSLOptions, and to the driver built-in implementations RemoteEndpointAwareJdkSSLOptions and RemoteEndpointAwareNettySSLOptions. This commit is based on original work by Tim Lamballais Tessensohn (@wimtie). It also contains contributions by Andrew Tolbert (@tolbertam) and Olivier Michallat (@olim7t).
1 parent 1ddd09e commit 3c96548

File tree

15 files changed

+476
-22
lines changed

15 files changed

+476
-22
lines changed

changelog/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
- [new feature] JAVA-1347: Add support for duration type.
66
- [new feature] JAVA-1248: Implement "beta" flag for native protocol v5.
77
- [new feature] JAVA-1362: Send query options flags as [int] for Protocol V5+.
8+
- [new feature] JAVA-1364: Enable creation of SSLHandler with remote address information.
89
- [improvement] JAVA-1367: Make protocol negotiation more resilient.
910
- [bug] JAVA-1397: Handle duration as native datatype in protocol v5+.
1011
- [improvement] JAVA-1308: CodecRegistry performance improvements.

driver-core/src/main/java/com/datastax/driver/core/Cluster.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1173,7 +1173,7 @@ public Builder withoutMetrics() {
11731173
* Enables the use of SSL for the created {@code Cluster}.
11741174
* <p/>
11751175
* Calling this method will use the JDK-based implementation with the default options
1176-
* (see {@link JdkSSLOptions.Builder}).
1176+
* (see {@link RemoteEndpointAwareJdkSSLOptions.Builder}).
11771177
* This is thus a shortcut for {@code withSSL(JdkSSLOptions.builder().build())}.
11781178
* <p/>
11791179
* Note that if SSL is enabled, the driver will not connect to any
@@ -1184,7 +1184,7 @@ public Builder withoutMetrics() {
11841184
* @return this builder.
11851185
*/
11861186
public Builder withSSL() {
1187-
this.sslOptions = JdkSSLOptions.builder().build();
1187+
this.sslOptions = RemoteEndpointAwareJdkSSLOptions.builder().build();
11881188
return this;
11891189
}
11901190

driver-co 57A6 re/src/main/java/com/datastax/driver/core/Connection.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1425,7 +1425,11 @@ protected void initChannel(SocketChannel channel) throws Exception {
14251425
ChannelPipeline pipeline = channel.pipeline();
14261426

14271427
if (sslOptions != null) {
1428-
pipeline.addLast("ssl", sslOptions.newSSLHandler(channel));
1428+
if (sslOptions instanceof RemoteEndpointAwareSSLOptions)
1429+
pipeline.addLast("ssl", ((RemoteEndpointAwareSSLOptions) sslOptions).newSSLHandler(channel, connection.address));
1430+
else
1431+
//noinspection deprecation
1432+
pipeline.addLast("ssl", sslOptions.newSSLHandler(channel));
14291433
}
14301434

14311435
// pipeline.addLast("debug", new LoggingHandler(LogLevel.INFO));

driver-core/src/main/java/com/datastax/driver/core/JdkSSLOptions.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,11 @@
2424

2525
/**
2626
* {@link SSLOptions} implementation based on built-in JDK classes.
27+
*
28+
* @deprecated Use {@link RemoteEndpointAwareJdkSSLOptions} instead.
2729
*/
30+
@SuppressWarnings("DeprecatedIsStillUsed")
31+
@Deprecated
2832
public class JdkSSLOptions implements SSLOptions {
2933

3034
/**
@@ -36,8 +40,8 @@ public static Builder builder() {
3640
return new Builder();
3741
}
3842

39-
private final SSLContext context;
40-
private final String[] cipherSuites;
43+
protected final SSLContext context;
44+
protected final String[] cipherSuites;
4145

4246
/**
4347
* Creates a new instance.
@@ -66,7 +70,7 @@ public SslHandler newSSLHandler(SocketChannel channel) {
6670
* @param channel the Netty channel for that connection.
6771
* @return the engine.
6872
*/
69-
protected SSLEngine newSSLEngine(SocketChannel channel) {
73+
protected SSLEngine newSSLEngine(@SuppressWarnings("unused") SocketChannel channel) {
7074
SSLEngine engine = context.createSSLEngine();
7175
engine.setUseClientMode(true);
7276
if (cipherSuites != null)
@@ -86,8 +90,8 @@ private static SSLContext makeDefaultContext() throws IllegalStateException {
8690
* Helper class to build JDK-based SSL options.
8791
*/
8892
public static class Builder {
89-
private SSLContext context;
90-
private String[] cipherSuites;
93+
protected SSLContext context;
94+
protected String[] cipherSuites;
9195

9296
/**
9397
* Set the SSL context to use.
@@ -124,6 +128,7 @@ public Builder withCipherSuites(String[] cipherSuites) {
124128
*
125129
* @return the new instance.
126130
*/
131+
@SuppressWarnings("deprecation")
127132
public JdkSSLOptions build() {
128133
return new JdkSSLOptions(context, cipherSuites);
129134
}

driver-core/src/main/java/com/datastax/driver/core/NettySSLOptions.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,13 @@
2323
* {@link SSLOptions} implementation based on Netty's SSL context.
2424
* <p/>
2525
* Netty has the ability to use OpenSSL if available, instead of the JDK's built-in engine. This yields better performance.
26+
*
27+
* @deprecated Use {@link RemoteEndpointAwareNettySSLOptions} instead.
2628
*/
29+
@SuppressWarnings("DeprecatedIsStillUsed")
30+
@Deprecated
2731
public class NettySSLOptions implements SSLOptions {
28-
private final SslContext context;
32+
protected final SslContext context;
2933

3034
/**
3135
* Create a new instance from a given context.
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*
2+
* Copyright (C) 2012-2015 DataStax Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.datastax.driver.core;
17+
18+
import io.netty.channel.socket.SocketChannel;
19+
import io.netty.handler.ssl.SslHandler;
20+
21+
import javax.net.ssl.SSLContext;
22+
import javax.net.ssl.SSLEngine;
23+
import java.net.InetSocketAddress;
24+
25+
/**
26+
* {@link RemoteEndpointAwareSSLOptions} implementation based on built-in JDK classes.
27+
*
28+
* @see <a href="https://datastax-oss.atlassian.net/browse/JAVA-1364">JAVA-1364</a>
29+
* @since 3.2.0
30+
*/
31+
@SuppressWarnings("deprecation")
32+
public class RemoteEndpointAwareJdkSSLOptions extends JdkSSLOptions implements RemoteEndpointAwareSSLOptions {
33+
34+
/**
35+
* Creates a builder to create a new instance.
36+
*
37+
* @return the builder.
38+
*/
39+
public static Builder builder() {
40+
return new Builder();
41+
}
42+
43+
/**
44+
* Creates a new instance.
45+
*
46+
* @param context the SSL context.
47+
* @param cipherSuites the cipher suites to use.
48+
*/
49+
protected RemoteEndpointAwareJdkSSLOptions(SSLContext context, String[] cipherSuites) {
50+
super(context, cipherSuites);
51+
}
52+
53+
@Override
54+
public SslHandler newSSLHandler(SocketChannel channel) {
55+
throw new AssertionError("This class implements RemoteEndpointAwareSSLOptions, this method should not be called");
56+
}
57+
58+
@Override
59+
public SslHandler newSSLHandler(SocketChannel channel, InetSocketAddress remoteEndpoint) {
60+
SSLEngine engine = newSSLEngine(channel, remoteEndpoint);
61+
return new SslHandler(engine);
62+
}
63+
64+
/**
65+
* Creates an SSL engine each time a connection is established.
66+
* <p/>
67+
* You might want to override this if you need to fine-tune the engine's configuration
68+
* (for example enabling hostname verification).
69+
*
70+
* @param channel the Netty channel for that connection.
71+
* @param remoteEndpoint the remote endpoint we are connecting to.
72+
* @return the engine.
73+
* @since 3.2.0
74+
*/
75+
protected SSLEngine newSSLEngine(@SuppressWarnings("unused") SocketChannel channel, InetSocketAddress remoteEndpoint) {
76+
SSLEngine engine = remoteEndpoint == null
77+
? context.createSSLEngine()
78+
: context.createSSLEngine(remoteEndpoint.getHostName(), remoteEndpoint.getPort());
79+
engine.setUseClientMode(true);
80+
if (cipherSuites != null)
81+
engine.setEnabledCipherSuites(cipherSuites);
82+
return engine;
83+
}
84+
85+
/**
86+
* Helper class to build JDK-based SSL options.
87+
*/
88+
public static class Builder extends JdkSSLOptions.Builder {
89+
90+
/**
91+
* Builds a new instance based on the parameters provided to this builder.
92+
*
93+
* @return the new instance.
94+
*/
95+
@Override
96+
public RemoteEndpointAwareJdkSSLOptions build() {
97+
return new RemoteEndpointAwareJdkSSLOptions(context, cipherSuites);
98+
}
99+
}
100+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Copyright (C) 2012-2015 DataStax Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.datastax.driver.core;
17+
18+
import io.netty.channel.socket.SocketChannel;
19+
import io.netty.handler.ssl.SslContext;
20+
import io.netty.handler.ssl.SslHandler;
21+
22+
import java.net.InetSocketAddress;
23+
24+
/**
25+
* {@link RemoteEndpointAwareSSLOptions} implementation based on Netty's SSL context.
26+
* <p/>
27+
* Netty has the ability to use OpenSSL if available, instead of the JDK's built-in engine. This yields better performance.
28+
*
29+
* @see <a href="https://datastax-oss.atlassian.net/browse/JAVA-1364">JAVA-1364</a>
30+
* @since 3.2.0
31+
*/
32+
@SuppressWarnings("deprecation")
33+
public class RemoteEndpointAwareNettySSLOptions extends NettySSLOptions implements RemoteEndpointAwareSSLOptions {
34+
35+
/**
36+
* Create a new instance from a given context.
37+
*
38+
* @param context the Netty context. {@code SslContextBuilder.forClient()} provides a fluent API to build it.
39+
*/
40+
public RemoteEndpointAwareNettySSLOptions(SslContext context) {
41+
super(context);
42+
}
43+
44+
@Override
45+
public SslHandler newSSLHandler(SocketChannel channel) {
46+
throw new AssertionError("This class implements RemoteEndpointAwareSSLOptions, this method should not be called");
47+
}
48+
49+
@Override
50+
public SslHandler newSSLHandler(SocketChannel channel, InetSocketAddress remoteEndpoint) {
51+
return context.newHandler(channel.alloc(), remoteEndpoint.getHostName(), remoteEndpoint.getPort());
52+
}
53+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Copyright (C) 2012-2015 DataStax Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
D7AE
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.datastax.driver.core;
17+
18+
import io.netty.channel.socket.SocketChannel;
19+
import io.netty.handler.ssl.SslHandler;
20+
21+
import java.net.InetSocketAddress;
22+
23+
/**
24+
* Child interface to {@link SSLOptions} with the possibility to pass remote endpoint data
25+
* when instantiating {@link SslHandler}s.
26+
* <p/>
27+
* This is needed when e.g. hostname verification is required.
28+
* See <a href="https://datastax-oss.atlassian.net/browse/JAVA-1364">JAVA-1364</a> for details.
29+
* <p/>
30+
* The reason this is a child interface is to keep {@link SSLOptions} backwards-compatible.
31+
* This interface may be be merged into {@link SSLOptions} in a later major release.
32+
*
33+
* @see <a href="https://datastax-oss.atlassian.net/browse/JAVA-1364">JAVA-1364</a>
34+
* @since 3.2.0
35+
*/
36+
public interface RemoteEndpointAwareSSLOptions extends SSLOptions {
37+
38+
/**
39+
* Creates a new SSL handler for the given Netty channel and the given remote endpoint.
40+
* <p/>
41+
* This gets called each time the driver opens a new connection to a Cassandra host. The newly created handler will be added
42+
* to the channel's pipeline to provide SSL support for the connection.
43+
* <p/>
44+
* You don't necessarily need to implement this method directly; see the provided implementations:
45+
* {@link RemoteEndpointAwareJdkSSLOptions} and {@link RemoteEndpointAwareNettySSLOptions}.
46+
*
47+
* @param channel the channel.
48+
* @param remoteEndpoint the remote endpoint address.
49+
* @return a newly-created {@link SslHandler}.
50+
*/
51+
SslHandler newSSLHandler(SocketChannel channel, InetSocketAddress remoteEndpoint);
52+
53+
}

driver-core/src/main/java/com/datastax/driver/core/SSLOptions.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,19 @@
1818
import io.netty.channel.socket.SocketChannel;
1919
import io.netty.handler.ssl.SslHandler;
2020

21+
import java.net.InetSocketAddress;
22+
2123
/**
2224
* Defines how the driver configures SSL connections.
25+
* <p/>
26+
* Note: since version 3.2.0, users are encouraged to implement
27+
* {@link RemoteEndpointAwareSSLOptions} instead.
2328
*
29+
* @see RemoteEndpointAwareSSLOptions
2430
* @see JdkSSLOptions
2531
* @see NettySSLOptions
2632
*/
33+
@SuppressWarnings("deprecation")
2734
public interface SSLOptions {
2835

2936
/**
@@ -37,6 +44,10 @@ public interface SSLOptions {
3744
*
3845
* @param channel the channel.
3946
* @return the handler.
47+
* @deprecated use {@link RemoteEndpointAwareSSLOptions#newSSLHandler(SocketChannel, InetSocketAddress)} instead.
48+
*
4049
*/
50+
@SuppressWarnings("DeprecatedIsStillUsed")
51+
@Deprecated
4152
SslHandler newSSLHandler(SocketChannel channel);
4253
}

0 commit comments

Comments
 (0)
0