This is an automated email from the ASF dual-hosted git repository.
szetszwo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ratis.git
The following commit(s) were added to refs/heads/master by this push:
new 51d3aef RATIS-1539. Refactor GrpcTlsConfig. (#613)
51d3aef is described below
commit 51d3aefaf72560cf0e8b57d721139bc2f2db8fe1
Author: Tsz-Wo Nicholas Sze <[email protected]>
AuthorDate: Tue Mar 1 22:58:16 2022 +0800
RATIS-1539. Refactor GrpcTlsConfig. (#613)
---
.../java/org/apache/ratis/security/TlsConf.java | 218 +++++++++++++++++++++
.../java/org/apache/ratis/grpc/GrpcTlsConfig.java | 91 +++++----
2 files changed, 274 insertions(+), 35 deletions(-)
diff --git a/ratis-common/src/main/java/org/apache/ratis/security/TlsConf.java
b/ratis-common/src/main/java/org/apache/ratis/security/TlsConf.java
new file mode 100644
index 0000000..e012d57
--- /dev/null
+++ b/ratis-common/src/main/java/org/apache/ratis/security/TlsConf.java
@@ -0,0 +1,218 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ratis.security;
+
+import org.apache.ratis.util.JavaUtils;
+import org.apache.ratis.util.Preconditions;
+
+import java.io.File;
+import java.security.PrivateKey;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * TLS configurations.
+ */
+public class TlsConf {
+ /**
+ * The value is either an actual object or a file containing the object.
+ * @param <V> The value type.
+ */
+ private static class FileBasedValue<V> {
+ private final V value;
+ private final File file;
+
+ FileBasedValue(V value) {
+ this.value = Objects.requireNonNull(value, () -> "value == null in " +
getClass());
+ this.file = null;
+
+ if (value instanceof Iterable) {
+ final Iterator<?> i = ((Iterable<?>) value).iterator();
+ Preconditions.assertTrue(i.hasNext(), "value is an empty Iterable in "
+ getClass());
+ Objects.requireNonNull(i.next(), () -> "The first item in value is
null in " + getClass());
+ }
+ }
+
+ FileBasedValue(File file) {
+ this.value = null;
+ this.file = Objects.requireNonNull(file, () -> "file == null in " +
getClass());
+ }
+
+ public V get() {
+ return value;
+ }
+
+ public File getFile() {
+ return file;
+ }
+
+ public final boolean isFileBased() {
+ return getFile() != null;
+ }
+ }
+
+ /** Configuration for {@link X509Certificate}s. */
+ public static class CertificatesConf extends
FileBasedValue<Iterable<X509Certificate>> {
+ public CertificatesConf(Iterable<X509Certificate> certificates) {
+ super(certificates);
+ }
+ public CertificatesConf(X509Certificate... certificates) {
+ this(Arrays.asList(certificates));
+ }
+ public CertificatesConf(File certificates) {
+ super(certificates);
+ }
+ }
+
+ /** Configuration for a {@link PrivateKey}. */
+ public static class PrivateKeyConf extends FileBasedValue<PrivateKey> {
+ public PrivateKeyConf(PrivateKey privateKey) {
+ super(privateKey);
+ }
+ public PrivateKeyConf(File privateKeyFile) {
+ super(privateKeyFile);
+ }
+ }
+
+ /** Configurations for a trust manager. */
+ public static final class TrustManagerConf {
+ /** Trust certificates. */
+ private final CertificatesConf trustCertificates;
+
+ private TrustManagerConf(CertificatesConf trustCertificates) {
+ this.trustCertificates = trustCertificates;
+ }
+
+ /** @return the trust certificates. */
+ public CertificatesConf getTrustCertificates() {
+ return trustCertificates;
+ }
+ }
+
+ /** Configurations for a key manager. */
+ public static final class KeyManagerConf {
+ /** A {@link PrivateKey}. */
+ private final PrivateKeyConf privateKey;
+ /** Certificates for the private key. */
+ private final CertificatesConf keyCertificates;
+
+ private KeyManagerConf(PrivateKeyConf privateKey, CertificatesConf
keyCertificates) {
+ this.privateKey = Objects.requireNonNull(privateKey, "privateKey ==
null");
+ this.keyCertificates = Objects.requireNonNull(keyCertificates,
"keyCertificates == null");
+ }
+
+ /** @return the private key. */
+ public PrivateKeyConf getPrivateKey() {
+ return privateKey;
+ }
+
+ /** @return the certificates for the private key. */
+ public CertificatesConf getKeyCertificates() {
+ return keyCertificates;
+ }
+ }
+
+ private static final AtomicInteger COUNT = new AtomicInteger();
+
+ private final String name;
+ private final KeyManagerConf keyManager;
+ private final TrustManagerConf trustManager;
+
+ private TlsConf(String name, KeyManagerConf keyManager, TrustManagerConf
trustManager) {
+ this.name = JavaUtils.getClassSimpleName(getClass()) +
COUNT.getAndIncrement() + (name == null? "": "-" + name);
+ this.keyManager = keyManager;
+ this.trustManager = trustManager;
+ }
+
+ protected TlsConf(Builder b) {
+ this(b.buildName(), b.buildKeyManagerConf(), b.buildTrustManagerConf());
+ }
+
+ /** @return the key manager configuration. */
+ public KeyManagerConf getKeyManager() {
+ return keyManager;
+ }
+
+ /** @return the trust manager configuration. */
+ public TrustManagerConf getTrustManager() {
+ return trustManager;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+
+ public static Builder newBuilder() {
+ return new Builder();
+ }
+
+ /** For building {@link TlsConf}. */
+ public static class Builder {
+ private String name;
+ private CertificatesConf trustCertificates;
+ private PrivateKeyConf privateKey;
+ private CertificatesConf keyCertificates;
+
+ public Builder setName(String name) {
+ this.name = name;
+ return this;
+ }
+
+ public Builder setTrustCertificates(CertificatesConf trustCertificates) {
+ this.trustCertificates = trustCertificates;
+ return this;
+ }
+
+ public Builder setPrivateKey(PrivateKeyConf privateKey) {
+ this.privateKey = privateKey;
+ return this;
+ }
+
+ public Builder setKeyCertificates(CertificatesConf keyCertificates) {
+ this.keyCertificates = keyCertificates;
+ return this;
+ }
+
+ private String buildName() {
+ return Optional.ofNullable(name).orElse("");
+ }
+
+ private TrustManagerConf buildTrustManagerConf() {
+ return new TrustManagerConf(trustCertificates);
+ }
+
+ private KeyManagerConf buildKeyManagerConf() {
+ if (privateKey == null && keyCertificates == null) {
+ return null;
+ } else if (privateKey != null && keyCertificates != null) {
+ return new KeyManagerConf(privateKey, keyCertificates);
+ }
+ throw new IllegalStateException("Must be either all null or all
non-null: privateKey == null? "
+ + (privateKey == null) + ", keyCertificates == null? " +
(keyCertificates == null));
+ }
+
+ public TlsConf build() {
+ return new TlsConf(this);
+ }
+ }
+}
\ No newline at end of file
diff --git a/ratis-grpc/src/main/java/org/apache/ratis/grpc/GrpcTlsConfig.java
b/ratis-grpc/src/main/java/org/apache/ratis/grpc/GrpcTlsConfig.java
index 3a17145..39aef11 100644
--- a/ratis-grpc/src/main/java/org/apache/ratis/grpc/GrpcTlsConfig.java
+++ b/ratis-grpc/src/main/java/org/apache/ratis/grpc/GrpcTlsConfig.java
@@ -17,31 +17,21 @@
*/
package org.apache.ratis.grpc;
+import org.apache.ratis.security.TlsConf;
+
import java.io.File;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.Collections;
+import java.util.Iterator;
import java.util.List;
+import java.util.Optional;
/**
* Ratis GRPC TLS configurations.
*/
-public class GrpcTlsConfig {
- // private key
- private PrivateKey privateKey;
- private File privateKeyFile;
-
- // certificate
- private X509Certificate certChain;
- private File certChainFile;
-
- // ca certificate
- private List<X509Certificate> trustStore;
- private File trustStoreFile;
-
- // mutual TLS enabled
+public class GrpcTlsConfig extends TlsConf {
private final boolean mTlsEnabled;
-
private final boolean fileBasedConfig;
public boolean isFileBasedConfig() {
@@ -49,27 +39,47 @@ public class GrpcTlsConfig {
}
public PrivateKey getPrivateKey() {
- return privateKey;
+ return Optional.ofNullable(getKeyManager())
+ .map(KeyManagerConf::getPrivateKey)
+ .map(PrivateKeyConf::get)
+ .orElse(null);
}
public File getPrivateKeyFile() {
- return privateKeyFile;
+ return Optional.ofNullable(getKeyManager())
+ .map(KeyManagerConf::getPrivateKey)
+ .map(PrivateKeyConf::getFile)
+ .orElse(null);
}
public X509Certificate getCertChain() {
- return certChain;
+ return Optional.ofNullable(getKeyManager())
+ .map(KeyManagerConf::getKeyCertificates)
+ .map(CertificatesConf::get)
+ .map(Iterable::iterator)
+ .map(Iterator::next)
+ .orElse(null);
}
public File getCertChainFile() {
- return certChainFile;
+ return Optional.ofNullable(getKeyManager())
+ .map(KeyManagerConf::getKeyCertificates)
+ .map(CertificatesConf::getFile)
+ .orElse(null);
}
public List<X509Certificate> getTrustStore() {
- return trustStore;
+ return (List<X509Certificate>) Optional.ofNullable(getTrustManager())
+ .map(TrustManagerConf::getTrustCertificates)
+ .map(CertificatesConf::get)
+ .orElse(null);
}
public File getTrustStoreFile() {
- return trustStoreFile;
+ return Optional.ofNullable(getTrustManager())
+ .map(TrustManagerConf::getTrustCertificates)
+ .map(CertificatesConf::getFile)
+ .orElse(null);
}
public boolean getMtlsEnabled() {
@@ -78,28 +88,39 @@ public class GrpcTlsConfig {
public GrpcTlsConfig(PrivateKey privateKey, X509Certificate certChain,
List<X509Certificate> trustStore, boolean mTlsEnabled) {
- this.privateKey = privateKey;
- this.certChain = certChain;
- this.trustStore = trustStore;
- this.mTlsEnabled = mTlsEnabled;
- this.fileBasedConfig = false;
+ this(newBuilder(privateKey, certChain, trustStore), mTlsEnabled, false);
}
public GrpcTlsConfig(PrivateKey privateKey, X509Certificate certChain,
X509Certificate trustStore, boolean mTlsEnabled) {
- this.privateKey = privateKey;
- this.certChain = certChain;
- this.trustStore = Collections.singletonList(trustStore);
- this.mTlsEnabled = mTlsEnabled;
- this.fileBasedConfig = false;
+ this(privateKey, certChain, Collections.singletonList(trustStore),
mTlsEnabled);
}
public GrpcTlsConfig(File privateKeyFile, File certChainFile,
File trustStoreFile, boolean mTlsEnabled) {
- this.privateKeyFile = privateKeyFile;
- this.certChainFile = certChainFile;
- this.trustStoreFile = trustStoreFile;
+ this(newBuilder(privateKeyFile, certChainFile, trustStoreFile),
mTlsEnabled, true);
+ }
+
+ private GrpcTlsConfig(Builder builder, boolean mTlsEnabled, boolean
fileBasedConfig) {
+ super(builder);
this.mTlsEnabled = mTlsEnabled;
- this.fileBasedConfig = true;
+ this.fileBasedConfig = fileBasedConfig;
+ }
+
+ private static Builder newBuilder(PrivateKey privateKey, X509Certificate
certChain,
+ List<X509Certificate> trustStore) {
+ final Builder b = newBuilder();
+
Optional.ofNullable(trustStore).map(CertificatesConf::new).ifPresent(b::setTrustCertificates);
+
Optional.ofNullable(privateKey).map(PrivateKeyConf::new).ifPresent(b::setPrivateKey);
+
Optional.ofNullable(certChain).map(CertificatesConf::new).ifPresent(b::setKeyCertificates);
+ return b;
+ }
+
+ private static Builder newBuilder(File privateKeyFile, File certChainFile,
File trustStoreFile) {
+ final Builder b = newBuilder();
+
Optional.ofNullable(trustStoreFile).map(CertificatesConf::new).ifPresent(b::setTrustCertificates);
+
Optional.ofNullable(privateKeyFile).map(PrivateKeyConf::new).ifPresent(b::setPrivateKey);
+
Optional.ofNullable(certChainFile).map(CertificatesConf::new).ifPresent(b::setKeyCertificates);
+ return b;
}
}
\ No newline at end of file