fapifta commented on code in PR #5649: URL: https://github.com/apache/ozone/pull/5649#discussion_r1418856343
########## hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/client/ClientTrustManager.java: ########## @@ -0,0 +1,230 @@ +/* + * 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.hadoop.hdds.scm.client; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.net.ssl.SSLEngine; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509ExtendedTrustManager; +import java.io.IOException; +import java.net.Socket; +import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.List; + +/** + * A {@link javax.net.ssl.TrustManager} implementation for gRPC and Ratis + * clients. + * + * This TrustManager instance is holding a reference to an externally supplied + * TrustManager instance, and forwards all requests to that one. + * This class is designed within the context of XceiverClientManager, where + * we have the TrustManager initialized based on a ServiceInfo object, and + * later on if the root of trust expires we need to refresh the rootCA + * certificate for long-running clients to deal with a rootCA rotation if + * necessary. + * + * The broader context where this class is usable is generally any place, where + * clients are created based on a factory, and that factory can cache the + * initial root of trust in this TrustManager, and a refresh mechanism as + * necessary if the root of trust is expected to change for the certificate + * of the server side. + * + * Note that in-memory provider is used to get the initial list of CA + * certificates, that will be used to verify server side certificates. + * In case of a certificate verification failure, the remote provider is used + * to fetch a new list of CA certificates that will be used to verify server + * side certificate from then on until the next failure. + * Failures expected to happen only after a CA certificate that issued + * the certificate of the servers is expired, or when the servers in preparation + * for this expiration event renewed their certificates with a new CA. + * + * Important to note that this logic without additional efforts is weak against + * a sophisticated attack, and should only be used with extra protection within + * the remote provider. In Ozone's case the supplied remote provider is + * an OzoneManager client, that verifies the identity of the server side + * via Kerberos and expects the other side to be identified as an Ozone Manager. + * + * The checkClientTrusted methods throw Unsupported operation exceptions, + * as this TrustManager instance is designed to be used only with client side + * SSL channels. + */ +public class ClientTrustManager extends X509ExtendedTrustManager { + + private static final Logger LOG = + LoggerFactory.getLogger(ClientTrustManager.class); + + private final CACertificateProvider remoteProvider; + private X509ExtendedTrustManager trustManager; + + /** + * An interface that defines a trust anchor provider API this class relies on. + */ + @FunctionalInterface + public interface CACertificateProvider { + List<X509Certificate> provideCACerts() throws IOException; + } + + /** + * Creates a ClientTrustManager instance based on an in-memory and a remote + * trust anchor provider. + * + * The TrustManager first loads itself utilizing the in-memory provider to + * provide a trust anchor (CA certificate) to be present in the trust store. + * + * Once the trust can not be established it uses the remote trust anchor + * provider to refresh the locally known list of certificates. + * + * Both provider is allowed to be null, if any of them is null, then it + * will not be used to get the certificate list to be trusted. + * If both the remote and in memory provider is null, any call to verify + * a server certificate will fail with an underlying SSL error. The trust + * check does not fall back to a system provided trust store, as in Ozone + * we are not currently rely on that. + * + * @param remoteProvider the provider to call once the root of trust has to + * be renewed potentially as certificate verification + * failed. + * @param inMemoryProvider the initial provider of the trusted certificates. + * @throws IOException in case an IO operation fails. + */ + public ClientTrustManager(CACertificateProvider remoteProvider, + CACertificateProvider inMemoryProvider) + throws IOException { + this.remoteProvider = remoteProvider; Review Comment: yes, agree, I added check for arguments to error out in case both are null. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
