Skip to content

Commit 72f746b

Browse files
authored
Add helper methods for setting cloud sslContext (#320)
1 parent e796ec4 commit 72f746b

File tree

2 files changed

+158
-2
lines changed

2 files changed

+158
-2
lines changed
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
/*
2+
* Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved.
3+
*
4+
* Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5+
*
6+
* Modifications copyright (C) 2017 Uber Technologies, Inc.
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License"). You may not
9+
* use this file except in compliance with the License. A copy of the License is
10+
* located at
11+
*
12+
* http://aws.amazon.com/apache2.0
13+
*
14+
* or in the "license" file accompanying this file. This file is distributed on
15+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
16+
* express or implied. See the License for the specific language governing
17+
* permissions and limitations under the License.
18+
*/
19+
20+
package io.temporal.serviceclient;
21+
22+
import io.grpc.netty.shaded.io.netty.handler.ssl.ApplicationProtocolConfig;
23+
import io.grpc.netty.shaded.io.netty.handler.ssl.ApplicationProtocolNames;
24+
import io.grpc.netty.shaded.io.netty.handler.ssl.SslContext;
25+
import io.grpc.netty.shaded.io.netty.handler.ssl.SslContextBuilder;
26+
import io.grpc.netty.shaded.io.netty.handler.ssl.util.InsecureTrustManagerFactory;
27+
import java.io.InputStream;
28+
import java.security.KeyStore;
29+
import java.security.KeyStoreException;
30+
import java.security.NoSuchAlgorithmException;
31+
import javax.net.ssl.SSLException;
32+
import javax.net.ssl.TrustManager;
33+
import javax.net.ssl.TrustManagerFactory;
34+
import javax.net.ssl.X509TrustManager;
35+
36+
public class SimpleSslContextBuilder {
37+
38+
// Default TLS protocol config that is used to communicate with TLS enabled temporal backend.
39+
private static final ApplicationProtocolConfig DEFAULT_APPLICATION_PROTOCOL_CONFIG =
40+
new ApplicationProtocolConfig(
41+
// HTTP/2 over TLS mandates the use of ALPN to negotiate the use of the protocol.
42+
ApplicationProtocolConfig.Protocol.ALPN,
43+
// NO_ADVERTISE is the only mode supported by both OpenSsl and JDK providers.
44+
ApplicationProtocolConfig.SelectorFailureBehavior.NO_ADVERTISE,
45+
// ACCEPT is the only mode supported by both OpenSsl and JDK providers.
46+
ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT,
47+
// gRPC requires http2 protocol.
48+
ApplicationProtocolNames.HTTP_2);
49+
50+
private final InputStream keyCertChain;
51+
private final InputStream key;
52+
private TrustManager trustManager;
53+
private boolean useInsecureTrustManager;
54+
private String keyPassword;
55+
56+
/**
57+
* @param keyCertChain - an input stream for an X.509 client certificate chain in PEM format.
58+
* @param key - an input stream for a PKCS#8 client private key in PEM format.
59+
*/
60+
public static SimpleSslContextBuilder newBuilder(InputStream keyCertChain, InputStream key) {
61+
return new SimpleSslContextBuilder(keyCertChain, key);
62+
}
63+
64+
private SimpleSslContextBuilder(InputStream keyCertChain, InputStream key) {
65+
this.keyCertChain = keyCertChain;
66+
this.key = key;
67+
}
68+
69+
/**
70+
* Builds {@link SslContext} from specified parameters. If trust manager is set then it will be
71+
* used to verify server authority, otherwise system default trust manager (or if {@link
72+
* #useInsecureTrustManager} is set then insecure trust manager) is going to be used.
73+
*
74+
* @return - {@link SslContext} that can be used with the {@link
75+
* WorkflowServiceStubsOptions.Builder#setSslContext(SslContext)}
76+
* @throws SSLException - when it was unable to build the context.
77+
*/
78+
public SslContext build() throws SSLException {
79+
if (trustManager != null && useInsecureTrustManager)
80+
throw new IllegalArgumentException(
81+
"Can not use insecure trust manager if custom trust manager is set.");
82+
return SslContextBuilder.forClient()
83+
.trustManager(
84+
trustManager != null
85+
? trustManager
86+
: useInsecureTrustManager
87+
? InsecureTrustManagerFactory.INSTANCE.getTrustManagers()[0]
88+
: getDefaultTrustManager())
89+
.keyManager(keyCertChain, key, keyPassword)
90+
.applicationProtocolConfig(DEFAULT_APPLICATION_PROTOCOL_CONFIG)
91+
.build();
92+
}
93+
94+
/**
95+
* @param trustManager - custom trust manager that should be used with the SSLContext for
96+
* verifying server CA authority.
97+
*/
98+
public void setTrustManager(TrustManager trustManager) {
99+
this.trustManager = trustManager;
100+
}
101+
102+
/**
103+
* @param useInsecureTrustManager - if set to true then insecure trust manager is going to be used
104+
* instead of the system default one. Note that this makes client vulnerable to man in the
105+
* middle attack. Use with caution.
106+
*/
107+
public void setUseInsecureTrustManager(boolean useInsecureTrustManager) {
108+
this.useInsecureTrustManager = useInsecureTrustManager;
109+
}
110+
111+
/** @param keyPassword - the password of the key, or null if it's not password-protected. */
112+
public void setKeyPassword(String keyPassword) {
113+
this.keyPassword = keyPassword;
114+
}
115+
116+
/**
117+
* @return system default trust manager.
118+
* @throws UnknownDefaultTrustManagerException, which can be caused by {@link
119+
* NoSuchAlgorithmException} if {@link TrustManagerFactory#getInstance(String)} doesn't
120+
* support default algorithm, {@link KeyStoreException} in case if {@link KeyStore}
121+
* initialization failed or if no {@link X509TrustManager} has been found.
122+
*/
123+
private X509TrustManager getDefaultTrustManager() {
124+
TrustManagerFactory tmf;
125+
try {
126+
tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
127+
// Using null here initialises the TMF with the default trust store.
128+
tmf.init((KeyStore) null);
129+
} catch (KeyStoreException | NoSuchAlgorithmException e) {
130+
throw new UnknownDefaultTrustManagerException(e);
131+
}
132+
133+
for (TrustManager tm : tmf.getTrustManagers()) {
134+
if (tm instanceof X509TrustManager) {
135+
return (X509TrustManager) tm;
136+
}
137+
}
138+
throw new UnknownDefaultTrustManagerException(
139+
"Unable to find X509TrustManager in the list of default trust managers.");
140+
}
141+
142+
/**
143+
* Exception that is thrown in case if builder was unable to derive default system trust manager.
144+
*/
145+
public static final class UnknownDefaultTrustManagerException extends RuntimeException {
146+
public UnknownDefaultTrustManagerException(Throwable cause) {
147+
super(cause);
148+
}
149+
150+
public UnknownDefaultTrustManagerException(String message) {
151+
super(message);
152+
}
153+
}
154+
}

temporal-serviceclient/src/main/java/io/temporal/serviceclient/WorkflowServiceStubsOptions.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -265,8 +265,10 @@ public Builder setChannel(ManagedChannel channel) {
265265
}
266266

267267
/**
268-
* Sets gRPC SSL Context to use, used for more advanced scenarios such as mTLS. Supercedes
269-
* enableHttps; Exclusive with channel.
268+
* Sets gRPC SSL Context to use, used for more advanced scenarios such as mTLS. Supersedes
269+
* enableHttps; Exclusive with channel. Consider using {@link SimpleSslContextBuilder} which
270+
* greatly simplifies creation of the TLS enabled SslContext with client and server key
271+
* validation.
270272
*/
271273
public Builder setSslContext(SslContext sslContext) {
272274
this.sslContext = sslContext;

0 commit comments

Comments
 (0)