Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 77 additions & 9 deletions ratis-common/src/main/java/org/apache/ratis/security/TlsConf.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/
package org.apache.ratis.security;

import org.apache.ratis.thirdparty.io.netty.handler.ssl.SslProvider;
import org.apache.ratis.util.JavaUtils;
import org.apache.ratis.util.Preconditions;

Expand All @@ -25,8 +26,11 @@
import java.io.File;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
Expand Down Expand Up @@ -170,16 +174,22 @@ public KeyManager getKeyManager() {
private final KeyManagerConf keyManager;
private final TrustManagerConf trustManager;
private final boolean mutualTls;

private TlsConf(String name, KeyManagerConf keyManager, TrustManagerConf trustManager, boolean mutualTls) {
this.name = JavaUtils.getClassSimpleName(getClass()) + COUNT.getAndIncrement() + (name == null? "": "-" + name);
this.keyManager = keyManager;
this.trustManager = trustManager;
this.mutualTls = mutualTls;
}
private final SslProvider sslProvider;
private final String jsseProviderName;
private final List<String> protocols;
private final List<String> cipherSuites;

protected TlsConf(Builder b) {
this(b.buildName(), b.buildKeyManagerConf(), b.buildTrustManagerConf(), b.isMutualTls());
final String buildName = b.buildName();
this.name = JavaUtils.getClassSimpleName(getClass()) + COUNT.getAndIncrement()
+ (buildName == null? "": "-" + buildName);
this.keyManager = b.buildKeyManagerConf();
this.trustManager = b.buildTrustManagerConf();
this.mutualTls = b.isMutualTls();
this.sslProvider = b.sslProvider;
this.jsseProviderName = b.jsseProviderName;
this.protocols = copy(b.protocols);
this.cipherSuites = copy(b.cipherSuites);
}

/** @return the key manager configuration. */
Expand All @@ -197,6 +207,22 @@ public boolean isMutualTls() {
return mutualTls;
}

public SslProvider getSslProvider() {
return sslProvider;
}

public String getJsseProviderName() {
return jsseProviderName;
}

public List<String> getProtocols() {
return copy(protocols);
}

public List<String> getCipherSuites() {
return copy(cipherSuites);
}

@Override
public String toString() {
return name;
Expand All @@ -206,6 +232,14 @@ public static Builder newBuilder() {
return new Builder();
}

private static List<String> copy(List<String> values) {
return values != null ? Collections.unmodifiableList(new ArrayList<>(values)) : null;
}

private static List<String> copy(String[] values) {
return values != null ? copy(Arrays.asList(values)) : null;
}

/** For building {@link TlsConf}. */
public static class Builder {
private String name;
Expand All @@ -215,6 +249,10 @@ public static class Builder {
private boolean mutualTls;
private KeyManager keyManager;
private TrustManager trustManager;
private SslProvider sslProvider;
private String jsseProviderName;
private List<String> protocols;
private List<String> cipherSuites;

public Builder setName(String name) {
this.name = name;
Expand Down Expand Up @@ -251,6 +289,36 @@ public Builder setMutualTls(boolean mutualTls) {
return this;
}

public Builder setSslProvider(SslProvider sslProvider) {
this.sslProvider = sslProvider;
return this;
}

public Builder setJsseProviderName(String jsseProviderName) {
this.jsseProviderName = jsseProviderName;
return this;
}

public Builder setProtocols(String... protocols) {
this.protocols = copy(protocols);
return this;
}

public Builder setProtocols(List<String> protocols) {
this.protocols = copy(protocols);
return this;
}

public Builder setCipherSuites(String... cipherSuites) {
this.cipherSuites = copy(cipherSuites);
return this;
}

public Builder setCipherSuites(List<String> cipherSuites) {
this.cipherSuites = copy(cipherSuites);
return this;
}

private boolean isMutualTls() {
return mutualTls;
}
Expand Down Expand Up @@ -285,4 +353,4 @@ public TlsConf build() {
return new TlsConf(this);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package org.apache.ratis.grpc;

import org.apache.ratis.security.TlsConf;
import org.apache.ratis.thirdparty.io.netty.handler.ssl.SslProvider;

import javax.net.ssl.KeyManager;
import javax.net.ssl.TrustManager;
Expand Down Expand Up @@ -131,4 +132,94 @@ private static Builder newBuilder(File privateKeyFile, File certChainFile, File
private static Builder newBuilder(KeyManager keyManager, TrustManager trustManager, boolean mTlsEnabled) {
return newBuilder().setMutualTls(mTlsEnabled).setKeyManager(keyManager).setTrustManager(trustManager);
}
}

public static Builder newBuilder() {
return new Builder();
}

/** For building {@link GrpcTlsConfig}. */
public static class Builder extends TlsConf.Builder {
@Override
public Builder setName(String name) {
super.setName(name);
return this;
}

@Override
public Builder setTrustCertificates(CertificatesConf trustCertificates) {
super.setTrustCertificates(trustCertificates);
return this;
}

@Override
public Builder setPrivateKey(PrivateKeyConf privateKey) {
super.setPrivateKey(privateKey);
return this;
}

@Override
public Builder setKeyCertificates(CertificatesConf keyCertificates) {
super.setKeyCertificates(keyCertificates);
return this;
}

@Override
public Builder setKeyManager(KeyManager keyManager) {
super.setKeyManager(keyManager);
return this;
}

@Override
public Builder setTrustManager(TrustManager trustManager) {
super.setTrustManager(trustManager);
return this;
}

@Override
public Builder setMutualTls(boolean mutualTls) {
super.setMutualTls(mutualTls);
return this;
}

@Override
public Builder setSslProvider(SslProvider sslProvider) {
super.setSslProvider(sslProvider);
return this;
}

@Override
public Builder setJsseProviderName(String jsseProviderName) {
super.setJsseProviderName(jsseProviderName);
return this;
}

@Override
public Builder setProtocols(String... protocols) {
super.setProtocols(protocols);
return this;
}

@Override
public Builder setProtocols(List<String> protocols) {
super.setProtocols(protocols);
return this;
}

@Override
public Builder setCipherSuites(String... cipherSuites) {
super.setCipherSuites(cipherSuites);
return this;
}

@Override
public Builder setCipherSuites(List<String> cipherSuites) {
super.setCipherSuites(cipherSuites);
return this;
}

@Override
public GrpcTlsConfig build() {
return new GrpcTlsConfig(this, false);
}
}
}
67 changes: 65 additions & 2 deletions ratis-grpc/src/main/java/org/apache/ratis/grpc/GrpcUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.util.function.Consumer;
import org.apache.ratis.protocol.exceptions.ServerNotReadyException;
import org.apache.ratis.protocol.exceptions.TimeoutIOException;
import org.apache.ratis.security.TlsConf;
import org.apache.ratis.security.TlsConf.TrustManagerConf;
import org.apache.ratis.security.TlsConf.CertificatesConf;
import org.apache.ratis.security.TlsConf.PrivateKeyConf;
Expand All @@ -30,9 +31,12 @@
import org.apache.ratis.thirdparty.io.grpc.StatusRuntimeException;
import org.apache.ratis.thirdparty.io.grpc.netty.GrpcSslContexts;
import org.apache.ratis.thirdparty.io.grpc.stub.StreamObserver;
import org.apache.ratis.thirdparty.io.netty.handler.ssl.ApplicationProtocolConfig;
import org.apache.ratis.thirdparty.io.netty.handler.ssl.ClientAuth;
import org.apache.ratis.thirdparty.io.netty.handler.ssl.IdentityCipherSuiteFilter;
import org.apache.ratis.thirdparty.io.netty.handler.ssl.SslContext;
import org.apache.ratis.thirdparty.io.netty.handler.ssl.SslContextBuilder;
import org.apache.ratis.thirdparty.io.netty.handler.ssl.SslProvider;
import org.apache.ratis.util.IOUtils;
import org.apache.ratis.util.JavaUtils;
import org.apache.ratis.util.LogUtils;
Expand All @@ -45,6 +49,9 @@
import javax.net.ssl.SSLException;
import javax.net.ssl.TrustManager;
import java.io.IOException;
import java.security.Provider;
import java.security.Security;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
Expand All @@ -64,6 +71,12 @@ public interface GrpcUtil {
Metadata.Key<String> HEARTBEAT =
Metadata.Key.of("heartbeat", Metadata.ASCII_STRING_MARSHALLER);

ApplicationProtocolConfig ALPN =
new ApplicationProtocolConfig(ApplicationProtocolConfig.Protocol.ALPN,
ApplicationProtocolConfig.SelectorFailureBehavior.NO_ADVERTISE,
ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT,
"h2");

static StatusRuntimeException wrapException(Throwable t) {
return wrapException(t, -1);
}
Expand Down Expand Up @@ -306,6 +319,56 @@ static void setKeyManager(SslContextBuilder b, KeyManagerConf keyManagerConfig)
}
}

static SslContextBuilder configureSslContextBuilder(
SslContextBuilder b, TlsConf tlsConf, SslProvider defaultSslProvider) {
final Provider jsseProvider = getJsseProvider(tlsConf);
if (jsseProvider != null) {
b = configureJsseProvider(b, jsseProvider);
} else {
final SslProvider sslProvider = tlsConf.getSslProvider() != null
? tlsConf.getSslProvider() : defaultSslProvider;
if (sslProvider == SslProvider.OPENSSL_REFCNT) {
b = GrpcSslContexts.configure(b, OPENSSL).sslProvider(SslProvider.OPENSSL_REFCNT);
} else {
b = sslProvider != null ? GrpcSslContexts.configure(b, sslProvider) : GrpcSslContexts.configure(b);
}
}
final List<String> protocols = tlsConf.getProtocols();
if (protocols != null && !protocols.isEmpty()) {
b.protocols(protocols.toArray(new String[0]));
}
final List<String> cipherSuites = tlsConf.getCipherSuites();
if (cipherSuites != null && !cipherSuites.isEmpty()) {
b.ciphers(cipherSuites, IdentityCipherSuiteFilter.INSTANCE);
}
return b;
}

static SslContextBuilder configureJsseProvider(SslContextBuilder b, Provider provider) {
try {
return GrpcSslContexts.configure(b, provider);
} catch (IllegalArgumentException e) {
if (!String.valueOf(e.getMessage()).contains("Unknown provider")) {
throw e;
}
return b.sslProvider(SslProvider.JDK)
.applicationProtocolConfig(ALPN)
.sslContextProvider(provider);
}
}

static Provider getJsseProvider(TlsConf tlsConf) {
final String providerName = tlsConf.getJsseProviderName();
if (providerName == null || providerName.trim().isEmpty()) {
return null;
}
final Provider namedProvider = Security.getProvider(providerName.trim());
if (namedProvider == null) {
throw new IllegalArgumentException("JSSE provider not found: " + providerName);
}
return namedProvider;
}

static SslContext buildSslContextForServer(GrpcTlsConfig tlsConf) {
if (tlsConf == null) {
return null;
Expand All @@ -315,7 +378,7 @@ static SslContext buildSslContextForServer(GrpcTlsConfig tlsConf) {
b.clientAuth(ClientAuth.REQUIRE);
setTrustManager(b, tlsConf.getTrustManager());
}
b = GrpcSslContexts.configure(b, OPENSSL);
b = configureSslContextBuilder(b, tlsConf, OPENSSL);
try {
return b.build();
} catch (Exception e) {
Expand All @@ -328,7 +391,7 @@ static SslContext buildSslContextForClient(GrpcTlsConfig tlsConf) {
return null;
}

final SslContextBuilder b = GrpcSslContexts.forClient();
final SslContextBuilder b = configureSslContextBuilder(SslContextBuilder.forClient(), tlsConf, null);
setTrustManager(b, tlsConf.getTrustManager());
if (tlsConf.getMtlsEnabled()) {
setKeyManager(b, tlsConf.getKeyManager());
Expand Down
Loading
Loading