Repository: knox Updated Branches: refs/heads/master 8773ba8de -> da478a557
KNOX-1623 - Kerberos support for KnoxShell Project: http://git-wip-us.apache.org/repos/asf/knox/repo Commit: http://git-wip-us.apache.org/repos/asf/knox/commit/da478a55 Tree: http://git-wip-us.apache.org/repos/asf/knox/tree/da478a55 Diff: http://git-wip-us.apache.org/repos/asf/knox/diff/da478a55 Branch: refs/heads/master Commit: da478a55717b2bb94afee872ed14fa8abbc4f517 Parents: 8773ba8 Author: Sandeep More <[email protected]> Authored: Wed Dec 5 10:10:03 2018 -0500 Committer: Sandeep More <[email protected]> Committed: Wed Dec 5 10:13:06 2018 -0500 ---------------------------------------------------------------------- gateway-shell/pom.xml | 7 +- .../knox/gateway/shell/ClientContext.java | 54 +++ .../apache/knox/gateway/shell/KnoxSession.java | 178 ++++++++-- gateway-shell/src/main/resources/jaas.conf | 28 ++ gateway-test-release/webhdfs-kerb-test/pom.xml | 15 + .../knox/gateway/SecureKnoxShellTest.java | 347 +++++++++++++++++++ .../knox/gateway/SecureKnoxShellTest/README | 57 +++ .../SecureWebHdfsPutGet.groovy | 37 ++ pom.xml | 5 + 9 files changed, 704 insertions(+), 24 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/knox/blob/da478a55/gateway-shell/pom.xml ---------------------------------------------------------------------- diff --git a/gateway-shell/pom.xml b/gateway-shell/pom.xml index f73ab36..e7c0c2a 100644 --- a/gateway-shell/pom.xml +++ b/gateway-shell/pom.xml @@ -92,18 +92,19 @@ <groupId>commons-configuration</groupId> <artifactId>commons-configuration</artifactId> </dependency> - <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> </dependency> - <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> </dependency> - + <dependency> + <groupId>de.thetaphi</groupId> + <artifactId>forbiddenapis</artifactId> + </dependency> </dependencies> </project> http://git-wip-us.apache.org/repos/asf/knox/blob/da478a55/gateway-shell/src/main/java/org/apache/knox/gateway/shell/ClientContext.java ---------------------------------------------------------------------- diff --git a/gateway-shell/src/main/java/org/apache/knox/gateway/shell/ClientContext.java b/gateway-shell/src/main/java/org/apache/knox/gateway/shell/ClientContext.java index b9d52ca..21aa7d7 100644 --- a/gateway-shell/src/main/java/org/apache/knox/gateway/shell/ClientContext.java +++ b/gateway-shell/src/main/java/org/apache/knox/gateway/shell/ClientContext.java @@ -29,12 +29,14 @@ public class ClientContext { private final PoolContext poolContext; private final SocketContext socketContext; private final ConnectionContext connectionContext; + private final KerberosContext kerberos; private ClientContext() { configuration = new MapConfiguration(new HashMap<>()); poolContext = new PoolContext(this); socketContext = new SocketContext(this); connectionContext = new ConnectionContext(this); + kerberos = new KerberosContext(this); } private static class Context { @@ -186,6 +188,54 @@ public class ClientContext { } } + /** + * Context for Kerberos properties + * @since 1.3.0 + */ + public static class KerberosContext extends Context { + + private KerberosContext(ClientContext clientContext) { + super(clientContext, "kerberos"); + } + + public KerberosContext jaasConf(final String path) { + configuration.addProperty("jaasConf", path); + return this; + } + + public String jaasConf() { + return configuration.getString("jaasConf"); + } + + public KerberosContext krb5Conf(final String path) { + configuration.addProperty("krb5Conf", path); + return this; + } + + public String krb5Conf() { + return configuration.getString("krb5Conf"); + } + + public KerberosContext enable(final boolean enable) { + configuration.addProperty("enable", enable); + return this; + } + + public boolean enable() { + return configuration.getBoolean("enable", false); + } + + public KerberosContext debug(final boolean debug) { + configuration.addProperty("debug", debug); + return this; + } + + public boolean debug() { + return configuration.getBoolean("debug"); + } + + } + public PoolContext pool() { return poolContext; } @@ -198,6 +248,10 @@ public class ClientContext { return connectionContext; } + public KerberosContext kerberos() { + return kerberos; + } + public static ClientContext with(final String username, final String password, final String url) { ClientContext context = new ClientContext(); context.configuration.addProperty("username", username); http://git-wip-us.apache.org/repos/asf/knox/blob/da478a55/gateway-shell/src/main/java/org/apache/knox/gateway/shell/KnoxSession.java ---------------------------------------------------------------------- diff --git a/gateway-shell/src/main/java/org/apache/knox/gateway/shell/KnoxSession.java b/gateway-shell/src/main/java/org/apache/knox/gateway/shell/KnoxSession.java index da57946..ca2672c 100644 --- a/gateway-shell/src/main/java/org/apache/knox/gateway/shell/KnoxSession.java +++ b/gateway-shell/src/main/java/org/apache/knox/gateway/shell/KnoxSession.java @@ -17,12 +17,17 @@ */ package org.apache.knox.gateway.shell; +import com.sun.security.auth.callback.TextCallbackHandler; +import org.apache.commons.lang3.StringUtils; import org.apache.http.HttpHost; import org.apache.http.HttpRequest; +import org.apache.http.auth.AuthSchemeProvider; import org.apache.http.auth.AuthScope; +import org.apache.http.auth.Credentials; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.AuthCache; import org.apache.http.client.CredentialsProvider; +import org.apache.http.client.config.AuthSchemes; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.config.ConnectionConfig; import org.apache.http.config.Registry; @@ -35,6 +40,7 @@ import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.conn.ssl.TrustSelfSignedStrategy; import org.apache.http.conn.ssl.TrustStrategy; import org.apache.http.impl.auth.BasicScheme; +import org.apache.http.impl.auth.SPNegoSchemeFactory; import org.apache.http.impl.client.BasicAuthCache; import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.client.CloseableHttpClient; @@ -45,6 +51,9 @@ import org.apache.http.ssl.SSLContexts; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; +import javax.security.auth.Subject; +import javax.security.auth.login.LoginContext; +import javax.security.auth.login.LoginException; import java.io.Closeable; import java.io.File; import java.io.FileInputStream; @@ -53,10 +62,13 @@ import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; +import java.net.URL; import java.security.GeneralSecurityException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; +import java.security.Principal; +import java.security.PrivilegedAction; import java.security.cert.CertificateException; import java.util.HashMap; import java.util.Map; @@ -67,6 +79,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import de.thetaphi.forbiddenapis.SuppressForbidden; public class KnoxSession implements Closeable { @@ -75,6 +88,10 @@ public class KnoxSession implements Closeable { 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"; + private static final String DEFAULT_JAAS_FILE = "/jaas.conf"; + public static final String JGSS_LOGIN_MOUDLE = "com.sun.security.jgss.initiate"; + + private boolean isKerberos = false; String base; HttpHost host; @@ -113,6 +130,46 @@ public class KnoxSession implements Closeable { .connection().secure(false).end()); } + /** + * Support kerberos authentication. + * + * @param url Gateway url + * @param jaasConf jaas configuration (optional- can be null) + * @param krb5Conf kerberos configuration (optional - can be null) + * @param debug enable debug messages + * @return + * @throws URISyntaxException + * @since 1.3.0 + */ + public static KnoxSession kerberosLogin(final String url, + final String jaasConf, + final String krb5Conf, + final boolean debug) + throws URISyntaxException { + + return new KnoxSession(ClientContext.with(url) + .kerberos() + .enable(true) + .jaasConf(jaasConf) + .krb5Conf(krb5Conf) + .debug(debug) + .end()); + } + + /** + * Support kerberos authentication. + * This method assumed kinit has already been called + * and the token is persisted on disk. + * @param url + * @return + * @throws URISyntaxException + * @since 1.3.0 + */ + public static KnoxSession kerberosLogin(final String url) + throws URISyntaxException { + return kerberosLogin(url, "", "", false); + } + protected KnoxSession() throws KnoxShellException, URISyntaxException { } @@ -173,24 +230,74 @@ public class KnoxSession implements Closeable { // Auth URI uri = URI.create(clientContext.url()); host = new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme()); - - CredentialsProvider credentialsProvider = null; - if (clientContext.username() != null && clientContext.password() != null) { - credentialsProvider = new BasicCredentialsProvider(); - credentialsProvider.setCredentials( - new AuthScope(host.getHostName(), host.getPort()), - new UsernamePasswordCredentials(clientContext.username(), clientContext.password())); - - AuthCache authCache = new BasicAuthCache(); - BasicScheme authScheme = new BasicScheme(); - authCache.put(host, authScheme); - context = new BasicHttpContext(); - context.setAttribute(org.apache.http.client.protocol.HttpClientContext.AUTH_CACHE, authCache); + + /* kerberos auth */ + if (clientContext.kerberos().enable()) { + isKerberos = true; + /* set up system properties */ + if (!StringUtils.isBlank(clientContext.kerberos().krb5Conf())) { + System.setProperty("java.security.krb5.conf", + clientContext.kerberos().krb5Conf()); + } + + if (!StringUtils.isBlank(clientContext.kerberos().jaasConf())) { + System.setProperty("java.security.auth.login.config", + clientContext.kerberos().jaasConf()); + } else { + final URL url = getClass().getResource(DEFAULT_JAAS_FILE); + System.setProperty("java.security.auth.login.config", + url.toExternalForm()); + } + + if (clientContext.kerberos().debug()) { + System.setProperty("sun.security.krb5.debug", "true"); + System.setProperty("sun.security.jgss.debug", "true"); + } + + System.setProperty("javax.security.auth.useSubjectCredsOnly", "false"); + + final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); + + credentialsProvider.setCredentials(AuthScope.ANY, new Credentials() { + @Override + public Principal getUserPrincipal() { + return null; + } + + @Override + public String getPassword() { + return null; + } + }); + + final Registry<AuthSchemeProvider> authSchemeRegistry = RegistryBuilder.<AuthSchemeProvider>create() + .register(AuthSchemes.SPNEGO, new SPNegoSchemeFactory(true)).build(); + + return HttpClients.custom() + .setConnectionManager(connectionManager) + .setDefaultAuthSchemeRegistry(authSchemeRegistry) + .setDefaultCredentialsProvider(credentialsProvider) + .build(); + + } else { + CredentialsProvider credentialsProvider = null; + if (clientContext.username() != null && clientContext.password() != null) { + credentialsProvider = new BasicCredentialsProvider(); + credentialsProvider.setCredentials( + new AuthScope(host.getHostName(), host.getPort()), + new UsernamePasswordCredentials(clientContext.username(), clientContext.password())); + + AuthCache authCache = new BasicAuthCache(); + BasicScheme authScheme = new BasicScheme(); + authCache.put(host, authScheme); + context = new BasicHttpContext(); + context.setAttribute(org.apache.http.client.protocol.HttpClientContext.AUTH_CACHE, authCache); + } + return HttpClients.custom() + .setConnectionManager(connectionManager) + .setDefaultCredentialsProvider(credentialsProvider) + .build(); } - return HttpClients.custom() - .setConnectionManager(connectionManager) - .setDefaultCredentialsProvider(credentialsProvider) - .build(); } @@ -276,13 +383,42 @@ public class KnoxSession implements Closeable { return base; } + @SuppressForbidden public CloseableHttpResponse executeNow(HttpRequest request ) throws IOException { - CloseableHttpResponse response = client.execute( host, request, context ); - if( response.getStatusLine().getStatusCode() < 400 ) { - return response; + /* check for kerberos */ + if (isKerberos) { + LoginContext lc; + try { + lc = new LoginContext(JGSS_LOGIN_MOUDLE, new TextCallbackHandler()); + lc.login(); + return Subject.doAs(lc.getSubject(), + (PrivilegedAction<CloseableHttpResponse>) () -> { + CloseableHttpResponse response = null; + try { + response = client.execute(host, request, context); + if (response.getStatusLine().getStatusCode() < 400) { + return response; + } else { + throw new ErrorResponse(response); + } + } catch (final IOException e) { + throw new KnoxShellException(e.toString(), e); + } + }); + + } catch (final LoginException e) { + throw new KnoxShellException(e.toString(), e); + } + } else { - throw new ErrorResponse( response ); + CloseableHttpResponse response = client.execute( host, request, context ); + if( response.getStatusLine().getStatusCode() < 400 ) { + return response; + } else { + throw new ErrorResponse( response ); + } } + } public <T> Future<T> executeLater( Callable<T> callable ) { http://git-wip-us.apache.org/repos/asf/knox/blob/da478a55/gateway-shell/src/main/resources/jaas.conf ---------------------------------------------------------------------- diff --git a/gateway-shell/src/main/resources/jaas.conf b/gateway-shell/src/main/resources/jaas.conf new file mode 100644 index 0000000..330ae7a --- /dev/null +++ b/gateway-shell/src/main/resources/jaas.conf @@ -0,0 +1,28 @@ +//########################################################################## +//# 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. +//########################################################################## +com.sun.security.jgss.initiate { + com.sun.security.auth.module.Krb5LoginModule required + useTicketCache=true + doNotPrompt=true + renewTGT=true + debug=true; + //ticketCache="/tmp/krb5cc_502" + //useKeyTab=true + //principal="guest/[email protected]" + //keyTab="/Users/username/spnego.service.keytab"; +}; \ No newline at end of file http://git-wip-us.apache.org/repos/asf/knox/blob/da478a55/gateway-test-release/webhdfs-kerb-test/pom.xml ---------------------------------------------------------------------- diff --git a/gateway-test-release/webhdfs-kerb-test/pom.xml b/gateway-test-release/webhdfs-kerb-test/pom.xml index 4ae8a03..041a685 100644 --- a/gateway-test-release/webhdfs-kerb-test/pom.xml +++ b/gateway-test-release/webhdfs-kerb-test/pom.xml @@ -40,6 +40,21 @@ <artifactId>httpclient</artifactId> <scope>test</scope> </dependency> + <dependency> + <groupId>org.hamcrest</groupId> + <artifactId>hamcrest-core</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.hamcrest</groupId> + <artifactId>hamcrest-library</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.codehaus.groovy</groupId> + <artifactId>groovy</artifactId> + <scope>test</scope> + </dependency> </dependencies> <build> http://git-wip-us.apache.org/repos/asf/knox/blob/da478a55/gateway-test-release/webhdfs-kerb-test/src/test/java/org/apache/knox/gateway/SecureKnoxShellTest.java ---------------------------------------------------------------------- diff --git a/gateway-test-release/webhdfs-kerb-test/src/test/java/org/apache/knox/gateway/SecureKnoxShellTest.java b/gateway-test-release/webhdfs-kerb-test/src/test/java/org/apache/knox/gateway/SecureKnoxShellTest.java new file mode 100644 index 0000000..817250e --- /dev/null +++ b/gateway-test-release/webhdfs-kerb-test/src/test/java/org/apache/knox/gateway/SecureKnoxShellTest.java @@ -0,0 +1,347 @@ +/* + * 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 + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * 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 com.mycila.xmltool.XMLDoc; +import com.mycila.xmltool.XMLTag; +import groovy.lang.Binding; +import groovy.lang.GroovyShell; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.fs.permission.FsPermission; +import org.apache.hadoop.hdfs.DistributedFileSystem; +import org.apache.hadoop.hdfs.HdfsConfiguration; +import org.apache.hadoop.hdfs.MiniDFSCluster; +import org.apache.hadoop.minikdc.MiniKdc; +import org.apache.hadoop.security.UserGroupInformation; +import org.apache.hadoop.security.ssl.KeyStoreTestUtil; +import org.apache.knox.test.TestUtils; +import org.apache.knox.test.category.ReleaseTest; +import org.apache.log4j.PropertyConfigurator; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.util.Locale; +import java.util.Properties; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +/** + * Test for KnoxShell Kerberos support + */ +@Category(ReleaseTest.class) +public class SecureKnoxShellTest { + + private static final String SCRIPT = "SecureWebHdfsPutGet.groovy"; + /** + * Referring {@link MiniKdc} as {@link Object} to prevent the class loader + * from trying to load it before @BeforeClass annotation is called. Need to + * play this game because {@link MiniKdc} is not compatible with Java 7 so if + * we detect Java 7 we quit the test. + * <p> + * As result we need to up cast this object to {@link MiniKdc} every place we + * use it. + * + */ + private static Object kdc; + private static String userName; + private static HdfsConfiguration configuration; + private static int nameNodeHttpPort; + private static File baseDir; + private static String krb5conf; + private static String hdfsPrincipal; + private static String spnegoPrincipal; + private static String keytab; + private static File ticketCache; + + private static MiniDFSCluster miniDFSCluster; + private static GatewayTestDriver driver = new GatewayTestDriver(); + + /** + * Test should run if java major version is greater or equal to this + * property. + * + * @since 0.10 + */ + private static int JAVA_MAJOR_VERSION_FOR_TEST = 8; + + public SecureKnoxShellTest() { + super(); + } + + @BeforeClass + public static void setupSuite() throws Exception { + + /* + * Run the test only if the jre version matches the one we want, see + * KNOX-769 + */ + org.junit.Assume.assumeTrue(isJreVersionOK()); + baseDir = new File( + KeyStoreTestUtil.getClasspathDir(SecureKnoxShellTest.class)); + ticketCache = new File( + KeyStoreTestUtil.getClasspathDir(SecureKnoxShellTest.class) + + "/ticketCache"); + + nameNodeHttpPort = TestUtils.findFreePort(); + configuration = new HdfsConfiguration(); + baseDir = new File( + KeyStoreTestUtil.getClasspathDir(SecureKnoxShellTest.class)); + System.setProperty(MiniDFSCluster.PROP_TEST_BUILD_DATA, + baseDir.getAbsolutePath()); + + miniDFSCluster = new MiniDFSCluster.Builder(configuration) + .nameNodePort(TestUtils.findFreePort()) + .nameNodeHttpPort(nameNodeHttpPort).numDataNodes(2).format(true) + .racks(null).build(); + + initKdc(); + setupKnox(keytab, hdfsPrincipal); + } + + private static void initKdc() throws Exception { + final Properties kdcConf = MiniKdc.createConf(); + kdc = new MiniKdc(kdcConf, baseDir); + ((MiniKdc) kdc).start(); + + userName = UserGroupInformation + .createUserForTesting("guest", new String[] { "users" }).getUserName(); + final File keytabFile = new File(baseDir, userName + ".keytab"); + keytab = keytabFile.getAbsolutePath(); + // Windows will not reverse name lookup "127.0.0.1" to "localhost". + final String krbInstance = Path.WINDOWS ? "127.0.0.1" : "localhost"; + ((MiniKdc) kdc).createPrincipal(keytabFile, userName + "/" + krbInstance, + "HTTP/" + krbInstance); + + hdfsPrincipal = + userName + "/" + krbInstance + "@" + ((MiniKdc) kdc).getRealm(); + spnegoPrincipal = "HTTP/" + krbInstance + "@" + ((MiniKdc) kdc).getRealm(); + + krb5conf = ((MiniKdc) kdc).getKrb5conf().getAbsolutePath(); + + } + + @AfterClass + public static void cleanupSuite() throws Exception { + /* No need to clean up if we did not start anything */ + if (isJreVersionOK()) { + ((MiniKdc) kdc).stop(); + Files.deleteIfExists(ticketCache.toPath()); + miniDFSCluster.shutdown(); + driver.cleanup(); + } + } + + private static File setupJaasConf(File baseDir, String keyTabFile, + String principal) throws IOException { + final File file = new File(baseDir, "jaas.conf"); + if (!file.exists()) { + file.createNewFile(); + } else { + file.delete(); + file.createNewFile(); + } + final Writer writer = new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8); + String content = String.format(Locale.ROOT, "com.sun.security.jgss.initiate {\n" + + "com.sun.security.auth.module.Krb5LoginModule required\n" + + "renewTGT=true\n" + "doNotPrompt=true\n" + "useKeyTab=true\n" + + "keyTab=\"%s\"\n" + "principal=\"%s\"\n" + "isInitiator=true\n" + + "storeKey=true\n" + "useTicketCache=true\n" + + //"ticketCache=\"%s\"\n" + + "debug=false\n" + "client=true;\n" + "};\n", keyTabFile, principal); + writer.write(content); + writer.close(); + return file; + } + + private static void setupKnox(String keytab, String hdfsPrincipal) + throws Exception { + + File jaasConf = setupJaasConf(baseDir, keytab, hdfsPrincipal); + + System.setProperty("java.security.krb5.conf", + ((MiniKdc) kdc).getKrb5conf().getAbsolutePath()); + System.setProperty("java.security.auth.login.config", + jaasConf.getAbsolutePath()); + System.setProperty("javax.security.auth.useSubjectCredsOnly", "false"); + System.setProperty("sun.security.krb5.debug", "false"); + + System.setProperty("gateway.hadoop.kerberos.secured", "false"); + GatewayTestConfig config = new GatewayTestConfig(); + config.setGatewayPath("gateway"); + config.setHadoopKerberosSecured(false); + + driver.setResourceBase(SecureKnoxShellTest.class); + driver.setupLdap(0); + driver.setupGateway(config, "secure", createSecureTopology(), true); + } + + /** + * Creates a Secure topology that is deployed to the gateway instance for the + * test suite. + * + * @return A populated XML structure for a topology file. + */ + private static XMLTag createSecureTopology() { + XMLTag xml = XMLDoc.newDocument(true).addRoot("topology").addTag("gateway") + .addTag("provider").addTag("role").addText("authentication") + .addTag("name").addText("HadoopAuth").addTag("enabled").addText("true") + + .addTag("param").addTag("name").addText("config.prefix").addTag("value") + .addText("hadoop.auth.config").gotoParent() + + .addTag("param").addTag("name") + .addText("hadoop.auth.config.signature.secret").addTag("value") + .addText("knox").gotoParent() + + .addTag("param").addTag("name").addText("hadoop.auth.config.type") + .addTag("value").addText("kerberos").gotoParent() + + .addTag("param").addTag("name") + .addText("hadoop.auth.config.simple.anonymous.allowed").addTag("value") + .addText("false").gotoParent() + + .addTag("param").addTag("name") + .addText("hadoop.auth.config.token.validity").addTag("value") + .addText("1800").gotoParent() + + .addTag("param").addTag("name") + .addText("hadoop.auth.config.cookie.domain").addTag("value") + .addText("localhost").gotoParent() + + .addTag("param").addTag("name") + .addText("hadoop.auth.config.cookie.path").addTag("value") + .addText("gateway/secure").gotoParent() + + .addTag("param").addTag("name") + .addText("hadoop.auth.config.kerberos.principal").addTag("value") + .addText(spnegoPrincipal).gotoParent() + + .addTag("param").addTag("name") + .addText("hadoop.auth.config.kerberos.keytab").addTag("value") + .addText(keytab).gotoParent() + + .addTag("param").addTag("name") + .addText("hadoop.auth.config.kerberos.name.rules").addTag("value") + .addText("DEFAULT").gotoParent().gotoParent() + + .addTag("provider").addTag("role").addText("identity-assertion") + .addTag("enabled").addText("true").addTag("name").addText("Default") + .gotoParent().addTag("provider").addTag("role").addText("authorization") + .addTag("enabled").addText("true").addTag("name").addText("AclsAuthz") + .gotoParent().gotoParent().gotoRoot() + + .addTag("service").addTag("role").addText("WEBHDFS").addTag("url") + .addText("http://localhost:" + nameNodeHttpPort + "/webhdfs/") + .gotoParent().gotoRoot(); + + //System.out.println( "GATEWAY=" + xml.toString() ); + return xml; + } + + private static void setupLogging() { + PropertyConfigurator + .configure(ClassLoader.getSystemResource("log4j.properties")); + } + + /** + * Check whether java version is >= {@link #JAVA_MAJOR_VERSION_FOR_TEST} + * + * @return + * @since 0.10 + */ + public static boolean isJreVersionOK() { + + final String jreVersion = System.getProperty("java.version"); + int majorVersion = Integer.parseInt(String.valueOf(jreVersion.charAt(2))); + + if (majorVersion >= JAVA_MAJOR_VERSION_FOR_TEST) { + return true; + } + return false; + } + + /** + * Test Kerberos login using KnoxShell using keytab. + * + * @throws Exception + */ + @Test + public void testCachedTicket() throws Exception { + setupLogging(); + + webhdfsPutGet(); + } + + /** + * Do the heavy lifting here. + * + * @throws Exception + */ + private void webhdfsPutGet() throws Exception { + DistributedFileSystem fileSystem = miniDFSCluster.getFileSystem(); + Path dir = new Path("/user/guest/example"); + fileSystem.delete(dir, true); + fileSystem.mkdirs(dir, new FsPermission("777")); + fileSystem.setOwner(dir, "guest", "users"); + + final File jaasFile = setupJaasConf(baseDir, keytab, hdfsPrincipal); + + final Binding binding = new Binding(); + + binding.setProperty("jaasConf", jaasFile.getAbsolutePath()); + binding.setProperty("krb5conf", krb5conf); + binding.setProperty("gateway", driver.getClusterUrl()); + + URL readme = driver.getResourceUrl("README"); + File file = new File(readme.toURI()); + //System.out.println(file.exists()); + binding.setProperty("file", file.getAbsolutePath()); + + final GroovyShell shell = new GroovyShell(binding); + + shell.evaluate(getResourceUrl(SCRIPT).toURI()); + + String status = (String) binding.getProperty("status"); + assertNotNull(status); + //System.out.println(status); + + String fetchedFile = (String) binding.getProperty("fetchedFile"); + assertNotNull(fetchedFile); + //`(fetchedFile); + assertTrue(fetchedFile.contains("README")); + } + + public URL getResourceUrl(String resource) { + String filePath = + this.getClass().getCanonicalName().replaceAll("\\.", "/") + "/" + + resource; + URL url = ClassLoader.getSystemResource(filePath); + return url; + } + +} http://git-wip-us.apache.org/repos/asf/knox/blob/da478a55/gateway-test-release/webhdfs-kerb-test/src/test/resources/org/apache/knox/gateway/SecureKnoxShellTest/README ---------------------------------------------------------------------- diff --git a/gateway-test-release/webhdfs-kerb-test/src/test/resources/org/apache/knox/gateway/SecureKnoxShellTest/README b/gateway-test-release/webhdfs-kerb-test/src/test/resources/org/apache/knox/gateway/SecureKnoxShellTest/README new file mode 100644 index 0000000..0ef01d4 --- /dev/null +++ b/gateway-test-release/webhdfs-kerb-test/src/test/resources/org/apache/knox/gateway/SecureKnoxShellTest/README @@ -0,0 +1,57 @@ +------------------------------------------------------------------------------ +README file for the Apache Knox Gateway +------------------------------------------------------------------------------ +This distribution includes cryptographic software. The country in +which you currently reside may have restrictions on the import, +possession, use, and/or re-export to another country, of +encryption software. BEFORE using any encryption software, please +check your country's laws, regulations and policies concerning the +import, possession, or use, and re-export of encryption software, to +see if this is permitted. See <http://www.wassenaar.org/> for more +information. + +The U.S. Government Department of Commerce, Bureau of Industry and +Security (BIS), has classified this software as Export Commodity +Control Number (ECCN) 5D002.C.1, which includes information security +software using or performing cryptographic functions with asymmetric +algorithms. The form and manner of this Apache Software Foundation +distribution makes it eligible for export under the License Exception +ENC Technology Software Unrestricted (TSU) exception (see the BIS +Export Administration Regulations, Section 740.13) for both object +code and source code. + +The following provides more details on the included cryptographic +software: + This package includes the use of ApacheDS which is dependent upon the +Bouncy Castle Crypto APIs written by the Legion of the Bouncy Castle +http://www.bouncycastle.org/ [email protected]. + +------------------------------------------------------------------------------ +Description +------------------------------------------------------------------------------ +Please see the Apache Knox site for detailed description. + +http://knox.apache.org/ + +------------------------------------------------------------------------------ +Changes +------------------------------------------------------------------------------ +Please see the CHANGES file. + +------------------------------------------------------------------------------ +Known Issues +------------------------------------------------------------------------------ +Please see the ISSUES file. + +------------------------------------------------------------------------------ +Installation & Usage +------------------------------------------------------------------------------ +Please see the Apache Knox Gateway User's Guide - available on the Knox site. +http://knox.apache.org/ + +------------------------------------------------------------------------------ +Troubleshooting & Filing bugs +------------------------------------------------------------------------------ +Please see the Apache Knox Gateway User's Guide for detailed information. +http://knox.apache.org + http://git-wip-us.apache.org/repos/asf/knox/blob/da478a55/gateway-test-release/webhdfs-kerb-test/src/test/resources/org/apache/knox/gateway/SecureKnoxShellTest/SecureWebHdfsPutGet.groovy ---------------------------------------------------------------------- diff --git a/gateway-test-release/webhdfs-kerb-test/src/test/resources/org/apache/knox/gateway/SecureKnoxShellTest/SecureWebHdfsPutGet.groovy b/gateway-test-release/webhdfs-kerb-test/src/test/resources/org/apache/knox/gateway/SecureKnoxShellTest/SecureWebHdfsPutGet.groovy new file mode 100644 index 0000000..1fd6906 --- /dev/null +++ b/gateway-test-release/webhdfs-kerb-test/src/test/resources/org/apache/knox/gateway/SecureKnoxShellTest/SecureWebHdfsPutGet.groovy @@ -0,0 +1,37 @@ +package org.apache.knox.gateway.ShellTest + +/* + * 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. + */ +import org.apache.knox.gateway.shell.KnoxSession +import org.apache.knox.gateway.shell.hdfs.Hdfs + +dataFile = "README" +username = "guest" +dataDir = "/user/" + username + "/example" + +/* Unit test will add 'gateway' and 'jaasConf' binding programmatically */ +session = KnoxSession.kerberosLogin(gateway, jaasConf, krb5conf, true) + +status = Hdfs.status(session).file( "/" ).now().string + +Hdfs.put( session ).file( file ).to( dataDir + "/" + dataFile ).now() +Hdfs.put( session ).file( file ).to( dataDir + "/" + dataFile ).overwrite(true).permission(777).now() + +fetchedFile = Hdfs.get( session ).from( dataDir + "/" + dataFile).now().string + +session.shutdown() http://git-wip-us.apache.org/repos/asf/knox/blob/da478a55/pom.xml ---------------------------------------------------------------------- diff --git a/pom.xml b/pom.xml index de85827..20c63c4 100644 --- a/pom.xml +++ b/pom.xml @@ -1699,6 +1699,11 @@ <artifactId>metrics-jmx</artifactId> <version>${metrics.version}</version> </dependency> + <dependency> + <groupId>de.thetaphi</groupId> + <artifactId>forbiddenapis</artifactId> + <version>${forbiddenapis.version}</version> + </dependency> <!-- ********** ********** ********** ********** ********** ********** --> <!-- ********** Test Dependencies ********** -->
