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");
+        }
+      }
+  }
+}

Reply via email to