I guess you have the required karma!

On 8/21/13 2:31 PM, Dilli Arumugam wrote:
Yes, Larry.
First commit.
Thank You.
Dilli


On Wed, Aug 21, 2013 at 11:24 AM, larry mccay <[email protected]> wrote:

First commit, Dilli?
Wahoo - Congrats!


On Wed, Aug 21, 2013 at 2:19 PM, <[email protected]> wrote:

Updated Branches:
   refs/heads/master 0f763c6bb -> e36fc4a31


patch to fix KNOX-89, Knox doing SPNego with Hadoop for every client
request is not scalable


Project: http://git-wip-us.apache.org/repos/asf/incubator-knox/repo
Commit:
http://git-wip-us.apache.org/repos/asf/incubator-knox/commit/e36fc4a3
Tree:
http://git-wip-us.apache.org/repos/asf/incubator-knox/tree/e36fc4a3
Diff:
http://git-wip-us.apache.org/repos/asf/incubator-knox/diff/e36fc4a3
Branch: refs/heads/master
Commit: e36fc4a3151d208e4327132f2bffb9e383d2c060
Parents: 0f763c6
Author: Dilli Dorai Arumugam <[email protected]>
Authored: Tue Aug 20 22:37:49 2013 -0700
Committer: Dilli Dorai Arumugam <[email protected]>
Committed: Wed Aug 21 11:12:19 2013 -0700

----------------------------------------------------------------------
  .../home/templates/krb5JAASLogin.conf           |  31 +--
  .../apache/hadoop/gateway/GatewayMessages.java  |   6 +
  .../gateway/dispatch/AppCookieManager.java      | 190
+++++++++++++++++++
  .../gateway/dispatch/HttpClientDispatch.java    | 109 ++++++-----
  .../gateway/dispatch/AppCookieManagerTest.java  |  53 ++++++
  5 files changed, 312 insertions(+), 77 deletions(-)
----------------------------------------------------------------------




http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e36fc4a3/gateway-release/home/templates/krb5JAASLogin.conf
----------------------------------------------------------------------
diff --git a/gateway-release/home/templates/krb5JAASLogin.conf
b/gateway-release/home/templates/krb5JAASLogin.conf
index cfb4d19..d9f8d7b 100644
--- a/gateway-release/home/templates/krb5JAASLogin.conf
+++ b/gateway-release/home/templates/krb5JAASLogin.conf
@@ -17,20 +17,6 @@
  *
  * IMPORTANT: REPLACE EXAMPLE.COM and keyTab file location with your
site
specific values
  */
-com.sun.security.jgss.login {
-    com.sun.security.auth.module.Krb5LoginModule required
-    renewTGT=true
-    doNotPrompt=true
-    useKeyTab=true
-    keyTab="/etc/knox/conf/knox.service.keytab"
-    principal="[email protected]"
-    isInitiator=true
-    storeKey=true
-    useTicketCache=true
-    client=true
-    debug=true;
-};
-
  com.sun.security.jgss.initiate {
      com.sun.security.auth.module.Krb5LoginModule required
      renewTGT=true
@@ -41,20 +27,5 @@ com.sun.security.jgss.initiate {
      isInitiator=true
      storeKey=true
      useTicketCache=true
-    client=true
-    debug=true;
-};
-
-com.sun.security.jgss.accept {
-    com.sun.security.auth.module.Krb5LoginModule required
-    renewTGT=true
-    doNotPrompt=true
-    useKeyTab=true
-    keyTab="/etc/knox/conf/knox.service.keytab"
-    principal="[email protected]"
-    isInitiator=true
-    storeKey=true
-    useTicketCache=true
-    client=true
-    debug=true;
+    client=true;
  };



http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e36fc4a3/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayMessages.java
----------------------------------------------------------------------
diff --git

a/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayMessages.java
b/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayMessages.java
index 3337b19..34ef775 100644
---

a/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayMessages.java
+++

b/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayMessages.java
@@ -260,4 +260,10 @@ public interface GatewayMessages {

    @Message( level = MessageLevel.ERROR, text = "Failed to get map from
Json string {0}: {1}" )
    void failedToGetMapFromJsonString( String json, @StackTrace( level =
MessageLevel.DEBUG ) Exception e );
+
+  @Message( level = MessageLevel.INFO, text = "Successful Knox->Hadoop
SPNegotiation authentication for URL: {0}" )
+  void successfulSPNegoAuthn(String uri);
+
+  @Message( level = MessageLevel.ERROR, text = "Failed Knox->Hadoop
SPNegotiation authentication for URL: {0}" )
+  void failedSPNegoAuthn(String uri);
  }



http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e36fc4a3/gateway-server/src/main/java/org/apache/hadoop/gateway/dispatch/AppCookieManager.java
----------------------------------------------------------------------
diff --git

a/gateway-server/src/main/java/org/apache/hadoop/gateway/dispatch/AppCookieManager.java
b/gateway-server/src/main/java/org/apache/hadoop/gateway/dispatch/AppCookieManager.java
new file mode 100644
index 0000000..d0f0ecc
--- /dev/null
+++

b/gateway-server/src/main/java/org/apache/hadoop/gateway/dispatch/AppCookieManager.java
@@ -0,0 +1,190 @@
+/**
+ * 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.dispatch;
+
+import java.io.IOException;
+import java.net.URI;
+import java.security.Principal;
+
+import org.apache.hadoop.gateway.GatewayMessages;
+import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
+import org.apache.http.Header;
+import org.apache.http.HeaderElement;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.Credentials;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpOptions;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.client.params.AuthPolicy;
+import org.apache.http.impl.auth.SPNegoSchemeFactory;
+import org.apache.http.impl.client.DefaultHttpClient;
+
+/**
+ * Handles SPNego authentication as a client of hadoop service, caches
+ * hadoop.auth cookie returned by hadoop service on successful SPNego
+ * authentication. Refreshes hadoop.auth cookie on demand if the cookie
has
+ * expired.
+ *
+ */
+public class AppCookieManager {
+
+  static final String HADOOP_AUTH = "hadoop.auth";
+  private static final String HADOOP_AUTH_EQ = "hadoop.auth=";
+  private static final String SET_COOKIE = "Set-Cookie";
+
+  private static GatewayMessages LOG =
MessagesFactory.get(GatewayMessages.class);
+
+  private static final EmptyJaasCredentials EMPTY_JAAS_CREDENTIALS = new
EmptyJaasCredentials();
+
+  String appCookie;
+
+  /**
+   * Utility method to excerise AppCookieManager directly
+   * @param args element 0 of args should be a URL to hadoop service
protected by SPengo
+   * @throws IOException in case of errors
+   */
+  public static void main(String[] args) throws IOException {
+    HttpUriRequest outboundRequest = new HttpGet(args[0]);
+    new AppCookieManager().getAppCookie(outboundRequest, false);
+  }
+
+  public AppCookieManager() {
+  }
+
+  /**
+   * Fetches hadoop.auth cookie from hadoop service authenticating using
SpNego
+   *
+   * @param outboundRequest
+   *          out going request
+   * @param refresh
+   *          flag indicating whether to refresh the cached cookie
+   * @return hadoop.auth cookie from hadoop service authenticating using
SpNego
+   * @throws IOException
+   *           in case of errors
+   */
+  public String getAppCookie(HttpUriRequest outboundRequest, boolean
refresh)
+      throws IOException {
+
+    URI uri = outboundRequest.getURI();
+    String scheme = uri.getScheme();
+    String host = uri.getHost();
+    int port = uri.getPort();
+    String path = uri.getPath();
+    if (!refresh) {
+      if (appCookie != null) {
+        return appCookie;
+      }
+    }
+
+    DefaultHttpClient client = new DefaultHttpClient();
+    SPNegoSchemeFactory spNegoSF = new SPNegoSchemeFactory(
+    /* stripPort */true);
+    // spNegoSF.setSpengoGenerator(new BouncySpnegoTokenGenerator());
+    client.getAuthSchemes().register(AuthPolicy.SPNEGO, spNegoSF);
+    client.getCredentialsProvider().setCredentials(
+        new AuthScope(/* host */null, /* port */-1, /* realm */null),
+        EMPTY_JAAS_CREDENTIALS);
+
+    clearAppCookie();
+    String hadoopAuthCookie = null;
+    HttpResponse httpResponse = null;
+    try {
+      HttpHost httpHost = new HttpHost(host, port, scheme);
+      HttpRequest httpRequest = new HttpOptions(path);
+      httpResponse = client.execute(httpHost, httpRequest);
+      Header[] headers = httpResponse.getHeaders(SET_COOKIE);
+      hadoopAuthCookie = getHadoopAuthCookieValue(headers);
+      if (hadoopAuthCookie == null) {
+        LOG.failedSPNegoAuthn(uri.toString());
+        throw new IOException(
+            "SPNego authn failed, can not get hadoop.auth cookie");
+      }
+    } finally {
+      if (httpResponse != null) {
+        HttpEntity entity = httpResponse.getEntity();
+        if (entity != null) {
+          entity.getContent().close();
+        }
+      }
+
+    }
+    LOG.successfulSPNegoAuthn(uri.toString());
+    hadoopAuthCookie = HADOOP_AUTH_EQ + quote(hadoopAuthCookie);
+    setAppCookie(hadoopAuthCookie);
+    return appCookie;
+  }
+
+  /**
+   * Returns the cached app cookie
+   *
+   * @return the cached app cookie, can be null
+   */
+  public String getCachedKnoxAppCookie() {
+    return appCookie;
+  }
+
+  private void setAppCookie(String appCookie) {
+    this.appCookie = appCookie;
+  }
+
+  private void clearAppCookie() {
+    appCookie = null;
+  }
+
+  static String quote(String s) {
+    return s == null ? s : "\"" + s + "\"";
+  }
+
+  static String getHadoopAuthCookieValue(Header[] headers) {
+    if (headers == null) {
+      return null;
+    }
+    for (Header header : headers) {
+      HeaderElement[] elements = header.getElements();
+      for (HeaderElement element : elements) {
+        String cookieName = element.getName();
+        if (cookieName.equals(HADOOP_AUTH)) {
+          if (element.getValue() != null) {
+            String trimmedVal = element.getValue().trim();
+            if (!trimmedVal.isEmpty()) {
+              return trimmedVal;
+            }
+          }
+        }
+      }
+    }
+    return null;
+  }
+
+  private static class EmptyJaasCredentials implements Credentials {
+
+    public String getPassword() {
+      return null;
+    }
+
+    public Principal getUserPrincipal() {
+      return null;
+    }
+
+  }
+
+}



http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e36fc4a3/gateway-server/src/main/java/org/apache/hadoop/gateway/dispatch/HttpClientDispatch.java
----------------------------------------------------------------------
diff --git

a/gateway-server/src/main/java/org/apache/hadoop/gateway/dispatch/HttpClientDispatch.java
b/gateway-server/src/main/java/org/apache/hadoop/gateway/dispatch/HttpClientDispatch.java
index 2d38aea..ac8d85c 100644
---

a/gateway-server/src/main/java/org/apache/hadoop/gateway/dispatch/HttpClientDispatch.java
+++

b/gateway-server/src/main/java/org/apache/hadoop/gateway/dispatch/HttpClientDispatch.java
@@ -17,7 +17,15 @@
   */
  package org.apache.hadoop.gateway.dispatch;

-import org.apache.commons.io.IOUtils;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.security.Principal;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
  import org.apache.hadoop.gateway.GatewayMessages;
  import org.apache.hadoop.gateway.GatewayResources;
  import org.apache.hadoop.gateway.config.GatewayConfig;
@@ -26,7 +34,7 @@ import
org.apache.hadoop.gateway.i18n.resources.ResourcesFactory;
  import org.apache.http.Header;
  import org.apache.http.HttpEntity;
  import org.apache.http.HttpResponse;
-import org.apache.http.auth.AuthScope;
+import org.apache.http.HttpStatus;
  import org.apache.http.auth.Credentials;
  import org.apache.http.client.methods.HttpDelete;
  import org.apache.http.client.methods.HttpGet;
@@ -34,39 +42,32 @@ 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.client.params.AuthPolicy;
  import org.apache.http.entity.BufferedHttpEntity;
-import org.apache.http.entity.ByteArrayEntity;
  import org.apache.http.entity.ContentType;
  import org.apache.http.entity.InputStreamEntity;
-import org.apache.http.impl.auth.SPNegoSchemeFactory;
  import org.apache.http.impl.client.DefaultHttpClient;
-import org.apache.http.protocol.BasicHttpContext;
-import org.apache.http.protocol.HttpContext;
-
-import javax.activation.MimeType;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.nio.charset.Charset;
-import java.security.Principal;
+import org.apache.http.message.BasicHeader;

  /**
   *
   */
  public class HttpClientDispatch extends AbstractGatewayDispatch {
-
-  private static final String CT_APP_WWW_FORM_URL_ENCODED =
"application/x-www-form-urlencoded";
-  private static final String CT_APP_XML = "application/xml";
+
+  // private static final String CT_APP_WWW_FORM_URL_ENCODED =
"application/x-www-form-urlencoded";
+  // private static final String CT_APP_XML = "application/xml";
+  private static final String Q_DELEGATION_EQ = "?delegation=";
+  private static final String AMP_DELEGATION_EQ = "&delegation=";
+  private static final String COOKIE = "Cookie";
+  private static final String SET_COOKIE = "Set-Cookie";
+  private static final String WWW_AUTHENTICATE = "WWW-Authenticate";
+  private static final String NEGOTIATE = "Negotiate";

    private static GatewayMessages LOG = MessagesFactory.get(
GatewayMessages.class );
    private static GatewayResources RES = ResourcesFactory.get(
GatewayResources.class );
-  private static final EmptyJaasCredentials EMPTY_JAAS_CREDENTIALS = new
EmptyJaasCredentials();
    private static final int REPLAY_BUFFER_MAX_SIZE = 1024 * 1024; //
limit
to 1MB

+  private AppCookieManager appCookieManager = new AppCookieManager();;
+
    protected void executeRequest(
        HttpUriRequest outboundRequest,
        HttpServletRequest inboundRequest,
@@ -74,22 +75,46 @@ public class HttpClientDispatch extends
AbstractGatewayDispatch {
            throws IOException {
      LOG.dispatchRequest( outboundRequest.getMethod(),
outboundRequest.getURI() );
      DefaultHttpClient client = new DefaultHttpClient();
-
-    if

("true".equals(System.getProperty(GatewayConfig.HADOOP_KERBEROS_SECURED))) {
-      SPNegoSchemeFactory nsf = new SPNegoSchemeFactory(/* stripPort */
true);
-      // nsf.setSpengoGenerator(new BouncySpnegoTokenGenerator());
-      client.getAuthSchemes().register(AuthPolicy.SPNEGO, nsf);

-      client.getCredentialsProvider().setCredentials(
-          new AuthScope(/* host */ null, /* port */ -1, /* realm */
null),
-          EMPTY_JAAS_CREDENTIALS);
-    }
-
-    HttpContext localContext = new BasicHttpContext();
-
      HttpResponse inboundResponse;
      try {
-      inboundResponse = client.execute(outboundRequest, localContext);
+      String query = outboundRequest.getURI().getQuery();
+      if

(!"true".equals(System.getProperty(GatewayConfig.HADOOP_KERBEROS_SECURED)))
{
+        // Hadoop cluster not Kerberos enabled
+        inboundResponse = client.execute(outboundRequest);
+      } else if (query.contains(Q_DELEGATION_EQ) ||
+        // query string carries delegation token
+        query.contains(AMP_DELEGATION_EQ)) {
+        inboundResponse = client.execute(outboundRequest);
+      } else {
+        // Kerberos secured, no delegation token in query string
+        outboundRequest.removeHeaders(COOKIE);
+        String appCookie = appCookieManager.getCachedKnoxAppCookie();
+        if (appCookie != null) {
+          outboundRequest.addHeader(new BasicHeader(COOKIE, appCookie));
+        }
+        inboundResponse = client.execute(outboundRequest);
+        // if inBoundResponse has status 401 and header
WWW-Authenticate:
Negoitate
+        // refresh hadoop.auth.cookie and attempt one more time
+        int statusCode =
inboundResponse.getStatusLine().getStatusCode();
+        if (statusCode == HttpStatus.SC_UNAUTHORIZED ) {
+          Header[] wwwAuthHeaders =
inboundResponse.getHeaders(WWW_AUTHENTICATE) ;
+          if (wwwAuthHeaders != null && wwwAuthHeaders.length != 0 &&
+
  wwwAuthHeaders[0].getValue().trim().startsWith(NEGOTIATE)) {
+            appCookie = appCookieManager.getAppCookie(outboundRequest,
true);
+            outboundRequest.removeHeaders(COOKIE);
+            outboundRequest.addHeader(new BasicHeader(COOKIE,
appCookie));
+            client = new DefaultHttpClient();
+            inboundResponse = client.execute(outboundRequest);
+          } else {
+            // no supported authentication type found
+            // we would let the original response propogate
+          }
+        } else {
+          // not a 401 Unauthorized status code
+          // we would let the original response propogate
+        }
+      }
      } catch (IOException e) {
        // we do not want to expose back end host. port end points to
clients, see JIRA KNOX-58
        LOG.dispatchServiceConnectionException( outboundRequest.getURI(),
e
);
@@ -101,6 +126,9 @@ public class HttpClientDispatch extends
AbstractGatewayDispatch {
      Header[] headers = inboundResponse.getAllHeaders();
      for( Header header : headers ) {
        String name = header.getName();
+      if (name.equals(SET_COOKIE) || name.equals(WWW_AUTHENTICATE)) {
+        continue;
+      }
        String value = header.getValue();
        outboundResponse.addHeader( name, value );
      }
@@ -239,18 +267,5 @@ public class HttpClientDispatch extends
AbstractGatewayDispatch {
  //    }
  //
  //  }
-
-  private static class EmptyJaasCredentials implements Credentials {
-
-    public String getPassword() {
-      return null;
-    }
-
-    public Principal getUserPrincipal() {
-      return null;
-    }
-
-  }
-

  }



http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/e36fc4a3/gateway-server/src/test/java/org/apache/hadoop/gateway/dispatch/AppCookieManagerTest.java
----------------------------------------------------------------------
diff --git

a/gateway-server/src/test/java/org/apache/hadoop/gateway/dispatch/AppCookieManagerTest.java
b/gateway-server/src/test/java/org/apache/hadoop/gateway/dispatch/AppCookieManagerTest.java
new file mode 100644
index 0000000..704c41c
--- /dev/null
+++

b/gateway-server/src/test/java/org/apache/hadoop/gateway/dispatch/AppCookieManagerTest.java
@@ -0,0 +1,53 @@
+/**
+ * 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.dispatch;
+
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import org.apache.http.Header;
+import org.apache.http.message.BasicHeader;
+import org.junit.Test;
+
+public class AppCookieManagerTest {
+
+  @Test
+  public void getCachedKnoxAppCookie() {
+    assertNull(new AppCookieManager().getCachedKnoxAppCookie());
+  }
+
+  @Test
+  public void getHadoopAuthCookieValueWithNullHeaders() {
+    assertNull(AppCookieManager.getHadoopAuthCookieValue(null));
+  }
+
+  @Test
+  public void getHadoopAuthCookieValueWitEmptylHeaders() {
+    assertNull(AppCookieManager.getHadoopAuthCookieValue(new
Header[0]));
+  }
+
+  @Test
+  public void getHadoopAuthCookieValueWithValidlHeaders() {
+    Header[] headers = new Header[1];
+    headers[0] = new BasicHeader("Set-Cookie",
AppCookieManager.HADOOP_AUTH + "=dummyvalue");
+    assertNotNull(AppCookieManager.getHadoopAuthCookieValue(headers));
+  }
+
+}
+




--
CONFIDENTIALITY NOTICE
NOTICE: This message is intended for the use of the individual or entity to which it is addressed and may contain information that is confidential, privileged and exempt from disclosure under applicable law. If the reader of this message is not the intended recipient, you are hereby notified that any printing, copying, dissemination, distribution, disclosure or forwarding of this communication is strictly prohibited. If you have received this communication in error, please contact the sender immediately and delete it from your system. Thank You.

Reply via email to