Repository: knox Updated Branches: refs/heads/master 495369f98 -> 684466faa
KNOX-733 - Add support for custom truststore to Knox shell client Project: http://git-wip-us.apache.org/repos/asf/knox/repo Commit: http://git-wip-us.apache.org/repos/asf/knox/commit/684466fa Tree: http://git-wip-us.apache.org/repos/asf/knox/tree/684466fa Diff: http://git-wip-us.apache.org/repos/asf/knox/diff/684466fa Branch: refs/heads/master Commit: 684466faadf4627391bd74042c782ec47a44d6b5 Parents: 495369f Author: Larry McCay <lmc...@hortonworks.com> Authored: Thu Sep 8 10:49:44 2016 -0400 Committer: Larry McCay <lmc...@hortonworks.com> Committed: Thu Sep 8 10:49:44 2016 -0400 ---------------------------------------------------------------------- .../shell/ClearInputCredentialCollector.java | 2 +- .../org/apache/hadoop/gateway/shell/Hadoop.java | 118 ++++++++++++++++++- .../shell/HiddenInputCredentialCollector.java | 2 +- .../shell/hbase/table/row/InsertableColumn.java | 3 - .../security/impl/X509CertificateUtil.java | 2 +- 5 files changed, 119 insertions(+), 8 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/knox/blob/684466fa/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/ClearInputCredentialCollector.java ---------------------------------------------------------------------- diff --git a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/ClearInputCredentialCollector.java b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/ClearInputCredentialCollector.java index 49e086c..496f6ea 100644 --- a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/ClearInputCredentialCollector.java +++ b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/ClearInputCredentialCollector.java @@ -19,7 +19,7 @@ package org.apache.hadoop.gateway.shell; public class ClearInputCredentialCollector extends AbstractJavaConsoleCredentialCollector { - public static String COLLECTOR_TYPE = "ClearInput"; + public static final String COLLECTOR_TYPE = "ClearInput"; /* (non-Javadoc) * @see org.apache.hadoop.gateway.shell.CredentialCollector#collect() */ http://git-wip-us.apache.org/repos/asf/knox/blob/684466fa/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/Hadoop.java ---------------------------------------------------------------------- diff --git a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/Hadoop.java b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/Hadoop.java index ac5e968..6bfc407 100644 --- a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/Hadoop.java +++ b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/Hadoop.java @@ -17,6 +17,7 @@ */ package org.apache.hadoop.gateway.shell; +import org.apache.commons.io.IOUtils; import org.apache.http.HttpHost; import org.apache.http.HttpRequest; import org.apache.http.HttpResponse; @@ -27,6 +28,7 @@ import org.apache.http.client.protocol.ClientContext; import org.apache.http.conn.scheme.PlainSocketFactory; import org.apache.http.conn.scheme.Scheme; import org.apache.http.conn.scheme.SchemeRegistry; +import org.apache.http.conn.ssl.SSLContextBuilder; import org.apache.http.conn.ssl.SSLSocketFactory; import org.apache.http.conn.ssl.TrustSelfSignedStrategy; import org.apache.http.impl.auth.BasicScheme; @@ -35,10 +37,18 @@ import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.conn.PoolingClientConnectionManager; import org.apache.http.protocol.BasicHttpContext; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; +import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; @@ -47,8 +57,16 @@ import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import javax.net.ssl.SSLContext; + public class Hadoop { + private static final String GATEWAY_CLIENT_TRUST_DEFAULT_PASS = "changeit"; + private static final String KNOX_CLIENT_TRUSTSTORE_PASS = "KNOX_CLIENT_TRUSTSTORE_PASS"; + private static final String GATEWAY_CLIENT_TRUST = "gateway-client-trust.jks"; + private static final String KNOX_CLIENT_TRUSTSTORE_FILENAME = "KNOX_CLIENT_TRUSTSTORE_FILENAME"; + private static final String KNOX_CLIENT_TRUSTSTORE_DIR = "KNOX_CLIENT_TRUSTSTORE_DIR"; + String base; HttpHost host; DefaultHttpClient client; @@ -58,10 +76,25 @@ public class Hadoop { ExecutorService executor; public static Hadoop login( String url, String username, String password ) throws URISyntaxException { + return new Hadoop( url, username, password, true ); + } + + public static Hadoop loginInsecure( String url, String username, String password ) throws URISyntaxException { + System.out.println("**************** WARNING ******************\n" + + "This is an insecure client instance and may\n" + + "leave the interactions subject to a man in\n" + + "the middle attack. Please use the login()\n" + + "method instead of loginInsecure() for any\n" + + "sensitive or production usecases.\n" + + "*******************************************"); return new Hadoop( url, username, password ); } private Hadoop( String url, String username, String password ) throws HadoopException, URISyntaxException { + this(url, username, password, false); + } + + private Hadoop( String url, String username, String password, boolean secure ) throws HadoopException, URISyntaxException { this.executor = Executors.newCachedThreadPool(); this.base = url; this.username = username; @@ -71,7 +104,12 @@ public class Hadoop { host = new HttpHost( uri.getHost(), uri.getPort(), uri.getScheme() ); try { - client = createClient(); + if (!secure) { + client = createInsecureClient(); + } + else { + client = createClient(); + } client.getCredentialsProvider().setCredentials( new AuthScope( host.getHostName(), host.getPort() ), new UsernamePasswordCredentials( username, password ) ); @@ -87,7 +125,83 @@ public class Hadoop { private static DefaultHttpClient createClient() throws GeneralSecurityException { SchemeRegistry registry = new SchemeRegistry(); - SSLSocketFactory socketFactory = new SSLSocketFactory( new TrustSelfSignedStrategy(), SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER ); + KeyStore trustStore = getTrustStore(); + SSLSocketFactory socketFactory = new SSLSocketFactory(trustStore); + registry.register( new Scheme( "https", 443, socketFactory ) ); + registry.register( new Scheme( "http", 80, new PlainSocketFactory() ) ); + PoolingClientConnectionManager mgr = new PoolingClientConnectionManager( registry ); + DefaultHttpClient client = new DefaultHttpClient( mgr, new DefaultHttpClient().getParams() ); + return client; + } + + private static KeyStore getTrustStore() throws GeneralSecurityException { + KeyStore ks = null; + String truststoreDir = System.getenv(KNOX_CLIENT_TRUSTSTORE_DIR); + if (truststoreDir == null) { + truststoreDir = System.getProperty("user.home"); + } + String truststoreFileName = System.getenv(KNOX_CLIENT_TRUSTSTORE_FILENAME); + if (truststoreFileName == null) { + truststoreFileName = GATEWAY_CLIENT_TRUST; + } + String truststorePass = System.getenv(KNOX_CLIENT_TRUSTSTORE_PASS); + if (truststorePass == null) { + truststorePass = GATEWAY_CLIENT_TRUST_DEFAULT_PASS; + } + + InputStream is = null; + try { + ks = KeyStore.getInstance("JKS"); + File file = new File(truststoreDir, truststoreFileName); + if (!file.exists()) { + String truststore = System.getProperty("javax.net.ssl.trustStore"); + if (truststore == null) { + truststoreDir = System.getProperty("java.home"); + truststore = truststoreDir + File.separator + "lib" + File.separator + + "security" + File.separator + "cacerts"; + truststorePass = System.getProperty("javax.net.ssl.trustStorePassword", "changeit"); + } + file = new File(truststore); + } + + if (file.exists()) { + is = new FileInputStream(file); + ks.load(is, truststorePass.toCharArray()); + } + else { + throw new HadoopException("Unable to find a truststore for secure login." + + "Please import the gateway-identity certificate into the JVM" + + " truststore or set the truststore location ENV variables."); + } + } catch (KeyStoreException e) { + throw new HadoopException("Unable to create keystore of expected type.", e); + } catch (FileNotFoundException e) { + throw new HadoopException("Unable to read truststore." + + " Please import the gateway-identity certificate into the JVM" + + " truststore or set the truststore location ENV variables.", e); + } catch (NoSuchAlgorithmException e) { + throw new HadoopException("Unable to load the truststore." + + " Please import the gateway-identity certificate into the JVM" + + " truststore or set the truststore location ENV variables.", e); + } catch (CertificateException e) { + throw new HadoopException("Certificate cannot be found in the truststore." + + " Please import the gateway-identity certificate into the JVM" + + " truststore or set the truststore location ENV variables.", e); + } catch (IOException e) { + throw new HadoopException("Unable to load truststore." + + " May be related to password setting or truststore format.", e); + } finally { + IOUtils.closeQuietly(is); + } + + return ks; + } + + private static DefaultHttpClient createInsecureClient() throws GeneralSecurityException { + SchemeRegistry registry = new SchemeRegistry(); + SSLSocketFactory socketFactory = new SSLSocketFactory( + new TrustSelfSignedStrategy(), + SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER ); registry.register( new Scheme( "https", 443, socketFactory ) ); registry.register( new Scheme( "http", 80, new PlainSocketFactory() ) ); PoolingClientConnectionManager mgr = new PoolingClientConnectionManager( registry ); http://git-wip-us.apache.org/repos/asf/knox/blob/684466fa/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/HiddenInputCredentialCollector.java ---------------------------------------------------------------------- diff --git a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/HiddenInputCredentialCollector.java b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/HiddenInputCredentialCollector.java index 6e350de..5d95d81 100644 --- a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/HiddenInputCredentialCollector.java +++ b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/HiddenInputCredentialCollector.java @@ -19,7 +19,7 @@ package org.apache.hadoop.gateway.shell; public class HiddenInputCredentialCollector extends AbstractJavaConsoleCredentialCollector { - public static String COLLECTOR_TYPE = "HiddenInput"; + public static final String COLLECTOR_TYPE = "HiddenInput"; /* (non-Javadoc) * @see org.apache.hadoop.gateway.shell.CredentialCollector#collect() */ http://git-wip-us.apache.org/repos/asf/knox/blob/684466fa/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/hbase/table/row/InsertableColumn.java ---------------------------------------------------------------------- diff --git a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/hbase/table/row/InsertableColumn.java b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/hbase/table/row/InsertableColumn.java index 12c4c29..77198bf 100644 --- a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/hbase/table/row/InsertableColumn.java +++ b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/hbase/table/row/InsertableColumn.java @@ -45,9 +45,6 @@ public class InsertableColumn extends Column { public String encodedValue() throws UnsupportedEncodingException { String stringValue = value.toString(); - if( stringValue == null ) { - stringValue = ""; - } return Base64.encodeBase64String( stringValue.getBytes( "UTF-8" ) ); } } http://git-wip-us.apache.org/repos/asf/knox/blob/684466fa/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/impl/X509CertificateUtil.java ---------------------------------------------------------------------- diff --git a/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/impl/X509CertificateUtil.java b/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/impl/X509CertificateUtil.java index e31c7d8..f6a7ecd 100644 --- a/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/impl/X509CertificateUtil.java +++ b/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/impl/X509CertificateUtil.java @@ -291,7 +291,7 @@ public class X509CertificateUtil { throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException { KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); - char[] password = "changeme".toCharArray(); + char[] password = "changeit".toCharArray(); ks.load(null, password); ks.setCertificateEntry("gateway-identity", cert); FileOutputStream fos = new FileOutputStream(file);