Skip to content

Commit 137b86d

Browse files
committed
add after connected
1 parent a3eeab8 commit 137b86d

File tree

16 files changed

+2485
-8
lines changed

16 files changed

+2485
-8
lines changed

hbase-client/src/main/java/org/apache/hadoop/hbase/ipc/NettyRpcConnection.java

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@
3030
import java.util.concurrent.ScheduledExecutorService;
3131
import java.util.concurrent.ThreadLocalRandom;
3232
import java.util.concurrent.TimeUnit;
33+
import javax.net.ssl.SSLContext;
34+
import javax.net.ssl.SSLEngine;
35+
import org.apache.hadoop.hbase.io.crypto.tls.X509Util;
3336
import org.apache.hadoop.hbase.ipc.BufferCallBeforeInitHandler.BufferCallEvent;
3437
import org.apache.hadoop.hbase.ipc.HBaseRpcController.CancellationCallback;
3538
import org.apache.hadoop.hbase.security.NettyHBaseRpcConnectionHeaderHandler;
@@ -55,6 +58,7 @@
5558
import org.apache.hbase.thirdparty.io.netty.channel.ChannelPipeline;
5659
import org.apache.hbase.thirdparty.io.netty.channel.EventLoop;
5760
import org.apache.hbase.thirdparty.io.netty.handler.codec.LengthFieldBasedFrameDecoder;
61+
import org.apache.hbase.thirdparty.io.netty.handler.ssl.SslHandler;
5862
import org.apache.hbase.thirdparty.io.netty.handler.timeout.IdleStateHandler;
5963
import org.apache.hbase.thirdparty.io.netty.handler.timeout.ReadTimeoutHandler;
6064
import org.apache.hbase.thirdparty.io.netty.util.ReferenceCountUtil;
@@ -277,14 +281,7 @@ private void connect() throws UnknownHostException {
277281
.handler(new BufferCallBeforeInitHandler()).localAddress(rpcClient.localAddr)
278282
.remoteAddress(remoteAddr).connect().addListener(new ChannelFutureListener() {
279283

280-
@Override
281-
public void operationComplete(ChannelFuture future) throws Exception {
282-
Channel ch = future.channel();
283-
if (!future.isSuccess()) {
284-
failInit(ch, toIOE(future.cause()));
285-
rpcClient.failedServers.addToFailedServers(remoteId.getAddress(), future.cause());
286-
return;
287-
}
284+
private void succeed(Channel ch) throws IOException {
288285
ch.writeAndFlush(connectionHeaderPreamble.retainedDuplicate());
289286
if (useSasl) {
290287
saslNegotiate(ch);
@@ -294,6 +291,42 @@ public void operationComplete(ChannelFuture future) throws Exception {
294291
established(ch);
295292
}
296293
}
294+
295+
private void fail(Channel ch, Throwable error) {
296+
failInit(ch, toIOE(error));
297+
rpcClient.failedServers.addToFailedServers(remoteId.getAddress(), error);
298+
}
299+
300+
@Override
301+
public void operationComplete(ChannelFuture future) throws Exception {
302+
Channel ch = future.channel();
303+
if (!future.isSuccess()) {
304+
fail(ch, future.cause());
305+
return;
306+
}
307+
if (conf.getBoolean(X509Util.HBASE_CLIENT_NETTY_TLS_ENABLED, false)) {
308+
X509Util x509Util = new X509Util(conf);
309+
SSLContext sslContext = x509Util.createSSLContextAndOptions().getSSLContext();
310+
SSLEngine sslEngine = sslContext.createSSLEngine(remoteId.address.getHostName(),
311+
remoteId.address.getPort());
312+
sslEngine.setUseClientMode(true);
313+
SslHandler sslHandler = new SslHandler(sslEngine);
314+
sslHandler.setHandshakeTimeoutMillis(
315+
conf.getInt(X509Util.HBASE_CLIENT_NETTY_TLS_HANDSHAKETIMEOUT,
316+
X509Util.DEFAULT_HANDSHAKE_DETECTION_TIMEOUT_MILLIS));
317+
sslHandler.handshakeFuture().addListener(f -> {
318+
if (f.isSuccess()) {
319+
succeed(ch);
320+
} else {
321+
fail(ch, f.cause());
322+
}
323+
});
324+
ch.pipeline().addFirst(sslHandler);
325+
} else {
326+
succeed(ch);
327+
}
328+
329+
}
297330
}).channel();
298331
}
299332

hbase-common/pom.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,16 @@
152152
<artifactId>kerb-simplekdc</artifactId>
153153
<scope>test</scope>
154154
</dependency>
155+
<dependency>
156+
<groupId>org.bouncycastle</groupId>
157+
<artifactId>bcprov-jdk15on</artifactId>
158+
<scope>test</scope>
159+
</dependency>
160+
<dependency>
161+
<groupId>org.bouncycastle</groupId>
162+
<artifactId>bcpkix-jdk15on</artifactId>
163+
<scope>test</scope>
164+
</dependency>
155165
</dependencies>
156166

157167
<build>
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
package org.apache.hadoop.hbase.exceptions;
19+
20+
import org.apache.yetus.audience.InterfaceAudience;
21+
22+
/**
23+
* This file has been copied from the Apache ZooKeeper project.
24+
* @see <a href=
25+
* "https://github.com/apache/zookeeper/blob/c74658d398cdc1d207aa296cb6e20de00faec03e/zookeeper-server/src/main/java/org/apache/zookeeper/common/X509Exception.java">Base
26+
* revision</a>
27+
*/
28+
@SuppressWarnings("serial")
29+
@InterfaceAudience.Private
30+
public class X509Exception extends Exception {
31+
32+
public X509Exception(String message) {
33+
super(message);
34+
}
35+
36+
public X509Exception(Throwable cause) {
37+
super(cause);
38+
}
39+
40+
public X509Exception(String message, Throwable cause) {
41+
super(message, cause);
42+
}
43+
44+
public static class KeyManagerException extends X509Exception {
45+
46+
public KeyManagerException(String message) {
47+
super(message);
48+
}
49+
50+
public KeyManagerException(Throwable cause) {
51+
super(cause);
52+
}
53+
54+
}
55+
56+
public static class TrustManagerException extends X509Exception {
57+
58+
public TrustManagerException(String message) {
59+
super(message);
60+
}
61+
62+
public TrustManagerException(Throwable cause) {
63+
super(cause);
64+
}
65+
66+
}
67+
68+
public static class SSLContextException extends X509Exception {
69+
70+
public SSLContextException(String message) {
71+
super(message);
72+
}
73+
74+
public SSLContextException(Throwable cause) {
75+
super(cause);
76+
}
77+
78+
public SSLContextException(String message, Throwable cause) {
79+
super(message, cause);
80+
}
81+
82+
}
83+
84+
}
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
package org.apache.hadoop.hbase.io.crypto.tls;
19+
20+
import org.apache.yetus.audience.InterfaceAudience;
21+
22+
/**
23+
* This enum represents the file type of a KeyStore or TrustStore. Currently, JKS (Java keystore),
24+
* PEM, PKCS12, and BCFKS types are supported.
25+
* <p/>
26+
* This file has been copied from the Apache ZooKeeper project.
27+
* @see <a href=
28+
* "https://github.com/apache/zookeeper/blob/c74658d398cdc1d207aa296cb6e20de00faec03e/zookeeper-server/src/main/java/org/apache/zookeeper/common/KeyStoreFileType.java">Base
29+
* revision</a>
30+
*/
31+
@InterfaceAudience.Private
32+
public enum KeyStoreFileType {
33+
JKS(".jks"),
34+
PEM(".pem"),
35+
PKCS12(".p12"),
36+
BCFKS(".bcfks");
37+
38+
private final String defaultFileExtension;
39+
40+
KeyStoreFileType(String defaultFileExtension) {
41+
this.defaultFileExtension = defaultFileExtension;
42+
}
43+
44+
/**
45+
* The property string that specifies that a key store or trust store should use this store file
46+
* type.
47+
*/
48+
public String getPropertyValue() {
49+
return this.name();
50+
}
51+
52+
/**
53+
* The file extension that is associated with this file type.
54+
*/
55+
public String getDefaultFileExtension() {
56+
return defaultFileExtension;
57+
}
58+
59+
/**
60+
* Converts a property value to a StoreFileType enum. If the property value is <code>null</code>
61+
* or an empty string, returns <code>null</code>.
62+
* @param propertyValue the property value.
63+
* @return the KeyStoreFileType, or <code>null</code> if <code>propertyValue</code> is
64+
* <code>null</code> or empty.
65+
* @throws IllegalArgumentException if <code>propertyValue</code> is not one of "JKS", "PEM",
66+
* "BCFKS", "PKCS12", or empty/null.
67+
*/
68+
public static KeyStoreFileType fromPropertyValue(String propertyValue) {
69+
if (propertyValue == null || propertyValue.length() == 0) {
70+
return null;
71+
}
72+
return KeyStoreFileType.valueOf(propertyValue.toUpperCase());
73+
}
74+
75+
/**
76+
* Detects the type of KeyStore / TrustStore file from the file extension. If the file name ends
77+
* with ".jks", returns <code>StoreFileType.JKS</code>. If the file name ends with ".pem", returns
78+
* <code>StoreFileType.PEM</code>. If the file name ends with ".p12", returns
79+
* <code>StoreFileType.PKCS12</code>. If the file name ends with ".bckfs", returns
80+
* <code>StoreFileType.BCKFS</code>. Otherwise, throws an IllegalArgumentException.
81+
* @param filename the filename of the key store or trust store file.
82+
* @return a KeyStoreFileType.
83+
* @throws IllegalArgumentException if the filename does not end with ".jks", ".pem", "p12" or
84+
* "bcfks".
85+
*/
86+
public static KeyStoreFileType fromFilename(String filename) {
87+
int i = filename.lastIndexOf('.');
88+
if (i >= 0) {
89+
String extension = filename.substring(i);
90+
for (KeyStoreFileType storeFileType : KeyStoreFileType.values()) {
91+
if (storeFileType.getDefaultFileExtension().equals(extension)) {
92+
return storeFileType;
93+
}
94+
}
95+
}
96+
throw new IllegalArgumentException(
97+
"Unable to auto-detect store file type from file name: " + filename);
98+
}
99+
100+
/**
101+
* If <code>propertyValue</code> is not null or empty, returns the result of
102+
* <code>KeyStoreFileType.fromPropertyValue(propertyValue)</code>. Else, returns the result of
103+
* <code>KeyStoreFileType.fromFileName(filename)</code>.
104+
* @param propertyValue property value describing the KeyStoreFileType, or null/empty to
105+
* auto-detect the type from the file name.
106+
* @param filename file name of the key store file. The file extension is used to auto-detect
107+
* the KeyStoreFileType when <code>propertyValue</code> is null or empty.
108+
* @return a KeyStoreFileType.
109+
* @throws IllegalArgumentException if <code>propertyValue</code> is not one of "JKS", "PEM",
110+
* "PKCS12", "BCFKS", or empty/null.
111+
* @throws IllegalArgumentException if <code>propertyValue</code>is empty or null and the type
112+
* could not be determined from the file name.
113+
*/
114+
public static KeyStoreFileType fromPropertyValueOrFileName(String propertyValue,
115+
String filename) {
116+
KeyStoreFileType result = KeyStoreFileType.fromPropertyValue(propertyValue);
117+
if (result == null) {
118+
result = KeyStoreFileType.fromFilename(filename);
119+
}
120+
return result;
121+
}
122+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
package org.apache.hadoop.hbase.io.crypto.tls;
19+
20+
import static java.util.Objects.requireNonNull;
21+
import static org.apache.hadoop.hbase.io.crypto.tls.X509Util.CONFIG_PREFIX;
22+
23+
import java.util.Arrays;
24+
import java.util.Collections;
25+
import java.util.List;
26+
import javax.net.ssl.SSLContext;
27+
import org.apache.hadoop.conf.Configuration;
28+
import org.apache.yetus.audience.InterfaceAudience;
29+
30+
import org.apache.hbase.thirdparty.io.netty.handler.ssl.ClientAuth;
31+
import org.apache.hbase.thirdparty.io.netty.handler.ssl.IdentityCipherSuiteFilter;
32+
import org.apache.hbase.thirdparty.io.netty.handler.ssl.JdkSslContext;
33+
import org.apache.hbase.thirdparty.io.netty.handler.ssl.SslContext;
34+
35+
/**
36+
* This file has been copied from the Apache ZooKeeper project.
37+
* @see <a href=
38+
* "https://github.com/apache/zookeeper/blob/c74658d398cdc1d207aa296cb6e20de00faec03e/zookeeper-server/src/main/java/org/apache/zookeeper/common/SSLContextAndOptions.java">Base
39+
* revision</a>
40+
*/
41+
@InterfaceAudience.Private
42+
public class SSLContextAndOptions {
43+
private static final String TLS_ENABLED_PROTOCOLS = CONFIG_PREFIX + "enabledProtocols";
44+
private static final String TLS_CIPHER_SUITES = CONFIG_PREFIX + "ciphersuites";
45+
46+
private final String[] enabledProtocols;
47+
private final List<String> cipherSuitesAsList;
48+
private final SSLContext sslContext;
49+
50+
/**
51+
* Note: constructor is intentionally package-private, only the X509Util class should be creating
52+
* instances of this class.
53+
* @param config The HBase configuration
54+
* @param sslContext The SSLContext.
55+
*/
56+
SSLContextAndOptions(final Configuration config, final SSLContext sslContext) {
57+
this.sslContext = requireNonNull(sslContext);
58+
this.enabledProtocols = getEnabledProtocols(requireNonNull(config), sslContext);
59+
String[] ciphers = getCipherSuites(config);
60+
this.cipherSuitesAsList = Collections.unmodifiableList(Arrays.asList(ciphers));
61+
}
62+
63+
public SSLContext getSSLContext() {
64+
return sslContext;
65+
}
66+
67+
public SslContext createNettyJdkSslContext(SSLContext sslContext, boolean isClientSocket) {
68+
return new JdkSslContext(sslContext, isClientSocket, cipherSuitesAsList,
69+
IdentityCipherSuiteFilter.INSTANCE, null, ClientAuth.NONE, enabledProtocols, false);
70+
}
71+
72+
private String[] getEnabledProtocols(final Configuration config, final SSLContext sslContext) {
73+
String enabledProtocolsInput = config.get(TLS_ENABLED_PROTOCOLS);
74+
if (enabledProtocolsInput == null) {
75+
return new String[] { sslContext.getProtocol() };
76+
}
77+
return enabledProtocolsInput.split(",");
78+
}
79+
80+
private String[] getCipherSuites(final Configuration config) {
81+
String cipherSuitesInput = config.get(TLS_CIPHER_SUITES);
82+
if (cipherSuitesInput == null) {
83+
return X509Util.getDefaultCipherSuites();
84+
} else {
85+
return cipherSuitesInput.split(",");
86+
}
87+
}
88+
}

0 commit comments

Comments
 (0)