http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/c1b83467/slider-core/src/main/java/org/apache/slider/api/proto/SliderClusterAPI.java ---------------------------------------------------------------------- diff --git a/slider-core/src/main/java/org/apache/slider/api/proto/SliderClusterAPI.java b/slider-core/src/main/java/org/apache/slider/api/proto/SliderClusterAPI.java index 0d473fc..3441625 100644 --- a/slider-core/src/main/java/org/apache/slider/api/proto/SliderClusterAPI.java +++ b/slider-core/src/main/java/org/apache/slider/api/proto/SliderClusterAPI.java @@ -274,12 +274,12 @@ public final class SliderClusterAPI { com.google.protobuf.RpcCallback<org.apache.slider.api.proto.Messages.WrappedJsonProto> done); /** - * <code>rpc signCertificate(.org.apache.slider.api.SignCertificateRequestProto) returns (.org.apache.slider.api.SignCertificateResponseProto);</code> + * <code>rpc getClientCertificateStore(.org.apache.slider.api.GetCertificateStoreRequestProto) returns (.org.apache.slider.api.GetCertificateStoreResponseProto);</code> */ - public abstract void signCertificate( + public abstract void getClientCertificateStore( com.google.protobuf.RpcController controller, - org.apache.slider.api.proto.Messages.SignCertificateRequestProto request, - com.google.protobuf.RpcCallback<org.apache.slider.api.proto.Messages.SignCertificateResponseProto> done); + org.apache.slider.api.proto.Messages.GetCertificateStoreRequestProto request, + com.google.protobuf.RpcCallback<org.apache.slider.api.proto.Messages.GetCertificateStoreResponseProto> done); } @@ -463,11 +463,11 @@ public final class SliderClusterAPI { } @java.lang.Override - public void signCertificate( + public void getClientCertificateStore( com.google.protobuf.RpcController controller, - org.apache.slider.api.proto.Messages.SignCertificateRequestProto request, - com.google.protobuf.RpcCallback<org.apache.slider.api.proto.Messages.SignCertificateResponseProto> done) { - impl.signCertificate(controller, request, done); + org.apache.slider.api.proto.Messages.GetCertificateStoreRequestProto request, + com.google.protobuf.RpcCallback<org.apache.slider.api.proto.Messages.GetCertificateStoreResponseProto> done) { + impl.getClientCertificateStore(controller, request, done); } }; @@ -537,7 +537,7 @@ public final class SliderClusterAPI { case 21: return impl.getLiveResources(controller, (org.apache.slider.api.proto.Messages.EmptyPayloadProto)request); case 22: - return impl.signCertificate(controller, (org.apache.slider.api.proto.Messages.SignCertificateRequestProto)request); + return impl.getClientCertificateStore(controller, (org.apache.slider.api.proto.Messages.GetCertificateStoreRequestProto)request); default: throw new java.lang.AssertionError("Can't get here."); } @@ -597,7 +597,7 @@ public final class SliderClusterAPI { case 21: return org.apache.slider.api.proto.Messages.EmptyPayloadProto.getDefaultInstance(); case 22: - return org.apache.slider.api.proto.Messages.SignCertificateRequestProto.getDefaultInstance(); + return org.apache.slider.api.proto.Messages.GetCertificateStoreRequestProto.getDefaultInstance(); default: throw new java.lang.AssertionError("Can't get here."); } @@ -657,7 +657,7 @@ public final class SliderClusterAPI { case 21: return org.apache.slider.api.proto.Messages.WrappedJsonProto.getDefaultInstance(); case 22: - return org.apache.slider.api.proto.Messages.SignCertificateResponseProto.getDefaultInstance(); + return org.apache.slider.api.proto.Messages.GetCertificateStoreResponseProto.getDefaultInstance(); default: throw new java.lang.AssertionError("Can't get here."); } @@ -919,12 +919,12 @@ public final class SliderClusterAPI { com.google.protobuf.RpcCallback<org.apache.slider.api.proto.Messages.WrappedJsonProto> done); /** - * <code>rpc signCertificate(.org.apache.slider.api.SignCertificateRequestProto) returns (.org.apache.slider.api.SignCertificateResponseProto);</code> + * <code>rpc getClientCertificateStore(.org.apache.slider.api.GetCertificateStoreRequestProto) returns (.org.apache.slider.api.GetCertificateStoreResponseProto);</code> */ - public abstract void signCertificate( + public abstract void getClientCertificateStore( com.google.protobuf.RpcController controller, - org.apache.slider.api.proto.Messages.SignCertificateRequestProto request, - com.google.protobuf.RpcCallback<org.apache.slider.api.proto.Messages.SignCertificateResponseProto> done); + org.apache.slider.api.proto.Messages.GetCertificateStoreRequestProto request, + com.google.protobuf.RpcCallback<org.apache.slider.api.proto.Messages.GetCertificateStoreResponseProto> done); public static final com.google.protobuf.Descriptors.ServiceDescriptor @@ -1059,8 +1059,8 @@ public final class SliderClusterAPI { done)); return; case 22: - this.signCertificate(controller, (org.apache.slider.api.proto.Messages.SignCertificateRequestProto)request, - com.google.protobuf.RpcUtil.<org.apache.slider.api.proto.Messages.SignCertificateResponseProto>specializeCallback( + this.getClientCertificateStore(controller, (org.apache.slider.api.proto.Messages.GetCertificateStoreRequestProto)request, + com.google.protobuf.RpcUtil.<org.apache.slider.api.proto.Messages.GetCertificateStoreResponseProto>specializeCallback( done)); return; default: @@ -1122,7 +1122,7 @@ public final class SliderClusterAPI { case 21: return org.apache.slider.api.proto.Messages.EmptyPayloadProto.getDefaultInstance(); case 22: - return org.apache.slider.api.proto.Messages.SignCertificateRequestProto.getDefaultInstance(); + return org.apache.slider.api.proto.Messages.GetCertificateStoreRequestProto.getDefaultInstance(); default: throw new java.lang.AssertionError("Can't get here."); } @@ -1182,7 +1182,7 @@ public final class SliderClusterAPI { case 21: return org.apache.slider.api.proto.Messages.WrappedJsonProto.getDefaultInstance(); case 22: - return org.apache.slider.api.proto.Messages.SignCertificateResponseProto.getDefaultInstance(); + return org.apache.slider.api.proto.Messages.GetCertificateStoreResponseProto.getDefaultInstance(); default: throw new java.lang.AssertionError("Can't get here."); } @@ -1534,19 +1534,19 @@ public final class SliderClusterAPI { org.apache.slider.api.proto.Messages.WrappedJsonProto.getDefaultInstance())); } - public void signCertificate( + public void getClientCertificateStore( com.google.protobuf.RpcController controller, - org.apache.slider.api.proto.Messages.SignCertificateRequestProto request, - com.google.protobuf.RpcCallback<org.apache.slider.api.proto.Messages.SignCertificateResponseProto> done) { + org.apache.slider.api.proto.Messages.GetCertificateStoreRequestProto request, + com.google.protobuf.RpcCallback<org.apache.slider.api.proto.Messages.GetCertificateStoreResponseProto> done) { channel.callMethod( getDescriptor().getMethods().get(22), controller, request, - org.apache.slider.api.proto.Messages.SignCertificateResponseProto.getDefaultInstance(), + org.apache.slider.api.proto.Messages.GetCertificateStoreResponseProto.getDefaultInstance(), com.google.protobuf.RpcUtil.generalizeCallback( done, - org.apache.slider.api.proto.Messages.SignCertificateResponseProto.class, - org.apache.slider.api.proto.Messages.SignCertificateResponseProto.getDefaultInstance())); + org.apache.slider.api.proto.Messages.GetCertificateStoreResponseProto.class, + org.apache.slider.api.proto.Messages.GetCertificateStoreResponseProto.getDefaultInstance())); } } @@ -1666,9 +1666,9 @@ public final class SliderClusterAPI { org.apache.slider.api.proto.Messages.EmptyPayloadProto request) throws com.google.protobuf.ServiceException; - public org.apache.slider.api.proto.Messages.SignCertificateResponseProto signCertificate( + public org.apache.slider.api.proto.Messages.GetCertificateStoreResponseProto getClientCertificateStore( com.google.protobuf.RpcController controller, - org.apache.slider.api.proto.Messages.SignCertificateRequestProto request) + org.apache.slider.api.proto.Messages.GetCertificateStoreRequestProto request) throws com.google.protobuf.ServiceException; } @@ -1943,15 +1943,15 @@ public final class SliderClusterAPI { } - public org.apache.slider.api.proto.Messages.SignCertificateResponseProto signCertificate( + public org.apache.slider.api.proto.Messages.GetCertificateStoreResponseProto getClientCertificateStore( com.google.protobuf.RpcController controller, - org.apache.slider.api.proto.Messages.SignCertificateRequestProto request) + org.apache.slider.api.proto.Messages.GetCertificateStoreRequestProto request) throws com.google.protobuf.ServiceException { - return (org.apache.slider.api.proto.Messages.SignCertificateResponseProto) channel.callBlockingMethod( + return (org.apache.slider.api.proto.Messages.GetCertificateStoreResponseProto) channel.callBlockingMethod( getDescriptor().getMethods().get(22), controller, request, - org.apache.slider.api.proto.Messages.SignCertificateResponseProto.getDefaultInstance()); + org.apache.slider.api.proto.Messages.GetCertificateStoreResponseProto.getDefaultInstance()); } } @@ -1970,7 +1970,7 @@ public final class SliderClusterAPI { java.lang.String[] descriptorData = { "\n\033SliderClusterProtocol.proto\022\025org.apach" + "e.slider.api\032\033SliderClusterMessages.prot" + - "o2\260\025\n\027SliderClusterProtocolPB\022n\n\013stopClu" + + "o2\303\025\n\027SliderClusterProtocolPB\022n\n\013stopClu" + "ster\022..org.apache.slider.api.StopCluster" + "RequestProto\032/.org.apache.slider.api.Sto" + "pClusterResponseProto\022n\n\013flexCluster\022..o" + @@ -2035,11 +2035,12 @@ public final class SliderClusterAPI { "pache.slider.api.WrappedJsonProto\022e\n\020get" + "LiveResources\022(.org.apache.slider.api.Em" + "ptyPayloadProto\032\'.org.apache.slider.api." + - "WrappedJsonProto\022z\n\017signCertificate\0222.or" + - "g.apache.slider.api.SignCertificateReque" + - "stProto\0323.org.apache.slider.api.SignCert", - "ificateResponseProtoB5\n\033org.apache.slide" + - "r.api.protoB\020SliderClusterAPI\210\001\001\240\001\001" + "WrappedJsonProto\022\214\001\n\031getClientCertificat" + + "eStore\0226.org.apache.slider.api.GetCertif" + + "icateStoreRequestProto\0327.org.apache.slid", + "er.api.GetCertificateStoreResponseProtoB" + + "5\n\033org.apache.slider.api.protoB\020SliderCl" + + "usterAPI\210\001\001\240\001\001" }; com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/c1b83467/slider-core/src/main/java/org/apache/slider/client/SliderClient.java ---------------------------------------------------------------------- diff --git a/slider-core/src/main/java/org/apache/slider/client/SliderClient.java b/slider-core/src/main/java/org/apache/slider/client/SliderClient.java index dfa7cd6..8c1a9b2 100644 --- a/slider-core/src/main/java/org/apache/slider/client/SliderClient.java +++ b/slider-core/src/main/java/org/apache/slider/client/SliderClient.java @@ -21,6 +21,7 @@ package org.apache.slider.client; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; +import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileStatus; @@ -154,6 +155,7 @@ import org.apache.slider.providers.agent.AgentKeys; import org.apache.slider.providers.slideram.SliderAMClientProvider; import org.apache.slider.server.appmaster.SliderAppMaster; import org.apache.slider.server.appmaster.rpc.RpcBinder; +import org.apache.slider.server.services.security.SecurityStore; import org.apache.slider.server.services.utility.AbstractSliderLaunchedService; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException; @@ -172,8 +174,10 @@ import java.io.InputStreamReader; import java.io.PrintStream; import java.io.StringWriter; import java.io.Writer; +import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.URISyntaxException; +import java.net.UnknownHostException; import java.nio.charset.Charset; import java.nio.file.Files; import java.util.ArrayList; @@ -916,15 +920,85 @@ public class SliderClient extends AbstractSliderLaunchedService implements RunSe @Override public int actionClient(ActionClientArgs clientInfo) throws - SliderException, + YarnException, IOException { + if (clientInfo.install) { + return doClientInstall(clientInfo); + } else if (clientInfo.getCertStore) { + return doCertificateStoreRetrieval(clientInfo); + } else { + throw new BadCommandArgumentsException( + "Only install, keystore, and truststore commands are supported for the client.\n" + + CommonArgs.usage(serviceArgs, ACTION_CLIENT)); + + } + } - if(!clientInfo.install) { + private int doCertificateStoreRetrieval(ActionClientArgs clientInfo) + throws YarnException, IOException { + if (clientInfo.keystore != null && clientInfo.truststore != null) { throw new BadCommandArgumentsException( - "Only install command is supported for the client.\n" + "Only one of either keystore or truststore can be retrieved at one time. " + + "Retrieval of both should be done separately\n" + CommonArgs.usage(serviceArgs, ACTION_CLIENT)); } + if (clientInfo.name == null) { + throw new BadCommandArgumentsException("No applicaiton name specified\n" + + CommonArgs.usage(serviceArgs, + ACTION_CLIENT)); + } + + File storeFile = null; + SecurityStore.StoreType type; + if (clientInfo.keystore != null) { + storeFile = clientInfo.keystore; + type = SecurityStore.StoreType.keystore; + } else { + storeFile = clientInfo.truststore; + type = SecurityStore.StoreType.truststore; + } + + if (storeFile.exists()) { + throw new BadCommandArgumentsException("File %s already exists. " + + "Please remove that file or select a different file name.", + storeFile.getAbsolutePath()); + } + String hostname = null; + if (type == SecurityStore.StoreType.keystore) { + hostname = clientInfo.hostname; + if (hostname == null) { + hostname = InetAddress.getLocalHost().getCanonicalHostName(); + log.info("No hostname specified via command line. Using {}", hostname); + } + } + + String password = clientInfo.password; + if (password == null) { + // get a password + BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); + try { + password = String.valueOf(readPassword(type.name(), br)); + } finally { + if (br != null) { + br.close(); + } + } + } + + byte[] + keystore = + createClusterOperations(clientInfo.name).getClientCertificateStore( + hostname, "client", password, type.name()); + // persist to file + IOUtils.write(keystore, new FileOutputStream(storeFile)); + + return EXIT_SUCCESS; + } + + private int doClientInstall(ActionClientArgs clientInfo) + throws IOException, SliderException { + if (clientInfo.installLocation == null) { throw new BadCommandArgumentsException( "A valid install location must be provided for the client.\n" @@ -963,7 +1037,8 @@ public class SliderClient extends AbstractSliderLaunchedService implements RunSe } // Only INSTALL is supported - AbstractClientProvider provider = createClientProvider(SliderProviderFactory.DEFAULT_CLUSTER_TYPE); + AbstractClientProvider + provider = createClientProvider(SliderProviderFactory.DEFAULT_CLUSTER_TYPE); provider.processClientOperation(sliderFileSystem, "INSTALL", clientInfo.installLocation, http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/c1b83467/slider-core/src/main/java/org/apache/slider/client/SliderClientAPI.java ---------------------------------------------------------------------- diff --git a/slider-core/src/main/java/org/apache/slider/client/SliderClientAPI.java b/slider-core/src/main/java/org/apache/slider/client/SliderClientAPI.java index efb1f7f..c7756da 100644 --- a/slider-core/src/main/java/org/apache/slider/client/SliderClientAPI.java +++ b/slider-core/src/main/java/org/apache/slider/client/SliderClientAPI.java @@ -134,7 +134,7 @@ public interface SliderClientAPI extends Service { * @throws IOException problems related to package and destination folders */ int actionClient(ActionClientArgs clientInfo) - throws IOException, SliderException; + throws IOException, YarnException; /** * Managing slider application package http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/c1b83467/slider-core/src/main/java/org/apache/slider/client/ipc/SliderClusterOperations.java ---------------------------------------------------------------------- diff --git a/slider-core/src/main/java/org/apache/slider/client/ipc/SliderClusterOperations.java b/slider-core/src/main/java/org/apache/slider/client/ipc/SliderClusterOperations.java index dae93b3..ae95b17 100644 --- a/slider-core/src/main/java/org/apache/slider/client/ipc/SliderClusterOperations.java +++ b/slider-core/src/main/java/org/apache/slider/client/ipc/SliderClusterOperations.java @@ -39,6 +39,7 @@ import org.apache.slider.core.exceptions.NoSuchNodeException; import org.apache.slider.core.exceptions.SliderException; import org.apache.slider.core.exceptions.WaitTimeoutException; import org.apache.slider.core.persist.ConfTreeSerDeser; +import org.apache.slider.server.services.security.SecurityStore; import org.apache.slider.server.services.security.SignCertResponse; import org.codehaus.jackson.JsonParseException; import org.slf4j.Logger; @@ -512,18 +513,22 @@ public class SliderClusterOperations { return unmarshall(proto); } - public SignCertResponse signCertificate(String hostname, String request, - String passphrase) throws IOException { - Messages.SignCertificateRequestProto requestProto = - Messages.SignCertificateRequestProto.newBuilder() - .setHostname(hostname) - .setCertRequest(request) - .setPassPhrase(passphrase) - .build(); - Messages.SignCertificateResponseProto response = - appMaster.signCertificate(requestProto); - // JON - return new SignCertResponse(); + public byte[] getClientCertificateStore(String hostname, String clientId, + String password, String type) throws IOException { + Messages.GetCertificateStoreRequestProto.Builder + builder = Messages.GetCertificateStoreRequestProto.newBuilder(); + if (hostname != null) { + builder.setHostname(hostname); + } + Messages.GetCertificateStoreRequestProto requestProto = + builder.setRequesterId(clientId) + .setPassword(password) + .setType(type) + .build(); + Messages.GetCertificateStoreResponseProto response = + appMaster.getClientCertificateStore(requestProto); + + return unmarshall(response); } } http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/c1b83467/slider-core/src/main/java/org/apache/slider/common/params/ActionClientArgs.java ---------------------------------------------------------------------- diff --git a/slider-core/src/main/java/org/apache/slider/common/params/ActionClientArgs.java b/slider-core/src/main/java/org/apache/slider/common/params/ActionClientArgs.java index 4154c9f..c7f8c2e 100644 --- a/slider-core/src/main/java/org/apache/slider/common/params/ActionClientArgs.java +++ b/slider-core/src/main/java/org/apache/slider/common/params/ActionClientArgs.java @@ -37,6 +37,30 @@ public class ActionClientArgs extends AbstractActionArgs { description = "Install client") public boolean install; + @Parameter(names = {ARG_GETCERTSTORE}, + description = "Get a certificate store") + public boolean getCertStore; + + @Parameter(names = {ARG_KEYSTORE}, + description = "Retrieve keystore to specified location") + public File keystore; + + @Parameter(names = {ARG_TRUSTSTORE}, + description = "Retrieve truststore to specified location") + public File truststore; + + @Parameter(names = {ARG_HOSTNAME}, + description = "(Optional) Specify the hostname to use for generation of keystore certificate") + public String hostname; + + @Parameter(names = {ARG_NAME}, + description = "The name of the application") + public String name; + + @Parameter(names = {ARG_PASSWORD}, + description = "The certificate store password") + public String password; + @Parameter(names = {ARG_PACKAGE}, description = "Path to app package") public String packageURI; http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/c1b83467/slider-core/src/main/java/org/apache/slider/common/params/Arguments.java ---------------------------------------------------------------------- diff --git a/slider-core/src/main/java/org/apache/slider/common/params/Arguments.java b/slider-core/src/main/java/org/apache/slider/common/params/Arguments.java index b8414e3..14be81e 100644 --- a/slider-core/src/main/java/org/apache/slider/common/params/Arguments.java +++ b/slider-core/src/main/java/org/apache/slider/common/params/Arguments.java @@ -52,14 +52,17 @@ public interface Arguments { String ARG_FOLDER = "--folder"; String ARG_FORCE = "--force"; String ARG_FORMAT = "--format"; + String ARG_GETCERTSTORE = "--getcertstore"; String ARG_GETCONF = "--getconf"; String ARG_GETEXP = "--getexp"; String ARG_GETFILES = "--getfiles"; String ARG_HELP = "--help"; + String ARG_HOSTNAME = "--hostname"; String ARG_ID = "--id"; String ARG_IMAGE = "--image"; String ARG_INTERNAL = "--internal"; String ARG_KEYTAB = "--keytab"; + String ARG_KEYSTORE = "--keystore"; String ARG_KEYTABINSTALL = "--install"; String ARG_KEYTABDELETE = "--delete"; String ARG_KEYTABLIST = "--list"; @@ -80,6 +83,7 @@ public interface Arguments { String ARG_OUTPUT_SHORT = "-o"; String ARG_OVERWRITE = "--overwrite"; String ARG_PACKAGE = "--package"; + String ARG_PASSWORD = "--password"; String ARG_PATH = "--path"; String ARG_PKGDELETE = "--delete"; String ARG_INSTALL = "--install"; @@ -99,6 +103,7 @@ public interface Arguments { String ARG_STATE = "--state"; String ARG_SYSPROP = "-S"; String ARG_TEMPLATE = "--template"; + String ARG_TRUSTSTORE = "--truststore"; String ARG_USER = "--user"; String ARG_VERBOSE = "--verbose"; String ARG_WAIT = "--wait"; http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/c1b83467/slider-core/src/main/java/org/apache/slider/common/params/SliderActions.java ---------------------------------------------------------------------- diff --git a/slider-core/src/main/java/org/apache/slider/common/params/SliderActions.java b/slider-core/src/main/java/org/apache/slider/common/params/SliderActions.java index 2599927..f7b97d5 100644 --- a/slider-core/src/main/java/org/apache/slider/common/params/SliderActions.java +++ b/slider-core/src/main/java/org/apache/slider/common/params/SliderActions.java @@ -88,10 +88,10 @@ public interface SliderActions { "Print the Slider version information"; String DESCRIBE_ACTION_INSTALL_PACKAGE = "Install the application package in the home directory under sub-folder packages"; String DESCRIBE_ACTION_PACKAGE = "Install/list/delete application packages and list app instances that use this package"; - String DESCRIBE_ACTION_CLIENT = "Install the application client in the specified directory"; + String DESCRIBE_ACTION_CLIENT = "Install the application client in the specified directory or obtain a client keystore or truststore"; String DESCRIBE_ACTION_INSTALL_KEYTAB = "Install the Kerberos keytab file in the sub-folder 'keytabs' of the user's Slider base directory"; String DESCRIBE_ACTION_KEYTAB = "Manage a Kerberos keytab file (install, delete, list) in the sub-folder 'keytabs' of the user's Slider base directory"; String DESCRIBE_ACTION_DIAGNOSTIC = "Diagnose the configuration of the running slider application and slider client"; - + } http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/c1b83467/slider-core/src/main/java/org/apache/slider/server/appmaster/SliderAppMaster.java ---------------------------------------------------------------------- diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/SliderAppMaster.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/SliderAppMaster.java index 35ab1d4..34bf20c 100644 --- a/slider-core/src/main/java/org/apache/slider/server/appmaster/SliderAppMaster.java +++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/SliderAppMaster.java @@ -720,7 +720,9 @@ public class SliderAppMaster extends AbstractSliderLaunchedService getConfig().set(KEY_PROTOCOL_ACL, "*"); } } - + + certificateManager = new CertificateManager(); + //bring up the Slider RPC service buildPortScanner(instanceDefinition); startSliderRPCServer(instanceDefinition); @@ -744,7 +746,6 @@ public class SliderAppMaster extends AbstractSliderLaunchedService providerRoles.addAll(SliderAMClientProvider.ROLES); // Start up the WebApp and track the URL for it - certificateManager = new CertificateManager(); MapOperations component = instanceDefinition.getAppConfOperations() .getComponent(SliderKeys.COMPONENT_AM); certificateManager.initialize(component, appMasterHostname, @@ -1502,6 +1503,7 @@ public class SliderAppMaster extends AbstractSliderLaunchedService sliderIPCService = new SliderIPCService( this, + certificateManager, stateForProviders, actionQueues, metricsAndMonitoring, http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/c1b83467/slider-core/src/main/java/org/apache/slider/server/appmaster/rpc/SliderClusterProtocolPBImpl.java ---------------------------------------------------------------------- diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/rpc/SliderClusterProtocolPBImpl.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/rpc/SliderClusterProtocolPBImpl.java index ca0d21e..14b2bef 100644 --- a/slider-core/src/main/java/org/apache/slider/server/appmaster/rpc/SliderClusterProtocolPBImpl.java +++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/rpc/SliderClusterProtocolPBImpl.java @@ -282,12 +282,13 @@ public class SliderClusterProtocolPBImpl implements SliderClusterProtocolPB { } } - @Override - public Messages.SignCertificateResponseProto signCertificate(RpcController controller, - Messages.SignCertificateRequestProto request) throws ServiceException { + public Messages.GetCertificateStoreResponseProto getClientCertificateStore( + RpcController controller, + Messages.GetCertificateStoreRequestProto request) + throws ServiceException { try { - return real.signCertificate(request); + return real.getClientCertificateStore(request); } catch (Exception e) { throw wrap(e); } http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/c1b83467/slider-core/src/main/java/org/apache/slider/server/appmaster/rpc/SliderClusterProtocolProxy.java ---------------------------------------------------------------------- diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/rpc/SliderClusterProtocolProxy.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/rpc/SliderClusterProtocolProxy.java index 901e4ad..ad4cca4 100644 --- a/slider-core/src/main/java/org/apache/slider/server/appmaster/rpc/SliderClusterProtocolProxy.java +++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/rpc/SliderClusterProtocolProxy.java @@ -316,10 +316,10 @@ public class SliderClusterProtocolProxy implements SliderClusterProtocol { } @Override - public Messages.SignCertificateResponseProto signCertificate(Messages.SignCertificateRequestProto request) throws + public Messages.GetCertificateStoreResponseProto getClientCertificateStore(Messages.GetCertificateStoreRequestProto request) throws IOException { try { - return endpoint.signCertificate(NULL_CONTROLLER, request); + return endpoint.getClientCertificateStore(NULL_CONTROLLER, request); } catch (ServiceException e) { throw convert(e); } http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/c1b83467/slider-core/src/main/java/org/apache/slider/server/appmaster/rpc/SliderIPCService.java ---------------------------------------------------------------------- diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/rpc/SliderIPCService.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/rpc/SliderIPCService.java index 1cc44bc..a924940 100644 --- a/slider-core/src/main/java/org/apache/slider/server/appmaster/rpc/SliderIPCService.java +++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/rpc/SliderIPCService.java @@ -34,6 +34,7 @@ import org.apache.slider.core.conf.AggregateConf; import org.apache.slider.core.conf.ConfTree; import org.apache.slider.core.exceptions.NoSuchNodeException; import org.apache.slider.core.exceptions.ServiceNotReadyException; +import org.apache.slider.core.exceptions.SliderException; import org.apache.slider.core.main.LauncherExitCodes; import org.apache.slider.core.persist.AggregateConfSerDeser; import org.apache.slider.core.persist.ConfTreeSerDeser; @@ -48,6 +49,9 @@ import org.apache.slider.server.appmaster.management.MetricsAndMonitoring; import org.apache.slider.server.appmaster.state.RoleInstance; import org.apache.slider.server.appmaster.state.StateAccessForProviders; import org.apache.slider.server.appmaster.web.rest.application.resources.ContentCache; +import org.apache.slider.server.services.security.CertificateManager; +import org.apache.slider.server.services.security.KeystoreGenerator; +import org.apache.slider.server.services.security.SecurityStore; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -84,6 +88,7 @@ public class SliderIPCService extends AbstractService private final MetricsAndMonitoring metricsAndMonitoring; private final AppMasterActionOperations amOperations; private final ContentCache cache; + private final CertificateManager certificateManager; /** * This is the prefix used for metrics @@ -100,6 +105,7 @@ public class SliderIPCService extends AbstractService * @param cache */ public SliderIPCService(AppMasterActionOperations amOperations, + CertificateManager certificateManager, StateAccessForProviders state, QueueAccess actionQueues, MetricsAndMonitoring metricsAndMonitoring, ContentCache cache) { @@ -115,6 +121,7 @@ public class SliderIPCService extends AbstractService this.metricsAndMonitoring = metricsAndMonitoring; this.amOperations = amOperations; this.cache = cache; + this.certificateManager = certificateManager; } @Override //SliderClusterProtocol @@ -463,8 +470,33 @@ public class SliderIPCService extends AbstractService } @Override - public Messages.SignCertificateResponseProto signCertificate(Messages.SignCertificateRequestProto request) throws + public Messages.GetCertificateStoreResponseProto getClientCertificateStore(Messages.GetCertificateStoreRequestProto request) throws IOException { - return null; + String hostname = request.getHostname(); + String clientId = request.getRequesterId(); + String password = request.getPassword(); + String type = request.getType(); + + SecurityStore store = null; + try { + if ( SecurityStore.StoreType.keystore.equals( + SecurityStore.StoreType.valueOf(type))) { + store = certificateManager.generateContainerKeystore(hostname, + clientId, + null, + password); + } else if (SecurityStore.StoreType.truststore.equals( + SecurityStore.StoreType.valueOf(type))) { + store = certificateManager.generateContainerTruststore(clientId, + null, + password); + + } else { + throw new IOException("Illegal store type"); + } + } catch (SliderException e) { + throw new IOException(e); + } + return marshall(store); } } http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/c1b83467/slider-core/src/main/java/org/apache/slider/server/services/security/CertificateManager.java ---------------------------------------------------------------------- diff --git a/slider-core/src/main/java/org/apache/slider/server/services/security/CertificateManager.java b/slider-core/src/main/java/org/apache/slider/server/services/security/CertificateManager.java index 8d8dfec..2cdcbec 100644 --- a/slider-core/src/main/java/org/apache/slider/server/services/security/CertificateManager.java +++ b/slider-core/src/main/java/org/apache/slider/server/services/security/CertificateManager.java @@ -203,18 +203,18 @@ public class CertificateManager { } public synchronized void generateContainerCertificate(String hostname, - String containerId) { - LOG.info("Generation of agent certificate for {}", hostname); + String identifier) { + LOG.info("Generation of certificate for {}", hostname); String srvrKstrDir = SecurityUtils.getSecurityDir(); - Object[] scriptArgs = {srvrKstrDir, getSubjectDN(hostname, containerId, - this.applicationName), containerId}; + Object[] scriptArgs = {srvrKstrDir, getSubjectDN(hostname, identifier, + this.applicationName), identifier}; try { String command = MessageFormat.format(GEN_AGENT_KEY, scriptArgs); runCommand(command); - signAgentCertificate(containerId); + signAgentCertificate(identifier); } catch (SliderException e) { LOG.error("Error generating the agent certificate", e); @@ -222,21 +222,21 @@ public class CertificateManager { } public synchronized SecurityStore generateContainerKeystore(String hostname, - String containerId, + String requesterId, String role, String keystorePass) throws SliderException { LOG.info("Generation of container keystore for container {} on {}", - containerId, hostname); + requesterId, hostname); - generateContainerCertificate(hostname, containerId); + generateContainerCertificate(hostname, requesterId); // come up with correct args to invoke keystore command String srvrCrtPass = SecurityUtils.getKeystorePass(); String srvrKstrDir = SecurityUtils.getSecurityDir(); - String containerCrtName = containerId + ".crt"; - String containerKeyName = containerId + ".key"; - String kstrName = getKeystoreFileName(containerId, role); + String containerCrtName = requesterId + ".crt"; + String containerKeyName = requesterId + ".key"; + String kstrName = getKeystoreFileName(requesterId, role); Object[] scriptArgs = {srvrCrtPass, keystorePass, srvrKstrDir, containerKeyName, containerCrtName, kstrName}; @@ -250,7 +250,8 @@ public class CertificateManager { private static String getKeystoreFileName(String containerId, String role) { - return String.format("keystore-%s-%s.p12", containerId, role); + return String.format("keystore-%s-%s.p12", containerId, + role != null ? role : ""); } private void generateAMKeystore(String hostname, String containerId) @@ -306,7 +307,8 @@ public class CertificateManager { } private static String getTruststoreFileName(String role, String containerId) { - return String.format("truststore-%s-%s.p12", containerId, role); + return String.format("truststore-%s-%s.p12", containerId, + role != null ? role : ""); } /** http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/c1b83467/slider-core/src/main/proto/SliderClusterMessages.proto ---------------------------------------------------------------------- diff --git a/slider-core/src/main/proto/SliderClusterMessages.proto b/slider-core/src/main/proto/SliderClusterMessages.proto index 0b95de9..9f8f20f 100644 --- a/slider-core/src/main/proto/SliderClusterMessages.proto +++ b/slider-core/src/main/proto/SliderClusterMessages.proto @@ -319,14 +319,13 @@ message WrappedJsonProto { required string json = 1; } -message SignCertificateRequestProto { - required string hostname = 1; - required string certRequest = 2; - required string passPhrase = 3; +message GetCertificateStoreRequestProto { + optional string hostname = 1; + required string requesterId = 2; + required string password = 3; + required string type = 4; } -message SignCertificateResponseProto { - required string result = 1; - required string signedCertificate = 2; - required string signingMessage = 3; +message GetCertificateStoreResponseProto { + required bytes store = 1; } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/c1b83467/slider-core/src/main/proto/SliderClusterProtocol.proto ---------------------------------------------------------------------- diff --git a/slider-core/src/main/proto/SliderClusterProtocol.proto b/slider-core/src/main/proto/SliderClusterProtocol.proto index 974bcd5..d2ba723 100644 --- a/slider-core/src/main/proto/SliderClusterProtocol.proto +++ b/slider-core/src/main/proto/SliderClusterProtocol.proto @@ -164,8 +164,8 @@ service SliderClusterProtocolPB { rpc getLiveResources(EmptyPayloadProto) returns(WrappedJsonProto); - rpc signCertificate(SignCertificateRequestProto) - returns(SignCertificateResponseProto); + rpc getClientCertificateStore(GetCertificateStoreRequestProto) + returns(GetCertificateStoreResponseProto); http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/c1b83467/slider-core/src/test/java/org/apache/slider/providers/agent/TestAgentClientProvider2.java ---------------------------------------------------------------------- diff --git a/slider-core/src/test/java/org/apache/slider/providers/agent/TestAgentClientProvider2.java b/slider-core/src/test/java/org/apache/slider/providers/agent/TestAgentClientProvider2.java index 1e4d834..6f637d8 100644 --- a/slider-core/src/test/java/org/apache/slider/providers/agent/TestAgentClientProvider2.java +++ b/slider-core/src/test/java/org/apache/slider/providers/agent/TestAgentClientProvider2.java @@ -204,13 +204,6 @@ public class TestAgentClientProvider2 { SliderClient client = new SliderClient(); client.bindArgs(new Configuration(), "client", "--dest", "a_random_path/none", "--package", "a_random_pkg.zip"); ActionClientArgs args = new ActionClientArgs(); - args.install = false; - try { - client.actionClient(args); - }catch(BadCommandArgumentsException e) { - log.info(e.getMessage()); - Assert.assertTrue(e.getMessage().contains("Only install command is supported for the client")); - } args.install = true; try { http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/c1b83467/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AMClientCertStoreRetrievalIT.groovy ---------------------------------------------------------------------- diff --git a/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AMClientCertStoreRetrievalIT.groovy b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AMClientCertStoreRetrievalIT.groovy new file mode 100644 index 0000000..ab632d2 --- /dev/null +++ b/slider-funtest/src/test/groovy/org/apache/slider/funtest/lifecycle/AMClientCertStoreRetrievalIT.groovy @@ -0,0 +1,174 @@ +/* + * 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.slider.funtest.lifecycle + +import com.jcraft.jsch.Session +import groovy.transform.CompileStatic +import groovy.util.logging.Slf4j +import org.apache.bigtop.itest.shell.Shell +import org.apache.chaos.remote.RemoteServer +import org.apache.chaos.remote.SshCommands +import org.apache.hadoop.security.UserGroupInformation +import org.apache.hadoop.yarn.api.records.YarnApplicationState +import org.apache.hadoop.yarn.conf.YarnConfiguration +import org.apache.slider.common.SliderExitCodes +import org.apache.slider.common.params.Arguments +import org.apache.slider.common.params.SliderActions +import org.apache.slider.funtest.framework.AgentCommandTestBase +import org.apache.slider.funtest.framework.FuntestProperties +import org.apache.slider.funtest.framework.SliderShell +import org.junit.After +import org.junit.Assert +import org.junit.BeforeClass +import org.junit.Test + +import javax.net.ssl.TrustManager +import javax.net.ssl.TrustManagerFactory +import javax.net.ssl.X509TrustManager +import java.security.KeyStore +import java.security.KeyStoreException +import java.security.NoSuchAlgorithmException +import java.security.Principal +import java.security.cert.Certificate +import java.security.cert.CertificateException +import java.security.cert.X509Certificate + +@CompileStatic +@Slf4j +public class AMClientCertStoreRetrievalIT extends AgentCommandTestBase +implements FuntestProperties, Arguments, SliderExitCodes, SliderActions { + + private static String COMMAND_LOGGER = "COMMAND_LOGGER" + private static String APPLICATION_NAME = "certs-retrieval" + + + @After + public void destroyCluster() { + cleanup(APPLICATION_NAME) + } + + @Test + public void testRetrieveCertificateStores() throws Throwable { + cleanup(APPLICATION_NAME) + File launchReportFile = createTempJsonFile(); + + SliderShell shell = createTemplatedSliderApplication( + APPLICATION_NAME, APP_TEMPLATE, APP_RESOURCE, + [], + launchReportFile) + logShell(shell) + + def appId = ensureYarnApplicationIsUp(launchReportFile) + expectContainerRequestedCountReached(APPLICATION_NAME, COMMAND_LOGGER, 1, + CONTAINER_LAUNCH_TIMEOUT) + + def cd = assertContainersLive(APPLICATION_NAME, COMMAND_LOGGER, 1) + def loggerInstances = cd.instances[COMMAND_LOGGER] + assert loggerInstances.size() == 1 + + def loggerStats = cd.statistics[COMMAND_LOGGER] + + assert loggerStats["containers.requested"] == 1 + assert loggerStats["containers.live"] == 1 + + + String filename = "/tmp/test.keystore" + String password = "welcome"; + + // ensure file doesn't exist + new File(filename).delete(); + + shell = slider(EXIT_SUCCESS, + [ + ACTION_CLIENT, + ARG_GETCERTSTORE, + ARG_KEYSTORE, filename, + ARG_NAME, APPLICATION_NAME, + ARG_PASSWORD, password + ]) + + assert new File(filename).exists() + + FileInputStream is = new FileInputStream(filename); + KeyStore keystore = KeyStore.getInstance("pkcs12"); + keystore.load(is, password.toCharArray()); + + Certificate certificate = keystore.getCertificate( + keystore.aliases().nextElement()); + Assert.assertNotNull(certificate); + + String hostname = InetAddress.localHost.canonicalHostName; + + if (certificate instanceof X509Certificate) { + X509Certificate x509cert = (X509Certificate) certificate; + + // Get subject + Principal principal = x509cert.getSubjectDN(); + String subjectDn = principal.getName(); + Assert.assertEquals("wrong DN", + "CN=" + hostname + ", OU=" + APPLICATION_NAME + ", OU=client", + subjectDn); + + } + + filename = "/tmp/test.truststore" + // ensure file doesn't exist + new File(filename).delete(); + + shell = slider(EXIT_SUCCESS, + [ + ACTION_CLIENT, + ARG_GETCERTSTORE, + ARG_TRUSTSTORE, filename, + ARG_NAME, APPLICATION_NAME, + ARG_PASSWORD, password + ]) + + assert new File(filename).exists() + + is = new FileInputStream(filename); + KeyStore truststore = KeyStore.getInstance("pkcs12"); + truststore.load(is, password.toCharArray()); + + validateTruststore(keystore, truststore); + + } + + private void validateTruststore(KeyStore keystore, KeyStore truststore) + throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException { + // obtain server cert + Certificate certificate = keystore.getCertificate( + keystore.aliases().nextElement()); + Assert.assertNotNull(certificate); + + // validate keystore cert using trust store + TrustManagerFactory trustManagerFactory = + TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + trustManagerFactory.init(truststore); + + for (TrustManager trustManager: trustManagerFactory.getTrustManagers()) { + if (trustManager instanceof X509TrustManager) { + X509TrustManager x509TrustManager = (X509TrustManager)trustManager; + x509TrustManager.checkServerTrusted( + [(X509Certificate) certificate] as X509Certificate[], + "RSA_EXPORT"); + } + } + } +}
