浏览代码

HADOOP-10835. Implement HTTP proxyuser support in HTTP authentication client/server libraries. (tucu)

git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1617384 13f79535-47bb-0310-9956-ffa450edef68
Alejandro Abdelnur 10 年之前
父节点
当前提交
6d7a6766bd

+ 23 - 2
hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/AuthenticationFilter.java

@@ -127,6 +127,7 @@ public class AuthenticationFilter implements Filter {
   public static final String SIGNATURE_PROVIDER_ATTRIBUTE =
       "org.apache.hadoop.security.authentication.util.SignerSecretProvider";
 
+  private Properties config;
   private Signer signer;
   private SignerSecretProvider secretProvider;
   private AuthenticationHandler authHandler;
@@ -150,7 +151,7 @@ public class AuthenticationFilter implements Filter {
   public void init(FilterConfig filterConfig) throws ServletException {
     String configPrefix = filterConfig.getInitParameter(CONFIG_PREFIX);
     configPrefix = (configPrefix != null) ? configPrefix + "." : "";
-    Properties config = getConfiguration(configPrefix, filterConfig);
+    config = getConfiguration(configPrefix, filterConfig);
     String authHandlerName = config.getProperty(AUTH_TYPE, null);
     String authHandlerClassName;
     if (authHandlerName == null) {
@@ -224,6 +225,17 @@ public class AuthenticationFilter implements Filter {
     cookiePath = config.getProperty(COOKIE_PATH, null);
   }
 
+  /**
+   * Returns the configuration properties of the {@link AuthenticationFilter}
+   * without the prefix. The returned properties are the same that the
+   * {@link #getConfiguration(String, FilterConfig)} method returned.
+   *
+   * @return the configuration properties.
+   */
+  protected Properties getConfiguration() {
+    return config;
+  }
+
   /**
    * Returns the authentication handler being used.
    *
@@ -457,7 +469,7 @@ public class AuthenticationFilter implements Filter {
             createAuthCookie(httpResponse, signedToken, getCookieDomain(),
                     getCookiePath(), token.getExpires(), isHttps);
           }
-          filterChain.doFilter(httpRequest, httpResponse);
+          doFilter(filterChain, httpRequest, httpResponse);
         }
       } else {
         unauthorizedResponse = false;
@@ -481,6 +493,15 @@ public class AuthenticationFilter implements Filter {
     }
   }
 
+  /**
+   * Delegates call to the servlet filter chain. Sub-classes my override this
+   * method to perform pre and post tasks.
+   */
+  protected void doFilter(FilterChain filterChain, HttpServletRequest request,
+      HttpServletResponse response) throws IOException, ServletException {
+    filterChain.doFilter(request, response);
+  }
+
   /**
    * Creates the Hadoop authentication HTTP cookie.
    *

+ 5 - 1
hadoop-common-project/hadoop-common/CHANGES.txt

@@ -496,7 +496,11 @@ Release 2.6.0 - UNRELEASED
     HADOOP-10791. AuthenticationFilter should support externalizing the 
     secret for signing and provide rotation support. (rkanter via tucu)
 
-    HADOOP-10771. Refactor HTTP delegation support out of httpfs to common, PART 1. (tucu)
+    HADOOP-10771. Refactor HTTP delegation support out of httpfs to common. 
+    (tucu)
+
+    HADOOP-10835. Implement HTTP proxyuser support in HTTP authentication 
+    client/server libraries. (tucu)
 
   OPTIMIZATIONS
 

+ 13 - 0
hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/token/delegation/web/DelegationTokenAuthenticatedURL.java

@@ -34,6 +34,7 @@ import java.io.IOException;
 import java.net.HttpURLConnection;
 import java.net.InetSocketAddress;
 import java.net.URL;
+import java.net.URLEncoder;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -60,6 +61,13 @@ import java.util.Map;
 @InterfaceStability.Unstable
 public class DelegationTokenAuthenticatedURL extends AuthenticatedURL {
 
+  /**
+   * Constant used in URL's query string to perform a proxy user request, the
+   * value of the <code>DO_AS</code> parameter is the user the request will be
+   * done on behalf of.
+   */
+  static final String DO_AS = "doAs";
+
   /**
    * Client side authentication token that handles Delegation Tokens.
    */
@@ -247,6 +255,11 @@ public class DelegationTokenAuthenticatedURL extends AuthenticatedURL {
       }
     }
 
+    // proxyuser
+    if (doAs != null) {
+      extraParams.put(DO_AS, URLEncoder.encode(doAs, "UTF-8"));
+    }
+
     url = augmentURL(url, extraParams);
     return super.openConnection(url, token);
   }

+ 175 - 3
hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/token/delegation/web/DelegationTokenAuthenticationFilter.java

@@ -17,17 +17,39 @@
  */
 package org.apache.hadoop.security.token.delegation.web;
 
+import com.google.common.annotations.VisibleForTesting;
 import org.apache.hadoop.classification.InterfaceAudience;
 import org.apache.hadoop.classification.InterfaceStability;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.security.SaslRpcServer;
+import org.apache.hadoop.security.UserGroupInformation;
 import org.apache.hadoop.security.authentication.server.AuthenticationFilter;
 import org.apache.hadoop.security.authentication.server.AuthenticationHandler;
+import org.apache.hadoop.security.authentication.server.AuthenticationToken;
 import org.apache.hadoop.security.authentication.server.KerberosAuthenticationHandler;
 import org.apache.hadoop.security.authentication.server.PseudoAuthenticationHandler;
+import org.apache.hadoop.security.authorize.AuthorizationException;
+import org.apache.hadoop.security.authorize.ProxyUsers;
 import org.apache.hadoop.security.token.delegation.AbstractDelegationTokenSecretManager;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.utils.URLEncodedUtils;
+import org.codehaus.jackson.map.ObjectMapper;
 
+import javax.servlet.FilterChain;
 import javax.servlet.FilterConfig;
 import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.Writer;
+import java.nio.charset.Charset;
+import java.security.Principal;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 import java.util.Properties;
 
 /**
@@ -49,6 +71,10 @@ import java.util.Properties;
 public class DelegationTokenAuthenticationFilter
     extends AuthenticationFilter {
 
+  private static final String APPLICATION_JSON_MIME = "application/json";
+  private static final String ERROR_EXCEPTION_JSON = "exception";
+  private static final String ERROR_MESSAGE_JSON = "message";
+
   /**
    * Sets an external <code>DelegationTokenSecretManager</code> instance to
    * manage creation and verification of Delegation Tokens.
@@ -60,6 +86,14 @@ public class DelegationTokenAuthenticationFilter
   public static final String DELEGATION_TOKEN_SECRET_MANAGER_ATTR =
       "hadoop.http.delegation-token-secret-manager";
 
+  private static final Charset UTF8_CHARSET = Charset.forName("UTF-8");
+
+  private static final ThreadLocal<UserGroupInformation> UGI_TL =
+      new ThreadLocal<UserGroupInformation>();
+  public static final String PROXYUSER_PREFIX = "proxyuser";
+
+  private SaslRpcServer.AuthMethod handlerAuthMethod;
+
   /**
    * It delegates to
    * {@link AuthenticationFilter#getConfiguration(String, FilterConfig)} and
@@ -86,17 +120,155 @@ public class DelegationTokenAuthenticationFilter
     return props;
   }
 
+  /**
+   * Returns the proxyuser configuration. All returned properties must start
+   * with <code>proxyuser.</code>'
+   * <p/>
+   * Subclasses may override this method if the proxyuser configuration is 
+   * read from other place than the filter init parameters.
+   *
+   * @param filterConfig filter configuration object
+   * @return the proxyuser configuration properties.
+   * @throws ServletException thrown if the configuration could not be created.
+   */
+  protected Configuration getProxyuserConfiguration(FilterConfig filterConfig)
+      throws ServletException {
+    // this filter class gets the configuration from the filter configs, we are
+    // creating an empty configuration and injecting the proxyuser settings in
+    // it. In the initialization of the filter, the returned configuration is
+    // passed to the ProxyUsers which only looks for 'proxyusers.' properties.
+    Configuration conf = new Configuration(false);
+    Enumeration<?> names = filterConfig.getInitParameterNames();
+    while (names.hasMoreElements()) {
+      String name = (String) names.nextElement();
+      if (name.startsWith(PROXYUSER_PREFIX + ".")) {
+        String value = filterConfig.getInitParameter(name);
+        conf.set(name, value);
+      }
+    }
+    return conf;
+  }
+
+
   @Override
   public void init(FilterConfig filterConfig) throws ServletException {
     super.init(filterConfig);
+    AuthenticationHandler handler = getAuthenticationHandler();
     AbstractDelegationTokenSecretManager dtSecretManager =
         (AbstractDelegationTokenSecretManager) filterConfig.getServletContext().
             getAttribute(DELEGATION_TOKEN_SECRET_MANAGER_ATTR);
-    if (dtSecretManager != null && getAuthenticationHandler()
+    if (dtSecretManager != null && handler
         instanceof DelegationTokenAuthenticationHandler) {
-      DelegationTokenAuthenticationHandler handler =
+      DelegationTokenAuthenticationHandler dtHandler =
           (DelegationTokenAuthenticationHandler) getAuthenticationHandler();
-      handler.setExternalDelegationTokenSecretManager(dtSecretManager);
+      dtHandler.setExternalDelegationTokenSecretManager(dtSecretManager);
     }
+    if (handler instanceof PseudoAuthenticationHandler ||
+        handler instanceof PseudoDelegationTokenAuthenticationHandler) {
+      setHandlerAuthMethod(SaslRpcServer.AuthMethod.SIMPLE);
+    }
+    if (handler instanceof KerberosAuthenticationHandler ||
+        handler instanceof KerberosDelegationTokenAuthenticationHandler) {
+      setHandlerAuthMethod(SaslRpcServer.AuthMethod.KERBEROS);
+    }
+
+    // proxyuser configuration
+    Configuration conf = getProxyuserConfiguration(filterConfig);
+    ProxyUsers.refreshSuperUserGroupsConfiguration(conf, PROXYUSER_PREFIX);
   }
+
+  protected void setHandlerAuthMethod(SaslRpcServer.AuthMethod authMethod) {
+    this.handlerAuthMethod = authMethod;
+  }
+
+  @VisibleForTesting
+  static String getDoAs(HttpServletRequest request) {
+    List<NameValuePair> list = URLEncodedUtils.parse(request.getQueryString(),
+        UTF8_CHARSET);
+    if (list != null) {
+      for (NameValuePair nv : list) {
+        if (DelegationTokenAuthenticatedURL.DO_AS.equals(nv.getName())) {
+          return nv.getValue();
+        }
+      }
+    }
+    return null;
+  }
+
+  static UserGroupInformation getHttpUserGroupInformationInContext() {
+    return UGI_TL.get();
+  }
+
+  @Override
+  protected void doFilter(FilterChain filterChain, HttpServletRequest request,
+      HttpServletResponse response) throws IOException, ServletException {
+    boolean requestCompleted = false;
+    UserGroupInformation ugi = null;
+    AuthenticationToken authToken = (AuthenticationToken)
+        request.getUserPrincipal();
+    if (authToken != null && authToken != AuthenticationToken.ANONYMOUS) {
+      // if the request was authenticated because of a delegation token,
+      // then we ignore proxyuser (this is the same as the RPC behavior).
+      ugi = (UserGroupInformation) request.getAttribute(
+          DelegationTokenAuthenticationHandler.DELEGATION_TOKEN_UGI_ATTRIBUTE);
+      if (ugi == null) {
+        String realUser = request.getUserPrincipal().getName();
+        ugi = UserGroupInformation.createRemoteUser(realUser,
+            handlerAuthMethod);
+        String doAsUser = getDoAs(request);
+        if (doAsUser != null) {
+          ugi = UserGroupInformation.createProxyUser(doAsUser, ugi);
+          try {
+            ProxyUsers.authorize(ugi, request.getRemoteHost());
+          } catch (AuthorizationException ex) {
+            String msg = String.format(
+                "User '%s' from host '%s' not allowed to impersonate user '%s'",
+                realUser, request.getRemoteHost(), doAsUser);
+            response.setStatus(HttpServletResponse.SC_FORBIDDEN);
+            response.setContentType(APPLICATION_JSON_MIME);
+            Map<String, String> json = new HashMap<String, String>();
+            json.put(ERROR_EXCEPTION_JSON,
+                AuthorizationException.class.getName());
+            json.put(ERROR_MESSAGE_JSON, msg);
+            Writer writer = response.getWriter();
+            ObjectMapper jsonMapper = new ObjectMapper();
+            jsonMapper.writeValue(writer, json);
+            requestCompleted = true;
+          }
+        }
+      }
+      UGI_TL.set(ugi);
+    }
+    if (!requestCompleted) {
+      final UserGroupInformation ugiF = ugi;
+      try {
+        request = new HttpServletRequestWrapper(request) {
+
+          @Override
+          public String getAuthType() {
+            return (ugiF != null) ? handlerAuthMethod.toString() : null;
+          }
+
+          @Override
+          public String getRemoteUser() {
+            return (ugiF != null) ? ugiF.getShortUserName() : null;
+          }
+
+          @Override
+          public Principal getUserPrincipal() {
+            return (ugiF != null) ? new Principal() {
+              @Override
+              public String getName() {
+                return ugiF.getUserName();
+              }
+            } : null;
+          }
+        };
+        super.doFilter(filterChain, request, response);
+      } finally {
+        UGI_TL.remove();
+      }
+    }
+  }
+
 }

+ 4 - 0
hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/token/delegation/web/DelegationTokenAuthenticationHandler.java

@@ -92,6 +92,9 @@ public abstract class DelegationTokenAuthenticationHandler
 
   private static final Set<String> DELEGATION_TOKEN_OPS = new HashSet<String>();
 
+  static final String DELEGATION_TOKEN_UGI_ATTRIBUTE =
+      "hadoop.security.delegation-token.ugi";
+
   static {
     DELEGATION_TOKEN_OPS.add(KerberosDelegationTokenAuthenticator.
         DelegationTokenOperation.GETDELEGATIONTOKEN.toString());
@@ -342,6 +345,7 @@ public abstract class DelegationTokenAuthenticationHandler
         token = new AuthenticationToken(shortName, ugi.getUserName(),
             getType());
         token.setExpires(0);
+        request.setAttribute(DELEGATION_TOKEN_UGI_ATTRIBUTE, ugi);
       } catch (Throwable ex) {
         throw new AuthenticationException("Could not verify DelegationToken, " +
             ex.toString(), ex);

+ 43 - 0
hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/token/delegation/web/HttpUserGroupInformation.java

@@ -0,0 +1,43 @@
+/**
+ * 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.security.token.delegation.web;
+
+import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.security.UserGroupInformation;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * Util class that returns the remote {@link UserGroupInformation} in scope
+ * for the HTTP request.
+ */
+@InterfaceAudience.Private
+public class HttpUserGroupInformation {
+
+  /**
+   * Returns the remote {@link UserGroupInformation} in context for the current
+   * HTTP request, taking into account proxy user requests.
+   *
+   * @return the remote {@link UserGroupInformation}, <code>NULL</code> if none.
+   */
+  public static UserGroupInformation get() {
+    return DelegationTokenAuthenticationFilter.
+        getHttpUserGroupInformationInContext();
+  }
+
+}

+ 158 - 16
hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/token/delegation/web/TestWebDelegationToken.java

@@ -72,6 +72,10 @@ import java.util.UUID;
 import java.util.concurrent.Callable;
 
 public class TestWebDelegationToken {
+  private static final String OK_USER = "ok-user";
+  private static final String FAIL_USER = "fail-user";
+  private static final String FOO_USER = "foo";
+  
   private Server jetty;
 
   public static class DummyAuthenticationHandler
@@ -330,13 +334,13 @@ public class TestWebDelegationToken {
           new DelegationTokenAuthenticatedURL();
 
       try {
-        aUrl.getDelegationToken(nonAuthURL, token, "foo");
+        aUrl.getDelegationToken(nonAuthURL, token, FOO_USER);
         Assert.fail();
       } catch (Exception ex) {
         Assert.assertTrue(ex.getMessage().contains("401"));
       }
 
-      aUrl.getDelegationToken(authURL, token, "foo");
+      aUrl.getDelegationToken(authURL, token, FOO_USER);
       Assert.assertNotNull(token.getDelegationToken());
       Assert.assertEquals(new Text("token-kind"),
           token.getDelegationToken().getKind());
@@ -350,7 +354,7 @@ public class TestWebDelegationToken {
         Assert.assertTrue(ex.getMessage().contains("401"));
       }
 
-      aUrl.getDelegationToken(authURL, token, "foo");
+      aUrl.getDelegationToken(authURL, token, FOO_USER);
 
       try {
         aUrl.renewDelegationToken(authURL2, token);
@@ -359,15 +363,15 @@ public class TestWebDelegationToken {
         Assert.assertTrue(ex.getMessage().contains("403"));
       }
 
-      aUrl.getDelegationToken(authURL, token, "foo");
+      aUrl.getDelegationToken(authURL, token, FOO_USER);
 
       aUrl.cancelDelegationToken(authURL, token);
 
-      aUrl.getDelegationToken(authURL, token, "foo");
+      aUrl.getDelegationToken(authURL, token, FOO_USER);
 
       aUrl.cancelDelegationToken(nonAuthURL, token);
 
-      aUrl.getDelegationToken(authURL, token, "foo");
+      aUrl.getDelegationToken(authURL, token, FOO_USER);
 
       try {
         aUrl.renewDelegationToken(nonAuthURL, token);
@@ -416,7 +420,7 @@ public class TestWebDelegationToken {
       DelegationTokenAuthenticatedURL aUrl =
           new DelegationTokenAuthenticatedURL();
 
-      aUrl.getDelegationToken(authURL, token, "foo");
+      aUrl.getDelegationToken(authURL, token, FOO_USER);
       Assert.assertNotNull(token.getDelegationToken());
       Assert.assertEquals(new Text("fooKind"),
           token.getDelegationToken().getKind());
@@ -488,7 +492,7 @@ public class TestWebDelegationToken {
       jetty.start();
       final URL url = new URL(getJettyURL() + "/foo/bar");
 
-      UserGroupInformation ugi = UserGroupInformation.createRemoteUser("foo");
+      UserGroupInformation ugi = UserGroupInformation.createRemoteUser(FOO_USER);
       ugi.doAs(new PrivilegedExceptionAction<Void>() {
         @Override
         public Void run() throws Exception {
@@ -501,10 +505,10 @@ public class TestWebDelegationToken {
               conn.getResponseCode());
           List<String> ret = IOUtils.readLines(conn.getInputStream());
           Assert.assertEquals(1, ret.size());
-          Assert.assertEquals("foo", ret.get(0));
+          Assert.assertEquals(FOO_USER, ret.get(0));
 
           try {
-            aUrl.getDelegationToken(url, token, "foo");
+            aUrl.getDelegationToken(url, token, FOO_USER);
             Assert.fail();
           } catch (AuthenticationException ex) {
             Assert.assertTrue(ex.getMessage().contains(
@@ -531,6 +535,16 @@ public class TestWebDelegationToken {
           "token-kind");
       return conf;
     }
+
+    @Override
+    protected org.apache.hadoop.conf.Configuration getProxyuserConfiguration(
+        FilterConfig filterConfig) throws ServletException {
+      org.apache.hadoop.conf.Configuration conf =
+          new org.apache.hadoop.conf.Configuration(false);
+      conf.set("proxyuser.foo.users", OK_USER);
+      conf.set("proxyuser.foo.hosts", "localhost");
+      return conf;
+    }
   }
 
   @Test
@@ -547,7 +561,7 @@ public class TestWebDelegationToken {
       jetty.start();
       final URL url = new URL(getJettyURL() + "/foo/bar");
 
-      UserGroupInformation ugi = UserGroupInformation.createRemoteUser("foo");
+      UserGroupInformation ugi = UserGroupInformation.createRemoteUser(FOO_USER);
       ugi.doAs(new PrivilegedExceptionAction<Void>() {
         @Override
         public Void run() throws Exception {
@@ -560,9 +574,9 @@ public class TestWebDelegationToken {
               conn.getResponseCode());
           List<String> ret = IOUtils.readLines(conn.getInputStream());
           Assert.assertEquals(1, ret.size());
-          Assert.assertEquals("foo", ret.get(0));
+          Assert.assertEquals(FOO_USER, ret.get(0));
 
-          aUrl.getDelegationToken(url, token, "foo");
+          aUrl.getDelegationToken(url, token, FOO_USER);
           Assert.assertNotNull(token.getDelegationToken());
           Assert.assertEquals(new Text("token-kind"),
               token.getDelegationToken().getKind());
@@ -684,7 +698,7 @@ public class TestWebDelegationToken {
       final URL url = new URL(getJettyURL() + "/foo/bar");
 
       try {
-        aUrl.getDelegationToken(url, token, "foo");
+        aUrl.getDelegationToken(url, token, FOO_USER);
         Assert.fail();
       } catch (AuthenticationException ex) {
         Assert.assertTrue(ex.getMessage().contains("GSSException"));
@@ -700,7 +714,7 @@ public class TestWebDelegationToken {
               aUrl.renewDelegationToken(url, token);
               Assert.assertNotNull(token.getDelegationToken());
 
-              aUrl.getDelegationToken(url, token, "foo");
+              aUrl.getDelegationToken(url, token, FOO_USER);
               Assert.assertNotNull(token.getDelegationToken());
 
               try {
@@ -710,7 +724,7 @@ public class TestWebDelegationToken {
                 Assert.assertTrue(ex.getMessage().contains("403"));
               }
 
-              aUrl.getDelegationToken(url, token, "foo");
+              aUrl.getDelegationToken(url, token, FOO_USER);
 
               aUrl.cancelDelegationToken(url, token);
               Assert.assertNull(token.getDelegationToken());
@@ -724,4 +738,132 @@ public class TestWebDelegationToken {
     }
   }
 
+  @Test
+  public void testProxyUser() throws Exception {
+    final Server jetty = createJettyServer();
+    Context context = new Context();
+    context.setContextPath("/foo");
+    jetty.setHandler(context);
+    context.addFilter(new FilterHolder(PseudoDTAFilter.class), "/*", 0);
+    context.addServlet(new ServletHolder(UserServlet.class), "/bar");
+
+    try {
+      jetty.start();
+      final URL url = new URL(getJettyURL() + "/foo/bar");
+
+      UserGroupInformation ugi = UserGroupInformation.createRemoteUser(FOO_USER);
+      ugi.doAs(new PrivilegedExceptionAction<Void>() {
+        @Override
+        public Void run() throws Exception {
+          DelegationTokenAuthenticatedURL.Token token =
+              new DelegationTokenAuthenticatedURL.Token();
+          DelegationTokenAuthenticatedURL aUrl =
+              new DelegationTokenAuthenticatedURL();
+
+          // proxyuser using authentication handler authentication
+          HttpURLConnection conn = aUrl.openConnection(url, token, OK_USER);
+          Assert.assertEquals(HttpURLConnection.HTTP_OK,
+              conn.getResponseCode());
+          List<String> ret = IOUtils.readLines(conn.getInputStream());
+          Assert.assertEquals(1, ret.size());
+          Assert.assertEquals(OK_USER, ret.get(0));
+
+          // unauthorized proxy user using authentication handler authentication
+          conn = aUrl.openConnection(url, token, FAIL_USER);
+          Assert.assertEquals(HttpURLConnection.HTTP_FORBIDDEN,
+              conn.getResponseCode());
+
+          // proxy using delegation token authentication
+          aUrl.getDelegationToken(url, token, FOO_USER);
+
+          UserGroupInformation ugi = UserGroupInformation.getCurrentUser();
+          ugi.addToken(token.getDelegationToken());
+          token = new DelegationTokenAuthenticatedURL.Token();
+
+          // requests using delegation token as auth do not honor doAs
+          conn = aUrl.openConnection(url, token, OK_USER);
+          Assert.assertEquals(HttpURLConnection.HTTP_OK,
+              conn.getResponseCode());
+          ret = IOUtils.readLines(conn.getInputStream());
+          Assert.assertEquals(1, ret.size());
+          Assert.assertEquals(FOO_USER, ret.get(0));
+
+          return null;
+        }
+      });
+    } finally {
+      jetty.stop();
+    }
+  }
+
+
+  public static class UGIServlet extends HttpServlet {
+
+    @Override
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+        throws ServletException, IOException {
+      UserGroupInformation ugi = HttpUserGroupInformation.get();
+      if (ugi != null) {
+        String ret = "remoteuser=" + req.getRemoteUser() + ":ugi=" +
+            ugi.getShortUserName();
+        if (ugi.getAuthenticationMethod() ==
+            UserGroupInformation.AuthenticationMethod.PROXY) {
+          ret = "realugi=" + ugi.getRealUser().getShortUserName() + ":" + ret;
+        }
+        resp.setStatus(HttpServletResponse.SC_OK);
+        resp.getWriter().write(ret);
+      } else {
+        resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+      }
+    }
+  }
+
+  @Test
+  public void testHttpUGI() throws Exception {
+    final Server jetty = createJettyServer();
+    Context context = new Context();
+    context.setContextPath("/foo");
+    jetty.setHandler(context);
+    context.addFilter(new FilterHolder(PseudoDTAFilter.class), "/*", 0);
+    context.addServlet(new ServletHolder(UGIServlet.class), "/bar");
+
+    try {
+      jetty.start();
+      final URL url = new URL(getJettyURL() + "/foo/bar");
+
+      UserGroupInformation ugi = UserGroupInformation.createRemoteUser(FOO_USER);
+      ugi.doAs(new PrivilegedExceptionAction<Void>() {
+        @Override
+        public Void run() throws Exception {
+          DelegationTokenAuthenticatedURL.Token token =
+              new DelegationTokenAuthenticatedURL.Token();
+          DelegationTokenAuthenticatedURL aUrl =
+              new DelegationTokenAuthenticatedURL();
+
+          // user foo
+          HttpURLConnection conn = aUrl.openConnection(url, token);
+          Assert.assertEquals(HttpURLConnection.HTTP_OK,
+              conn.getResponseCode());
+          List<String> ret = IOUtils.readLines(conn.getInputStream());
+          Assert.assertEquals(1, ret.size());
+          Assert.assertEquals("remoteuser=" + FOO_USER+ ":ugi=" + FOO_USER, 
+              ret.get(0));
+
+          // user ok-user via proxyuser foo
+          conn = aUrl.openConnection(url, token, OK_USER);
+          Assert.assertEquals(HttpURLConnection.HTTP_OK,
+              conn.getResponseCode());
+          ret = IOUtils.readLines(conn.getInputStream());
+          Assert.assertEquals(1, ret.size());
+          Assert.assertEquals("realugi=" + FOO_USER +":remoteuser=" + OK_USER + 
+                  ":ugi=" + OK_USER, ret.get(0));
+
+          return null;
+        }
+      });
+    } finally {
+      jetty.stop();
+    }
+  }
+
 }