http://git-wip-us.apache.org/repos/asf/knox/blob/e5fd0622/gateway-server/src/main/java/org/apache/knox/gateway/util/KnoxCLI.java
----------------------------------------------------------------------
diff --cc gateway-server/src/main/java/org/apache/knox/gateway/util/KnoxCLI.java
index 928c37e,0000000..a987433
mode 100644,000000..100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/util/KnoxCLI.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/util/KnoxCLI.java
@@@ -1,2154 -1,0 +1,2205 @@@
 +/**
 + * 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.knox.gateway.util;
 +
 +import java.io.BufferedReader;
 +import java.io.Console;
 +import java.io.File;
 +import java.io.IOException;
 +import java.io.InputStream;
 +import java.io.InputStreamReader;
 +import java.io.PrintStream;
 +import java.net.InetAddress;
 +import java.net.UnknownHostException;
 +import java.security.cert.Certificate;
 +import java.util.Arrays;
 +import java.util.HashMap;
 +import java.util.HashSet;
 +import java.util.List;
 +import java.util.Map;
 +import java.util.Properties;
 +import java.util.UUID;
 +import javax.net.ssl.SSLContext;
 +import javax.net.ssl.SSLException;
 +
 +import org.apache.commons.codec.binary.Base64;
 +import org.apache.commons.io.FileUtils;
 +import org.apache.hadoop.conf.Configuration;
 +import org.apache.hadoop.conf.Configured;
 +import org.apache.knox.gateway.GatewayCommandLine;
 +import org.apache.knox.gateway.config.GatewayConfig;
 +import org.apache.knox.gateway.config.impl.GatewayConfigImpl;
 +import org.apache.knox.gateway.deploy.DeploymentFactory;
 +import org.apache.knox.gateway.services.CLIGatewayServices;
 +import org.apache.knox.gateway.services.GatewayServices;
 +import org.apache.knox.gateway.services.Service;
 +import org.apache.knox.gateway.services.ServiceLifecycleException;
 +import 
org.apache.knox.gateway.services.config.client.RemoteConfigurationRegistryClient;
 +import 
org.apache.knox.gateway.services.config.client.RemoteConfigurationRegistryClientService;
 +import org.apache.knox.gateway.services.security.AliasService;
 +import org.apache.knox.gateway.services.security.KeystoreService;
 +import org.apache.knox.gateway.services.security.KeystoreServiceException;
 +import org.apache.knox.gateway.services.security.MasterService;
 +import org.apache.knox.gateway.services.security.impl.X509CertificateUtil;
 +import org.apache.knox.gateway.services.topology.TopologyService;
 +import org.apache.knox.gateway.topology.Provider;
 +import org.apache.knox.gateway.topology.Topology;
 +import org.apache.knox.gateway.topology.validation.TopologyValidator;
 +import org.apache.hadoop.util.Tool;
 +import org.apache.hadoop.util.ToolRunner;
 +import org.apache.http.client.ClientProtocolException;
 +import org.apache.http.client.methods.CloseableHttpResponse;
 +import org.apache.http.client.methods.HttpGet;
 +import org.apache.http.conn.ssl.SSLContexts;
 +import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
 +import org.apache.http.impl.client.CloseableHttpClient;
 +import org.apache.http.impl.client.HttpClients;
 +import org.apache.log4j.PropertyConfigurator;
 +import org.apache.shiro.SecurityUtils;
 +import org.apache.shiro.authc.AuthenticationException;
 +import org.apache.shiro.authc.UsernamePasswordToken;
 +import org.apache.shiro.config.ConfigurationException;
 +import org.apache.shiro.config.Ini;
 +import org.apache.shiro.config.IniSecurityManagerFactory;
 +import org.apache.shiro.subject.Subject;
 +import org.apache.shiro.util.Factory;
 +import org.apache.shiro.util.ThreadContext;
 +import org.eclipse.persistence.oxm.MediaType;
 +import org.jboss.shrinkwrap.api.exporter.ExplodedExporter;
 +import org.jboss.shrinkwrap.api.spec.EnterpriseArchive;
 +
 +/**
 + *
 + */
 +public class KnoxCLI extends Configured implements Tool {
 +
 +  private static final String USAGE_PREFIX = "KnoxCLI {cmd} [options]";
 +  static final private String COMMANDS =
 +      "   [--help]\n" +
 +      "   [" + VersionCommand.USAGE + "]\n" +
 +      "   [" + MasterCreateCommand.USAGE + "]\n" +
 +      "   [" + CertCreateCommand.USAGE + "]\n" +
 +      "   [" + CertExportCommand.USAGE + "]\n" +
 +      "   [" + AliasCreateCommand.USAGE + "]\n" +
 +      "   [" + AliasDeleteCommand.USAGE + "]\n" +
 +      "   [" + AliasListCommand.USAGE + "]\n" +
 +      "   [" + RedeployCommand.USAGE + "]\n" +
 +      "   [" + ListTopologiesCommand.USAGE + "]\n" +
 +      "   [" + ValidateTopologyCommand.USAGE + "]\n" +
 +      "   [" + LDAPAuthCommand.USAGE + "]\n" +
 +      "   [" + LDAPSysBindCommand.USAGE + "]\n" +
 +      "   [" + ServiceTestCommand.USAGE + "]\n" +
 +      "   [" + RemoteRegistryClientsListCommand.USAGE + "]\n" +
++      "   [" + RemoteRegistryListProviderConfigsCommand.USAGE + "]\n" +
 +      "   [" + RemoteRegistryUploadProviderConfigCommand.USAGE + "]\n" +
++      "   [" + RemoteRegistryListDescriptorsCommand.USAGE + "]\n" +
 +      "   [" + RemoteRegistryUploadDescriptorCommand.USAGE + "]\n" +
 +      "   [" + RemoteRegistryDeleteProviderConfigCommand.USAGE + "]\n" +
 +      "   [" + RemoteRegistryDeleteDescriptorCommand.USAGE + "]\n" +
 +      "   [" + RemoteRegistryGetACLCommand.USAGE + "]\n";
 +
 +  /** allows stdout to be captured if necessary */
 +  public PrintStream out = System.out;
 +  /** allows stderr to be captured if necessary */
 +  public PrintStream err = System.err;
 +
 +  private static GatewayServices services = new CLIGatewayServices();
 +  private Command command;
 +  private String value = null;
 +  private String cluster = null;
 +  private String path = null;
 +  private String generate = "false";
 +  private String hostname = null;
 +  private String port = null;
 +  private boolean force = false;
 +  private boolean debug = false;
 +  private String user = null;
 +  private String pass = null;
 +  private boolean groups = false;
 +
 +  private String remoteRegistryClient = null;
 +  private String remoteRegistryEntryName = null;
 +
 +  // For testing only
 +  private String master = null;
 +  private String type = null;
 +
 +  /* (non-Javadoc)
 +   * @see org.apache.hadoop.util.Tool#run(java.lang.String[])
 +   */
 +  @Override
 +  public int run(String[] args) throws Exception {
 +    int exitCode = 0;
 +    try {
 +      exitCode = init(args);
 +      if (exitCode != 0) {
 +        return exitCode;
 +      }
 +      if (command != null && command.validate()) {
 +        initializeServices( command instanceof MasterCreateCommand );
 +        command.execute();
 +      } else if (!(command instanceof MasterCreateCommand)){
 +        out.println("ERROR: Invalid Command" + "\n" + "Unrecognized option:" +
 +            args[0] + "\n" +
 +            "A fatal exception has occurred. Program will exit.");
 +        exitCode = -2;
 +      }
 +    } catch (ServiceLifecycleException sle) {
 +      out.println("ERROR: Internal Error: Please refer to the knoxcli.log " +
 +          "file for details. " + sle.getMessage());
 +    } catch (Exception e) {
 +      e.printStackTrace( err );
 +      err.flush();
 +      return -3;
 +    }
 +    return exitCode;
 +  }
 +
 +  GatewayServices getGatewayServices() {
 +    return services;
 +  }
 +
 +  private void initializeServices(boolean persisting) throws 
ServiceLifecycleException {
 +    GatewayConfig config = getGatewayConfig();
 +    Map<String,String> options = new HashMap<>();
 +    options.put(GatewayCommandLine.PERSIST_LONG, 
Boolean.toString(persisting));
 +    if (master != null) {
 +      options.put("master", master);
 +    }
 +    services.init(config, options);
 +  }
 +
 +  /**
 +   * Parse the command line arguments and initialize the data
 +   * <pre>
 +   * % knoxcli version
 +   * % knoxcli list-topologies
 +   * % knoxcli master-create keyName [--size size] [--generate]
 +   * % knoxcli create-alias alias [--cluster clustername] [--generate] 
[--value v]
 +   * % knoxcli list-alias [--cluster clustername]
 +   * % knoxcli delete=alias alias [--cluster clustername]
 +   * % knoxcli create-cert alias [--hostname h]
 +   * % knoxcli redeploy [--cluster clustername]
 +   * % knoxcli validate-topology [--cluster clustername] | [--path 
<path/to/file>]
 +   * % knoxcli user-auth-test [--cluster clustername] [--u username] [--p 
password]
 +   * % knoxcli system-user-auth-test [--cluster clustername] [--d]
 +   * % knoxcli service-test [--u user] [--p password] [--cluster clustername] 
[--hostname name] [--port port]
 +   * % knoxcli list-registry-clients
 +   * % knoxcli get-registry-acl entryName --registry-client name
++   * % knoxcli list-provider-configs --registry-client
 +   * % knoxcli upload-provider-config filePath --registry-client name 
[--entry-name entryName]
++   * % knoxcli list-descriptors --registry-client
 +   * % knoxcli upload-descriptor filePath --registry-client name 
[--entry-name entryName]
 +   * % knoxcli delete-provider-config providerConfig --registry-client name
 +   * % knoxcli delete-descriptor descriptor --registry-client name
 +   * </pre>
 +   * @param args
 +   * @return
 +   * @throws IOException
 +   */
 +  private int init(String[] args) throws IOException {
 +    if (args.length == 0) {
 +      printKnoxShellUsage();
 +      return -1;
 +    }
 +    for (int i = 0; i < args.length; i++) { // parse command line
 +      if (args[i].equals("create-master")) {
 +        command = new MasterCreateCommand();
 +        if ((args.length > i + 1) && args[i + 1].equals("--help")) {
 +          printKnoxShellUsage();
 +          return -1;
 +        }
 +      } else if (args[i].equals("delete-alias")) {
 +        String alias = null;
 +        if (args.length >= 2) {
 +          alias = args[++i];
 +        }
 +        command = new AliasDeleteCommand(alias);
 +        if (alias == null || alias.equals("--help")) {
 +          printKnoxShellUsage();
 +          return -1;
 +        }
 +      } else if (args[i].equals("create-alias")) {
 +        String alias = null;
 +        if (args.length >= 2) {
 +          alias = args[++i];
 +        }
 +        command = new AliasCreateCommand(alias);
 +        if (alias == null || alias.equals("--help")) {
 +          printKnoxShellUsage();
 +          return -1;
 +        }
 +      } else if (args[i].equals("create-cert")) {
 +        command = new CertCreateCommand();
 +        if ((args.length > i + 1) && args[i + 1].equals("--help")) {
 +          printKnoxShellUsage();
 +          return -1;
 +        }
 +      } else if (args[i].equals("export-cert")) {
 +        command = new CertExportCommand();
 +        if ((args.length > i + 1) && args[i + 1].equals("--help")) {
 +          printKnoxShellUsage();
 +          return -1;
 +        }
 +      }else if(args[i].equals("user-auth-test")) {
 +        if(i + 1 >= args.length) {
 +          printKnoxShellUsage();
 +          return -1;
 +        } else {
 +          command = new LDAPAuthCommand();
 +        }
 +      } else if(args[i].equals("system-user-auth-test")) {
 +        if (i + 1 >= args.length){
 +          printKnoxShellUsage();
 +          return -1;
 +        } else {
 +          command = new LDAPSysBindCommand();
 +        }
 +      } else if (args[i].equals("list-alias")) {
 +        command = new AliasListCommand();
 +      } else if (args[i].equals("--value")) {
 +        if( i+1 >= args.length || args[i+1].startsWith( "-" ) ) {
 +          printKnoxShellUsage();
 +          return -1;
 +        }
 +        this.value = args[++i];
 +        if ( command != null && command instanceof MasterCreateCommand ) {
 +          this.master = this.value;
 +        }
 +      } else if ( args[i].equals("version") ) {
 +        command = new VersionCommand();
 +      } else if ( args[i].equals("redeploy") ) {
 +        command = new RedeployCommand();
 +      } else if ( args[i].equals("validate-topology") ) {
 +        if(i + 1 >= args.length) {
 +          printKnoxShellUsage();
 +          return -1;
 +        } else {
 +          command = new ValidateTopologyCommand();
 +        }
 +      } else if( args[i].equals("list-topologies") ){
 +        command = new ListTopologiesCommand();
 +      }else if ( args[i].equals("--cluster") || args[i].equals("--topology") 
) {
 +        if( i+1 >= args.length || args[i+1].startsWith( "-" ) ) {
 +          printKnoxShellUsage();
 +          return -1;
 +        }
 +        this.cluster = args[++i];
 +      } else if (args[i].equals("service-test")) {
 +        if( i + 1 >= args.length) {
 +          printKnoxShellUsage();
 +          return -1;
 +        } else {
 +          command = new ServiceTestCommand();
 +        }
 +      } else if (args[i].equals("--generate")) {
 +        if ( command != null && command instanceof MasterCreateCommand ) {
 +          this.master = UUID.randomUUID().toString();
 +        } else {
 +          this.generate = "true";
 +        }
 +      } else if(args[i].equals("--type")) {
 +        if( i+1 >= args.length || args[i+1].startsWith( "-" ) ) {
 +          printKnoxShellUsage();
 +          return -1;
 +        }
 +        this.type = args[++i];
 +      } else if(args[i].equals("--path")) {
 +        if( i+1 >= args.length || args[i+1].startsWith( "-" ) ) {
 +          printKnoxShellUsage();
 +          return -1;
 +        }
 +        this.path = args[++i];
 +      }else if (args[i].equals("--hostname")) {
 +        if( i+1 >= args.length || args[i+1].startsWith( "-" ) ) {
 +          printKnoxShellUsage();
 +          return -1;
 +        }
 +        this.hostname = args[++i];
 +      } else if (args[i].equals("--port")) {
 +        if( i+1 >= args.length || args[i+1].startsWith( "-" ) ) {
 +          printKnoxShellUsage();
 +          return -1;
 +        }
 +        this.port = args[++i];
 +      } else if (args[i].equals("--master")) {
 +        // For testing only
 +        if( i+1 >= args.length || args[i+1].startsWith( "-" ) ) {
 +          printKnoxShellUsage();
 +          return -1;
 +        }
 +        this.master = args[++i];
 +      } else if (args[i].equals("--force")) {
 +        this.force = true;
 +      } else if (args[i].equals("--help")) {
 +        printKnoxShellUsage();
 +        return -1;
 +      } else if(args[i].equals("--d")) {
 +        this.debug = true;
 +      } else if(args[i].equals("--u")) {
 +        if(i + 1 <= args.length) {
 +          this.user = args[++i];
 +        } else{
 +          printKnoxShellUsage();
 +          return -1;
 +        }
 +      } else if(args[i].equals("--p")) {
 +        if(i + 1 <= args.length) {
 +          this.pass = args[++i];
 +        } else{
 +          printKnoxShellUsage();
 +          return -1;
 +        }
 +      } else if (args[i].equals("--g")) {
 +        this.groups = true;
 +      } else if (args[i].equals("list-registry-clients")) {
 +        command = new RemoteRegistryClientsListCommand();
 +      } else if (args[i].equals("--registry-client")) {
 +        if (i + 1 >= args.length || args[i + 1].startsWith("-")) {
 +          printKnoxShellUsage();
 +          return -1;
 +        }
 +        this.remoteRegistryClient = args[++i];
++      } else if (args[i].equalsIgnoreCase("list-provider-configs")) {
++        command = new RemoteRegistryListProviderConfigsCommand();
++      } else if (args[i].equalsIgnoreCase("list-descriptors")) {
++        command = new RemoteRegistryListDescriptorsCommand();
 +      } else if (args[i].equalsIgnoreCase("upload-provider-config")) {
 +        String fileName;
 +        if (i <= (args.length - 1)) {
 +          fileName = args[++i];
 +          command = new RemoteRegistryUploadProviderConfigCommand(fileName);
 +        } else {
 +          printKnoxShellUsage();
 +          return -1;
 +        }
 +      } else if (args[i].equals("upload-descriptor")) {
 +        String fileName;
 +        if (i <= (args.length - 1)) {
 +          fileName = args[++i];
 +          command = new RemoteRegistryUploadDescriptorCommand(fileName);
 +        } else {
 +          printKnoxShellUsage();
 +          return -1;
 +        }
 +      } else if (args[i].equals("--entry-name")) {
 +        if (i <= (args.length - 1)) {
 +          remoteRegistryEntryName = args[++i];
 +        } else {
 +          printKnoxShellUsage();
 +          return -1;
 +        }
 +      } else if (args[i].equals("delete-descriptor")) {
 +        if (i <= (args.length - 1)) {
 +          String entry = args[++i];
 +          command = new RemoteRegistryDeleteDescriptorCommand(entry);
 +        } else {
 +          printKnoxShellUsage();
 +          return -1;
 +        }
 +      } else if (args[i].equals("delete-provider-config")) {
 +        if (i <= (args.length - 1)) {
 +          String entry = args[++i];
 +          command = new RemoteRegistryDeleteProviderConfigCommand(entry);
 +        } else {
 +          printKnoxShellUsage();
 +          return -1;
 +        }
 +      } else if (args[i].equalsIgnoreCase("get-registry-acl")) {
 +        if (i <= (args.length - 1)) {
 +          String entry = args[++i];
 +          command = new RemoteRegistryGetACLCommand(entry);
 +        } else {
 +          printKnoxShellUsage();
 +          return -1;
 +        }
 +      } else {
 +        printKnoxShellUsage();
 +        //ToolRunner.printGenericCommandUsage(System.err);
 +        return -1;
 +      }
 +    }
 +    return 0;
 +  }
 +
 +  private void printKnoxShellUsage() {
 +    out.println( USAGE_PREFIX + "\n" + COMMANDS );
 +    if ( command != null ) {
 +      out.println(command.getUsage());
 +    } else {
 +      char[] chars = new char[79];
 +      Arrays.fill( chars, '=' );
 +      String div = new String( chars );
 +
 +      out.println( div );
 +      out.println( VersionCommand.USAGE + "\n\n" + VersionCommand.DESC );
 +      out.println();
 +      out.println( div );
 +      out.println( MasterCreateCommand.USAGE + "\n\n" + 
MasterCreateCommand.DESC );
 +      out.println();
 +      out.println( div );
 +      out.println( CertCreateCommand.USAGE + "\n\n" + CertCreateCommand.DESC 
);
 +      out.println();
 +      out.println( div );
 +      out.println( CertExportCommand.USAGE + "\n\n" + CertExportCommand.DESC 
);
 +      out.println();
 +      out.println( div );
 +      out.println( AliasCreateCommand.USAGE + "\n\n" + 
AliasCreateCommand.DESC );
 +      out.println();
 +      out.println( div );
 +      out.println( AliasDeleteCommand.USAGE + "\n\n" + 
AliasDeleteCommand.DESC );
 +      out.println();
 +      out.println( div );
 +      out.println( AliasListCommand.USAGE + "\n\n" + AliasListCommand.DESC );
 +      out.println();
 +      out.println( div );
 +      out.println( RedeployCommand.USAGE + "\n\n" + RedeployCommand.DESC );
 +      out.println();
 +      out.println( div );
 +      out.println(ValidateTopologyCommand.USAGE + "\n\n" + 
ValidateTopologyCommand.DESC);
 +      out.println();
 +      out.println( div );
 +      out.println(ListTopologiesCommand.USAGE + "\n\n" + 
ListTopologiesCommand.DESC);
 +      out.println();
 +      out.println( div );
 +      out.println(LDAPAuthCommand.USAGE + "\n\n" + LDAPAuthCommand.DESC);
 +      out.println();
 +      out.println( div );
 +      out.println(LDAPSysBindCommand.USAGE + "\n\n" + 
LDAPSysBindCommand.DESC);
 +      out.println();
 +      out.println( div );
 +      out.println(ServiceTestCommand.USAGE + "\n\n" + 
ServiceTestCommand.DESC);
 +      out.println();
 +      out.println( div );
 +      out.println(RemoteRegistryClientsListCommand.USAGE + "\n\n" + 
RemoteRegistryClientsListCommand.DESC);
 +      out.println();
 +      out.println( div );
 +      out.println(RemoteRegistryGetACLCommand.USAGE + "\n\n" + 
RemoteRegistryGetACLCommand.DESC);
 +      out.println();
 +      out.println( div );
++      out.println(RemoteRegistryListProviderConfigsCommand.USAGE + "\n\n" + 
RemoteRegistryListProviderConfigsCommand.DESC);
++      out.println();
++      out.println( div );
++      out.println(RemoteRegistryListDescriptorsCommand.USAGE + "\n\n" + 
RemoteRegistryListDescriptorsCommand.DESC);
++      out.println();
++      out.println( div );
 +      out.println(RemoteRegistryUploadProviderConfigCommand.USAGE + "\n\n" + 
RemoteRegistryUploadProviderConfigCommand.DESC);
 +      out.println();
 +      out.println( div );
 +      out.println(RemoteRegistryUploadDescriptorCommand.USAGE + "\n\n" + 
RemoteRegistryUploadDescriptorCommand.DESC);
 +      out.println();
 +      out.println( div );
 +      out.println(RemoteRegistryDeleteProviderConfigCommand.USAGE + "\n\n" + 
RemoteRegistryDeleteProviderConfigCommand.DESC);
 +      out.println();
 +      out.println( div );
 +      out.println(RemoteRegistryDeleteDescriptorCommand.USAGE + "\n\n" + 
RemoteRegistryDeleteDescriptorCommand.DESC);
 +      out.println();
 +      out.println( div );
 +    }
 +  }
 +
 +  private abstract class Command {
 +
 +    public boolean validate() {
 +      return true;
 +    }
 +
 +    protected Service getService(String serviceName) {
 +      Service service = null;
 +
 +      return service;
 +    }
 +
 +    public abstract void execute() throws Exception;
 +
 +    public abstract String getUsage();
 +
 +    protected AliasService getAliasService() {
 +      AliasService as = services.getService(GatewayServices.ALIAS_SERVICE);
 +      return as;
 +    }
 +
 +    protected KeystoreService getKeystoreService() {
 +      KeystoreService ks = 
services.getService(GatewayServices.KEYSTORE_SERVICE);
 +      return ks;
 +    }
 +
 +    protected TopologyService getTopologyService()  {
 +      TopologyService ts = 
services.getService(GatewayServices.TOPOLOGY_SERVICE);
 +      return ts;
 +    }
 +
 +    protected RemoteConfigurationRegistryClientService 
getRemoteConfigRegistryClientService() {
 +      return 
services.getService(GatewayServices.REMOTE_REGISTRY_CLIENT_SERVICE);
 +    }
 +
 +  }
 +
 + private class AliasListCommand extends Command {
 +
 +  public static final String USAGE = "list-alias [--cluster clustername]";
 +  public static final String DESC = "The list-alias command lists all of the 
aliases\n" +
 +                                    "for the given hadoop --cluster. The 
default\n" +
 +                                    "--cluster being the gateway itself.";
 +
 +   /* (non-Javadoc)
 +    * @see KnoxCLI.Command#execute()
 +    */
 +   @Override
 +   public void execute() throws Exception {
 +     AliasService as = getAliasService();
 +      KeystoreService keystoreService = getKeystoreService();
 +
 +     if (cluster == null) {
 +       cluster = "__gateway";
 +     }
 +      boolean credentialStoreForClusterAvailable =
 +          keystoreService.isCredentialStoreForClusterAvailable(cluster);
 +      if (credentialStoreForClusterAvailable) {
 +        out.println("Listing aliases for: " + cluster);
 +        List<String> aliases = as.getAliasesForCluster(cluster);
 +        for (String alias : aliases) {
 +          out.println(alias);
 +        }
 +        out.println("\n" + aliases.size() + " items.");
 +      } else {
 +        out.println("Invalid cluster name provided: " + cluster);
 +      }
 +   }
 +
 +   /* (non-Javadoc)
 +    * @see org.apache.knox.gateway.util.KnoxCLI.Command#getUsage()
 +    */
 +   @Override
 +   public String getUsage() {
 +     return USAGE + ":\n\n" + DESC;
 +   }
 + }
 +
 + public class CertExportCommand extends Command {
 +
 +   public static final String USAGE = "export-cert";
 +   public static final String DESC = "The export-cert command exports the 
public certificate\n" +
 +                                     "from the a gateway.jks keystore with 
the alias of gateway-identity.";
 +   private static final String GATEWAY_CREDENTIAL_STORE_NAME = "__gateway";
 +   private static final String GATEWAY_IDENTITY_PASSPHRASE = 
"gateway-identity-passphrase";
 +
 +    public CertExportCommand() {
 +    }
 +
 +    private GatewayConfig getGatewayConfig() {
 +      GatewayConfig result;
 +      Configuration conf = getConf();
 +      if( conf != null && conf instanceof GatewayConfig ) {
 +        result = (GatewayConfig)conf;
 +      } else {
 +        result = new GatewayConfigImpl();
 +      }
 +      return result;
 +    }
 +
 +    /* (non-Javadoc)
 +     * @see org.apache.knox.gateway.util.KnoxCLI.Command#execute()
 +     */
 +    @Override
 +    public void execute() throws Exception {
 +      KeystoreService ks = getKeystoreService();
 +
 +      AliasService as = getAliasService();
 +
 +      if (ks != null) {
 +        try {
 +          if (!ks.isKeystoreForGatewayAvailable()) {
 +            out.println("No keystore has been created for the gateway. Please 
use the create-cert command or populate with a CA signed cert of your own.");
 +          }
 +          char[] passphrase = 
as.getPasswordFromAliasForCluster(GATEWAY_CREDENTIAL_STORE_NAME, 
GATEWAY_IDENTITY_PASSPHRASE);
 +          if (passphrase == null) {
 +            MasterService ms = services.getService("MasterService");
 +            passphrase = ms.getMasterSecret();
 +          }
 +          Certificate cert = 
ks.getKeystoreForGateway().getCertificate("gateway-identity");
 +          String keyStoreDir = getGatewayConfig().getGatewaySecurityDir() + 
File.separator + "keystores" + File.separator;
 +          File ksd = new File(keyStoreDir);
 +          if (!ksd.exists()) {
 +            if( !ksd.mkdirs() ) {
 +              // certainly should not happen if the keystore is known to be 
available
 +              throw new ServiceLifecycleException("Unable to create keystores 
directory" + ksd.getAbsolutePath());
 +            }
 +          }
 +          if ("PEM".equals(type) || type == null) {
 +            X509CertificateUtil.writeCertificateToFile(cert, new 
File(keyStoreDir + "gateway-identity.pem"));
 +            out.println("Certificate gateway-identity has been successfully 
exported to: " + keyStoreDir + "gateway-identity.pem");
 +          }
 +          else if ("JKS".equals(type)) {
 +            X509CertificateUtil.writeCertificateToJKS(cert, new 
File(keyStoreDir + "gateway-client-trust.jks"));
 +            out.println("Certificate gateway-identity has been successfully 
exported to: " + keyStoreDir + "gateway-client-trust.jks");
 +          }
 +          else {
 +            out.println("Invalid type for export file provided. Export has 
not been done. Please use: [PEM|JKS] default value is PEM.");
 +          }
 +        } catch (KeystoreServiceException e) {
 +          throw new ServiceLifecycleException("Keystore was not loaded 
properly - the provided (or persisted) master secret may not match the password 
for the keystore.", e);
 +        }
 +      }
 +    }
 +
 +    /* (non-Javadoc)
 +     * @see org.apache.knox.gateway.util.KnoxCLI.Command#getUsage()
 +     */
 +    @Override
 +    public String getUsage() {
 +      return USAGE + ":\n\n" + DESC;
 +    }
 +  }
 +
 + public class CertCreateCommand extends Command {
 +
 +  public static final String USAGE = "create-cert [--hostname h]";
 +  public static final String DESC = "The create-cert command creates and 
populates\n" +
 +                                    "a gateway.jks keystore with a 
self-signed certificate\n" +
 +                                    "to be used as the gateway identity. It 
also adds an alias\n" +
 +                                    "to the __gateway-credentials.jceks 
credential store for the\n" +
 +                                    "key passphrase.";
 +  private static final String GATEWAY_CREDENTIAL_STORE_NAME = "__gateway";
 +  private static final String GATEWAY_IDENTITY_PASSPHRASE = 
"gateway-identity-passphrase";
 +
 +   public CertCreateCommand() {
 +   }
 +
 +   /* (non-Javadoc)
 +    * @see org.apache.knox.gateway.util.KnoxCLI.Command#execute()
 +    */
 +   @Override
 +   public void execute() throws Exception {
 +     KeystoreService ks = getKeystoreService();
 +
 +     AliasService as = getAliasService();
 +
 +     if (ks != null) {
 +       try {
 +         if 
(!ks.isCredentialStoreForClusterAvailable(GATEWAY_CREDENTIAL_STORE_NAME)) {
 +//           log.creatingCredentialStoreForGateway();
 +           ks.createCredentialStoreForCluster(GATEWAY_CREDENTIAL_STORE_NAME);
 +         }
 +         else {
 +//           log.credentialStoreForGatewayFoundNotCreating();
 +         }
 +         // LET'S NOT GENERATE A DIFFERENT KEY PASSPHRASE BY DEFAULT ANYMORE
 +         // IF A DEPLOYMENT WANTS TO CHANGE THE KEY PASSPHRASE TO MAKE IT 
MORE SECURE THEN
 +         // THEY CAN ADD THE ALIAS EXPLICITLY WITH THE CLI
 +         //as.generateAliasForCluster(GATEWAY_CREDENTIAL_STORE_NAME, 
GATEWAY_IDENTITY_PASSPHRASE);
 +       } catch (KeystoreServiceException e) {
 +         throw new ServiceLifecycleException("Keystore was not loaded 
properly - the provided (or persisted) master secret may not match the password 
for the keystore.", e);
 +       }
 +
 +       try {
 +         if (!ks.isKeystoreForGatewayAvailable()) {
 +//           log.creatingKeyStoreForGateway();
 +           ks.createKeystoreForGateway();
 +         }
 +         else {
 +//           log.keyStoreForGatewayFoundNotCreating();
 +         }
 +         char[] passphrase = 
as.getPasswordFromAliasForCluster(GATEWAY_CREDENTIAL_STORE_NAME, 
GATEWAY_IDENTITY_PASSPHRASE);
 +         if (passphrase == null) {
 +           MasterService ms = services.getService("MasterService");
 +           passphrase = ms.getMasterSecret();
 +         }
 +         ks.addSelfSignedCertForGateway("gateway-identity", passphrase, 
hostname);
 +//         logAndValidateCertificate();
 +         out.println("Certificate gateway-identity has been successfully 
created.");
 +       } catch (KeystoreServiceException e) {
 +         throw new ServiceLifecycleException("Keystore was not loaded 
properly - the provided (or persisted) master secret may not match the password 
for the keystore.", e);
 +       }
 +     }
 +   }
 +
 +   /* (non-Javadoc)
 +    * @see org.apache.knox.gateway.util.KnoxCLI.Command#getUsage()
 +    */
 +   @Override
 +   public String getUsage() {
 +     return USAGE + ":\n\n" + DESC;
 +   }
 +
 + }
 +
 + public class AliasCreateCommand extends Command {
 +
 +  public static final String USAGE = "create-alias aliasname [--cluster 
clustername] " +
 +                                     "[ (--value v) | (--generate) ]";
 +  public static final String DESC = "The create-alias command will create an 
alias\n"
 +                                       + "and secret pair within the 
credential store for the\n"
 +                                       + "indicated --cluster otherwise 
within the gateway\n"
 +                                       + "credential store. The actual secret 
may be specified via\n"
 +                                       + "the --value option or --generate 
(will create a random secret\n"
 +                                       + "for you) or user will be prompt to 
provide password.";
 +
 +  private String name = null;
 +
 +  /**
 +    * @param alias
 +    */
 +   public AliasCreateCommand(String alias) {
 +     name = alias;
 +   }
 +
 +   /* (non-Javadoc)
 +    * @see org.apache.knox.gateway.util.KnoxCLI.Command#execute()
 +    */
 +   @Override
 +   public void execute() throws Exception {
 +     AliasService as = getAliasService();
 +     if (cluster == null) {
 +       cluster = "__gateway";
 +     }
 +     if (value != null) {
 +       as.addAliasForCluster(cluster, name, value);
 +       out.println(name + " has been successfully created.");
 +     }
 +     else {
 +       if ("true".equals(generate)) {
 +         as.generateAliasForCluster(cluster, name);
 +         out.println(name + " has been successfully generated.");
 +       }
 +       else {
 +          value = new String(promptUserForPassword());
 +          as.addAliasForCluster(cluster, name, value);
 +          out.println(name + " has been successfully created.");
 +       }
 +     }
 +   }
 +
 +   /* (non-Javadoc)
 +    * @see org.apache.knox.gateway.util.KnoxCLI.Command#getUsage()
 +    */
 +   @Override
 +   public String getUsage() {
 +     return USAGE + ":\n\n" + DESC;
 +   }
 +
 +    protected char[] promptUserForPassword() {
 +      char[] password = null;
 +      Console c = System.console();
 +      if (c == null) {
 +        System.err
 +            .println("No console to fetch password from user.Consider setting 
via --generate or --value.");
 +        System.exit(1);
 +      }
 +
 +      boolean noMatch;
 +      do {
 +        char[] newPassword1 = c.readPassword("Enter password: ");
 +        char[] newPassword2 = c.readPassword("Enter password again: ");
 +        noMatch = !Arrays.equals(newPassword1, newPassword2);
 +        if (noMatch) {
 +          c.format("Passwords don't match. Try again.%n");
 +        } else {
 +          password = Arrays.copyOf(newPassword1, newPassword1.length);
 +        }
 +        Arrays.fill(newPassword1, ' ');
 +        Arrays.fill(newPassword2, ' ');
 +      } while (noMatch);
 +      return password;
 +    }
 +
 + }
 +
 + /**
 +  *
 +  */
 + public class AliasDeleteCommand extends Command {
 +  public static final String USAGE = "delete-alias aliasname [--cluster 
clustername]";
 +  public static final String DESC = "The delete-alias command removes the\n" +
 +                                    "indicated alias from the --cluster 
specific\n" +
 +                                    "credential store or the gateway 
credential store.";
 +
 +  private String name = null;
 +
 +  /**
 +    * @param alias
 +    */
 +   public AliasDeleteCommand(String alias) {
 +     name = alias;
 +   }
 +
 +   /* (non-Javadoc)
 +    * @see org.apache.knox.gateway.util.KnoxCLI.Command#execute()
 +    */
 +   @Override
 +   public void execute() throws Exception {
 +     AliasService as = getAliasService();
 +      KeystoreService keystoreService = getKeystoreService();
 +     if (as != null) {
 +       if (cluster == null) {
 +         cluster = "__gateway";
 +       }
 +        boolean credentialStoreForClusterAvailable =
 +            keystoreService.isCredentialStoreForClusterAvailable(cluster);
 +        if (credentialStoreForClusterAvailable) {
 +          List<String> aliasesForCluster = as.getAliasesForCluster(cluster);
 +          if (null == aliasesForCluster || !aliasesForCluster.contains(name)) 
{
 +            out.println("Deletion of Alias: " + name + " from cluster: " + 
cluster + " Failed. "
 +                + "\n" + "No such alias exists in the cluster.");
 +          } else {
 +            as.removeAliasForCluster(cluster, name);
 +            out.println(name + " has been successfully deleted.");
 +          }
 +        } else {
 +          out.println("Invalid cluster name provided: " + cluster);
 +        }
 +     }
 +   }
 +
 +   /* (non-Javadoc)
 +    * @see org.apache.knox.gateway.util.KnoxCLI.Command#getUsage()
 +    */
 +   @Override
 +   public String getUsage() {
 +     return USAGE + ":\n\n" + DESC;
 +   }
 +
 + }
 +
 + /**
 +  *
 +  */
 + public class MasterCreateCommand extends Command {
 +  public static final String USAGE = "create-master [--force]";
 +  public static final String DESC = "The create-master command persists 
the\n" +
 +                                    "master secret in a file located at:\n" +
 +                                    "{GATEWAY_HOME}/data/security/master. 
It\n" +
 +                                    "will prompt the user for the secret to 
persist.\n" +
 +                                    "Use --force to overwrite the master 
secret.";
 +
 +   public MasterCreateCommand() {
 +   }
 +
 +   private GatewayConfig getGatewayConfig() {
 +     GatewayConfig result;
 +     Configuration conf = getConf();
 +     if( conf != null && conf instanceof GatewayConfig ) {
 +       result = (GatewayConfig)conf;
 +     } else {
 +       result = new GatewayConfigImpl();
 +     }
 +     return result;
 +   }
 +
 +   public boolean validate() {
 +     boolean valid = true;
 +     GatewayConfig config = getGatewayConfig();
 +     File dir = new File( config.getGatewaySecurityDir() );
 +     File file = new File( dir, "master" );
 +     if( file.exists() ) {
 +       if( force ) {
 +         if( !file.canWrite() ) {
 +           out.println(
 +               "This command requires write permissions on the master secret 
file: " +
 +                   file.getAbsolutePath() );
 +           valid = false;
 +         } else if( !file.canWrite() ) {
 +           out.println(
 +               "This command requires write permissions on the master secret 
file: " +
 +                   file.getAbsolutePath() );
 +           valid = false;
 +         } else {
 +           valid = file.delete();
 +           if( !valid ) {
 +             out.println(
 +                 "Unable to delete the master secret file: " +
 +                     file.getAbsolutePath() );
 +           }
 +         }
 +       } else {
 +         out.println(
 +             "Master secret is already present on disk. " +
 +                 "Please be aware that overwriting it will require updating 
other security artifacts. " +
 +                 " Use --force to overwrite the existing master secret." );
 +         valid = false;
 +       }
 +     } else if( dir.exists() && !dir.canWrite() ) {
 +       out.println(
 +           "This command requires write permissions on the security 
directory: " +
 +               dir.getAbsolutePath() );
 +       valid = false;
 +     }
 +     return valid;
 +   }
 +
 +   /* (non-Javadoc)
 +    * @see org.apache.knox.gateway.util.KnoxCLI.Command#execute()
 +    */
 +   @Override
 +   public void execute() throws Exception {
 +     out.println("Master secret has been persisted to disk.");
 +   }
 +
 +   /* (non-Javadoc)
 +    * @see org.apache.knox.gateway.util.KnoxCLI.Command#getUsage()
 +    */
 +   @Override
 +   public String getUsage() {
 +     return USAGE + ":\n\n" + DESC;
 +   }
 + }
 +
 +  private class VersionCommand extends Command {
 +
 +    public static final String USAGE = "version";
 +    public static final String DESC = "Displays Knox version information.";
 +
 +    @Override
 +    public void execute() throws Exception {
 +      Properties buildProperties = loadBuildProperties();
 +      System.out.println(
 +          String.format(
 +              "Apache Knox: %s (%s)",
 +              buildProperties.getProperty( "build.version", "unknown" ),
 +              buildProperties.getProperty( "build.hash", "unknown" ) ) );
 +    }
 +
 +    @Override
 +    public String getUsage() {
 +      return USAGE + ":\n\n" + DESC;
 +    }
 +
 +  }
 +
 +  private class RedeployCommand extends Command {
 +
 +    public static final String USAGE = "redeploy [--cluster clustername]";
 +    public static final String DESC =
 +        "Redeploys one or all of the gateway's clusters (a.k.a topologies).";
 +
 +    @Override
 +    public void execute() throws Exception {
 +      TopologyService ts = getTopologyService();
 +      ts.reloadTopologies();
 +      if (cluster != null) {
 +        if (validateClusterName(cluster, ts)) {
 +          ts.redeployTopologies(cluster);
 +        }
 +        else {
 +          out.println("Invalid cluster name provided. Nothing to redeploy.");
 +        }
 +      }
 +    }
 +
 +    /**
 +     * @param cluster
 +     * @param ts
 +     */
 +    private boolean validateClusterName(String cluster, TopologyService ts) {
 +      boolean valid = false;
 +      for (Topology t : ts.getTopologies() ) {
 +        if (t.getName().equals(cluster)) {
 +          valid = true;
 +          break;
 +        }
 +      }
 +      return valid;
 +    }
 +
 +    @Override
 +    public String getUsage() {
 +      return USAGE + ":\n\n" + DESC;
 +    }
 +
 +  }
 +
 +  private class ValidateTopologyCommand extends Command {
 +
 +    public static final String USAGE = "validate-topology [--cluster 
clustername] | [--path \"path/to/file\"]";
 +    public static final String DESC = "Ensures that a cluster's description 
(a.k.a topology) \n" +
 +        "follows the correct formatting rules.\n" +
 +        "use the list-topologies command to get a list of available cluster 
names";
 +    private String file = "";
 +
 +    @Override
 +    public String getUsage() {
 +      return USAGE + ":\n\n" + DESC;
 +    }
 +
 +    public void execute() throws Exception {
 +      GatewayConfig gc = getGatewayConfig();
 +      String topDir = gc.getGatewayTopologyDir();
 +
 +      if(path != null) {
 +        file = path;
 +      } else if(cluster == null) {
 +        // The following block of code retreieves the list of files in the 
topologies directory
 +        File tops = new File(topDir + "/topologies");
 +        if(tops.isDirectory()) {
 +          out.println("List of files available in the topologies directory");
 +          for (File f : tops.listFiles()) {
 +            if(f.getName().endsWith(".xml")) {
 +              String fName = f.getName().replace(".xml", "");
 +              out.println(fName);
 +            }
 +          }
 +          return;
 +        } else {
 +          out.println("Could not locate topologies directory");
 +          return;
 +        }
 +
 +      } else {
 +        file = topDir + "/" + cluster + ".xml";
 +      }
 +
 +      // The following block checks a topology against the XSD
 +      out.println();
 +      out.println("File to be validated: ");
 +      out.println(file);
 +      out.println("==========================================");
 +
 +      if(new File(file).exists()) {
 +        TopologyValidator tv = new TopologyValidator(file);
 +
 +        if(tv.validateTopology()) {
 +          out.println("Topology file validated successfully");
 +        } else {
 +          out.println(tv.getErrorString()) ;
 +          out.println("Topology validation unsuccessful");
 +        }
 +      } else {
 +        out.println("The topology file specified does not exist.");
 +      }
 +    }
 +
 +  }
 +
 +  private class ListTopologiesCommand extends Command {
 +
 +    public static final String USAGE = "list-topologies";
 +    public static final String DESC = "Retrieves a list of the available 
topologies within the\n" +
 +        "default topologies directory. Will return topologies that may not be 
deployed due\n" +
 +        "errors in file formatting.";
 +
 +    @Override
 +    public String getUsage() {
 +      return USAGE + ":\n\n" + DESC;
 +    }
 +
 +    @Override
 +    public void execute() {
 +
 +      String confDir = getGatewayConfig().getGatewayConfDir();
 +      File tops = new File(confDir + "/topologies");
 +      out.println("List of files available in the topologies directory");
 +      out.println(tops.toString());
 +      if(tops.isDirectory()) {
 +        for (File f : tops.listFiles()) {
 +          if(f.getName().endsWith(".xml")) {
 +            String fName = f.getName().replace(".xml", "");
 +            out.println(fName);
 +          }
 +        }
 +        return;
 +      } else {
 +        out.println("ERR: Topologies directory does not exist.");
 +        return;
 +      }
 +
 +    }
 +
 +  }
 +
 +  private class LDAPCommand extends Command {
 +
 +    public static final String USAGE = "ldap-command";
 +    public static final String DESC = "This is an internal command. It should 
not be used.";
 +    protected String username = null;
 +    protected char[] password = null;
 +    protected static final String debugMessage = "For more information use 
--d for debug output.";
 +    protected Topology topology;
 +
 +    @Override
 +    public String getUsage() {
 +      return USAGE + ":\n\n" + DESC;
 +    }
 +
 +    @Override
 +    public void execute() {
 +      out.println("This command does not have any functionality.");
 +    }
 +
 +
 +//    First define a few Exceptions
 +    protected class NoSuchTopologyException extends Exception {
 +      public NoSuchTopologyException() {}
 +      public NoSuchTopologyException(String message) { super(message); }
 +    }
 +    protected class MissingPasswordException extends Exception {
 +      public MissingPasswordException() {}
 +      public MissingPasswordException(String message) { super(message); }
 +    }
 +
 +    protected class MissingUsernameException extends Exception {
 +      public MissingUsernameException() {};
 +      public MissingUsernameException(String message) { super(message); }
 +    }
 +
 +    protected class BadSubjectException extends Exception {
 +      public BadSubjectException() {}
 +      public BadSubjectException(String message) { super(message); }
 +    }
 +
 +    protected class NoSuchProviderException extends Exception {
 +      public NoSuchProviderException() {}
 +      public NoSuchProviderException(String name, String role, String 
topology) {
 +        super("Could not find provider with role: " + role + ", name: " + 
name + " inside of topology: " + topology);
 +      }
 +    }
 +
 +    //    returns false if any errors are printed
 +    protected boolean hasShiroProviderErrors(Topology topology, boolean 
groupLookup) {
 +//      First let's define the variables that represent the ShiroProvider 
params
 +      String mainLdapRealm = "main.ldapRealm";
 +      String contextFactory = mainLdapRealm + ".contextFactory";
 +      String groupContextFactory = "main.ldapGroupContextFactory";
 +      String authorizationEnabled = mainLdapRealm + ".authorizationEnabled";
 +      String userSearchAttributeName = mainLdapRealm + 
".userSearchAttributeName";
 +      String userObjectClass = mainLdapRealm + ".userObjectClass";
 +      String authenticationMechanism = mainLdapRealm + 
".authenticationMechanism"; // Should not be used up to v0.6.0)
 +      String searchBase = mainLdapRealm + ".searchBase";
 +      String groupSearchBase = mainLdapRealm + ".groupSearchBase";
 +      String userSearchBase = mainLdapRealm + ".userSearchBase";
 +      String groupObjectClass = mainLdapRealm + ".groupObjectClass";
 +      String memberAttribute = mainLdapRealm + ".memberAttribute";
 +      String memberAttributeValueTemplate = mainLdapRealm + 
".memberAttributeValueTemplate";
 +      String systemUsername = contextFactory + ".systemUsername";
 +      String systemPassword = contextFactory + ".systemPassword";
 +      String url = contextFactory + ".url";
 +      String userDnTemplate = mainLdapRealm + ".userDnTemplate";
 +
 +
 +      Provider shiro = topology.getProvider("authentication", 
"ShiroProvider");
 +      if(shiro != null) {
 +        Map<String, String> params = shiro.getParams();
 +        int errs = 0;
 +        if(groupLookup) {
 +          int errors = 0;
 +          errors += hasParam(params, groupContextFactory, true) ? 0 : 1;
 +          errors += hasParam(params, groupObjectClass, true) ? 0 : 1;
 +          errors += hasParam(params, memberAttributeValueTemplate, true) ? 0 
: 1;
 +          errors += hasParam(params, memberAttribute, true) ? 0 : 1;
 +          errors += hasParam(params, authorizationEnabled, true) ? 0 : 1;
 +          errors += hasParam(params, systemUsername, true) ? 0 : 1;
 +          errors += hasParam(params, systemPassword, true) ? 0 : 1;
 +          errors += hasParam(params, userSearchBase, true) ? 0 : 1;
 +          errors += hasParam(params, groupSearchBase, true) ? 0 : 1;
 +          errs += errors;
 +
 +        } else {
 +
 +//        Realm + Url is always required.
 +          errs += hasParam(params, mainLdapRealm, true) ? 0 : 1;
 +          errs += hasParam(params, url, true) ? 0 : 1;
 +
 +          if(hasParam(params, authorizationEnabled, false)) {
 +            int errors = 0;
 +            int searchBaseErrors = 0;
 +            errors += hasParam(params, systemUsername, true) ? 0 : 1;
 +            errors += hasParam(params, systemPassword, true) ? 0 : 1;
 +            searchBaseErrors += hasParam(params, searchBase, false) ? 0 : 
hasParam(params, userSearchBase, false) ? 0 : 1;
 +            if (searchBaseErrors > 0) {
 +              out.println("Warn: Both " + searchBase + " and " + 
userSearchBase + " are missing from the topology");
 +            }
 +            errors += searchBaseErrors;
 +            errs += errors;
 +          }
 +
 +//        If any one of these is present they must all be present
 +          if( hasParam(params, userSearchAttributeName, false) ||
 +              hasParam(params, userObjectClass, false) ||
 +              hasParam(params, searchBase, false) ||
 +              hasParam(params, userSearchBase, false)) {
 +
 +            int errors = 0;
 +            errors += hasParam(params, userSearchAttributeName, true) ? 0 : 1;
 +            errors += hasParam(params, userObjectClass, true) ? 0 : 1;
 +            errors += hasParam(params, searchBase, false) ? 0 : 
hasParam(params, userSearchBase, false) ? 0 : 1;
 +            errors += hasParam(params, systemUsername, true) ? 0 : 1;
 +            errors += hasParam(params, systemPassword, true) ? 0 : 1;
 +
 +            if(errors > 0) {
 +              out.println(userSearchAttributeName + " or " + userObjectClass 
+ " or " + searchBase + " or " + userSearchBase + " was found in the topology");
 +              out.println("If any one of the above params is present then " + 
userSearchAttributeName + 
 +                  " and " + userObjectClass + " must both be present and 
either " + searchBase + " or " + userSearchBase + " must also be present.");
 +            }
 +            errs += errors;
 +          } else {
 +            errs += hasParam(params, userDnTemplate, true) ?  0 : 1;
 +
 +          }
 +        }
 +        return (errs > 0);
 +      } else {
 +        out.println("Could not obtain ShiroProvider");
 +        return true;
 +      }
 +    }
 +
 +    // Checks to see if the param name is present. If not, notify the user
 +    protected boolean hasParam(Map<String, String> params, String key, 
boolean notifyUser){
 +      if(params.get(key) == null){
 +        if(notifyUser) { out.println("Warn: " + key + " is not present in 
topology"); }
 +        return false;
 +      } else { return true; }
 +    }
 +
 +    /**
 +     *
 +     * @param ini - the path to the shiro.ini file within a topology 
deployment.
 +     * @param token - token for username and password
 +     * @return - true/false whether a user was successfully able to 
authenticate or not.
 +     */
 +    protected boolean authenticateUser(Ini ini, UsernamePasswordToken token){
 +      boolean result = false;
 +      try {
 +        Subject subject = getSubject(ini);
 +        try{
 +          subject.login(token);
 +          if(subject.isAuthenticated()){
 +            result = true;
 +          }
 +        } catch (AuthenticationException e){
 +          out.println(e.toString());
 +          out.println(e.getCause().getMessage());
 +          if (debug) {
 +            e.printStackTrace(out);
 +          } else {
 +            out.println(debugMessage);
 +          }
 +        } finally {
 +          subject.logout();
 +        }
 +      } catch (BadSubjectException e) {
 +        out.println(e.toString());
 +        if (debug){
 +          e.printStackTrace();
 +        } else {
 +          out.println(debugMessage);
 +        }
 +      } catch (ConfigurationException e) {
 +        out.println(e.toString());
 +      } catch ( Exception e ) {
 +        out.println(e.getCause());
 +        out.println(e.toString());
 +      }
 +      return result;
 +    }
 +
 +    protected boolean authenticateUser(String config, UsernamePasswordToken 
token) throws ConfigurationException {
 +      Ini ini = new Ini();
 +      try {
 +        ini.loadFromPath(config);
 +        return authenticateUser(ini, token);
 +      } catch (ConfigurationException e) {
 +        throw e;
 +      }
 +    }
 +
 +    /**
 +     *
 +     * @param userDn - fully qualified userDn used for LDAP authentication
 +     * @return - returns the principal found in the userDn after "uid="
 +     */
 +    protected String getPrincipal(String userDn){
 +      String result = "";
 +
 +//      Need to determine whether we are using AD or LDAP?
 +//      LDAP userDn usually starts with "uid="
 +//      AD userDn usually starts with cn/CN
 +//      Find the userDN template
 +
 +      try {
 +        Topology t = getTopology(cluster);
 +        Provider shiro = t.getProvider("authentication", "ShiroProvider");
 +
 +        String p1 = shiro.getParams().get("main.ldapRealm.userDnTemplate");
 +
 +//        We know everything between first "=" and "," will be part of the 
principal.
 +        int eq = userDn.indexOf("=");
 +        int com = userDn.indexOf(",");
 +        if(eq != -1 && com > eq && com != -1) {
 +          result = userDn.substring(eq + 1, com);
 +        } else {
 +          result = "";
 +        }
 +      } catch (NoSuchTopologyException e) {
 +        out.println(e.toString());
 +        result = userDn;
 +      } finally {
 +        return result;
 +      }
 +    }
 +
 +    /**
 +     *
 +     * @param t - topology configuration to use
 +     * @param config - the path to the shiro.ini file from the topology 
deployment.
 +     * @return - true/false whether LDAP successfully authenticated with 
system credentials.
 +     */
 +    protected boolean testSysBind(Topology t, String config) {
 +      boolean result = false;
 +      String username;
 +      char[] password;
 +
 +      try {
 +//        Pull out contextFactory.url param for light shiro config
 +        Provider shiro = t.getProvider("authentication", "ShiroProvider");
 +        Map<String, String> params = shiro.getParams();
 +        String url = params.get("main.ldapRealm.contextFactory.url");
 +
 +//        Build the Ini with minimum requirements
 +        Ini ini = new Ini();
 +        ini.addSection("main");
 +        ini.setSectionProperty("main", "ldapRealm", 
"org.apache.knox.gateway.shirorealm.KnoxLdapRealm");
 +        ini.setSectionProperty("main", "ldapContextFactory", 
"org.apache.knox.gateway.shirorealm.KnoxLdapContextFactory");
 +        ini.setSectionProperty("main", "ldapRealm.contextFactory.url", url);
 +
 +        username = getSystemUsername(t);
 +        password = getSystemPassword(t);
 +        result = authenticateUser(ini, new UsernamePasswordToken(username, 
password));
 +      } catch (MissingUsernameException | NoSuchProviderException | 
MissingPasswordException e) {
 +        out.println(e.toString());
 +      } catch (NullPointerException e) {
 +        out.println(e.toString());
 +      }
 +      return result;
 +    }
 +
 +    /**
 +     *
 +     * @param t - topology configuration to use
 +     * @return - the principal of the systemUsername specified in topology. 
null if non-existent
 +     */
 +    private String getSystemUsername(Topology t) throws 
MissingUsernameException, NoSuchProviderException {
 +      final String SYSTEM_USERNAME = 
"main.ldapRealm.contextFactory.systemUsername";
 +      String user = null;
 +      Provider shiroProvider = t.getProvider("authentication", 
"ShiroProvider");
 +      if(shiroProvider != null){
 +        Map<String, String> params = shiroProvider.getParams();
 +        String userDn = params.get(SYSTEM_USERNAME);
 +        user = userDn;
 +      } else {
 +        throw new NoSuchProviderException("ShiroProvider", "authentication", 
t.getName());
 +      }
 +      return user;
 +    }
 +
 +    /**
 +     *
 +     * @param t - topology configuration to use
 +     * @return - the systemPassword specified in topology. null if 
non-existent
 +     */
 +    private char[] getSystemPassword(Topology t) throws 
NoSuchProviderException, MissingPasswordException{
 +      final String SYSTEM_PASSWORD = 
"main.ldapRealm.contextFactory.systemPassword";
 +      String pass = null;
 +      Provider shiro = t.getProvider("authentication", "ShiroProvider");
 +      if(shiro != null){
 +        Map<String, String> params = shiro.getParams();
 +        pass = params.get(SYSTEM_PASSWORD);
 +      } else {
 +        throw new NoSuchProviderException("ShiroProvider", "authentication", 
t.getName());
 +      }
 +
 +      if(pass != null) {
 +        return pass.toCharArray();
 +      } else {
 +        throw new MissingPasswordException("ShiroProvider did not contain 
param: " + SYSTEM_PASSWORD);
 +      }
 +    }
 +
 +    /**
 +     *
 +     * @param config - the shiro.ini config file created in topology 
deployment.
 +     * @return returns the Subject given by the shiro config's settings.
 +     */
 +    protected Subject getSubject(Ini config) throws BadSubjectException {
 +      try {
 +        ThreadContext.unbindSubject();
 +        Factory factory = new IniSecurityManagerFactory(config);
 +        org.apache.shiro.mgt.SecurityManager securityManager = 
(org.apache.shiro.mgt.SecurityManager) factory.getInstance();
 +        SecurityUtils.setSecurityManager(securityManager);
 +        Subject subject = SecurityUtils.getSubject();
 +        if( subject != null) {
 +          return subject;
 +        } else {
 +          out.println("Error Creating Subject from config at: " + config);
 +        }
 +      } catch (Exception e){
 +        out.println(e.toString());
 +      }
 +      throw new BadSubjectException("Subject could not be created with Shiro 
Config at " + config);
 +    }
 +
 +    protected Subject getSubject(String config) throws ConfigurationException 
{
 +      Ini ini = new Ini();
 +      ini.loadFromPath(config);
 +      try {
 +        return getSubject(ini);
 +      } catch (BadSubjectException e) {
 +        throw new ConfigurationException("Could not get Subject with Ini at " 
+ config);
 +      }
 +    }
 +
 +    /**
 +     * prompts the user for credentials in the command line if necessary
 +     * populates the username and password members.
 +     */
 +    protected void promptCredentials() {
 +      if(this.username == null){
 +        Console c = System.console();
 +        if( c != null) {
 +          this.username = c.readLine("Username: ");
 +        }else{
 +          try {
 +            BufferedReader reader = new BufferedReader(new 
InputStreamReader(System.in));
 +            out.println("Username: ");
 +            this.username = reader.readLine();
 +            reader.close();
 +          } catch (IOException e){
 +            out.println(e.toString());
 +            this.username = "";
 +          }
 +        }
 +      }
 +
 +      if(this.password == null){
 +        Console c = System.console();
 +        if( c != null) {
 +          this.password = c.readPassword("Password: ");
 +        }else{
 +          try {
 +            BufferedReader reader = new BufferedReader(new 
InputStreamReader(System.in));
 +            out.println("Password: ");
 +            String pw = reader.readLine();
 +            if(pw != null){
 +              this.password = pw.toCharArray();
 +            } else {
 +              this.password = new char[0];
 +            }
 +            reader.close();
 +          } catch (IOException e){
 +            out.println(e.toString());
 +            this.password = new char[0];
 +          }
 +        }
 +      }
 +    }
 +
 +    /**
 +     *
 +     * @param topologyName - the name of the topology to retrieve
 +     * @return - Topology object with specified name. null if topology 
doesn't exist in TopologyService
 +     */
 +    protected Topology getTopology(String topologyName) throws 
NoSuchTopologyException {
 +      TopologyService ts = getTopologyService();
 +      ts.reloadTopologies();
 +      for (Topology t : ts.getTopologies()) {
 +        if(t.getName().equals(topologyName)) {
 +          return t;
 +        }
 +      }
 +      throw new  NoSuchTopologyException("Topology " + topologyName + " does 
not" +
 +          " exist in the topologies directory.");
 +    }
 +
 +    /**
 +     *
 +     * @param t - Topology to use for config
 +     * @return - path of shiro.ini config file.
 +     */
 +    protected String getConfig(Topology t){
 +      File tmpDir = new File(System.getProperty("java.io.tmpdir"));
 +      DeploymentFactory.setGatewayServices(services);
 +      EnterpriseArchive archive = 
DeploymentFactory.createDeployment(getGatewayConfig(), t);
 +      File war = archive.as(ExplodedExporter.class).exportExploded(tmpDir, 
t.getName() + "_deploy.tmp");
 +      war.deleteOnExit();
 +      String config = war.getAbsolutePath() + "/%2F/WEB-INF/shiro.ini";
 +      try{
 +        FileUtils.forceDeleteOnExit(war);
 +      } catch (IOException e) {
 +        out.println(e.toString());
 +        war.deleteOnExit();
 +      }
 +      return config;
 +    }
 +
 +    /**
 +     * populates username and password if they were passed as arguments, if 
not will prompt user for them.
 +     */
 +    void acquireCredentials(){
 +      if(user != null){
 +        this.username = user;
 +      }
 +      if(pass != null){
 +        this.password = pass.toCharArray();
 +      }
 +      promptCredentials();
 +    }
 +
 +    /**
 +     *
 +     * @return - true or false if the topology was acquired from the topology 
service and populated in the topology
 +     * field.
 +     */
 +    protected boolean acquireTopology(){
 +      try {
 +        topology = getTopology(cluster);
 +      } catch (NoSuchTopologyException e) {
 +        out.println(e.toString());
 +        return false;
 +      }
 +      return true;
 +    }
 +  }
 +
 +  private class LDAPAuthCommand extends LDAPCommand {
 +
 +    public static final String USAGE = "user-auth-test [--cluster 
clustername] [--u username] [--p password] [--g]";
 +    public static final String DESC = "This command tests a cluster's 
configuration ability to\n " +
 +        "authenticate a user with a cluster's ShiroProvider settings.\n Use 
\"--g\" if you want to list the groups a" +
 +        " user is a member of. \nOptional: [--u username]: Provide a username 
argument to the command\n" +
 +        "Optional: [--p password]: Provide a password argument to the 
command.\n" +
 +        "If a username and password argument are not supplied, the terminal 
will prompt you for one.";
 +
 +    private static final String  SUBJECT_USER_GROUPS = "subject.userGroups";
 +    private HashSet<String> groupSet = new HashSet<>();
 +
 +    @Override
 +    public String getUsage() {
 +      return USAGE + ":\n\n" + DESC;
 +    }
 +
 +    @Override
 +    public void execute() {
 +      if(!acquireTopology()){
 +        return;
 +      }
 +      acquireCredentials();
 +
 +      if(topology.getProvider("authentication", "ShiroProvider") == null) {
 +        out.println("ERR: This tool currently only works with Shiro as the 
authentication provider.");
 +        out.println("Please update the topology to use \"ShiroProvider\" as 
the authentication provider.");
 +        return;
 +      }
 +
 +      String config = getConfig(topology);
 +
 +      if(new File(config).exists()) {
 +          if(authenticateUser(config, new UsernamePasswordToken(username, 
password))) {
 +            out.println("LDAP authentication successful!");
 +            if(groups) {
 +              if(testSysBind(topology, config)) {
 +                groupSet = getGroups(topology, new 
UsernamePasswordToken(username, password));
 +                if(groupSet == null || groupSet.isEmpty()) {
 +                  out.println(username + " does not belong to any groups");
 +                  if(groups) {
 +                    hasShiroProviderErrors(topology, true);
 +                    out.println("You were looking for this user's groups but 
this user does not belong to any.");
 +                    out.println("Your topology file may be incorrectly 
configured for group lookup.");
 +                  }
 +                } else {
 +                  for (Object o : groupSet.toArray()) {
 +                    out.println(username + " is a member of: " + 
o.toString());
 +                  }
 +                }
 +              }
 +            }
 +          } else {
 +            out.println("ERR: Unable to authenticate user: " + username);
 +          }
 +      } else {
 +        out.println("ERR: No shiro config file found.");
 +      }
 +    }
 +
 +    private HashSet<String> getGroups(Topology t, UsernamePasswordToken 
token){
 +      HashSet<String> groups = null;
 +      try {
 +        Subject subject = getSubject(getConfig(t));
 +        if(!subject.isAuthenticated()) {
 +          subject.login(token);
 +        }
 +        subject.hasRole(""); //Populate subject groups
 +        groups = (HashSet) 
subject.getSession().getAttribute(SUBJECT_USER_GROUPS);
 +        subject.logout();
 +      } catch (AuthenticationException e) {
 +        out.println("Error retrieving groups");
 +        out.println(e.toString());
 +        if(debug) {
 +          e.printStackTrace();
 +        } else {
 +          out.println(debugMessage);
 +        }
 +      } catch (ConfigurationException e) {
 +        out.println(e.toString());
 +        if(debug){
 +          e.printStackTrace();
 +        }
 +      }
 +      return groups;
 +    }
 +
 +  }
 +
 +  public class LDAPSysBindCommand extends LDAPCommand {
 +
 +    public static final String USAGE = "system-user-auth-test [--cluster 
clustername] [--d]";
 +    public static final String DESC = "This command tests a cluster 
configuration's ability to\n " +
 +        "authenticate a user with a cluster's ShiroProvider settings.";
 +
 +    @Override
 +    public String getUsage() {
 +      return USAGE + ":\n\n" + DESC;
 +    }
 +
 +    @Override
 +    public void execute() {
 +
 +      if(!acquireTopology()) {
 +        return;
 +      }
 +
 +      if(hasShiroProviderErrors(topology, false)) {
 +        out.println("Topology warnings present. SystemUser may not bind.");
 +      }
 +
 +      if(testSysBind(topology, getConfig(topology))) {
 +        out.println("System LDAP Bind successful.");
 +      } else {
 +        out.println("Unable to successfully bind to LDAP server with topology 
credentials. Are your parameters correct?");
 +      }
 +    }
 +  }
 +
 +  private GatewayConfig getGatewayConfig() {
 +    GatewayConfig result;
 +    Configuration conf = getConf();
 +    if(conf != null && conf instanceof GatewayConfig) {
 +      result = (GatewayConfig) conf;
 +    } else {
 +      result = new GatewayConfigImpl();
 +    }
 +    return result;
 +  }
 +
 +  public class ServiceTestCommand extends Command {
 +    public static final String USAGE = "service-test [--u username] [--p 
password] [--cluster clustername] [--hostname name] " +
 +        "[--port port]";
 +    public static final String DESC =
 +                        "This command requires a running instance of Knox to 
be present on the same machine.\n" +
 +                        "It will execute a test to make sure all services are 
accessible through the gateway URLs.\n" +
 +                        "Errors are reported and suggestions to resolve any 
problems are returned. JSON formatted.\n";
 +
 +    private boolean ssl = true;
 +    private int attempts = 0;
 +
 +    @Override
 +    public String getUsage() { return USAGE + ":\n\n" + DESC; };
 +
 +    @Override
 +    public void execute() {
 +      attempts++;
 +      SSLContext ctx = null;
 +      CloseableHttpClient client;
 +      String http = "http://";;
 +      String https = "https://";;
 +      GatewayConfig conf = getGatewayConfig();
 +      String gatewayPort;
 +      String host;
 +
 +
 +      if(cluster == null) {
 +        printKnoxShellUsage();
 +        out.println("A --cluster argument is required.");
 +        return;
 +      }
 +
 +      if(hostname != null) {
 +        host = hostname;
 +      } else {
 +        try {
 +          host = InetAddress.getLocalHost().getHostAddress();
 +        } catch (UnknownHostException e) {
 +          out.println(e.toString());
 +          out.println("Defaulting address to localhost. Use --hostname option 
to specify a different hostname");
 +          host = "localhost";
 +        }
 +      }
 +
 +      if (port != null) {
 +        gatewayPort = port;
 +      } else if (conf.getGatewayPort() > -1) {
 +        gatewayPort = Integer.toString(conf.getGatewayPort());
 +      } else {
 +        out.println("Could not get port. Please supply it using the --port 
option");
 +        return;
 +      }
 +
 +
 +      String path = "/" + conf.getGatewayPath();
 +      String topology = "/" + cluster;
 +      String httpServiceTestURL = http + host + ":" + gatewayPort + path + 
topology + "/service-test";
 +      String httpsServiceTestURL = https + host + ":" + gatewayPort + path + 
topology + "/service-test";
 +
 +      String authString = "";
 +//    Create Authorization String
 +      if( user != null && pass != null) {
 +        authString = "Basic " + Base64.encodeBase64String((user + ":" + 
pass).getBytes());
 +      } else {
 +        out.println("Username and/or password not supplied. Expect HTTP 401 
Unauthorized responses.");
 +      }
 +
 +//    Attempt to build SSL context for HTTP client.
 +      try {
 +        ctx = SSLContexts.custom().loadTrustMaterial(null, new 
TrustSelfSignedStrategy()).build();
 +      } catch (Exception e) {
 +        out.println(e.toString());
 +      }
 +
 +//    Initialize the HTTP client
 +      if(ctx == null) {
 +        client = HttpClients.createDefault();
 +      } else {
 +        client = HttpClients.custom().setSslcontext(ctx).build();
 +      }
 +
 +      HttpGet request;
 +      if(ssl) {
 +        request = new HttpGet(httpsServiceTestURL);
 +      } else {
 +        request = new HttpGet(httpServiceTestURL);
 +      }
 +
 +
 +      request.setHeader("Authorization", authString);
 +      request.setHeader("Accept", MediaType.APPLICATION_JSON.getMediaType());
 +      try {
 +        out.println(request.toString());
 +        CloseableHttpResponse response = client.execute(request);
 +
 +        switch (response.getStatusLine().getStatusCode()) {
 +
 +          case 200:
 +            response.getEntity().writeTo(out);
 +            break;
 +          case 404:
 +            out.println("Could not find service-test resource");
 +            out.println("Make sure you have configured the SERVICE-TEST 
service in your topology.");
 +            break;
 +          case 500:
 +            out.println("HTTP 500 Server error");
 +            break;
 +
 +          default:
 +            out.println("Unexpected HTTP response code.");
 +            out.println(response.getStatusLine().toString());
 +            response.getEntity().writeTo(out);
 +            break;
 +        }
 +
 +        response.close();
 +        request.releaseConnection();
 +
 +      } catch (ClientProtocolException e) {
 +        out.println(e.toString());
 +        if (debug) {
 +          e.printStackTrace(out);
 +        }
 +      } catch (SSLException e) {
 +        out.println(e.toString());
 +        retryRequest();
 +      } catch (IOException e) {
 +        out.println(e.toString());
 +        retryRequest();
 +        if(debug) {
 +          e.printStackTrace(out);
 +        }
 +      } finally {
 +        try {
 +          client.close();
 +        } catch (IOException e) {
 +          out.println(e.toString());
 +        }
 +      }
 +
 +    }
 +
 +    public void retryRequest(){
 +      if(attempts < 2) {
 +        if(ssl) {
 +          ssl = false;
 +          out.println("Attempting request without SSL.");
 +        } else {
 +          ssl = true;
 +          out.println("Attempting request with SSL ");
 +        }
 +        execute();
 +      } else {
 +        out.println("Unable to successfully make request. Try using the API 
with cURL.");
 +      }
 +    }
 +
 +  }
 +
 +  public class RemoteRegistryClientsListCommand extends Command {
 +
 +    static final String USAGE = "list-registry-clients";
 +    static final String DESC = "Lists all of the remote configuration 
registry clients defined in gateway-site.xml.\n";
 +
 +    /* (non-Javadoc)
 +     * @see org.apache.knox.gateway.util.KnoxCLI.Command#execute()
 +     */
 +    @Override
 +    public void execute() throws Exception {
 +      GatewayConfig config = getGatewayConfig();
 +      List<String> remoteConfigRegistryClientNames = 
config.getRemoteRegistryConfigurationNames();
 +      if (!remoteConfigRegistryClientNames.isEmpty()) {
 +        out.println("Listing remote configuration registry clients:");
 +        for (String name : remoteConfigRegistryClientNames) {
 +          out.println(name);
 +        }
 +      }
 +    }
 +
 +    /* (non-Javadoc)
 +     * @see org.apache.knox.gateway.util.KnoxCLI.Command#getUsage()
 +     */
 +    @Override
 +    public String getUsage() {
 +      return USAGE + ":\n\n" + DESC;
 +    }
 + }
 +
++  private abstract class RemoteRegistryCommand extends Command {
++    static final String ROOT_ENTRY = "/knox";
++    static final String CONFIG_ENTRY = ROOT_ENTRY + "/config";
++    static final String PROVIDER_CONFIG_ENTRY = CONFIG_ENTRY + 
"/shared-providers";
++    static final String DESCRIPTORS_ENTRY = CONFIG_ENTRY + "/descriptors";
++
++    protected RemoteConfigurationRegistryClient getClient() {
++      RemoteConfigurationRegistryClient client = null;
++      if (remoteRegistryClient != null) {
++        RemoteConfigurationRegistryClientService cs = 
getRemoteConfigRegistryClientService();
++        client = cs.get(remoteRegistryClient);
++        if (client == null) {
++          out.println("No remote configuration registry identified by '" + 
remoteRegistryClient + "' could be found.");
++        }
++      } else {
++        out.println("Missing required argument : --registry-client\n");
++      }
++      return client;
++    }
++  }
++
++
++  public class RemoteRegistryListProviderConfigsCommand extends 
RemoteRegistryCommand {
++    static final String USAGE = "list-provider-configs --registry-client 
name";
++    static final String DESC = "Lists the provider configurations present in 
the specified remote registry\n";
++
++    @Override
++    public void execute() {
++      RemoteConfigurationRegistryClient client = getClient();
++      if (client != null) {
++        out.println("Provider Configurations (@" + client.getAddress() + ")");
++        List<String> entries = client.listChildEntries(PROVIDER_CONFIG_ENTRY);
++        for (String entry : entries) {
++          out.println(entry);
++        }
++        out.println();
++      }
++    }
++
++    @Override
++    public String getUsage() {
++      return USAGE + ":\n\n" + DESC;
++    }
++  }
++
++
++  public class RemoteRegistryListDescriptorsCommand extends 
RemoteRegistryCommand {
++    static final String USAGE = "list-descriptors --registry-client name";
++    static final String DESC = "Lists the descriptors present in the 
specified remote registry\n";
++
++    @Override
++    public void execute() {
++      RemoteConfigurationRegistryClient client = getClient();
++      if (client != null) {
++        out.println("Descriptors (@" + client.getAddress() + ")");
++        List<String> entries = client.listChildEntries(DESCRIPTORS_ENTRY);
++        for (String entry : entries) {
++          out.println(entry);
++        }
++        out.println();
++      }
++    }
++
++    @Override
++    public String getUsage() {
++      return USAGE + ":\n\n" + DESC;
++    }
++  }
++
 +
 +  /**
 +   * Base class for remote config registry upload commands
 +   */
-   public abstract class RemoteRegistryUploadCommand extends Command {
-     protected static final String ROOT_ENTRY = "/knox";
-     protected static final String CONFIG_ENTRY = ROOT_ENTRY + "/config";
-     protected static final String PROVIDER_CONFIG_ENTRY = CONFIG_ENTRY + 
"/shared-providers";
-     protected static final String DESCRIPTORS__ENTRY = CONFIG_ENTRY + 
"/descriptors";
- 
++  public abstract class RemoteRegistryUploadCommand extends 
RemoteRegistryCommand {
 +    private File sourceFile = null;
 +    protected String filename = null;
 +
 +    protected RemoteRegistryUploadCommand(String sourceFileName) {
 +      this.filename = sourceFileName;
 +    }
 +
 +    private void upload(RemoteConfigurationRegistryClient client, String 
entryPath, File source) throws Exception {
 +      String content = FileUtils.readFileToString(source);
 +      if (client.entryExists(entryPath)) {
 +        // If it exists, then we're going to set the data
 +        client.setEntryData(entryPath, content);
 +      } else {
 +        // If it does not exist, then create it and set the data
 +        client.createEntry(entryPath, content);
 +      }
 +    }
 +
 +    File getSourceFile() {
 +      if (sourceFile == null) {
 +        sourceFile = new File(filename);
 +      }
 +      return sourceFile;
 +    }
 +
 +    String getEntryName(String prefixPath) {
 +      String entryName = remoteRegistryEntryName;
 +      if (entryName == null) {
 +        File sourceFile = getSourceFile();
 +        if (sourceFile.exists()) {
 +          String path = sourceFile.getAbsolutePath();
 +          entryName = path.substring(path.lastIndexOf(File.separator) + 1);
 +        } else {
 +          out.println("Could not locate source file: " + filename);
 +        }
 +      }
 +      return prefixPath + "/" + entryName;
 +    }
 +
 +    protected void execute(String entryName, File sourceFile) throws 
Exception {
-       if (remoteRegistryClient != null) {
-         RemoteConfigurationRegistryClientService cs = 
getRemoteConfigRegistryClientService();
-         RemoteConfigurationRegistryClient client = 
cs.get(remoteRegistryClient);
-         if (client != null) {
-           if (entryName != null) {
-             upload(client, entryName, sourceFile);
-           }
-         } else {
-           out.println("No remote configuration registry identified by '" + 
remoteRegistryClient + "' could be found.");
++      RemoteConfigurationRegistryClient client = getClient();
++      if (client != null) {
++        if (entryName != null) {
++          upload(client, entryName, sourceFile);
 +        }
-       } else {
-         out.println("Missing required argument : --registry-client\n");
 +      }
 +    }
- 
 +  }
 +
 +
 +  public class RemoteRegistryUploadProviderConfigCommand extends 
RemoteRegistryUploadCommand {
 +
 +    static final String USAGE = "upload-provider-config providerConfigFile 
--registry-client name [--entry-name entryName]";
 +    static final String DESC = "Uploads a provider configuration to the 
specified remote registry client, optionally " +
 +                               "renaming the entry.\nIf the entry name is not 
specified, the name of the uploaded " +
 +                               "file is used.\n";
 +
 +    RemoteRegistryUploadProviderConfigCommand(String fileName) {
 +      super(fileName);
 +    }
 +
 +    /* (non-Javadoc)
 +     * @see org.apache.knox.gateway.util.KnoxCLI.Command#execute()
 +     */
 +    @Override
 +    public void execute() throws Exception {
 +      super.execute(getEntryName(PROVIDER_CONFIG_ENTRY), getSourceFile());
 +    }
 +
 +    /* (non-Javadoc)
 +     * @see org.apache.knox.gateway.util.KnoxCLI.Command#getUsage()
 +     */
 +    @Override
 +    public String getUsage() {
 +      return USAGE + ":\n\n" + DESC;
 +    }
 +  }
 +
 +
 +  public class RemoteRegistryUploadDescriptorCommand extends 
RemoteRegistryUploadCommand {
 +
 +    static final String USAGE = "upload-descriptor descriptorFile 
--registry-client name [--entry-name entryName]";
 +    static final String DESC = "Uploads a simple descriptor using the 
specified remote registry client, optionally " +
 +                               "renaming the entry.\nIf the entry name is not 
specified, the name of the uploaded " +
 +                               "file is used.\n";
 +
 +    RemoteRegistryUploadDescriptorCommand(String fileName) {
 +      super(fileName);
 +    }
 +
 +    /* (non-Javadoc)
 +     * @see org.apache.knox.gateway.util.KnoxCLI.Command#execute()
 +     */
 +    @Override
 +    public void execute() throws Exception {
-       super.execute(getEntryName(DESCRIPTORS__ENTRY), getSourceFile());
++      super.execute(getEntryName(DESCRIPTORS_ENTRY), getSourceFile());
 +    }
 +
 +    /* (non-Javadoc)
 +     * @see org.apache.knox.gateway.util.KnoxCLI.Command#getUsage()
 +     */
 +    @Override
 +    public String getUsage() {
 +      return USAGE + ":\n\n" + DESC;
 +    }
 +  }
 +
 +
-   public class RemoteRegistryGetACLCommand extends Command {
++  public class RemoteRegistryGetACLCommand extends RemoteRegistryCommand {
 +
 +    static final String USAGE = "get-registry-acl entry --registry-client 
name";
 +    static final String DESC = "Presents the ACL settings for the specified 
remote registry entry.\n";
 +
 +    private String entry = null;
 +
 +    RemoteRegistryGetACLCommand(String entry) {
 +      this.entry = entry;
 +    }
 +
 +    /* (non-Javadoc)
 +     * @see org.apache.knox.gateway.util.KnoxCLI.Command#execute()
 +     */
 +    @Override
 +    public void execute() throws Exception {
-       if (remoteRegistryClient != null) {
-         RemoteConfigurationRegistryClientService cs = 
getRemoteConfigRegistryClientService();
-         RemoteConfigurationRegistryClient client = 
cs.get(remoteRegistryClient);
-         if (client != null) {
-           if (entry != null) {
-             List<RemoteConfigurationRegistryClient.EntryACL> acls = 
client.getACL(entry);
-             for (RemoteConfigurationRegistryClient.EntryACL acl : acls) {
-               out.println(acl.getType() + ":" + acl.getId() + ":" + 
acl.getPermissions());
-             }
++      RemoteConfigurationRegistryClient client = getClient();
++      if (client != null) {
++        if (entry != null) {
++          List<RemoteConfigurationRegistryClient.EntryACL> acls = 
client.getACL(entry);
++          for (RemoteConfigurationRegistryClient.EntryACL acl : acls) {
++            out.println(acl.getType() + ":" + acl.getId() + ":" + 
acl.getPermissions());
 +          }
-         } else {
-           out.println("No remote configuration registry identified by '" + 
remoteRegistryClient + "' could be found.");
 +        }
-       } else {
-         out.println("Missing required argument : --registry-client\n");
 +      }
 +    }
 +
 +    /* (non-Javadoc)
 +     * @see org.apache.knox.gateway.util.KnoxCLI.Command#getUsage()
 +     */
 +    @Override
 +    public String getUsage() {
 +      return USAGE + ":\n\n" + DESC;
 +    }
 +  }
 +
 +
 +  /**
 +   * Base class for remote config registry delete commands
 +   */
-   public abstract class RemoteRegistryDeleteCommand extends Command {
-     protected static final String ROOT_ENTRY = "/knox";
-     protected static final String CONFIG_ENTRY = ROOT_ENTRY + "/config";
-     protected static final String PROVIDER_CONFIG_ENTRY = CONFIG_ENTRY + 
"/shared-providers";
-     protected static final String DESCRIPTORS__ENTRY = CONFIG_ENTRY + 
"/descriptors";
- 
++  public abstract class RemoteRegistryDeleteCommand extends 
RemoteRegistryCommand {
 +    protected String entryName = null;
 +
 +    protected RemoteRegistryDeleteCommand(String entryName) {
 +      this.entryName = entryName;
 +    }
 +
 +    private void delete(RemoteConfigurationRegistryClient client, String 
entryPath) throws Exception {
 +      if (client.entryExists(entryPath)) {
 +        // If it exists, then delete it
 +        client.deleteEntry(entryPath);
 +      }
 +    }
 +
 +    protected void execute(String entryName) throws Exception {
-       if (remoteRegistryClient != null) {
-         RemoteConfigurationRegistryClientService cs = 
getRemoteConfigRegistryClientService();
-         RemoteConfigurationRegistryClient client = 
cs.get(remoteRegistryClient);
-         if (client != null) {
-           if (entryName != null) {
-             delete(client, entryName);
-           }
-         } else {
-           out.println("No remote configuration registry identified by '" + 
remoteRegistryClient + "' could be found.");
++      RemoteConfigurationRegistryClient client = getClient();
++      if (client != null) {
++        if (entryName != null) {
++          delete(client, entryName);
 +        }
-       } else {
-         out.println("Missing required argument : --registry-client\n");
 +      }
 +    }
 +  }
 +
 +
 +  public class RemoteRegistryDeleteProviderConfigCommand extends 
RemoteRegistryDeleteCommand {
 +    static final String USAGE = "delete-provider-config providerConfig 
--registry-client name";
 +    static final String DESC = "Deletes a shared provider configuration from 
the specified remote registry.\n";
 +
 +    public RemoteRegistryDeleteProviderConfigCommand(String entryName) {
 +      super(entryName);
 +    }
 +
 +    @Override
 +    public void execute() throws Exception {
 +      execute(PROVIDER_CONFIG_ENTRY + "/" + entryName);
 +    }
 +
 +    @Override
 +    public String getUsage() {
 +      return USAGE + ":\n\n" + DESC;
 +    }
 +  }
 +
 +
 +  public class RemoteRegistryDeleteDescriptorCommand extends 
RemoteRegistryDeleteCommand {
 +    static final String USAGE = "delete-descriptor descriptor 
--registry-client name";
 +    static final String DESC = "Deletes a simple descriptor from the 
specified remote registry.\n";
 +
 +    public RemoteRegistryDeleteDescriptorCommand(String entryName) {
 +      super(entryName);
 +    }
 +
 +    @Override
 +    public void execute() throws Exception {
-       execute(DESCRIPTORS__ENTRY + "/" + entryName);
++      execute(DESCRIPTORS_ENTRY + "/" + entryName);
 +    }
 +
 +    @Override
 +    public String getUsage() {
 +      return USAGE + ":\n\n" + DESC;
 +    }
 +  }
 +
 +
 +  private static Properties loadBuildProperties() {
 +    Properties properties = new Properties();
 +    InputStream inputStream = 
KnoxCLI.class.getClassLoader().getResourceAsStream( "build.properties" );
 +    if( inputStream != null ) {
 +      try {
 +        properties.load( inputStream );
 +        inputStream.close();
 +      } catch( IOException e ) {
 +        // Ignore.
 +      }
 +    }
 +    return properties;
 +  }
 +
 +  /**
 +   * @param args
 +   * @throws Exception
 +   */
 +  public static void main(String[] args) throws Exception {
 +    PropertyConfigurator.configure( System.getProperty( "log4j.configuration" 
) );
 +    int res = ToolRunner.run(new GatewayConfigImpl(), new KnoxCLI(), args);
 +    System.exit(res);
 +  }
 +}

Reply via email to