knox-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From m...@apache.org
Subject [20/24] knox git commit: Merge branch 'master' into KNOX-998-Package_Restructuring
Date Fri, 08 Sep 2017 15:15:13 GMT
http://git-wip-us.apache.org/repos/asf/knox/blob/50f46e9e/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 1cd1e11,0000000..9071a1d
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,1777 -1,0 +1,1777 @@@
 +/**
 + * 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.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";
 +
 +  /** 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;
 +
 +  // 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]
 +   *
 +   * </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[i].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 {
 +        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 );
 +    }
 +  }
 +
 +  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;
 +    }
 +  }
 +
 + 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 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 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 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 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 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 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 (generate.equals("true")) {
++       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 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 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 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 KnoxCLI.Command#execute()
 +    */
 +   @Override
 +   public void execute() throws Exception {
 +     out.println("Master secret has been persisted to disk.");
 +   }
 +
 +   /* (non-Javadoc)
 +    * @see 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. It will execute a test to make sure all services are accessible through the gateway URLs. Errors are " +
 +        "reported and suggestions to resolve any problems are returned. JSON formatted.";
 +
 +    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.");
 +      }
 +    }
 +
 +  }
 +
 +  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);
 +  }
 +}

http://git-wip-us.apache.org/repos/asf/knox/blob/50f46e9e/gateway-server/src/test/java/org/apache/knox/gateway/AuditLoggingTest.java
----------------------------------------------------------------------
diff --cc gateway-server/src/test/java/org/apache/knox/gateway/AuditLoggingTest.java
index feea617,0000000..82890c4
mode 100644,000000..100644
--- a/gateway-server/src/test/java/org/apache/knox/gateway/AuditLoggingTest.java
+++ b/gateway-server/src/test/java/org/apache/knox/gateway/AuditLoggingTest.java
@@@ -1,255 -1,0 +1,258 @@@
 +/**
 + * 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;
 +
 +import static org.hamcrest.CoreMatchers.is;
 +import static org.hamcrest.MatcherAssert.assertThat;
 +import static org.hamcrest.core.IsNull.notNullValue;
 +import static org.hamcrest.core.IsNull.nullValue;
 +import static org.junit.Assert.fail;
 +
 +import java.io.IOException;
 +import java.net.URI;
 +import java.net.URISyntaxException;
 +import java.util.ArrayList;
 +import java.util.Collections;
 +import java.util.Iterator;
 +
 +import javax.servlet.Filter;
 +import javax.servlet.FilterChain;
 +import javax.servlet.FilterConfig;
 +import javax.servlet.ServletContext;
 +import javax.servlet.ServletException;
 +import javax.servlet.http.HttpServletRequest;
 +import javax.servlet.http.HttpServletResponse;
 +
 +import org.apache.knox.gateway.audit.api.Action;
 +import org.apache.knox.gateway.audit.api.ActionOutcome;
 +import org.apache.knox.gateway.audit.api.AuditContext;
 +import org.apache.knox.gateway.audit.api.AuditServiceFactory;
 +import org.apache.knox.gateway.audit.api.CorrelationContext;
 +import org.apache.knox.gateway.audit.api.ResourceType;
 +import org.apache.knox.gateway.audit.log4j.audit.AuditConstants;
 +import org.apache.knox.gateway.audit.log4j.audit.Log4jAuditService;
 +import org.apache.knox.gateway.audit.log4j.correlation.Log4jCorrelationService;
 +import org.apache.knox.gateway.config.GatewayConfig;
 +import org.apache.knox.gateway.dispatch.DefaultDispatch;
 +import org.apache.knox.gateway.i18n.resources.ResourcesFactory;
 +import org.apache.hadoop.test.log.CollectAppender;
- import org.apache.http.impl.client.DefaultHttpClient;
++import org.apache.http.impl.client.CloseableHttpClient;
++import org.apache.http.impl.client.HttpClientBuilder;
 +import org.apache.log4j.spi.LoggingEvent;
 +import org.easymock.EasyMock;
 +import org.junit.After;
 +import org.junit.Before;
 +import org.junit.Test;
 +
 +public class AuditLoggingTest {
 +  private static final String METHOD = "GET";
 +  private static final String PATH = "path";
 +  private static final String CONTEXT_PATH = "contextPath/";
 +  private static final String ADDRESS = "address";
 +  private static final String HOST = "host";
 +
 +  private static final GatewayResources RES = ResourcesFactory.get( GatewayResources.class );
 +
 +  @Before
 +  public void loggingSetup() {
 +    AuditServiceFactory.getAuditService().createContext();
 +    CollectAppender.queue.clear();
 +  }
 +
 +  @After
 +  public void reset() {
 +    AuditServiceFactory.getAuditService().detachContext();
 +  }
 +
 +  @Test
 +  /**
 +   * Empty filter chain. Two events with same correlation ID are expected:
-    * 
++   *
 +   * action=access request_type=uri outcome=unavailable
 +   * action=access request_type=uri outcome=success message=Response status: 404
 +   */
 +  public void testNoFiltersAudit() throws ServletException, IOException {
 +    FilterConfig config = EasyMock.createNiceMock( FilterConfig.class );
 +    EasyMock.replay( config );
 +
 +    HttpServletRequest request = EasyMock.createNiceMock( HttpServletRequest.class );
 +    ServletContext context = EasyMock.createNiceMock( ServletContext.class );
 +    GatewayConfig gatewayConfig = EasyMock.createNiceMock( GatewayConfig.class );
 +    EasyMock.expect( request.getMethod() ).andReturn( METHOD ).anyTimes();
 +    EasyMock.expect( request.getPathInfo() ).andReturn( PATH ).anyTimes();
 +    EasyMock.expect( request.getContextPath() ).andReturn( CONTEXT_PATH ).anyTimes();
 +    EasyMock.expect( request.getRemoteAddr() ).andReturn( ADDRESS ).anyTimes();
 +    EasyMock.expect( request.getRemoteHost() ).andReturn( HOST ).anyTimes();
 +    EasyMock.expect( request.getServletContext() ).andReturn( context ).anyTimes();
 +    EasyMock.expect( context.getAttribute(
 +        GatewayConfig.GATEWAY_CONFIG_ATTRIBUTE)).andReturn(gatewayConfig).anyTimes();
 +    EasyMock.expect(gatewayConfig.getHeaderNameForRemoteAddress()).andReturn(
 +        "Custom-Forwarded-For").anyTimes();
 +    EasyMock.replay( request );
 +    EasyMock.replay( context );
 +    EasyMock.replay( gatewayConfig );
 +
 +    HttpServletResponse response = EasyMock.createNiceMock( HttpServletResponse.class );
 +    EasyMock.replay( response );
 +
 +    FilterChain chain = EasyMock.createNiceMock( FilterChain.class );
 +    EasyMock.replay( chain );
 +
 +    GatewayFilter gateway = new GatewayFilter();
 +    gateway.init( config );
 +    gateway.doFilter( request, response, chain );
 +    gateway.destroy();
 +
 +    assertThat( CollectAppender.queue.size(), is( 1 ) );
 +    Iterator<LoggingEvent> iterator = CollectAppender.queue.iterator();
 +    LoggingEvent accessEvent = iterator.next();
 +    verifyAuditEvent( accessEvent, CONTEXT_PATH + PATH, ResourceType.URI, Action.ACCESS, ActionOutcome.UNAVAILABLE, null, "Request method: GET" );
 +  }
 +
 +  @Test
 +  /**
 +   * One NoOp filter in chain. Single audit event with same with specified request URI is expected:
-    * 
++   *
 +   * action=access request_type=uri outcome=unavailable
 +   */
 +  public void testNoopFilter() throws ServletException, IOException,
 +      URISyntaxException {
 +
 +    FilterConfig config = EasyMock.createNiceMock( FilterConfig.class );
 +    EasyMock.replay( config );
 +
 +    HttpServletRequest request = EasyMock.createNiceMock( HttpServletRequest.class );
 +    ServletContext context = EasyMock.createNiceMock( ServletContext.class );
 +    GatewayConfig gatewayConfig = EasyMock.createNiceMock( GatewayConfig.class );
 +    EasyMock.expect( request.getMethod() ).andReturn( METHOD ).anyTimes();
 +    EasyMock.expect( request.getPathInfo() ).andReturn( PATH ).anyTimes();
 +    EasyMock.expect( request.getContextPath() ).andReturn( CONTEXT_PATH ).anyTimes();
 +    EasyMock.expect( request.getRemoteAddr() ).andReturn( ADDRESS ).anyTimes();
 +    EasyMock.expect( request.getRemoteHost() ).andReturn( HOST ).anyTimes();
 +    EasyMock.expect( request.getServletContext() ).andReturn( context ).anyTimes();
 +    EasyMock.expect( context.getAttribute(
 +        GatewayConfig.GATEWAY_CONFIG_ATTRIBUTE)).andReturn(gatewayConfig).anyTimes();
 +    EasyMock.expect(gatewayConfig.getHeaderNameForRemoteAddress()).andReturn(
 +        "Custom-Forwarded-For").anyTimes();
 +    EasyMock.replay( request );
 +    EasyMock.replay( context );
 +    EasyMock.replay( gatewayConfig );
 +
 +    HttpServletResponse response = EasyMock.createNiceMock( HttpServletResponse.class );
 +    EasyMock.replay( response );
 +
 +    FilterChain chain = EasyMock.createNiceMock( FilterChain.class );
 +    EasyMock.replay( chain );
 +
 +    Filter filter = EasyMock.createNiceMock( Filter.class );
 +    EasyMock.replay( filter );
 +
 +    GatewayFilter gateway = new GatewayFilter();
 +    gateway.addFilter( "path", "filter", filter, null, null );
 +    gateway.init( config );
 +    gateway.doFilter( request, response, chain );
 +    gateway.destroy();
 +
 +    assertThat( CollectAppender.queue.size(), is( 1 ) );
 +    Iterator<LoggingEvent> iterator = CollectAppender.queue.iterator();
 +    LoggingEvent accessEvent = iterator.next();
 +    verifyAuditEvent( accessEvent, CONTEXT_PATH + PATH, ResourceType.URI,
 +        Action.ACCESS, ActionOutcome.UNAVAILABLE, null, "Request method: GET" );
 +
 +  }
 +
 +  @Test
 +  /**
 +   * Dispatching outbound request. Remote host is unreachable. Two log events is expected:
-    * 
++   *
 +   * action=dispatch request_type=uri outcome=FAILED
 +   * action=dispatch request_type=uri outcome=unavailable
 +   */
 +  public void testHttpClientOutboundException() throws IOException,
 +      URISyntaxException {
 +    String uri = "http://outbound-host:port/path";
 +
 +    HttpServletRequest inboundRequest = EasyMock.createNiceMock( HttpServletRequest.class );
 +    EasyMock.expect( inboundRequest.getHeaderNames() ).andReturn( Collections.enumeration( new ArrayList<String>() ) ).anyTimes();
 +    EasyMock.replay( inboundRequest );
 +
 +    HttpServletResponse outboundResponse = EasyMock.createNiceMock( HttpServletResponse.class );
 +    EasyMock.replay( outboundResponse );
 +
 +    DefaultDispatch dispatch = new DefaultDispatch();
-     dispatch.setHttpClient(new DefaultHttpClient());
++    HttpClientBuilder builder = HttpClientBuilder.create();
++    CloseableHttpClient client = builder.build();
++    dispatch.setHttpClient(client);
 +    try {
 +      dispatch.doGet( new URI( uri ), inboundRequest, outboundResponse );
 +      fail( "Expected exception while accessing to unreachable host" );
 +    } catch ( IOException e ) {
 +      Iterator<LoggingEvent> iterator = CollectAppender.queue.iterator();
 +
 +      LoggingEvent unavailableEvent = iterator.next();
 +      verifyValue( (String) unavailableEvent.getMDC( AuditConstants.MDC_RESOURCE_NAME_KEY ), uri );
 +      verifyValue( (String) unavailableEvent.getMDC( AuditConstants.MDC_RESOURCE_TYPE_KEY ), ResourceType.URI );
 +      verifyValue( (String) unavailableEvent.getMDC( AuditConstants.MDC_ACTION_KEY ), Action.DISPATCH );
 +      verifyValue( (String) unavailableEvent.getMDC( AuditConstants.MDC_OUTCOME_KEY ), ActionOutcome.UNAVAILABLE );
 +
 +      LoggingEvent failureEvent = iterator.next();
 +      verifyValue( (String) failureEvent.getMDC( AuditConstants.MDC_RESOURCE_NAME_KEY ), uri );
 +      verifyValue( (String) failureEvent.getMDC( AuditConstants.MDC_RESOURCE_TYPE_KEY ), ResourceType.URI );
 +      verifyValue( (String) failureEvent.getMDC( AuditConstants.MDC_ACTION_KEY ), Action.DISPATCH );
 +      verifyValue( (String) failureEvent.getMDC( AuditConstants.MDC_OUTCOME_KEY ), ActionOutcome.FAILURE );
 +
 +    }
 +  }
 +
 +  private void verifyAuditEvent( LoggingEvent event, String resourceName,
 +      String resourceType, String action, String outcome, String targetService,
 +      String message ) {
 +    event.getMDCCopy();
 +    CorrelationContext cc = (CorrelationContext) event.getMDC( Log4jCorrelationService.MDC_CORRELATION_CONTEXT_KEY );
 +    assertThat( cc, notNullValue() );
 +    assertThat( cc.getRequestId(), is( notNullValue() ) );
 +    AuditContext ac = (AuditContext) event.getMDC( Log4jAuditService.MDC_AUDIT_CONTEXT_KEY );
 +    assertThat( ac, notNullValue() );
 +    assertThat( ac.getRemoteIp(), is( ADDRESS ) );
 +    assertThat( ac.getRemoteHostname(), is( HOST ) );
 +    assertThat( (String) event.getMDC( AuditConstants.MDC_SERVICE_KEY ), is( AuditConstants.KNOX_SERVICE_NAME ) );
 +    assertThat( (String) event.getMDC( AuditConstants.MDC_COMPONENT_KEY ), is( AuditConstants.KNOX_COMPONENT_NAME ) );
 +    assertThat( (String) event.getLoggerName(), is( AuditConstants.DEFAULT_AUDITOR_NAME ) );
 +    verifyValue( (String) event.getMDC( AuditConstants.MDC_RESOURCE_NAME_KEY ), resourceName );
 +    verifyValue( (String) event.getMDC( AuditConstants.MDC_RESOURCE_TYPE_KEY ), resourceType );
 +    verifyValue( (String) event.getMDC( AuditConstants.MDC_ACTION_KEY ), action );
 +    verifyValue( (String) event.getMDC( AuditConstants.MDC_OUTCOME_KEY ), outcome );
 +    verifyValue( ac.getTargetServiceName(), targetService );
 +    verifyValue( event.getRenderedMessage(), message );
 +  }
 +
 +  private void verifyValue( String actual, String expected ) {
 +    if( expected == null ) {
 +      assertThat( actual, nullValue() );
 +    } else {
 +      assertThat( actual, is( expected ) );
 +    }
 +  }
 +
 +  private String getRequestId( LoggingEvent event ) {
 +    CorrelationContext cc = (CorrelationContext) event
 +        .getMDC( Log4jCorrelationService.MDC_CORRELATION_CONTEXT_KEY );
 +    return cc == null ? null : cc.getRequestId();
 +  }
 +
 +}

http://git-wip-us.apache.org/repos/asf/knox/blob/50f46e9e/gateway-server/src/test/java/org/apache/knox/gateway/TempletonDemo.java
----------------------------------------------------------------------
diff --cc gateway-server/src/test/java/org/apache/knox/gateway/TempletonDemo.java
index dffb5fb,0000000..66321ea
mode 100644,000000..100644
--- a/gateway-server/src/test/java/org/apache/knox/gateway/TempletonDemo.java
+++ b/gateway-server/src/test/java/org/apache/knox/gateway/TempletonDemo.java
@@@ -1,70 -1,0 +1,72 @@@
 +/**
 + * 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;
 +
 +import org.apache.hadoop.test.category.ManualTests;
 +import org.apache.hadoop.test.category.SlowTests;
 +import org.apache.http.HttpResponse;
 +import org.apache.http.NameValuePair;
- import org.apache.http.client.HttpClient;
 +import org.apache.http.client.entity.UrlEncodedFormEntity;
 +import org.apache.http.client.methods.HttpPost;
- import org.apache.http.impl.client.DefaultHttpClient;
++import org.apache.http.impl.client.CloseableHttpClient;
++import org.apache.http.impl.client.HttpClientBuilder;
 +import org.apache.http.message.BasicNameValuePair;
 +import org.apache.http.util.EntityUtils;
 +import org.apache.log4j.helpers.Loader;
 +import org.junit.Test;
 +import org.junit.experimental.categories.Category;
 +
 +import java.io.IOException;
 +import java.net.URL;
 +import java.nio.charset.Charset;
 +import java.util.ArrayList;
 +import java.util.List;
 +
 +@Category( { ManualTests.class, SlowTests.class } )
 +public class TempletonDemo {
 +
 +  @Test
 +  public void demoDirect() throws IOException {
 +    demo( "http://vm:50111/templeton/v1/mapreduce/jar" );
 +  }
 +
 +  @Test
 +  public void demoGateway() throws IOException {
 +    URL url = Loader.getResource( "log4j.properties" );
 +    System.out.println( url );
 +    demo( "http://localhost:8888/gateway/cluster/templeton/v1/mapreduce/jar" );
 +  }
 +
 +  private void demo( String url ) throws IOException {
-     HttpClient client = new DefaultHttpClient();
 +    List<NameValuePair> parameters = new ArrayList<NameValuePair>();
 +    parameters.add( new BasicNameValuePair( "user.name", "hdfs" ) );
 +    parameters.add( new BasicNameValuePair( "jar", "wordcount/org.apache.hadoop-examples.jar" ) );
 +    parameters.add( new BasicNameValuePair( "class", "org.apache.org.apache.hadoop.examples.WordCount" ) );
 +    parameters.add( new BasicNameValuePair( "arg", "wordcount/input" ) );
 +    parameters.add( new BasicNameValuePair( "arg", "wordcount/output" ) );
 +    UrlEncodedFormEntity entity = new UrlEncodedFormEntity( parameters, Charset.forName( "UTF-8" ) );
 +    HttpPost request = new HttpPost( url );
 +    request.setEntity( entity );
++
++    HttpClientBuilder builder = HttpClientBuilder.create();
++    CloseableHttpClient client = builder.build();
 +    HttpResponse response = client.execute( request );
 +    System.out.println( EntityUtils.toString( response.getEntity() ) );
 +  }
 +
 +}


Mime
View raw message