HDDS-1060. Add API to get OM certificate from SCM CA. Contributed by Ajay Kumar.

This commit is contained in:
Xiaoyu Yao 2019-02-20 11:11:36 -08:00
parent aa3ad36605
commit 1374f8f548
10 changed files with 340 additions and 12 deletions

View File

@ -22,15 +22,29 @@ import com.google.common.base.Preconditions;
import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability; import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.conf.Configuration; 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.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.OzoneConfigKeys;
import org.apache.hadoop.ozone.OzoneConsts; import org.apache.hadoop.ozone.OzoneConsts;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.http.client.config.RequestConfig; import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.client.HttpClients;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.text.ParseException; import java.text.ParseException;
import java.time.Instant; import java.time.Instant;
import java.time.ZoneId; import java.time.ZoneId;
@ -38,6 +52,7 @@ import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
/** /**
* Utility methods for Ozone and Container Clients. * Utility methods for Ozone and Container Clients.
* *
@ -252,4 +267,27 @@ public final class HddsClientUtils {
ScmConfigKeys ScmConfigKeys
.SCM_CONTAINER_CLIENT_MAX_OUTSTANDING_REQUESTS_DEFAULT); .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;
}
} }

View File

@ -410,4 +410,54 @@ public final class HddsUtils {
public static long getUtcTime() { public static long getUtcTime() {
return Calendar.getInstance(UTC_ZONE).getTimeInMillis(); 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));
}
} }

View File

@ -45,11 +45,30 @@ public interface SCMSecurityProtocol {
/** /**
* Get SCM signed certificate for OM. * Get SCM signed certificate for OM.
* *
* @param omDetails - DataNode Details. * @param omDetails - DataNode Details.
* @param certSignReq - Certificate signing request. * @param certSignReq - Certificate signing request.
* @return byte[] - SCM signed certificate. * @return String - pem encoded SCM signed
* certificate.
*/ */
String getOMCertificate(OzoneManagerDetailsProto omDetails, String getOMCertificate(OzoneManagerDetailsProto omDetails,
String certSignReq) throws IOException; 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;
} }

View File

@ -22,6 +22,9 @@ import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
import org.apache.hadoop.hdds.protocol.proto.HddsProtos.DatanodeDetailsProto; 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.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.proto.SCMSecurityProtocolProtos.SCMGetDataNodeCertRequestProto;
import org.apache.hadoop.hdds.protocol.SCMSecurityProtocol; import org.apache.hadoop.hdds.protocol.SCMSecurityProtocol;
import org.apache.hadoop.ipc.ProtobufHelper; import org.apache.hadoop.ipc.ProtobufHelper;
@ -112,6 +115,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.
* *

View File

@ -20,7 +20,9 @@ import com.google.protobuf.RpcController;
import com.google.protobuf.ServiceException; import com.google.protobuf.ServiceException;
import java.io.IOException; 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.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.SCMGetDataNodeCertRequestProto;
import org.apache.hadoop.hdds.protocol.proto.SCMSecurityProtocolProtos.SCMGetCertResponseProto.ResponseCode; import org.apache.hadoop.hdds.protocol.proto.SCMSecurityProtocolProtos.SCMGetCertResponseProto.ResponseCode;
import org.apache.hadoop.hdds.protocol.SCMSecurityProtocol; import org.apache.hadoop.hdds.protocol.SCMSecurityProtocol;
@ -91,4 +93,37 @@ public class SCMSecurityProtocolServerSideTranslatorPB implements
throw new ServiceException(e); 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);
}
}
} }

View File

@ -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.exception.SCMSecurityException;
import org.apache.hadoop.hdds.security.x509.SecurityConfig; 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.cert.X509CertificateHolder;
import org.bouncycastle.pkcs.PKCS10CertificationRequest; import org.bouncycastle.pkcs.PKCS10CertificationRequest;
@ -30,8 +31,8 @@ import java.security.cert.X509Certificate;
import java.util.concurrent.Future; import java.util.concurrent.Future;
/** /**
* Interface for Certificate Authority. This can be extended to talk to external * Interface for Certificate Authority. This can be extended to talk to
* CAs later or HSMs later. * external CAs later or HSMs later.
*/ */
public interface CertificateServer { public interface CertificateServer {
/** /**
@ -56,6 +57,18 @@ public interface CertificateServer {
X509CertificateHolder getCACertificate() X509CertificateHolder getCACertificate()
throws CertificateException, IOException; 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. * Request a Certificate based on Certificate Signing Request.
* *
@ -80,11 +93,8 @@ public interface CertificateServer {
* approved. * approved.
* @throws SCMSecurityException - on Error. * @throws SCMSecurityException - on Error.
*/ */
Future<X509CertificateHolder> Future<X509CertificateHolder> requestCertificate(String csr,
requestCertificate(String csr, CertificateApprover.ApprovalType type) ApprovalType type) throws IOException;
throws IOException;
/** /**
* Revokes a Certificate issued by this CertificateServer. * Revokes a Certificate issued by this CertificateServer.
@ -95,7 +105,7 @@ public interface CertificateServer {
* @throws SCMSecurityException - on Error. * @throws SCMSecurityException - on Error.
*/ */
Future<Boolean> revokeCertificate(X509Certificate certificate, 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 * TODO : CRL, OCSP etc. Later. This is the start of a CertificateServer

View File

@ -36,6 +36,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.IOException; import java.io.IOException;
import java.math.BigInteger;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; 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 { private KeyPair getCAKeys() throws IOException {
KeyCodec keyCodec = new KeyCodec(config, componentName); KeyCodec keyCodec = new KeyCodec(config, componentName);
try { try {

View File

@ -52,6 +52,19 @@ message SCMGetOMCertRequestProto {
required string CSR = 2; required string CSR = 2;
} }
/**
* 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. * Returns a certificate signed by SCM.
*/ */
@ -79,4 +92,15 @@ service SCMSecurityProtocolService {
rpc getOMCertificate (SCMGetOMCertRequestProto) returns rpc getOMCertificate (SCMGetOMCertRequestProto) returns
(SCMGetCertResponseProto); (SCMGetCertResponseProto);
/**
* Get SCM signed certificate for DataNode.
*/
rpc getCertificate (SCMGetCertificateRequestProto) returns
(SCMGetCertResponseProto);
/**
* Get SCM signed certificate for DataNode.
*/
rpc getCACertificate (SCMGetCACertificateRequestProto) returns
(SCMGetCertResponseProto);
} }

View File

@ -19,6 +19,8 @@ package org.apache.hadoop.hdds.scm.server;
import com.google.protobuf.BlockingService; import com.google.protobuf.BlockingService;
import java.io.IOException; import java.io.IOException;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future; 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() { public RPC.Server getRpcServer() {
return rpcServer; return rpcServer;
} }

View File

@ -17,6 +17,7 @@
*/ */
package org.apache.hadoop.ozone; 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.hdds.HddsConfigKeys.OZONE_METADATA_DIRS;
import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_ADMINISTRATORS; import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_ADMINISTRATORS;
import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_ENABLED; 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_ERROR_OTHER;
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.TOKEN_EXPIRED; 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.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 static org.slf4j.event.Level.INFO;
import java.io.File; import java.io.File;
@ -37,14 +39,17 @@ import java.security.PrivilegedExceptionAction;
import java.util.Properties; import java.util.Properties;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.RandomStringUtils;
import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.CommonConfigurationKeysPublic; import org.apache.hadoop.fs.CommonConfigurationKeysPublic;
import org.apache.hadoop.hdds.HddsConfigKeys; import org.apache.hadoop.hdds.HddsConfigKeys;
import org.apache.hadoop.hdds.conf.OzoneConfiguration; 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.ScmConfigKeys;
import org.apache.hadoop.hdds.scm.ScmInfo; 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.SCMStorageConfig;
import org.apache.hadoop.hdds.scm.server.StorageContainerManager; import org.apache.hadoop.hdds.scm.server.StorageContainerManager;
import org.apache.hadoop.hdds.security.x509.certificate.client.CertificateClient; 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.io.Text;
import org.apache.hadoop.ipc.Client; import org.apache.hadoop.ipc.Client;
import org.apache.hadoop.ipc.RPC; import org.apache.hadoop.ipc.RPC;
import org.apache.hadoop.ipc.RemoteException;
import org.apache.hadoop.ipc.Server; import org.apache.hadoop.ipc.Server;
import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem; import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem;
import org.apache.hadoop.minikdc.MiniKdc; import org.apache.hadoop.minikdc.MiniKdc;
@ -105,7 +111,10 @@ public final class TestSecureOzoneCluster {
private File scmKeytab; private File scmKeytab;
private File spnegoKeytab; private File spnegoKeytab;
private File omKeyTab; private File omKeyTab;
private File testUserKeytab;
private String curUser; private String curUser;
private String testUserPrincipal;
private UserGroupInformation testKerberosUgi;
private StorageContainerManager scm; private StorageContainerManager scm;
private OzoneManager om; private OzoneManager om;
@ -163,8 +172,7 @@ public final class TestSecureOzoneCluster {
createPrincipal(spnegoKeytab, createPrincipal(spnegoKeytab,
configuration.get(ScmConfigKeys configuration.get(ScmConfigKeys
.HDDS_SCM_HTTP_KERBEROS_PRINCIPAL_KEY)); .HDDS_SCM_HTTP_KERBEROS_PRINCIPAL_KEY));
configuration.get(OMConfigKeys createPrincipal(testUserKeytab, testUserPrincipal);
.OZONE_OM_HTTP_KERBEROS_PRINCIPAL_KEY);
createPrincipal(omKeyTab, createPrincipal(omKeyTab,
configuration.get(OMConfigKeys.OZONE_OM_KERBEROS_PRINCIPAL_KEY)); configuration.get(OMConfigKeys.OZONE_OM_KERBEROS_PRINCIPAL_KEY));
} }
@ -212,6 +220,8 @@ public final class TestSecureOzoneCluster {
scmKeytab = new File(workDir, "scm.keytab"); scmKeytab = new File(workDir, "scm.keytab");
spnegoKeytab = new File(workDir, "http.keytab"); spnegoKeytab = new File(workDir, "http.keytab");
omKeyTab = new File(workDir, "om.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, configuration.set(ScmConfigKeys.HDDS_SCM_KERBEROS_KEYTAB_FILE_KEY,
scmKeytab.getAbsolutePath()); scmKeytab.getAbsolutePath());
@ -235,6 +245,47 @@ public final class TestSecureOzoneCluster {
Assert.assertEquals(scmId, scmInfo.getScmId()); 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() private void initSCM()
throws IOException, AuthenticationException { throws IOException, AuthenticationException {