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

Reply via email to