You are viewing a plain text version of this content. The canonical link for it is here.
Posted to common-commits@hadoop.apache.org by xy...@apache.org on 2019/02/20 19:36:06 UTC

[hadoop] branch trunk updated: HDDS-1060. Add API to get OM certificate from SCM CA. Contributed by Ajay Kumar.

This is an automated email from the ASF dual-hosted git repository.

xyao pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/hadoop.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 1374f8f  HDDS-1060. Add API to get OM certificate from SCM CA. Contributed by Ajay Kumar.
1374f8f is described below

commit 1374f8f548a64d8b3b4a6352969ce24cc1d34f46
Author: Xiaoyu Yao <xy...@apache.org>
AuthorDate: Wed Feb 20 11:11:36 2019 -0800

    HDDS-1060. Add API to get OM certificate from SCM CA. Contributed by Ajay Kumar.
---
 .../hadoop/hdds/scm/client/HddsClientUtils.java    | 38 +++++++++++++++
 .../java/org/apache/hadoop/hdds/HddsUtils.java     | 50 ++++++++++++++++++++
 .../hadoop/hdds/protocol/SCMSecurityProtocol.java  | 23 ++++++++-
 .../SCMSecurityProtocolClientSideTranslatorPB.java | 40 ++++++++++++++++
 .../SCMSecurityProtocolServerSideTranslatorPB.java | 35 ++++++++++++++
 .../certificate/authority/CertificateServer.java   | 26 ++++++----
 .../certificate/authority/DefaultCAServer.java     | 18 +++++++
 .../src/main/proto/SCMSecurityProtocol.proto       | 24 ++++++++++
 .../hdds/scm/server/SCMSecurityProtocolServer.java | 43 +++++++++++++++++
 .../hadoop/ozone/TestSecureOzoneCluster.java       | 55 +++++++++++++++++++++-
 10 files changed, 340 insertions(+), 12 deletions(-)

diff --git a/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/client/HddsClientUtils.java b/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/client/HddsClientUtils.java
index 9c59038..be9bc93 100644
--- a/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/client/HddsClientUtils.java
+++ b/hadoop-hdds/client/src/main/java/org/apache/hadoop/hdds/scm/client/HddsClientUtils.java
@@ -22,15 +22,29 @@ import com.google.common.base.Preconditions;
 import org.apache.hadoop.classification.InterfaceAudience;
 import org.apache.hadoop.classification.InterfaceStability;
 import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hdds.HddsUtils;
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.hdds.protocol.SCMSecurityProtocol;
+import org.apache.hadoop.hdds.protocolPB.SCMSecurityProtocolClientSideTranslatorPB;
+import org.apache.hadoop.hdds.protocolPB.SCMSecurityProtocolPB;
 import org.apache.hadoop.hdds.scm.ScmConfigKeys;
+import org.apache.hadoop.hdds.scm.protocol.ScmBlockLocationProtocol;
+import org.apache.hadoop.hdds.scm.protocolPB.ScmBlockLocationProtocolPB;
+import org.apache.hadoop.ipc.Client;
+import org.apache.hadoop.ipc.ProtobufRpcEngine;
+import org.apache.hadoop.ipc.RPC;
+import org.apache.hadoop.net.NetUtils;
 import org.apache.hadoop.ozone.OzoneConfigKeys;
 import org.apache.hadoop.ozone.OzoneConsts;
+import org.apache.hadoop.security.UserGroupInformation;
 import org.apache.http.client.config.RequestConfig;
 import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.impl.client.HttpClients;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.io.IOException;
+import java.net.InetSocketAddress;
 import java.text.ParseException;
 import java.time.Instant;
 import java.time.ZoneId;
@@ -38,6 +52,7 @@ import java.time.ZonedDateTime;
 import java.time.format.DateTimeFormatter;
 import java.util.concurrent.TimeUnit;
 
+
 /**
  * Utility methods for Ozone and Container Clients.
  *
@@ -252,4 +267,27 @@ public final class HddsClientUtils {
             ScmConfigKeys
                 .SCM_CONTAINER_CLIENT_MAX_OUTSTANDING_REQUESTS_DEFAULT);
   }
+
+  /**
+   * Create a scm block client, used by putKey() and getKey().
+   *
+   * @return {@link ScmBlockLocationProtocol}
+   * @throws IOException
+   */
+  public static SCMSecurityProtocol getScmSecurityClient(
+      OzoneConfiguration conf, UserGroupInformation ugi) throws IOException {
+    RPC.setProtocolEngine(conf, SCMSecurityProtocolPB.class,
+        ProtobufRpcEngine.class);
+    long scmVersion =
+        RPC.getProtocolVersion(ScmBlockLocationProtocolPB.class);
+    InetSocketAddress scmSecurityProtoAdd =
+        HddsUtils.getScmAddressForSecurityProtocol(conf);
+    SCMSecurityProtocolClientSideTranslatorPB scmSecurityClient =
+        new SCMSecurityProtocolClientSideTranslatorPB(
+            RPC.getProxy(SCMSecurityProtocolPB.class, scmVersion,
+                scmSecurityProtoAdd, ugi, conf,
+                NetUtils.getDefaultSocketFactory(conf),
+                Client.getRpcTimeout(conf)));
+    return scmSecurityClient;
+  }
 }
\ No newline at end of file
diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/HddsUtils.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/HddsUtils.java
index 9bae6d8..1556a57 100644
--- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/HddsUtils.java
+++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/HddsUtils.java
@@ -410,4 +410,54 @@ public final class HddsUtils {
   public static long getUtcTime() {
     return Calendar.getInstance(UTC_ZONE).getTimeInMillis();
   }
+
+  /**
+   * Retrieve the socket address that should be used by clients to connect
+   * to the SCM for
+   * {@link org.apache.hadoop.hdds.protocol.SCMSecurityProtocol}. If
+   * {@link ScmConfigKeys#OZONE_SCM_SECURITY_SERVICE_ADDRESS_KEY} is not defined
+   * then {@link ScmConfigKeys#OZONE_SCM_CLIENT_ADDRESS_KEY} is used. If neither
+   * is defined then {@link ScmConfigKeys#OZONE_SCM_NAMES} is used.
+   *
+   * @param conf
+   * @return Target InetSocketAddress for the SCM block client endpoint.
+   * @throws IllegalArgumentException if configuration is not defined.
+   */
+  public static InetSocketAddress getScmAddressForSecurityProtocol(
+      Configuration conf) {
+    Optional<String> host = getHostNameFromConfigKeys(conf,
+        ScmConfigKeys.OZONE_SCM_SECURITY_SERVICE_ADDRESS_KEY);
+
+    if (!host.isPresent()) {
+      host = getHostNameFromConfigKeys(conf,
+          ScmConfigKeys.OZONE_SCM_CLIENT_ADDRESS_KEY);
+    }
+
+    if (!host.isPresent()) {
+      // Fallback to Ozone SCM names.
+      Collection<InetSocketAddress> scmAddresses = getSCMAddresses(conf);
+      if (scmAddresses.size() > 1) {
+        throw new IllegalArgumentException(
+            ScmConfigKeys.OZONE_SCM_NAMES +
+                " must contain a single hostname. Multiple SCM hosts are " +
+                "currently unsupported");
+      }
+      host = Optional.of(scmAddresses.iterator().next().getHostName());
+    }
+
+    if (!host.isPresent()) {
+      throw new IllegalArgumentException(
+          ScmConfigKeys.OZONE_SCM_SECURITY_SERVICE_ADDRESS_KEY
+              + " must be defined. See"
+              + " https://wiki.apache.org/hadoop/Ozone#Configuration"
+              + " for details on configuring Ozone.");
+    }
+
+    final Optional<Integer> port = getPortNumberFromConfigKeys(conf,
+        ScmConfigKeys.OZONE_SCM_SECURITY_SERVICE_PORT_KEY);
+
+    return NetUtils.createSocketAddr(host.get() + ":" + port
+        .orElse(ScmConfigKeys.OZONE_SCM_SECURITY_SERVICE_PORT_DEFAULT));
+  }
+
 }
diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/protocol/SCMSecurityProtocol.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/protocol/SCMSecurityProtocol.java
index 000e5ab..696836a 100644
--- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/protocol/SCMSecurityProtocol.java
+++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/protocol/SCMSecurityProtocol.java
@@ -45,11 +45,30 @@ public interface SCMSecurityProtocol {
   /**
    * Get SCM signed certificate for OM.
    *
-   * @param omDetails - DataNode Details.
+   * @param omDetails       - DataNode Details.
    * @param certSignReq     - Certificate signing request.
-   * @return byte[]         - SCM signed certificate.
+   * @return String         - pem encoded SCM signed
+   *                          certificate.
    */
   String getOMCertificate(OzoneManagerDetailsProto omDetails,
       String certSignReq) throws IOException;
 
+  /**
+   * Get SCM signed certificate for given certificate serial id if it exists.
+   * Throws exception if it's not found.
+   *
+   * @param certSerialId    - Certificate serial id.
+   * @return String         - pem encoded SCM signed
+   *                          certificate with given cert id if it
+   *                          exists.
+   */
+  String getCertificate(String certSerialId) throws IOException;
+
+  /**
+   * Get CA certificate.
+   *
+   * @return String         - pem encoded CA certificate.
+   */
+  String getCACertificate() throws IOException;
+
 }
diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/protocolPB/SCMSecurityProtocolClientSideTranslatorPB.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/protocolPB/SCMSecurityProtocolClientSideTranslatorPB.java
index c1895bc..7cf9476 100644
--- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/protocolPB/SCMSecurityProtocolClientSideTranslatorPB.java
+++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/protocolPB/SCMSecurityProtocolClientSideTranslatorPB.java
@@ -22,6 +22,9 @@ import java.io.Closeable;
 import java.io.IOException;
 import org.apache.hadoop.hdds.protocol.proto.HddsProtos.DatanodeDetailsProto;
 import org.apache.hadoop.hdds.protocol.proto.HddsProtos.OzoneManagerDetailsProto;
+import org.apache.hadoop.hdds.protocol.proto.SCMSecurityProtocolProtos.SCMGetCACertificateRequestProto;
+import org.apache.hadoop.hdds.protocol.proto.SCMSecurityProtocolProtos.SCMGetCertificateRequestProto;
+import org.apache.hadoop.hdds.protocol.proto.SCMSecurityProtocolProtos.SCMGetCertificateRequestProto.Builder;
 import org.apache.hadoop.hdds.protocol.proto.SCMSecurityProtocolProtos.SCMGetDataNodeCertRequestProto;
 import org.apache.hadoop.hdds.protocol.SCMSecurityProtocol;
 import org.apache.hadoop.ipc.ProtobufHelper;
@@ -113,6 +116,43 @@ public class SCMSecurityProtocolClientSideTranslatorPB implements
   }
 
   /**
+   * Get SCM signed certificate with given serial id. Throws exception if
+   * certificate is not found.
+   *
+   * @param certSerialId    - Certificate serial id.
+   * @return string         - pem encoded certificate.
+   */
+  @Override
+  public String getCertificate(String certSerialId) throws IOException {
+    Builder builder = SCMGetCertificateRequestProto
+        .newBuilder()
+        .setCertSerialId(certSerialId);
+    try {
+      return rpcProxy.getCertificate(NULL_RPC_CONTROLLER, builder.build())
+          .getX509Certificate();
+    } catch (ServiceException e) {
+      throw ProtobufHelper.getRemoteException(e);
+    }
+  }
+
+  /**
+   * Get CA certificate.
+   *
+   * @return serial   - Root certificate.
+   */
+  @Override
+  public String getCACertificate() throws IOException {
+    SCMGetCACertificateRequestProto protoIns = SCMGetCACertificateRequestProto
+        .getDefaultInstance();
+    try {
+      return rpcProxy.getCACertificate(NULL_RPC_CONTROLLER, protoIns)
+          .getX509Certificate();
+    } catch (ServiceException e) {
+      throw ProtobufHelper.getRemoteException(e);
+    }
+  }
+
+  /**
    * Return the proxy object underlying this protocol translator.
    *
    * @return the proxy object underlying this protocol translator.
diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/protocolPB/SCMSecurityProtocolServerSideTranslatorPB.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/protocolPB/SCMSecurityProtocolServerSideTranslatorPB.java
index 6deb027..c7c4ff6 100644
--- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/protocolPB/SCMSecurityProtocolServerSideTranslatorPB.java
+++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/protocolPB/SCMSecurityProtocolServerSideTranslatorPB.java
@@ -20,7 +20,9 @@ import com.google.protobuf.RpcController;
 import com.google.protobuf.ServiceException;
 import java.io.IOException;
 
+import org.apache.hadoop.hdds.protocol.proto.SCMSecurityProtocolProtos;
 import org.apache.hadoop.hdds.protocol.proto.SCMSecurityProtocolProtos.SCMGetCertResponseProto;
+import org.apache.hadoop.hdds.protocol.proto.SCMSecurityProtocolProtos.SCMGetCertificateRequestProto;
 import org.apache.hadoop.hdds.protocol.proto.SCMSecurityProtocolProtos.SCMGetDataNodeCertRequestProto;
 import org.apache.hadoop.hdds.protocol.proto.SCMSecurityProtocolProtos.SCMGetCertResponseProto.ResponseCode;
 import org.apache.hadoop.hdds.protocol.SCMSecurityProtocol;
@@ -91,4 +93,37 @@ public class SCMSecurityProtocolServerSideTranslatorPB implements
       throw new ServiceException(e);
     }
   }
+
+  @Override
+  public SCMGetCertResponseProto getCertificate(RpcController controller,
+      SCMGetCertificateRequestProto request) throws ServiceException {
+    try {
+      String certificate = impl.getCertificate(request.getCertSerialId());
+      SCMGetCertResponseProto.Builder builder =
+          SCMGetCertResponseProto
+              .newBuilder()
+              .setResponseCode(ResponseCode.success)
+              .setX509Certificate(certificate);
+      return builder.build();
+    } catch (IOException e) {
+      throw new ServiceException(e);
+    }
+  }
+
+  @Override
+  public SCMGetCertResponseProto getCACertificate(RpcController controller,
+      SCMSecurityProtocolProtos.SCMGetCACertificateRequestProto request)
+      throws ServiceException {
+    try {
+      String certificate = impl.getCACertificate();
+      SCMGetCertResponseProto.Builder builder =
+          SCMGetCertResponseProto
+              .newBuilder()
+              .setResponseCode(ResponseCode.success)
+              .setX509Certificate(certificate);
+      return builder.build();
+    } catch (IOException e) {
+      throw new ServiceException(e);
+    }
+  }
 }
\ No newline at end of file
diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/CertificateServer.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/CertificateServer.java
index 944883b..b1d7d6b 100644
--- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/CertificateServer.java
+++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/CertificateServer.java
@@ -21,6 +21,7 @@ package org.apache.hadoop.hdds.security.x509.certificate.authority;
 
 import org.apache.hadoop.hdds.security.exception.SCMSecurityException;
 import org.apache.hadoop.hdds.security.x509.SecurityConfig;
+import org.apache.hadoop.hdds.security.x509.certificate.authority.CertificateApprover.ApprovalType;
 import org.bouncycastle.cert.X509CertificateHolder;
 import org.bouncycastle.pkcs.PKCS10CertificationRequest;
 
@@ -30,8 +31,8 @@ import java.security.cert.X509Certificate;
 import java.util.concurrent.Future;
 
 /**
- * Interface for Certificate Authority. This can be extended to talk to external
- * CAs later or HSMs later.
+ * Interface for Certificate Authority. This can be extended to talk to
+ * external CAs later or HSMs later.
  */
 public interface CertificateServer {
   /**
@@ -57,6 +58,18 @@ public interface CertificateServer {
       throws CertificateException, IOException;
 
   /**
+   * Returns the Certificate corresponding to given certificate serial id if
+   * exist. Return null if it doesn't exist.
+   *
+   * @return certSerialId         - Certificate serial id.
+   * @throws CertificateException - usually thrown if this CA is not
+   *                              initialized.
+   * @throws IOException          - on Error.
+   */
+  X509Certificate getCertificate(String certSerialId)
+      throws CertificateException, IOException;
+
+  /**
    * Request a Certificate based on Certificate Signing Request.
    *
    * @param csr  - Certificate Signing Request.
@@ -80,11 +93,8 @@ public interface CertificateServer {
    * approved.
    * @throws SCMSecurityException - on Error.
    */
-  Future<X509CertificateHolder>
-      requestCertificate(String csr, CertificateApprover.ApprovalType type)
-      throws IOException;
-
-
+  Future<X509CertificateHolder> requestCertificate(String csr,
+      ApprovalType type) throws IOException;
 
   /**
    * Revokes a Certificate issued by this CertificateServer.
@@ -95,7 +105,7 @@ public interface CertificateServer {
    * @throws SCMSecurityException - on Error.
    */
   Future<Boolean> revokeCertificate(X509Certificate certificate,
-      CertificateApprover.ApprovalType approver) throws SCMSecurityException;
+      ApprovalType approver) throws SCMSecurityException;
 
   /**
    * TODO : CRL, OCSP etc. Later. This is the start of a CertificateServer
diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/DefaultCAServer.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/DefaultCAServer.java
index ef289e1..fffde90 100644
--- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/DefaultCAServer.java
+++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/DefaultCAServer.java
@@ -36,6 +36,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
+import java.math.BigInteger;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
@@ -171,6 +172,23 @@ public class DefaultCAServer implements CertificateServer {
     }
   }
 
+  /**
+   * Returns the Certificate corresponding to given certificate serial id if
+   * exist. Return null if it doesn't exist.
+   *
+   * @param certSerialId         - Certificate for this CA.
+   * @return X509CertificateHolder
+   * @throws CertificateException - usually thrown if this CA is not
+   * initialized.
+   * @throws IOException - on Error.
+   */
+  @Override
+  public X509Certificate getCertificate(String certSerialId) throws
+      IOException {
+    return store.getCertificateByID(new BigInteger(certSerialId),
+        CertificateStore.CertType.VALID_CERTS);
+  }
+
   private KeyPair getCAKeys() throws IOException {
     KeyCodec keyCodec = new KeyCodec(config, componentName);
     try {
diff --git a/hadoop-hdds/common/src/main/proto/SCMSecurityProtocol.proto b/hadoop-hdds/common/src/main/proto/SCMSecurityProtocol.proto
index bd8553d..5fcd98e 100644
--- a/hadoop-hdds/common/src/main/proto/SCMSecurityProtocol.proto
+++ b/hadoop-hdds/common/src/main/proto/SCMSecurityProtocol.proto
@@ -53,6 +53,19 @@ message SCMGetOMCertRequestProto {
 }
 
 /**
+* Proto request to get a certificate with given serial id.
+*/
+message SCMGetCertificateRequestProto {
+  required string certSerialId = 1;
+}
+
+/**
+* Proto request to get CA certificate.
+*/
+message SCMGetCACertificateRequestProto {
+}
+
+/**
  * Returns a certificate signed by SCM.
  */
 message SCMGetCertResponseProto {
@@ -79,4 +92,15 @@ service SCMSecurityProtocolService {
   rpc getOMCertificate (SCMGetOMCertRequestProto) returns
   (SCMGetCertResponseProto);
 
+  /**
+   * Get SCM signed certificate for DataNode.
+   */
+  rpc getCertificate (SCMGetCertificateRequestProto) returns
+  (SCMGetCertResponseProto);
+
+  /**
+   * Get SCM signed certificate for DataNode.
+   */
+  rpc getCACertificate (SCMGetCACertificateRequestProto) returns
+  (SCMGetCertResponseProto);
 }
diff --git a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/SCMSecurityProtocolServer.java b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/SCMSecurityProtocolServer.java
index 55904d8..86bcbcc 100644
--- a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/SCMSecurityProtocolServer.java
+++ b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/SCMSecurityProtocolServer.java
@@ -19,6 +19,8 @@ package org.apache.hadoop.hdds.scm.server;
 import com.google.protobuf.BlockingService;
 import java.io.IOException;
 import java.net.InetSocketAddress;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
 import java.util.Objects;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
@@ -137,6 +139,47 @@ public class SCMSecurityProtocolServer implements SCMSecurityProtocol {
     }
   }
 
+  /**
+   * Get SCM signed certificate with given serial id.
+   *
+   * @param certSerialId    - Certificate serial id.
+   * @return string         - pem encoded SCM signed certificate.
+   */
+  @Override
+  public String getCertificate(String certSerialId) throws IOException {
+    LOGGER.debug("Getting certificate with certificate serial id",
+        certSerialId);
+    try {
+      X509Certificate certificate =
+          certificateServer.getCertificate(certSerialId);
+      if (certificate != null) {
+        return CertificateCodec.getPEMEncodedString(certificate);
+      }
+    } catch (CertificateException e) {
+      LOGGER.error("getCertificate operation failed. ", e);
+      throw new IOException("getCertificate operation failed. ", e);
+    }
+    LOGGER.debug("Certificate with serial id {} not found.", certSerialId);
+    throw new IOException("Certificate not found");
+  }
+
+  /**
+   * Get SCM signed certificate for OM.
+   *
+   * @return string         - Root certificate.
+   */
+  @Override
+  public String getCACertificate() throws IOException {
+    LOGGER.debug("Getting CA certificate.");
+    try {
+      return CertificateCodec.getPEMEncodedString(
+          certificateServer.getCACertificate());
+    } catch (CertificateException e) {
+      LOGGER.error("getRootCertificate operation failed. ", e);
+      throw new IOException("getRootCertificate operation failed. ", e);
+    }
+  }
+
   public RPC.Server getRpcServer() {
     return rpcServer;
   }
diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/TestSecureOzoneCluster.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/TestSecureOzoneCluster.java
index 2a4dbd5..439e945 100644
--- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/TestSecureOzoneCluster.java
+++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/TestSecureOzoneCluster.java
@@ -17,6 +17,7 @@
  */
 package org.apache.hadoop.ozone;
 
+import static junit.framework.TestCase.assertNotNull;
 import static org.apache.hadoop.hdds.HddsConfigKeys.OZONE_METADATA_DIRS;
 import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_ADMINISTRATORS;
 import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_ENABLED;
@@ -25,6 +26,7 @@ import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.INVA
 import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.TOKEN_ERROR_OTHER;
 import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.TOKEN_EXPIRED;
 import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.VOLUME_NOT_FOUND;
+import static org.apache.hadoop.security.UserGroupInformation.AuthenticationMethod.KERBEROS;
 import static org.slf4j.event.Level.INFO;
 
 import java.io.File;
@@ -37,14 +39,17 @@ import java.security.PrivilegedExceptionAction;
 import java.util.Properties;
 import java.util.UUID;
 import java.util.concurrent.Callable;
+
 import org.apache.commons.lang3.RandomStringUtils;
 import org.apache.hadoop.classification.InterfaceAudience;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.fs.CommonConfigurationKeysPublic;
 import org.apache.hadoop.hdds.HddsConfigKeys;
 import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.hdds.protocol.SCMSecurityProtocol;
 import org.apache.hadoop.hdds.scm.ScmConfigKeys;
 import org.apache.hadoop.hdds.scm.ScmInfo;
+import org.apache.hadoop.hdds.scm.client.HddsClientUtils;
 import org.apache.hadoop.hdds.scm.server.SCMStorageConfig;
 import org.apache.hadoop.hdds.scm.server.StorageContainerManager;
 import org.apache.hadoop.hdds.security.x509.certificate.client.CertificateClient;
@@ -53,6 +58,7 @@ import org.apache.hadoop.hdds.security.x509.keys.KeyCodec;
 import org.apache.hadoop.io.Text;
 import org.apache.hadoop.ipc.Client;
 import org.apache.hadoop.ipc.RPC;
+import org.apache.hadoop.ipc.RemoteException;
 import org.apache.hadoop.ipc.Server;
 import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem;
 import org.apache.hadoop.minikdc.MiniKdc;
@@ -105,7 +111,10 @@ public final class TestSecureOzoneCluster {
   private File scmKeytab;
   private File spnegoKeytab;
   private File omKeyTab;
+  private File testUserKeytab;
   private String curUser;
+  private String testUserPrincipal;
+  private UserGroupInformation testKerberosUgi;
   private StorageContainerManager scm;
   private OzoneManager om;
 
@@ -163,8 +172,7 @@ public final class TestSecureOzoneCluster {
     createPrincipal(spnegoKeytab,
         configuration.get(ScmConfigKeys
             .HDDS_SCM_HTTP_KERBEROS_PRINCIPAL_KEY));
-    configuration.get(OMConfigKeys
-        .OZONE_OM_HTTP_KERBEROS_PRINCIPAL_KEY);
+    createPrincipal(testUserKeytab, testUserPrincipal);
     createPrincipal(omKeyTab,
         configuration.get(OMConfigKeys.OZONE_OM_KERBEROS_PRINCIPAL_KEY));
   }
@@ -212,6 +220,8 @@ public final class TestSecureOzoneCluster {
     scmKeytab = new File(workDir, "scm.keytab");
     spnegoKeytab = new File(workDir, "http.keytab");
     omKeyTab = new File(workDir, "om.keytab");
+    testUserKeytab = new File(workDir, "testuser.keytab");
+    testUserPrincipal = "test@" + realm;
 
     configuration.set(ScmConfigKeys.HDDS_SCM_KERBEROS_KEYTAB_FILE_KEY,
         scmKeytab.getAbsolutePath());
@@ -235,6 +245,47 @@ public final class TestSecureOzoneCluster {
     Assert.assertEquals(scmId, scmInfo.getScmId());
   }
 
+  @Test
+  public void testSCMSecurityProtocol() throws Exception {
+
+    initSCM();
+    scm = StorageContainerManager.createSCM(null, conf);
+    //Reads the SCM Info from SCM instance
+    try {
+      scm.start();
+
+      // Case 1: User with Kerberos credentials should succeed.
+      UserGroupInformation ugi =
+          UserGroupInformation.loginUserFromKeytabAndReturnUGI(
+              testUserPrincipal, testUserKeytab.getCanonicalPath());
+      ugi.setAuthenticationMethod(KERBEROS);
+      SCMSecurityProtocol scmSecurityProtocolClient =
+          HddsClientUtils.getScmSecurityClient(conf, ugi);
+      assertNotNull(scmSecurityProtocolClient);
+      String caCert = scmSecurityProtocolClient.getCACertificate();
+      LambdaTestUtils.intercept(RemoteException.class, "Certificate not found",
+          () -> scmSecurityProtocolClient.getCertificate("1"));
+      assertNotNull(caCert);
+
+      // Case 2: User without Kerberos credentials should fail.
+      ugi = UserGroupInformation.createRemoteUser("test");
+      ugi.setAuthenticationMethod(AuthMethod.TOKEN);
+      SCMSecurityProtocol finalScmSecurityProtocolClient =
+          HddsClientUtils.getScmSecurityClient(conf, ugi);
+
+      LambdaTestUtils.intercept(IOException.class, "Client cannot" +
+              " authenticate via:[KERBEROS]",
+          () -> finalScmSecurityProtocolClient.getCACertificate());
+      LambdaTestUtils.intercept(IOException.class, "Client cannot" +
+              " authenticate via:[KERBEROS]",
+          () -> finalScmSecurityProtocolClient.getCertificate("1"));
+    } finally {
+      if (scm != null) {
+        scm.stop();
+      }
+    }
+  }
+
   private void initSCM()
       throws IOException, AuthenticationException {
 


---------------------------------------------------------------------
To unsubscribe, e-mail: common-commits-unsubscribe@hadoop.apache.org
For additional commands, e-mail: common-commits-help@hadoop.apache.org