Repository: knox Updated Branches: refs/heads/master e739efea4 -> d1c1ca5f7
KNOX-1341 - Constrain cookies added to the HadoopAuthCookieStore Project: http://git-wip-us.apache.org/repos/asf/knox/repo Commit: http://git-wip-us.apache.org/repos/asf/knox/commit/d1c1ca5f Tree: http://git-wip-us.apache.org/repos/asf/knox/tree/d1c1ca5f Diff: http://git-wip-us.apache.org/repos/asf/knox/diff/d1c1ca5f Branch: refs/heads/master Commit: d1c1ca5f74c027c5d4d32aecf162e0d1154b61ae Parents: e739efe Author: Phil Zampino <pzamp...@apache.org> Authored: Thu May 31 21:26:34 2018 -0400 Committer: Phil Zampino <pzamp...@apache.org> Committed: Tue Jun 5 22:12:52 2018 -0400 ---------------------------------------------------------------------- .../apache/knox/gateway/SpiGatewayMessages.java | 3 + .../dispatch/DefaultHttpClientFactory.java | 2 +- .../gateway/dispatch/HadoopAuthCookieStore.java | 61 +++++++- .../dispatch/HadoopAuthCookieStoreTest.java | 138 +++++++++++++++++-- 4 files changed, 191 insertions(+), 13 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/knox/blob/d1c1ca5f/gateway-spi/src/main/java/org/apache/knox/gateway/SpiGatewayMessages.java ---------------------------------------------------------------------- diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/SpiGatewayMessages.java b/gateway-spi/src/main/java/org/apache/knox/gateway/SpiGatewayMessages.java index 8718b1d..38e81be 100644 --- a/gateway-spi/src/main/java/org/apache/knox/gateway/SpiGatewayMessages.java +++ b/gateway-spi/src/main/java/org/apache/knox/gateway/SpiGatewayMessages.java @@ -78,4 +78,7 @@ public interface SpiGatewayMessages { @Message( level = MessageLevel.DEBUG, text = "Accepting service cookie: {0}" ) void acceptingServiceCookie( Cookie cookie ); + @Message( level = MessageLevel.ERROR, text = "Error reading Kerberos login configuration {0} : {1}" ) + void errorReadingKerberosLoginConfig(String fileName, @StackTrace(level=MessageLevel.ERROR) Exception e); + } http://git-wip-us.apache.org/repos/asf/knox/blob/d1c1ca5f/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/DefaultHttpClientFactory.java ---------------------------------------------------------------------- diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/DefaultHttpClientFactory.java b/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/DefaultHttpClientFactory.java index dcb7465..80a045b 100644 --- a/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/DefaultHttpClientFactory.java +++ b/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/DefaultHttpClientFactory.java @@ -114,7 +114,7 @@ public class DefaultHttpClientFactory implements HttpClientFactory { .build(); builder = builder.setDefaultAuthSchemeRegistry(authSchemeRegistry) - .setDefaultCookieStore(new HadoopAuthCookieStore()) + .setDefaultCookieStore(new HadoopAuthCookieStore(gatewayConfig)) .setDefaultCredentialsProvider(credentialsProvider); } else { builder = builder.setDefaultCookieStore(new NoCookieStore()); http://git-wip-us.apache.org/repos/asf/knox/blob/d1c1ca5f/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/HadoopAuthCookieStore.java ---------------------------------------------------------------------- diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/HadoopAuthCookieStore.java b/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/HadoopAuthCookieStore.java index 1bab384..ea72abb 100644 --- a/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/HadoopAuthCookieStore.java +++ b/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/HadoopAuthCookieStore.java @@ -17,27 +17,82 @@ */ package org.apache.knox.gateway.dispatch; +import java.io.FileInputStream; +import java.io.IOException; import java.lang.reflect.Field; import java.util.Date; +import java.util.Properties; import org.apache.commons.lang3.builder.ReflectionToStringBuilder; import org.apache.http.cookie.Cookie; import org.apache.http.impl.client.BasicCookieStore; import org.apache.http.impl.cookie.BasicClientCookie; import org.apache.knox.gateway.SpiGatewayMessages; +import org.apache.knox.gateway.config.GatewayConfig; import org.apache.knox.gateway.i18n.messages.MessagesFactory; public class HadoopAuthCookieStore extends BasicCookieStore { private static SpiGatewayMessages LOG = MessagesFactory.get( SpiGatewayMessages.class ); + private GatewayConfig gatewayConfig = null; + + + HadoopAuthCookieStore(GatewayConfig config) { + this.gatewayConfig = config; + } + @Override public void addCookie(Cookie cookie) { if (cookie.getName().equals("hadoop.auth") || cookie.getName().equals("hive.server2.auth")) { - Wrapper wrapper = new Wrapper( cookie ); - LOG.acceptingServiceCookie( wrapper ); - super.addCookie( wrapper ); + // Only add the cookie if it's Knox's cookie + if (isKnoxCookie(gatewayConfig, cookie)) { + Wrapper wrapper = new Wrapper(cookie); + LOG.acceptingServiceCookie(wrapper); + super.addCookie(wrapper); + } + } + } + + + private static boolean isKnoxCookie(GatewayConfig config, Cookie cookie) { + boolean result = false; + + if (cookie != null) { + String value = cookie.getValue(); + if (value != null && !value.isEmpty()) { + String principal = null; + + String[] cookieParts = value.split("&"); + if (cookieParts.length > 1) { + String[] elementParts = cookieParts[1].split("="); + if (elementParts.length == 2) { + principal = elementParts[1]; + } + + if (principal != null) { + String krb5Config = config.getKerberosLoginConfig(); + if (krb5Config != null && !krb5Config.isEmpty()) { + Properties p = new Properties(); + try { + p.load(new FileInputStream(krb5Config)); + String configuredPrincipal = p.getProperty("principal"); + // Strip off enclosing quotes, if present + if (configuredPrincipal.startsWith("\"")) { + configuredPrincipal = configuredPrincipal.substring(1, configuredPrincipal.length() - 1); + } + // Check if they're the same principal + result = principal.equals(configuredPrincipal); + } catch (IOException e) { + LOG.errorReadingKerberosLoginConfig(krb5Config, e); + } + } + } + } + } } + + return result; } private static class Wrapper extends BasicClientCookie { http://git-wip-us.apache.org/repos/asf/knox/blob/d1c1ca5f/gateway-spi/src/test/java/org/apache/knox/gateway/dispatch/HadoopAuthCookieStoreTest.java ---------------------------------------------------------------------- diff --git a/gateway-spi/src/test/java/org/apache/knox/gateway/dispatch/HadoopAuthCookieStoreTest.java b/gateway-spi/src/test/java/org/apache/knox/gateway/dispatch/HadoopAuthCookieStoreTest.java index 93070d5..b1685f3 100644 --- a/gateway-spi/src/test/java/org/apache/knox/gateway/dispatch/HadoopAuthCookieStoreTest.java +++ b/gateway-spi/src/test/java/org/apache/knox/gateway/dispatch/HadoopAuthCookieStoreTest.java @@ -17,14 +17,17 @@ */ package org.apache.knox.gateway.dispatch; +import java.io.File; +import java.io.FileOutputStream; import java.util.List; import org.apache.http.cookie.Cookie; import org.apache.http.impl.cookie.BasicClientCookie; +import org.apache.knox.gateway.config.GatewayConfig; +import org.easymock.EasyMock; import org.junit.Test; import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.nullValue; import static org.junit.Assert.*; public class HadoopAuthCookieStoreTest { @@ -45,29 +48,146 @@ public class HadoopAuthCookieStoreTest { List<Cookie> cookies; Cookie cookie; - store = new HadoopAuthCookieStore(); + GatewayConfig gatewayConfig = EasyMock.createNiceMock(GatewayConfig.class); + File krb5LoginConf = createTestKrb5LoginConfigFile("krb5JAASLogin", + getTestKrb5LoginConf("knox/host.example.com....@example.com")); + assertNotNull(krb5LoginConf); + EasyMock.expect(gatewayConfig.getKerberosLoginConfig()).andReturn(krb5LoginConf.getAbsolutePath()).anyTimes(); + EasyMock.replay(gatewayConfig); + + store = new HadoopAuthCookieStore(gatewayConfig); store.addCookie( new BasicClientCookie( "hadoop.auth", rawValue ) ); cookies = store.getCookies(); cookie = cookies.get( 0 ); assertThat( cookie.getValue(), is(quotedValue) ); - store = new HadoopAuthCookieStore(); + store = new HadoopAuthCookieStore(gatewayConfig); store.addCookie( new BasicClientCookie( "hadoop.auth", quotedValue ) ); cookies = store.getCookies(); cookie = cookies.get( 0 ); assertThat( cookie.getValue(), is(quotedValue) ); - store = new HadoopAuthCookieStore(); + store = new HadoopAuthCookieStore(gatewayConfig); store.addCookie( new BasicClientCookie( "hadoop.auth", null ) ); cookies = store.getCookies(); - cookie = cookies.get( 0 ); - assertThat( cookie.getValue(), is(nullValue()) ); + assertNotNull(cookies); + assertTrue(cookies.isEmpty()); - store = new HadoopAuthCookieStore(); + store = new HadoopAuthCookieStore(gatewayConfig); store.addCookie( new BasicClientCookie( "hadoop.auth", "" ) ); cookies = store.getCookies(); - cookie = cookies.get( 0 ); - assertThat( cookie.getValue(), is("") ); + assertNotNull(cookies); + assertTrue(cookies.isEmpty()); + } + + @Test + public void testKnoxCookieInclusionDefaultUserAndPrincipal() { + doTestKnoxCookieInclusion("u=knox&p=knox/myhost.example....@example.com&t=kerberos&e=1517900515610&s=HpSXUOhoXR/2wXrsgPz5lSbNuf8="); + } + + @Test + public void testKnoxCookieInclusionDefaultUser() { + doTestKnoxCookieExclusion("u=knox&p=anotherUser/myhost.example....@example.com&t=kerberos&e=1517900515610&s=HpSXUOhoXR/2wXrsgPz5lSbNuf8="); + } + + @Test + public void testKnoxCookieInclusionDefaultPrincipal() { + doTestKnoxCookieInclusion("u=anotherUser&p=knox/myhost.example....@example.com&t=kerberos&e=1517900515610&s=HpSXUOhoXR/2wXrsgPz5lSbNuf8="); + } + + @Test + public void testKnoxCookieExclusionWrongUserAndPrincipal() { + doTestKnoxCookieExclusion("u=test&p=dummy/h...@example.com&t=kerberos&e=1517900515610&s=HpSXUOhoXR/2wXrsgPz5lSbNuf8="); + } + + @Test + public void testKnoxCookieExclusionWrongUserNoPrincipal() { + doTestKnoxCookieExclusion("u=test&t=kerberos&e=1517900515610&s=HpSXUOhoXR/2wXrsgPz5lSbNuf8="); + } + + @Test + public void testKnoxCookieInclusionDefaultUserAndCustomPrincipal() { + final String principal = "myTestPrincipal/t...@example.com"; + + GatewayConfig gatewayConfig = EasyMock.createNiceMock(GatewayConfig.class); + File krb5LoginConf = createTestKrb5LoginConfigFile("krb5Login", getTestKrb5LoginConf(principal)); + assertNotNull(krb5LoginConf); + EasyMock.expect(gatewayConfig.getKerberosLoginConfig()).andReturn(krb5LoginConf.getAbsolutePath()).anyTimes(); + EasyMock.replay(gatewayConfig); + + doTestKnoxCookieInclusion(gatewayConfig, + "u=knox&p=" + principal + "&t=kerberos&e=1517900515610&s=HpSXUOhoXR/2wXrsgPz5lSbNuf8="); + } + + @Test + public void testKnoxCookieInclusionDefaultUserAndMissingPrincipal() { + doTestKnoxCookieExclusion("u=knox&t=kerberos&e=1517900515610&s=HpSXUOhoXR/2wXrsgPz5lSbNuf8="); + } + + private void doTestKnoxCookieInclusion(final String cookieValue) { + GatewayConfig gatewayConfig = EasyMock.createNiceMock(GatewayConfig.class); + File krb5LoginConf = createTestKrb5LoginConfigFile(); + assertNotNull(krb5LoginConf); + EasyMock.expect(gatewayConfig.getKerberosLoginConfig()).andReturn(krb5LoginConf.getAbsolutePath()).anyTimes(); + EasyMock.replay(gatewayConfig); + + doTestKnoxCookieInclusion(gatewayConfig, cookieValue); + } + + private void doTestKnoxCookieInclusion(final GatewayConfig gatewayConfig, final String cookieValue) { + HadoopAuthCookieStore store = new HadoopAuthCookieStore(gatewayConfig); + store.addCookie(new BasicClientCookie("hadoop.auth", cookieValue)); + List<Cookie> cookies = store.getCookies(); + assertNotNull(cookies); + assertFalse(cookies.isEmpty()); + assertThat(cookies.get(0).getValue(), is("\"" + cookieValue + "\"")); + } + + private void doTestKnoxCookieExclusion(final String cookieValue) { + GatewayConfig gConf = EasyMock.createNiceMock(GatewayConfig.class); + EasyMock.replay(gConf); + + HadoopAuthCookieStore store = new HadoopAuthCookieStore(gConf); + store.addCookie(new BasicClientCookie("hadoop.auth", cookieValue)); + List<Cookie> cookies = store.getCookies(); + assertNotNull(cookies); + assertTrue(cookies.isEmpty()); + } + + private static File createTestKrb5LoginConfigFile() { + return createTestKrb5LoginConfigFile("krb5JAASLogin", getTestKrb5LoginConf()); + } + + private static File createTestKrb5LoginConfigFile(String filename, String contents) { + File result = null; + try { + File f = File.createTempFile(filename, ".conf"); + FileOutputStream out = new FileOutputStream(f); + out.write(contents.getBytes()); + out.flush(); + out.close(); + result = f; + } catch (Exception e) { + // + } + + return result; + } + + private static String getTestKrb5LoginConf() { + return getTestKrb5LoginConf("knox/myhost.example....@example.com"); + } + + private static String getTestKrb5LoginConf(String principal) { + return "com.sun.security.jgss.initiate {\n" + + "com.sun.security.auth.module.Krb5LoginModule required\n" + + "renewTGT=false\n" + + "doNotPrompt=true\n" + + "useKeyTab=true\n" + + "keyTab=\"/etc/security/keytabs/knox.service.keytab\"\n" + + (principal != null ? "principal=\"" + principal + "\"\n" : "") + + "storeKey=true\n" + + "useTicketCache=false;"; } } \ No newline at end of file