You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@knox.apache.org by mo...@apache.org on 2017/09/27 14:08:56 UTC

[1/4] knox git commit: KNOX-998 - Adding Shims

Repository: knox
Updated Branches:
  refs/heads/KNOX-998-Package_Restructuring 668aea180 -> 51348f838


KNOX-998 - Adding Shims


Project: http://git-wip-us.apache.org/repos/asf/knox/repo
Commit: http://git-wip-us.apache.org/repos/asf/knox/commit/ca93de84
Tree: http://git-wip-us.apache.org/repos/asf/knox/tree/ca93de84
Diff: http://git-wip-us.apache.org/repos/asf/knox/diff/ca93de84

Branch: refs/heads/KNOX-998-Package_Restructuring
Commit: ca93de84346ac58a39a7339df9297f7925b0db47
Parents: 668aea1
Author: Sandeep More <mo...@apache.org>
Authored: Tue Sep 26 13:52:54 2017 -0400
Committer: Sandeep More <mo...@apache.org>
Committed: Tue Sep 26 13:52:54 2017 -0400

----------------------------------------------------------------------
 gateway-adapter/pom.xml                         |  55 +++++
 .../gateway/shirorealm/KnoxLdapRealm.java       | 247 +++++++++++++++++++
 .../hadoop/gateway/shirorealm/KnoxPamRealm.java |  55 +++++
 .../src/main/resources/META-INF/launcher.cfg    |  17 ++
 .../gateway/shirorealm/KnoxLdapRealmTest.java   | 104 ++++++++
 .../gateway/shirorealm/KnoxPamRealmTest.java    |  68 +++++
 pom.xml                                         |   6 +
 7 files changed, 552 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/knox/blob/ca93de84/gateway-adapter/pom.xml
----------------------------------------------------------------------
diff --git a/gateway-adapter/pom.xml b/gateway-adapter/pom.xml
new file mode 100644
index 0000000..2498f85
--- /dev/null
+++ b/gateway-adapter/pom.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <artifactId>gateway</artifactId>
+        <groupId>org.apache.knox</groupId>
+        <version>0.14.0-SNAPSHOT</version>
+    </parent>
+    <artifactId>gateway-adapter</artifactId>
+    <name>gateway-adapter</name>
+    <description>Adapter/Shims for old package structure to ensure compatibility.</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>${gateway-group}</groupId>
+            <artifactId>gateway-util-launcher</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.easymock</groupId>
+            <artifactId>easymock</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.knox</groupId>
+            <artifactId>gateway-provider-security-shiro</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/knox/blob/ca93de84/gateway-adapter/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxLdapRealm.java
----------------------------------------------------------------------
diff --git a/gateway-adapter/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxLdapRealm.java b/gateway-adapter/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxLdapRealm.java
new file mode 100644
index 0000000..8aa3fd5
--- /dev/null
+++ b/gateway-adapter/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxLdapRealm.java
@@ -0,0 +1,247 @@
+package org.apache.hadoop.gateway.shirorealm;
+
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.AuthenticationInfo;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authz.AuthorizationInfo;
+import org.apache.shiro.realm.ldap.LdapContextFactory;
+import org.apache.shiro.subject.PrincipalCollection;
+
+import javax.naming.NamingException;
+import javax.naming.ldap.LdapContext;
+import java.util.Map;
+
+/**
+ * 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.
+ */
+public class KnoxLdapRealm extends org.apache.knox.gateway.shirorealm.KnoxLdapRealm {
+
+  /**
+   * Create an instance
+   */
+  public KnoxLdapRealm() {
+    super();
+  }
+
+  @Override
+  protected AuthenticationInfo doGetAuthenticationInfo(
+      AuthenticationToken token) throws AuthenticationException {
+    return super.doGetAuthenticationInfo(token);
+  }
+
+  /**
+   * Get groups from LDAP.
+   *
+   * @param principals         the principals of the Subject whose
+   *                           AuthenticationInfo should be queried from the
+   *                           LDAP server.
+   * @param ldapContextFactory factory used to retrieve LDAP connections.
+   * @return an {@link AuthorizationInfo} instance containing information
+   * retrieved from the LDAP server.
+   * @throws NamingException if any LDAP errors occur during the search.
+   */
+  @Override
+  protected AuthorizationInfo queryForAuthorizationInfo(
+      PrincipalCollection principals, LdapContextFactory ldapContextFactory)
+      throws NamingException {
+    return super.queryForAuthorizationInfo(principals, ldapContextFactory);
+  }
+
+  @Override
+  public String getSearchBase() {
+    return super.getSearchBase();
+  }
+
+  @Override
+  public void setSearchBase(String searchBase) {
+    super.setSearchBase(searchBase);
+  }
+
+  @Override
+  public String getUserSearchBase() {
+    return super.getUserSearchBase();
+  }
+
+  @Override
+  public void setUserSearchBase(String userSearchBase) {
+    super.setUserSearchBase(userSearchBase);
+  }
+
+  @Override
+  public String getGroupSearchBase() {
+    return super.getGroupSearchBase();
+  }
+
+  @Override
+  public void setGroupSearchBase(String groupSearchBase) {
+    super.setGroupSearchBase(groupSearchBase);
+  }
+
+  @Override
+  public String getGroupObjectClass() {
+    return super.getGroupObjectClass();
+  }
+
+  @Override
+  public void setGroupObjectClass(String groupObjectClassAttribute) {
+    super.setGroupObjectClass(groupObjectClassAttribute);
+  }
+
+  @Override
+  public String getMemberAttribute() {
+    return super.getMemberAttribute();
+  }
+
+  @Override
+  public void setMemberAttribute(String memberAttribute) {
+    super.setMemberAttribute(memberAttribute);
+  }
+
+  @Override
+  public String getGroupIdAttribute() {
+    return super.getGroupIdAttribute();
+  }
+
+  @Override
+  public void setGroupIdAttribute(String groupIdAttribute) {
+    super.setGroupIdAttribute(groupIdAttribute);
+  }
+
+  @Override
+  public void setMemberAttributeValueTemplate(String template) {
+    super.setMemberAttributeValueTemplate(template);
+  }
+
+  @Override
+  public void setRolesByGroup(Map<String, String> rolesByGroup) {
+    super.setRolesByGroup(rolesByGroup);
+  }
+
+  @Override
+  public void setPermissionsByRole(String permissionsByRoleStr) {
+    super.setPermissionsByRole(permissionsByRoleStr);
+  }
+
+  @Override
+  public boolean isAuthorizationEnabled() {
+    return super.isAuthorizationEnabled();
+  }
+
+  @Override
+  public void setAuthorizationEnabled(boolean authorizationEnabled) {
+    super.setAuthorizationEnabled(authorizationEnabled);
+  }
+
+  @Override
+  public String getUserSearchAttributeName() {
+    return super.getUserSearchAttributeName();
+  }
+
+  @Override
+  public void setUserSearchAttributeName(String userSearchAttributeName) {
+    super.setUserSearchAttributeName(userSearchAttributeName);
+  }
+
+  @Override
+  public String getUserObjectClass() {
+    return super.getUserObjectClass();
+  }
+
+  @Override
+  public void setUserObjectClass(String userObjectClass) {
+    super.setUserObjectClass(userObjectClass);
+  }
+
+  @Override
+  public String getPrincipalRegex() {
+    return super.getPrincipalRegex();
+  }
+
+  @Override
+  public void setPrincipalRegex(String regex) {
+    super.setPrincipalRegex(regex);
+  }
+
+  @Override
+  public String getUserSearchAttributeTemplate() {
+    return super.getUserSearchAttributeTemplate();
+  }
+
+  @Override
+  public void setUserSearchAttributeTemplate(String template) {
+    super.setUserSearchAttributeTemplate(template);
+  }
+
+  @Override
+  public String getUserSearchFilter() {
+    return super.getUserSearchFilter();
+  }
+
+  @Override
+  public void setUserSearchFilter(String filter) {
+    super.setUserSearchFilter(filter);
+  }
+
+  @Override
+  public String getUserSearchScope() {
+    return super.getUserSearchScope();
+  }
+
+  @Override
+  public void setUserSearchScope(String scope) {
+    super.setUserSearchScope(scope);
+  }
+
+  @Override
+  public void setUserDnTemplate(String template)
+      throws IllegalArgumentException {
+    super.setUserDnTemplate(template);
+  }
+
+  /**
+   * Returns the LDAP User Distinguished Name (DN) to use when acquiring an
+   * {@link LdapContext LdapContext} from the {@link LdapContextFactory}.
+   * <p/>
+   * If the the {@link #getUserDnTemplate() userDnTemplate} property has been
+   * set, this implementation will construct the User DN by substituting the
+   * specified {@code principal} into the configured template.  If the {@link
+   * #getUserDnTemplate() userDnTemplate} has not been set, the method argument
+   * will be returned directly (indicating that the submitted authentication
+   * token principal <em>is</em> the User DN).
+   *
+   * @param principal the principal to substitute into the configured {@link
+   *                  #getUserDnTemplate() userDnTemplate}.
+   * @return the constructed User DN to use at runtime when acquiring an {@link
+   * LdapContext}.
+   * @throws IllegalArgumentException if the method argument is null or empty
+   * @throws IllegalStateException    if the {@link #getUserDnTemplate
+   *                                  userDnTemplate} has not been set.
+   * @see LdapContextFactory#getLdapContext(Object, Object)
+   */
+  @Override
+  protected String getUserDn(String principal)
+      throws IllegalArgumentException, IllegalStateException {
+    return super.getUserDn(principal);
+  }
+
+  @Override
+  protected AuthenticationInfo createAuthenticationInfo(
+      AuthenticationToken token, Object ldapPrincipal, Object ldapCredentials,
+      LdapContext ldapContext) throws NamingException {
+    return super.createAuthenticationInfo(token, ldapPrincipal, ldapCredentials,
+        ldapContext);
+  }
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/ca93de84/gateway-adapter/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxPamRealm.java
----------------------------------------------------------------------
diff --git a/gateway-adapter/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxPamRealm.java b/gateway-adapter/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxPamRealm.java
new file mode 100644
index 0000000..20f06fe
--- /dev/null
+++ b/gateway-adapter/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxPamRealm.java
@@ -0,0 +1,55 @@
+package org.apache.hadoop.gateway.shirorealm;
+
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.AuthenticationInfo;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authz.AuthorizationInfo;
+import org.apache.shiro.subject.PrincipalCollection;
+
+/**
+ * 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.
+ */
+public class KnoxPamRealm extends org.apache.knox.gateway.shirorealm.KnoxPamRealm {
+
+  /**
+   * Create an instance
+   */
+  public KnoxPamRealm() {
+    super();
+  }
+
+  @Override
+  public void setService(String service) {
+    super.setService(service);
+  }
+
+  @Override
+  public String getService() {
+    return super.getService();
+  }
+
+  @Override
+  protected AuthorizationInfo doGetAuthorizationInfo(
+      PrincipalCollection principals) {
+    return super.doGetAuthorizationInfo(principals);
+  }
+
+  @Override
+  protected AuthenticationInfo doGetAuthenticationInfo(
+      AuthenticationToken token) throws AuthenticationException {
+    return super.doGetAuthenticationInfo(token);
+  }
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/ca93de84/gateway-adapter/src/main/resources/META-INF/launcher.cfg
----------------------------------------------------------------------
diff --git a/gateway-adapter/src/main/resources/META-INF/launcher.cfg b/gateway-adapter/src/main/resources/META-INF/launcher.cfg
new file mode 100644
index 0000000..35b32f3
--- /dev/null
+++ b/gateway-adapter/src/main/resources/META-INF/launcher.cfg
@@ -0,0 +1,17 @@
+# 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.
+main.class = org.apache.knox.gateway.security.ldap.SimpleLdapDirectoryServer
+class.path = ../lib/*.jar;../dep/*.jar;../ext;../ext/*.jar
+log4j.configuration=${launcher.dir}/../conf/${launcher.name}-log4j.properties

http://git-wip-us.apache.org/repos/asf/knox/blob/ca93de84/gateway-adapter/src/test/java/org/apache/hadoop/gateway/shirorealm/KnoxLdapRealmTest.java
----------------------------------------------------------------------
diff --git a/gateway-adapter/src/test/java/org/apache/hadoop/gateway/shirorealm/KnoxLdapRealmTest.java b/gateway-adapter/src/test/java/org/apache/hadoop/gateway/shirorealm/KnoxLdapRealmTest.java
new file mode 100644
index 0000000..6ffa2cd
--- /dev/null
+++ b/gateway-adapter/src/test/java/org/apache/hadoop/gateway/shirorealm/KnoxLdapRealmTest.java
@@ -0,0 +1,104 @@
+/*
+ *  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.hadoop.gateway.shirorealm;
+
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+public class KnoxLdapRealmTest {
+
+  @Test
+  public void setGetSearchBase() {
+    KnoxLdapRealm realm = new KnoxLdapRealm();
+    realm.setSearchBase("dc=hadoop,dc=apache,dc=org");
+    assertEquals(realm.getSearchBase(), "dc=hadoop,dc=apache,dc=org");
+  }
+
+  @Test
+  public void setGetGroupObjectClass() {
+    KnoxLdapRealm realm = new KnoxLdapRealm();
+    realm.setGroupObjectClass("groupOfMembers");
+    assertEquals(realm.getGroupObjectClass(), "groupOfMembers");
+  }
+
+  @Test
+  public void setGetUniqueMemberAttribute() {
+    KnoxLdapRealm realm = new KnoxLdapRealm();
+    realm.setMemberAttribute("member");
+    assertEquals(realm.getMemberAttribute(), "member");
+  }
+
+  @Test
+  public void setGetUserSearchAttributeName() {
+    KnoxLdapRealm realm = new KnoxLdapRealm();
+    realm.setUserSearchAttributeName("uid");
+    assertEquals(realm.getUserSearchAttributeName(), "uid");
+  }
+
+  @Test
+  public void setGetUserObjectClass() {
+    KnoxLdapRealm realm = new KnoxLdapRealm();
+    realm.setUserObjectClass("inetuser");
+    assertEquals(realm.getUserObjectClass(), "inetuser");
+  }
+
+  @Test
+  public void setGetUserSearchBase() {
+    KnoxLdapRealm realm = new KnoxLdapRealm();
+    realm.setSearchBase("dc=example,dc=com");
+    realm.setUserSearchBase("dc=knox,dc=example,dc=com");
+    assertEquals(realm.getUserSearchBase(), "dc=knox,dc=example,dc=com");
+  }
+
+  @Test
+  public void setGetGroupSearchBase() {
+    KnoxLdapRealm realm = new KnoxLdapRealm();
+    realm.setSearchBase("dc=example,dc=com");
+    realm.setGroupSearchBase("dc=knox,dc=example,dc=com");
+    assertEquals(realm.getGroupSearchBase(), "dc=knox,dc=example,dc=com");
+  }
+
+  @Test
+  public void verifyDefaultUserSearchAttributeName() {
+    KnoxLdapRealm realm = new KnoxLdapRealm();
+    assertNull(realm.getUserSearchAttributeName());
+  }
+
+  @Test
+  public void verifyDefaultGetUserObjectClass() {
+    KnoxLdapRealm realm = new KnoxLdapRealm();
+    assertEquals(realm.getUserObjectClass(), "person");
+  }
+
+  @Test
+  public void verifyDefaultUserSearchBase() {
+    KnoxLdapRealm realm = new KnoxLdapRealm();
+    realm.setSearchBase("dc=knox,dc=example,dc=com");
+    assertEquals(realm.getUserSearchBase(), "dc=knox,dc=example,dc=com");
+  }
+
+  @Test
+  public void verifyDefaultGroupSearchBase() {
+    KnoxLdapRealm realm = new KnoxLdapRealm();
+    realm.setSearchBase("dc=knox,dc=example,dc=com");
+    assertEquals(realm.getGroupSearchBase(), "dc=knox,dc=example,dc=com");
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/ca93de84/gateway-adapter/src/test/java/org/apache/hadoop/gateway/shirorealm/KnoxPamRealmTest.java
----------------------------------------------------------------------
diff --git a/gateway-adapter/src/test/java/org/apache/hadoop/gateway/shirorealm/KnoxPamRealmTest.java b/gateway-adapter/src/test/java/org/apache/hadoop/gateway/shirorealm/KnoxPamRealmTest.java
new file mode 100644
index 0000000..0f1754f
--- /dev/null
+++ b/gateway-adapter/src/test/java/org/apache/hadoop/gateway/shirorealm/KnoxPamRealmTest.java
@@ -0,0 +1,68 @@
+/*
+ *  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.hadoop.gateway.shirorealm;
+
+import org.junit.Test;
+
+import org.apache.shiro.authc.AuthenticationInfo;
+import org.apache.shiro.authc.UsernamePasswordToken;
+
+import static org.junit.Assert.*;
+import static org.junit.Assume.assumeTrue;
+import static org.easymock.EasyMock.*;
+
+public class KnoxPamRealmTest {
+  @Test
+  public void setService() {
+    KnoxPamRealm realm = new KnoxPamRealm();
+    realm.setService("knox-pam-os-service");
+    //assertEquals(realm.getService(), "knox-pam-os-service");
+  }
+
+  @Test
+  public void testDoGetAuthenticationInfo() {
+    KnoxPamRealm realm = new KnoxPamRealm();
+    realm.setService("sshd");  // pam settings being used: /etc/pam.d/sshd
+
+    // use environment variables and skip the test if not set.
+    String pamuser = System.getenv("PAMUSER");
+    String pampass = System.getenv("PAMPASS");
+    assumeTrue(pamuser != null);
+    assumeTrue(pampass != null);
+
+    // mock shiro auth token
+    UsernamePasswordToken authToken = createMock(UsernamePasswordToken.class);
+    expect(authToken.getUsername()).andReturn(pamuser);
+    expect(authToken.getPassword()).andReturn(pampass.toCharArray());
+    expect(authToken.getCredentials()).andReturn(pampass);
+    replay(authToken);
+
+    // login
+    AuthenticationInfo authInfo = realm.doGetAuthenticationInfo(authToken);
+
+    // verify success
+    assertTrue(authInfo.getCredentials() != null);
+  }
+
+  public static void main(String[] args) throws Exception {
+    KnoxPamRealmTest pamTest = new KnoxPamRealmTest();
+    pamTest.testDoGetAuthenticationInfo();
+  }
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/ca93de84/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 2708f6b..4bddc61 100644
--- a/pom.xml
+++ b/pom.xml
@@ -88,6 +88,7 @@
         <module>gateway-shell</module>
         <module>gateway-shell-launcher</module>
         <module>knox-cli-launcher</module>
+        <module>gateway-adapter</module>
         <module>hadoop-examples</module>
         <module>gateway-release</module>
         <module>gateway-test</module>
@@ -680,6 +681,11 @@
             </dependency>
             <dependency>
                 <groupId>${gateway-group}</groupId>
+                <artifactId>gateway-adapter</artifactId>
+                <version>${gateway-version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${gateway-group}</groupId>
                 <artifactId>hadoop-examples</artifactId>
                 <version>${gateway-version}</version>
             </dependency>


[4/4] knox git commit: Merge branch 'master' into KNOX-998-Package_Restructuring

Posted by mo...@apache.org.
Merge branch 'master' into KNOX-998-Package_Restructuring


Project: http://git-wip-us.apache.org/repos/asf/knox/repo
Commit: http://git-wip-us.apache.org/repos/asf/knox/commit/51348f83
Tree: http://git-wip-us.apache.org/repos/asf/knox/tree/51348f83
Diff: http://git-wip-us.apache.org/repos/asf/knox/diff/51348f83

Branch: refs/heads/KNOX-998-Package_Restructuring
Commit: 51348f838106241efbf34534168c478d77a35d6e
Parents: 7815945 10b3473
Author: Sandeep More <mo...@apache.org>
Authored: Wed Sep 27 10:07:08 2017 -0400
Committer: Sandeep More <mo...@apache.org>
Committed: Wed Sep 27 10:07:08 2017 -0400

----------------------------------------------------------------------
 .../knox/gateway/dispatch/AbstractGatewayDispatch.java      | 8 ++++++++
 .../org/apache/knox/gateway/dispatch/DefaultDispatch.java   | 9 +++++++++
 .../java/org/apache/knox/gateway/dispatch/Dispatch.java     | 6 ++++++
 .../apache/knox/gateway/dispatch/GatewayDispatchFilter.java | 8 ++++++++
 4 files changed, 31 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/knox/blob/51348f83/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/AbstractGatewayDispatch.java
----------------------------------------------------------------------
diff --cc gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/AbstractGatewayDispatch.java
index fbc86e7,0000000..aad7d4c
mode 100644,000000..100644
--- a/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/AbstractGatewayDispatch.java
+++ b/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/AbstractGatewayDispatch.java
@@@ -1,144 -1,0 +1,152 @@@
 +/**
 + * 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.dispatch;
 +
 +import org.apache.knox.gateway.filter.GatewayResponse;
 +import org.apache.hadoop.io.IOUtils;
 +import org.apache.http.client.HttpClient;
 +import org.apache.http.client.methods.HttpUriRequest;
 +
 +import javax.servlet.http.HttpServletRequest;
 +import javax.servlet.http.HttpServletResponse;
 +import java.io.IOException;
 +import java.io.InputStream;
 +import java.io.OutputStream;
 +import java.net.URI;
 +import java.net.URISyntaxException;
 +import java.util.Enumeration;
 +import java.util.HashSet;
 +import java.util.Set;
 +
 +public abstract class AbstractGatewayDispatch implements Dispatch {
 +
 +  private static final int STREAM_COPY_BUFFER_SIZE = 4096;
 +  private static final Set<String> REQUEST_EXCLUDE_HEADERS = new HashSet<>();
 +  
 +  static {
 +      REQUEST_EXCLUDE_HEADERS.add("Host");
 +      REQUEST_EXCLUDE_HEADERS.add("Authorization");
 +      REQUEST_EXCLUDE_HEADERS.add("Content-Length");
 +      REQUEST_EXCLUDE_HEADERS.add("Transfer-Encoding");
 +  }
 +  
 +  protected  HttpClient client;
 +
 +  @Override
 +  public void init() {
 +  }
 +
 +  protected void writeResponse(HttpServletRequest request, HttpServletResponse response, InputStream stream )
 +      throws IOException {
 +//    ResponseStreamer streamer =
 +//        (ResponseStreamer)request.getAttribute( RESPONSE_STREAMER_ATTRIBUTE_NAME );
 +//    if( streamer != null ) {
 +//      streamer.streamResponse( stream, response.getOutputStream() );
 +//    } else {
 +      if( response instanceof GatewayResponse ) {
 +        ((GatewayResponse)response).streamResponse( stream );
 +      } else {
 +        OutputStream output = response.getOutputStream();
 +        IOUtils.copyBytes( stream, output, STREAM_COPY_BUFFER_SIZE );
 +        //KNOX-685: output.flush();
 +        output.close();
 +      }
 +//    }
 +  }
 +
 +  @Override
 +  public HttpClient getHttpClient() {
 +    return client;
 +  }
 +
 +  @Override
 +  public void setHttpClient(HttpClient client) {
 +    this.client = client;
 +  }
 +
 +  @Override
 +  public URI getDispatchUrl(HttpServletRequest request) {
 +    StringBuffer str = request.getRequestURL();
 +    String query = request.getQueryString();
 +    if ( query != null ) {
 +      str.append('?');
 +      str.append(query);
 +    }
 +    URI url = URI.create(str.toString());
 +    return url;
 +  }
 +
 +  public void doGet( URI url, HttpServletRequest request, HttpServletResponse response )
 +      throws IOException, URISyntaxException {
 +    response.sendError( HttpServletResponse.SC_METHOD_NOT_ALLOWED );
 +  }
 +
 +  public void doPost( URI url, HttpServletRequest request, HttpServletResponse response )
 +      throws IOException, URISyntaxException {
 +    response.sendError( HttpServletResponse.SC_METHOD_NOT_ALLOWED );
 +  }
 +
 +  public void doPut( URI url, HttpServletRequest request, HttpServletResponse response )
 +      throws IOException, URISyntaxException {
 +    response.sendError( HttpServletResponse.SC_METHOD_NOT_ALLOWED );
 +  }
 +
 +  public void doDelete( URI url, HttpServletRequest request, HttpServletResponse response )
 +      throws IOException, URISyntaxException {
 +    response.sendError( HttpServletResponse.SC_METHOD_NOT_ALLOWED );
 +  }
 +
 +  public void doOptions( URI url, HttpServletRequest request, HttpServletResponse response )
++      throws IOException, URISyntaxException {
++    response.sendError( HttpServletResponse.SC_METHOD_NOT_ALLOWED );
++  }
++
++  /**
++   * @sine 0.14.0
++   */
++  public void doHead( URI url, HttpServletRequest request, HttpServletResponse response )
 +      throws IOException, URISyntaxException {
 +    response.sendError( HttpServletResponse.SC_METHOD_NOT_ALLOWED );
 +  }
 +  
 +  public void copyRequestHeaderFields(HttpUriRequest outboundRequest,
 +      HttpServletRequest inboundRequest) {
 +    Enumeration<String> headerNames = inboundRequest.getHeaderNames();
 +    while( headerNames.hasMoreElements() ) {
 +      String name = headerNames.nextElement();
 +      if ( !outboundRequest.containsHeader( name )
 +          && !getOutboundRequestExcludeHeaders().contains( name ) ) {
 +        String value = inboundRequest.getHeader( name );
 +        outboundRequest.addHeader( name, value );
 +      }
 +    }
 +  }
 +
 +  public Set<String> getOutboundRequestExcludeHeaders() {
 +    return REQUEST_EXCLUDE_HEADERS;
 +  }
 +
 +  protected void encodeUnwiseCharacters(StringBuffer str) {
 +    int pipe = str.indexOf("|");
 +    while (pipe > -1) {
 +      str.replace(pipe, pipe+1, "%7C");
 +      pipe = str.indexOf("|", pipe+1);
 +    }
 +  }
 +
 +}

http://git-wip-us.apache.org/repos/asf/knox/blob/51348f83/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/DefaultDispatch.java
----------------------------------------------------------------------
diff --cc gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/DefaultDispatch.java
index 94f64ee,0000000..aeb33b2
mode 100644,000000..100644
--- a/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/DefaultDispatch.java
+++ b/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/DefaultDispatch.java
@@@ -1,319 -1,0 +1,328 @@@
 +/**
 + * 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.dispatch;
 +
 +import org.apache.knox.gateway.SpiGatewayMessages;
 +import org.apache.knox.gateway.SpiGatewayResources;
 +import org.apache.knox.gateway.audit.api.Action;
 +import org.apache.knox.gateway.audit.api.ActionOutcome;
 +import org.apache.knox.gateway.audit.api.AuditServiceFactory;
 +import org.apache.knox.gateway.audit.api.Auditor;
 +import org.apache.knox.gateway.audit.api.ResourceType;
 +import org.apache.knox.gateway.audit.log4j.audit.AuditConstants;
 +import org.apache.knox.gateway.config.Configure;
 +import org.apache.knox.gateway.config.Default;
 +import org.apache.knox.gateway.config.GatewayConfig;
 +import org.apache.knox.gateway.i18n.messages.MessagesFactory;
 +import org.apache.knox.gateway.i18n.resources.ResourcesFactory;
 +import org.apache.knox.gateway.util.MimeTypes;
 +import org.apache.http.Header;
 +import org.apache.http.HttpEntity;
 +import org.apache.http.HttpResponse;
 +import org.apache.http.client.methods.HttpDelete;
 +import org.apache.http.client.methods.HttpGet;
++import org.apache.http.client.methods.HttpHead;
 +import org.apache.http.client.methods.HttpOptions;
 +import org.apache.http.client.methods.HttpPost;
 +import org.apache.http.client.methods.HttpPut;
 +import org.apache.http.client.methods.HttpUriRequest;
 +import org.apache.http.entity.ContentType;
 +
 +import javax.servlet.http.HttpServletRequest;
 +import javax.servlet.http.HttpServletResponse;
 +import java.io.Closeable;
 +import java.io.IOException;
 +import java.io.InputStream;
 +import java.net.URI;
 +import java.net.URISyntaxException;
 +import java.util.HashSet;
 +import java.util.Set;
 +
 +/**
 + *
 + */
 +public class DefaultDispatch extends AbstractGatewayDispatch {
 +
 +  protected static final String SET_COOKIE = "SET-COOKIE";
 +  protected static final String WWW_AUTHENTICATE = "WWW-AUTHENTICATE";
 +
 +  protected static SpiGatewayMessages LOG = MessagesFactory.get(SpiGatewayMessages.class);
 +  protected static SpiGatewayResources RES = ResourcesFactory.get(SpiGatewayResources.class);
 +  protected static Auditor auditor = AuditServiceFactory.getAuditService().getAuditor(AuditConstants.DEFAULT_AUDITOR_NAME,
 +      AuditConstants.KNOX_SERVICE_NAME, AuditConstants.KNOX_COMPONENT_NAME);
 +
 +  private Set<String> outboundResponseExcludeHeaders;
 +
 +  //Buffer size in bytes
 +  private int replayBufferSize = -1;
 +
 +  @Override
 +  public void init() {
 +    super.init();
 +    outboundResponseExcludeHeaders = new HashSet<>();
 +    outboundResponseExcludeHeaders.add(SET_COOKIE);
 +    outboundResponseExcludeHeaders.add(WWW_AUTHENTICATE);
 +  }
 +
 +  @Override
 +  public void destroy() {
 +
 +  }
 +
 +  protected int getReplayBufferSize() {
 +    if (replayBufferSize > 0) {
 +      return Math.abs(replayBufferSize/1024);
 +    }
 +    return replayBufferSize;
 +  }
 +
 +  @Configure
 +  protected void setReplayBufferSize(@Default("-1")int size) {
 +    setReplayBufferSizeInBytes(size);
 +  }
 +
 +  protected int getReplayBufferSizeInBytes() {
 +    return replayBufferSize;
 +  }
 +
 +  protected void setReplayBufferSizeInBytes(int size) {
 +    if (size > 0) {
 +      size *= 1024;
 +    }
 +    replayBufferSize = size;
 +  }
 +
 +
 +  protected void executeRequest(
 +         HttpUriRequest outboundRequest,
 +         HttpServletRequest inboundRequest,
 +         HttpServletResponse outboundResponse)
 +         throws IOException {
 +      HttpResponse inboundResponse = executeOutboundRequest(outboundRequest);
 +      writeOutboundResponse(outboundRequest, inboundRequest, outboundResponse, inboundResponse);
 +   }
 +
 +  protected HttpResponse executeOutboundRequest( HttpUriRequest outboundRequest ) throws IOException {
 +    LOG.dispatchRequest( outboundRequest.getMethod(), outboundRequest.getURI() );
 +    HttpResponse inboundResponse;
 +
 +    try {
 +      auditor.audit( Action.DISPATCH, outboundRequest.getURI().toString(), ResourceType.URI, ActionOutcome.UNAVAILABLE, RES.requestMethod( outboundRequest.getMethod() ) );
 +      if( !"true".equals( System.getProperty( GatewayConfig.HADOOP_KERBEROS_SECURED ) ) ) {
 +        // Hadoop cluster not Kerberos enabled
 +        addCredentialsToRequest( outboundRequest );
 +      }
 +      inboundResponse = client.execute( outboundRequest );
 +
 +      int statusCode = inboundResponse.getStatusLine().getStatusCode();
 +      if( statusCode != 201 ) {
 +        LOG.dispatchResponseStatusCode( statusCode );
 +      } else {
 +        Header location = inboundResponse.getFirstHeader( "Location" );
 +        if( location == null ) {
 +          LOG.dispatchResponseStatusCode( statusCode );
 +        } else {
 +          LOG.dispatchResponseCreatedStatusCode( statusCode, location.getValue() );
 +        }
 +      }
 +      auditor.audit( Action.DISPATCH, outboundRequest.getURI().toString(), ResourceType.URI, ActionOutcome.SUCCESS, RES.responseStatus( statusCode ) );
 +    } catch( Exception e ) {
 +      // We do not want to expose back end host. port end points to clients, see JIRA KNOX-58
 +      auditor.audit( Action.DISPATCH, outboundRequest.getURI().toString(), ResourceType.URI, ActionOutcome.FAILURE );
 +      LOG.dispatchServiceConnectionException( outboundRequest.getURI(), e );
 +      throw new IOException( RES.dispatchConnectionError() );
 +    }
 +    return inboundResponse;
 +  }
 +
 +  protected void writeOutboundResponse(HttpUriRequest outboundRequest, HttpServletRequest inboundRequest, HttpServletResponse outboundResponse, HttpResponse inboundResponse) throws IOException {
 +    // Copy the client respond header to the server respond.
 +    outboundResponse.setStatus(inboundResponse.getStatusLine().getStatusCode());
 +    Header[] headers = inboundResponse.getAllHeaders();
 +    Set<String> excludeHeaders = getOutboundResponseExcludeHeaders();
 +    boolean hasExcludeHeaders = false;
 +    if ((excludeHeaders != null) && !(excludeHeaders.isEmpty())) {
 +      hasExcludeHeaders = true;
 +    }
 +    for ( Header header : headers ) {
 +      String name = header.getName();
 +      if (hasExcludeHeaders && excludeHeaders.contains(name.toUpperCase())) {
 +        continue;
 +      }
 +      String value = header.getValue();
 +      outboundResponse.addHeader(name, value);
 +    }
 +
 +    HttpEntity entity = inboundResponse.getEntity();
 +    if( entity != null ) {
 +      outboundResponse.setContentType( getInboundResponseContentType( entity ) );
 +      //KM[ If this is set here it ends up setting the content length to the content returned from the server.
 +      // This length might not match if the the content is rewritten.
 +      //      long contentLength = entity.getContentLength();
 +      //      if( contentLength <= Integer.MAX_VALUE ) {
 +      //        outboundResponse.setContentLength( (int)contentLength );
 +      //      }
 +      //]
 +      InputStream stream = entity.getContent();
 +      try {
 +        writeResponse( inboundRequest, outboundResponse, stream );
 +      } finally {
 +        closeInboundResponse( inboundResponse, stream );
 +      }
 +    }
 +  }
 +
 +  private String getInboundResponseContentType( final HttpEntity entity ) {
 +    String fullContentType = null;
 +    if( entity != null ) {
 +      ContentType entityContentType = ContentType.get( entity );
 +      if( entityContentType != null ) {
 +        if( entityContentType.getCharset() == null ) {
 +          final String entityMimeType = entityContentType.getMimeType();
 +          final String defaultCharset = MimeTypes.getDefaultCharsetForMimeType( entityMimeType );
 +          if( defaultCharset != null ) {
 +            LOG.usingDefaultCharsetForEntity( entityMimeType, defaultCharset );
 +            entityContentType = entityContentType.withCharset( defaultCharset );
 +          }
 +        } else {
 +          LOG.usingExplicitCharsetForEntity( entityContentType.getMimeType(), entityContentType.getCharset() );
 +        }
 +        fullContentType = entityContentType.toString();
 +      }
 +    }
 +    if( fullContentType == null ) {
 +      LOG.unknownResponseEntityContentType();
 +    } else {
 +      LOG.inboundResponseEntityContentType( fullContentType );
 +    }
 +    return fullContentType;
 +  }
 +
 +  protected void closeInboundResponse( HttpResponse response, InputStream stream ) throws IOException {
 +    try {
 +      stream.close();
 +    } finally {
 +      if( response instanceof Closeable ) {
 +        ( (Closeable)response).close();
 +      }
 +    }
 +  }
 +
 +   /**
 +    * This method provides a hook for specialized credential propagation
 +    * in subclasses.
 +    *
 +    * @param outboundRequest
 +    */
 +   protected void addCredentialsToRequest(HttpUriRequest outboundRequest) {
 +   }
 +
 +
 +   protected HttpEntity createRequestEntity(HttpServletRequest request)
 +         throws IOException {
 +
 +      String contentType = request.getContentType();
 +      int contentLength = request.getContentLength();
 +      InputStream contentStream = request.getInputStream();
 +
 +      HttpEntity entity;
 +      if (contentType == null) {
 +         entity = new InputStreamEntity(contentStream, contentLength);
 +      } else {
 +         entity = new InputStreamEntity(contentStream, contentLength, ContentType.parse(contentType));
 +      }
 +      GatewayConfig config =
 +         (GatewayConfig)request.getServletContext().getAttribute( GatewayConfig.GATEWAY_CONFIG_ATTRIBUTE );
 +      if( config != null && config.isHadoopKerberosSecured() ) {
 +        //Check if delegation token is supplied in the request
 +        boolean delegationTokenPresent = false;
 +        String queryString = request.getQueryString();
 +        if (queryString != null) {
 +          delegationTokenPresent = queryString.startsWith("delegation=") || queryString.contains("&delegation=");
 +        }
 +        if (replayBufferSize < 0) {
 +          replayBufferSize = config.getHttpServerRequestBuffer();
 +        }
 +        if (!delegationTokenPresent && replayBufferSize > 0 ) {
 +          entity = new PartiallyRepeatableHttpEntity(entity, replayBufferSize);
 +        }
 +      }
 +
 +      return entity;
 +   }
 +
 +   @Override
 +   public void doGet(URI url, HttpServletRequest request, HttpServletResponse response)
 +         throws IOException, URISyntaxException {
 +      HttpGet method = new HttpGet(url);
 +      // https://issues.apache.org/jira/browse/KNOX-107 - Service URLs not rewritten for WebHDFS GET redirects
 +      // This is now taken care of in DefaultHttpClientFactory.createHttpClient
 +      // and setting params here causes configuration setup there to be ignored there.
 +      // method.getParams().setBooleanParameter("http.protocol.handle-redirects", false);
 +      copyRequestHeaderFields(method, request);
 +      executeRequest(method, request, response);
 +   }
 +
 +   @Override
 +   public void doOptions(URI url, HttpServletRequest request, HttpServletResponse response)
 +         throws IOException, URISyntaxException {
 +      HttpOptions method = new HttpOptions(url);
 +      executeRequest(method, request, response);
 +   }
 +
 +   @Override
 +   public void doPut(URI url, HttpServletRequest request, HttpServletResponse response)
 +         throws IOException, URISyntaxException {
 +      HttpPut method = new HttpPut(url);
 +      HttpEntity entity = createRequestEntity(request);
 +      method.setEntity(entity);
 +      copyRequestHeaderFields(method, request);
 +      executeRequest(method, request, response);
 +   }
 +
 +   @Override
 +   public void doPost(URI url, HttpServletRequest request, HttpServletResponse response)
 +         throws IOException, URISyntaxException {
 +      HttpPost method = new HttpPost(url);
 +      HttpEntity entity = createRequestEntity(request);
 +      method.setEntity(entity);
 +      copyRequestHeaderFields(method, request);
 +      executeRequest(method, request, response);
 +   }
 +
 +   @Override
 +   public void doDelete(URI url, HttpServletRequest request, HttpServletResponse response)
 +         throws IOException, URISyntaxException {
 +      HttpDelete method = new HttpDelete(url);
 +      copyRequestHeaderFields(method, request);
 +      executeRequest(method, request, response);
 +   }
 +
++  @Override
++  public void doHead(URI url, HttpServletRequest request, HttpServletResponse response)
++      throws IOException, URISyntaxException {
++    final HttpHead method = new HttpHead(url);
++    copyRequestHeaderFields(method, request);
++    executeRequest(method, request, response);
++  }
++
 +  public Set<String> getOutboundResponseExcludeHeaders() {
 +    return outboundResponseExcludeHeaders;
 +  }
 +
 +}

http://git-wip-us.apache.org/repos/asf/knox/blob/51348f83/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/Dispatch.java
----------------------------------------------------------------------
diff --cc gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/Dispatch.java
index ffd472f,0000000..30220b2
mode 100644,000000..100644
--- a/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/Dispatch.java
+++ b/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/Dispatch.java
@@@ -1,56 -1,0 +1,62 @@@
 +/**
 + * 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.dispatch;
 +
 +import org.apache.http.client.HttpClient;
 +
 +import javax.servlet.ServletException;
 +import javax.servlet.http.HttpServletRequest;
 +import javax.servlet.http.HttpServletResponse;
 +import java.io.IOException;
 +import java.net.URI;
 +import java.net.URISyntaxException;
 +
 +public interface Dispatch {
 +
 +  void init();
 +
 +  void destroy();
 +
 +  HttpClient getHttpClient();
 +
 +  void setHttpClient(HttpClient httpClient);
 +
 +  URI getDispatchUrl( HttpServletRequest request );
 +
 +  void doGet( URI url, HttpServletRequest request, HttpServletResponse response )
 +      throws IOException, ServletException, URISyntaxException;
 +
 +  void doPost( URI url, HttpServletRequest request, HttpServletResponse response )
 +      throws IOException, ServletException, URISyntaxException;
 +
 +  void doPut( URI url, HttpServletRequest request, HttpServletResponse response )
 +      throws IOException, ServletException, URISyntaxException;
 +
 +  void doDelete( URI url, HttpServletRequest request, HttpServletResponse response )
 +      throws IOException, ServletException, URISyntaxException;
 +
 +  void doOptions( URI url, HttpServletRequest request, HttpServletResponse response )
 +      throws IOException, ServletException, URISyntaxException;
 +
++  /**
++   * @since 0.14.0
++   */
++  void doHead( URI url, HttpServletRequest request, HttpServletResponse response )
++      throws IOException, ServletException, URISyntaxException;
++
 +}

http://git-wip-us.apache.org/repos/asf/knox/blob/51348f83/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/GatewayDispatchFilter.java
----------------------------------------------------------------------
diff --cc gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/GatewayDispatchFilter.java
index eef3718,0000000..7b887d1
mode 100644,000000..100644
--- a/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/GatewayDispatchFilter.java
+++ b/gateway-spi/src/main/java/org/apache/knox/gateway/dispatch/GatewayDispatchFilter.java
@@@ -1,169 -1,0 +1,177 @@@
 +/**
 + * 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.dispatch;
 +
 +import org.apache.knox.gateway.SpiGatewayMessages;
 +import org.apache.knox.gateway.filter.AbstractGatewayFilter;
 +import org.apache.knox.gateway.config.ConfigurationInjectorBuilder;
 +import org.apache.knox.gateway.i18n.messages.MessagesFactory;
 +import org.apache.http.client.HttpClient;
 +import org.apache.http.impl.client.CloseableHttpClient;
 +
 +import javax.servlet.FilterChain;
 +import javax.servlet.FilterConfig;
 +import javax.servlet.ServletException;
 +import javax.servlet.http.HttpServletRequest;
 +import javax.servlet.http.HttpServletResponse;
 +import java.io.IOException;
 +import java.net.URISyntaxException;
 +import java.util.Collections;
 +import java.util.HashMap;
 +import java.util.Map;
 +
 +public class GatewayDispatchFilter extends AbstractGatewayFilter {
 +
 +  private static Map<String, Adapter> METHOD_ADAPTERS = createMethodAdapters();
 +
 +  protected static SpiGatewayMessages LOG = MessagesFactory.get(SpiGatewayMessages.class);
 +
 +  private Dispatch dispatch;
 +
 +  private HttpClient httpClient;
 +
 +  private static Map<String, Adapter> createMethodAdapters() {
 +    Map<String, Adapter> map = new HashMap<>();
 +    map.put("GET", new GetAdapter());
 +    map.put("POST", new PostAdapter());
 +    map.put("PUT", new PutAdapter());
 +    map.put("DELETE", new DeleteAdapter());
 +    map.put("OPTIONS", new OptionsAdapter());
++    map.put("HEAD", new HeadAdapter());
 +    return Collections.unmodifiableMap(map);
 +  }
 +
 +  @Override
 +  public void init(FilterConfig filterConfig) throws ServletException {
 +    super.init(filterConfig);
 +    if (dispatch == null) {
 +      String dispatchImpl = filterConfig.getInitParameter("dispatch-impl");
 +      dispatch = newInstanceFromName(dispatchImpl);
 +    }
 +    ConfigurationInjectorBuilder.configuration().target(dispatch).source(filterConfig).inject();
 +    HttpClientFactory httpClientFactory;
 +    String httpClientFactoryClass = filterConfig.getInitParameter("httpClientFactory");
 +    if (httpClientFactoryClass != null) {
 +      httpClientFactory = newInstanceFromName(httpClientFactoryClass);
 +    } else {
 +      httpClientFactory = new DefaultHttpClientFactory();
 +    }
 +    httpClient = httpClientFactory.createHttpClient(filterConfig);
 +    dispatch.setHttpClient(httpClient);
 +    dispatch.init();
 +  }
 +
 +  @Override
 +  public void destroy() {
 +    dispatch.destroy();
 +    try {
 +      if (httpClient instanceof  CloseableHttpClient) {
 +        ((CloseableHttpClient) httpClient).close();
 +      }
 +    } catch ( IOException e ) {
 +      LOG.errorClosingHttpClient(e);
 +    }
 +  }
 +
 +  public Dispatch getDispatch() {
 +    return dispatch;
 +  }
 +
 +  public void setDispatch(Dispatch dispatch) {
 +    this.dispatch = dispatch;
 +  }
 +
 +  @Override
 +  protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
 +    String method = request.getMethod().toUpperCase();
 +    Adapter adapter = METHOD_ADAPTERS.get(method);
 +    if ( adapter != null ) {
 +      try {
 +        adapter.doMethod(dispatch, request, response);
 +      } catch ( URISyntaxException e ) {
 +        throw new ServletException(e);
 +      }
 +    } else {
 +      response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
 +    }
 +  }
 +
 +  private interface Adapter {
 +    public void doMethod(Dispatch dispatch, HttpServletRequest request, HttpServletResponse response)
 +        throws IOException, ServletException, URISyntaxException;
 +  }
 +
 +  private static class GetAdapter implements Adapter {
 +    public void doMethod(Dispatch dispatch, HttpServletRequest request, HttpServletResponse response)
 +        throws IOException, ServletException, URISyntaxException {
 +      dispatch.doGet( dispatch.getDispatchUrl(request), request, response);
 +    }
 +  }
 +
 +  private static class PostAdapter implements Adapter {
 +    public void doMethod(Dispatch dispatch, HttpServletRequest request, HttpServletResponse response)
 +        throws IOException, ServletException, URISyntaxException {
 +      dispatch.doPost( dispatch.getDispatchUrl(request), request, response);
 +    }
 +  }
 +
 +  private static class PutAdapter implements Adapter {
 +    public void doMethod(Dispatch dispatch, HttpServletRequest request, HttpServletResponse response)
 +        throws IOException, ServletException, URISyntaxException {
 +      dispatch.doPut( dispatch.getDispatchUrl(request), request, response);
 +    }
 +  }
 +
 +  private static class DeleteAdapter implements Adapter {
 +    public void doMethod(Dispatch dispatch, HttpServletRequest request, HttpServletResponse response)
 +        throws IOException, ServletException, URISyntaxException {
 +      dispatch.doDelete( dispatch.getDispatchUrl(request), request, response);
 +    }
 +  }
 +
 +  private static class OptionsAdapter implements Adapter {
 +    public void doMethod(Dispatch dispatch, HttpServletRequest request, HttpServletResponse response)
 +        throws IOException, ServletException, URISyntaxException {
 +      dispatch.doOptions( dispatch.getDispatchUrl(request), request, response);
 +    }
 +  }
 +
++  private static class HeadAdapter implements Adapter {
++    public void doMethod(Dispatch dispatch, HttpServletRequest request, HttpServletResponse response)
++        throws IOException, ServletException, URISyntaxException {
++      dispatch.doHead( dispatch.getDispatchUrl(request), request, response);
++    }
++  }
++
 +  private <T> T newInstanceFromName(String dispatchImpl) throws ServletException {
 +    try {
 +      Class<T> clazz = loadClass(dispatchImpl);
 +      return clazz.newInstance();
 +    } catch ( Exception e ) {
 +      throw new ServletException(e);
 +    }
 +  }
 +
 +  private <T> Class<T> loadClass(String className) throws ClassNotFoundException {
 +      ClassLoader loader = Thread.currentThread().getContextClassLoader();
 +      if ( loader == null ) {
 +        loader = this.getClass().getClassLoader();
 +      }
 +      return (Class<T>) loader.loadClass(className);
 +  }
 +}


[3/4] knox git commit: KNOX-998 - Adding Adapters for some common configurations and UnitTests for them

Posted by mo...@apache.org.
KNOX-998 - Adding Adapters for some common configurations and UnitTests for them


Project: http://git-wip-us.apache.org/repos/asf/knox/repo
Commit: http://git-wip-us.apache.org/repos/asf/knox/commit/7815945d
Tree: http://git-wip-us.apache.org/repos/asf/knox/tree/7815945d
Diff: http://git-wip-us.apache.org/repos/asf/knox/diff/7815945d

Branch: refs/heads/KNOX-998-Package_Restructuring
Commit: 7815945dcc1e4a5b81d237fe9c98fa4a1af0e5c3
Parents: ca93de8
Author: Sandeep More <mo...@apache.org>
Authored: Wed Sep 27 10:05:37 2017 -0400
Committer: Sandeep More <mo...@apache.org>
Committed: Wed Sep 27 10:05:37 2017 -0400

----------------------------------------------------------------------
 gateway-adapter/pom.xml                         | 14 ++++
 .../gateway/audit/log4j/layout/AuditLayout.java | 52 +++++++++++++++
 .../shirorealm/KnoxLdapContextFactory.java      | 69 ++++++++++++++++++++
 .../gateway/shirorealm/KnoxLdapRealm.java       |  9 ++-
 .../hadoop/gateway/shirorealm/KnoxPamRealm.java | 17 +++--
 gateway-release/pom.xml                         |  4 ++
 6 files changed, 159 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/knox/blob/7815945d/gateway-adapter/pom.xml
----------------------------------------------------------------------
diff --git a/gateway-adapter/pom.xml b/gateway-adapter/pom.xml
index 2498f85..0f1ae4c 100644
--- a/gateway-adapter/pom.xml
+++ b/gateway-adapter/pom.xml
@@ -28,6 +28,14 @@
     <artifactId>gateway-adapter</artifactId>
     <name>gateway-adapter</name>
     <description>Adapter/Shims for old package structure to ensure compatibility.</description>
+    
+    <licenses>
+        <license>
+            <name>The Apache Software License, Version 2.0</name>
+            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+            <distribution>repo</distribution>
+        </license>
+    </licenses>
 
     <dependencies>
         <dependency>
@@ -41,6 +49,12 @@
         </dependency>
 
         <dependency>
+            <groupId>org.apache.knox</groupId>
+            <artifactId>gateway-test-utils</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
             <groupId>org.easymock</groupId>
             <artifactId>easymock</artifactId>
             <scope>test</scope>

http://git-wip-us.apache.org/repos/asf/knox/blob/7815945d/gateway-adapter/src/main/java/org/apache/hadoop/gateway/audit/log4j/layout/AuditLayout.java
----------------------------------------------------------------------
diff --git a/gateway-adapter/src/main/java/org/apache/hadoop/gateway/audit/log4j/layout/AuditLayout.java b/gateway-adapter/src/main/java/org/apache/hadoop/gateway/audit/log4j/layout/AuditLayout.java
new file mode 100644
index 0000000..9f97ece
--- /dev/null
+++ b/gateway-adapter/src/main/java/org/apache/hadoop/gateway/audit/log4j/layout/AuditLayout.java
@@ -0,0 +1,52 @@
+package org.apache.hadoop.gateway.audit.log4j.layout;
+
+/**
+ * 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.
+ */
+
+import org.apache.log4j.spi.LoggingEvent;
+
+/**
+ * An adapter class that deligates calls to {@link org.apache.knox.gateway.audit.log4j.layout.AuditLayout}
+ * for backwards compatability with package structure.
+ *
+ * @since 0.14.0
+ */
+public class AuditLayout
+    extends org.apache.knox.gateway.audit.log4j.layout.AuditLayout {
+
+  /**
+   * Create an instance
+   */
+  public AuditLayout() {
+    super();
+  }
+
+  @Override
+  public void activateOptions() {
+    super.activateOptions();
+  }
+
+  @Override
+  public String format(LoggingEvent event) {
+    return super.format(event);
+  }
+
+  @Override
+  public boolean ignoresThrowable() {
+    return super.ignoresThrowable();
+  }
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/7815945d/gateway-adapter/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxLdapContextFactory.java
----------------------------------------------------------------------
diff --git a/gateway-adapter/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxLdapContextFactory.java b/gateway-adapter/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxLdapContextFactory.java
new file mode 100644
index 0000000..ab54b48
--- /dev/null
+++ b/gateway-adapter/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxLdapContextFactory.java
@@ -0,0 +1,69 @@
+package org.apache.hadoop.gateway.shirorealm;
+
+/**
+ * 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.
+ */
+
+import javax.naming.NamingException;
+import javax.naming.ldap.LdapContext;
+import java.util.Hashtable;
+
+/**
+ * An adapter class that deligates calls to {@link org.apache.knox.gateway.shirorealm.KnoxLdapContextFactory}
+ * for backwards compatability with package structure.
+ * @since 0.14.0
+ */
+public class KnoxLdapContextFactory extends org.apache.knox.gateway.shirorealm.KnoxLdapContextFactory {
+
+  /**
+   * Create an instance
+   */
+  public KnoxLdapContextFactory() {
+    super();
+  }
+
+  @Override
+  protected LdapContext createLdapContext(Hashtable env)
+      throws NamingException {
+    return super.createLdapContext(env);
+  }
+
+  @Override
+  public String getSystemAuthenticationMechanism() {
+    return super.getSystemAuthenticationMechanism();
+  }
+
+  @Override
+  public void setSystemAuthenticationMechanism(
+      String systemAuthenticationMechanism) {
+    super.setSystemAuthenticationMechanism(systemAuthenticationMechanism);
+  }
+
+  @Override
+  public void setSystemPassword(String systemPass) {
+    super.setSystemPassword(systemPass);
+  }
+
+  @Override
+  public String getClusterName() {
+    return super.getClusterName();
+  }
+
+  @Override
+  public void setClusterName(String clusterName) {
+    super.setClusterName(clusterName);
+  }
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/7815945d/gateway-adapter/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxLdapRealm.java
----------------------------------------------------------------------
diff --git a/gateway-adapter/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxLdapRealm.java b/gateway-adapter/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxLdapRealm.java
index 8aa3fd5..4ce1b6c 100644
--- a/gateway-adapter/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxLdapRealm.java
+++ b/gateway-adapter/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxLdapRealm.java
@@ -27,7 +27,14 @@ import java.util.Map;
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-public class KnoxLdapRealm extends org.apache.knox.gateway.shirorealm.KnoxLdapRealm {
+
+/**
+ * An adapter class that deligates calls to {@link org.apache.knox.gateway.shirorealm.KnoxLdapRealm}
+ * for backwards compatability with package structure.
+ * @since 0.14.0
+ */
+public class KnoxLdapRealm
+    extends org.apache.knox.gateway.shirorealm.KnoxLdapRealm {
 
   /**
    * Create an instance

http://git-wip-us.apache.org/repos/asf/knox/blob/7815945d/gateway-adapter/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxPamRealm.java
----------------------------------------------------------------------
diff --git a/gateway-adapter/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxPamRealm.java b/gateway-adapter/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxPamRealm.java
index 20f06fe..32bbe32 100644
--- a/gateway-adapter/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxPamRealm.java
+++ b/gateway-adapter/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxPamRealm.java
@@ -22,7 +22,14 @@ import org.apache.shiro.subject.PrincipalCollection;
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-public class KnoxPamRealm extends org.apache.knox.gateway.shirorealm.KnoxPamRealm {
+
+/**
+ * An adapter class that deligates calls to {@link org.apache.knox.gateway.shirorealm.KnoxPamRealm}
+ * for backwards compatability with package structure.
+ * @since 0.14.0
+ */
+public class KnoxPamRealm
+    extends org.apache.knox.gateway.shirorealm.KnoxPamRealm {
 
   /**
    * Create an instance
@@ -32,13 +39,13 @@ public class KnoxPamRealm extends org.apache.knox.gateway.shirorealm.KnoxPamReal
   }
 
   @Override
-  public void setService(String service) {
-    super.setService(service);
+  public String getService() {
+    return super.getService();
   }
 
   @Override
-  public String getService() {
-    return super.getService();
+  public void setService(String service) {
+    super.setService(service);
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/knox/blob/7815945d/gateway-release/pom.xml
----------------------------------------------------------------------
diff --git a/gateway-release/pom.xml b/gateway-release/pom.xml
index cbff307..1db3749 100644
--- a/gateway-release/pom.xml
+++ b/gateway-release/pom.xml
@@ -338,6 +338,10 @@
             <groupId>${gateway-group}</groupId>
             <artifactId>gateway-discovery-ambari</artifactId>
         </dependency>
+        <dependency>
+            <groupId>${gateway-group}</groupId>
+            <artifactId>gateway-adapter</artifactId>
+        </dependency>
 
         <dependency>
             <groupId>junit</groupId>


[2/4] knox git commit: KNOX-1068 - Add support for HTTP Head request

Posted by mo...@apache.org.
KNOX-1068 - Add support for HTTP Head request


Project: http://git-wip-us.apache.org/repos/asf/knox/repo
Commit: http://git-wip-us.apache.org/repos/asf/knox/commit/10b3473a
Tree: http://git-wip-us.apache.org/repos/asf/knox/tree/10b3473a
Diff: http://git-wip-us.apache.org/repos/asf/knox/diff/10b3473a

Branch: refs/heads/KNOX-998-Package_Restructuring
Commit: 10b3473ae0ab88645322ef4798f9eb696cb59b93
Parents: a841e26
Author: Sandeep More <mo...@apache.org>
Authored: Tue Sep 26 14:24:30 2017 -0400
Committer: Sandeep More <mo...@apache.org>
Committed: Tue Sep 26 14:24:30 2017 -0400

----------------------------------------------------------------------
 .../hadoop/gateway/dispatch/AbstractGatewayDispatch.java    | 8 ++++++++
 .../org/apache/hadoop/gateway/dispatch/DefaultDispatch.java | 9 +++++++++
 .../java/org/apache/hadoop/gateway/dispatch/Dispatch.java   | 6 ++++++
 .../hadoop/gateway/dispatch/GatewayDispatchFilter.java      | 8 ++++++++
 4 files changed, 31 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/knox/blob/10b3473a/gateway-spi/src/main/java/org/apache/hadoop/gateway/dispatch/AbstractGatewayDispatch.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/hadoop/gateway/dispatch/AbstractGatewayDispatch.java b/gateway-spi/src/main/java/org/apache/hadoop/gateway/dispatch/AbstractGatewayDispatch.java
index 70a6996..16a09fc 100644
--- a/gateway-spi/src/main/java/org/apache/hadoop/gateway/dispatch/AbstractGatewayDispatch.java
+++ b/gateway-spi/src/main/java/org/apache/hadoop/gateway/dispatch/AbstractGatewayDispatch.java
@@ -115,6 +115,14 @@ public abstract class AbstractGatewayDispatch implements Dispatch {
       throws IOException, URISyntaxException {
     response.sendError( HttpServletResponse.SC_METHOD_NOT_ALLOWED );
   }
+
+  /**
+   * @sine 0.14.0
+   */
+  public void doHead( URI url, HttpServletRequest request, HttpServletResponse response )
+      throws IOException, URISyntaxException {
+    response.sendError( HttpServletResponse.SC_METHOD_NOT_ALLOWED );
+  }
   
   public void copyRequestHeaderFields(HttpUriRequest outboundRequest,
       HttpServletRequest inboundRequest) {

http://git-wip-us.apache.org/repos/asf/knox/blob/10b3473a/gateway-spi/src/main/java/org/apache/hadoop/gateway/dispatch/DefaultDispatch.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/hadoop/gateway/dispatch/DefaultDispatch.java b/gateway-spi/src/main/java/org/apache/hadoop/gateway/dispatch/DefaultDispatch.java
index 4b9e95d..d3633a9 100644
--- a/gateway-spi/src/main/java/org/apache/hadoop/gateway/dispatch/DefaultDispatch.java
+++ b/gateway-spi/src/main/java/org/apache/hadoop/gateway/dispatch/DefaultDispatch.java
@@ -36,6 +36,7 @@ import org.apache.http.HttpEntity;
 import org.apache.http.HttpResponse;
 import org.apache.http.client.methods.HttpDelete;
 import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpHead;
 import org.apache.http.client.methods.HttpOptions;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.client.methods.HttpPut;
@@ -312,6 +313,14 @@ public class DefaultDispatch extends AbstractGatewayDispatch {
       executeRequest(method, request, response);
    }
 
+  @Override
+  public void doHead(URI url, HttpServletRequest request, HttpServletResponse response)
+      throws IOException, URISyntaxException {
+    final HttpHead method = new HttpHead(url);
+    copyRequestHeaderFields(method, request);
+    executeRequest(method, request, response);
+  }
+
   public Set<String> getOutboundResponseExcludeHeaders() {
     return outboundResponseExcludeHeaders;
   }

http://git-wip-us.apache.org/repos/asf/knox/blob/10b3473a/gateway-spi/src/main/java/org/apache/hadoop/gateway/dispatch/Dispatch.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/hadoop/gateway/dispatch/Dispatch.java b/gateway-spi/src/main/java/org/apache/hadoop/gateway/dispatch/Dispatch.java
index de08117..506e22b 100644
--- a/gateway-spi/src/main/java/org/apache/hadoop/gateway/dispatch/Dispatch.java
+++ b/gateway-spi/src/main/java/org/apache/hadoop/gateway/dispatch/Dispatch.java
@@ -53,4 +53,10 @@ public interface Dispatch {
   void doOptions( URI url, HttpServletRequest request, HttpServletResponse response )
       throws IOException, ServletException, URISyntaxException;
 
+  /**
+   * @since 0.14.0
+   */
+  void doHead( URI url, HttpServletRequest request, HttpServletResponse response )
+      throws IOException, ServletException, URISyntaxException;
+
 }

http://git-wip-us.apache.org/repos/asf/knox/blob/10b3473a/gateway-spi/src/main/java/org/apache/hadoop/gateway/dispatch/GatewayDispatchFilter.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/hadoop/gateway/dispatch/GatewayDispatchFilter.java b/gateway-spi/src/main/java/org/apache/hadoop/gateway/dispatch/GatewayDispatchFilter.java
index acfa92e..4799ec2 100644
--- a/gateway-spi/src/main/java/org/apache/hadoop/gateway/dispatch/GatewayDispatchFilter.java
+++ b/gateway-spi/src/main/java/org/apache/hadoop/gateway/dispatch/GatewayDispatchFilter.java
@@ -54,6 +54,7 @@ public class GatewayDispatchFilter extends AbstractGatewayFilter {
     map.put("PUT", new PutAdapter());
     map.put("DELETE", new DeleteAdapter());
     map.put("OPTIONS", new OptionsAdapter());
+    map.put("HEAD", new HeadAdapter());
     return Collections.unmodifiableMap(map);
   }
 
@@ -152,6 +153,13 @@ public class GatewayDispatchFilter extends AbstractGatewayFilter {
     }
   }
 
+  private static class HeadAdapter implements Adapter {
+    public void doMethod(Dispatch dispatch, HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException, URISyntaxException {
+      dispatch.doHead( dispatch.getDispatchUrl(request), request, response);
+    }
+  }
+
   private <T> T newInstanceFromName(String dispatchImpl) throws ServletException {
     try {
       Class<T> clazz = loadClass(dispatchImpl);