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

git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/branches/branch-2@1617385 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Alejandro Abdelnur 2014-08-12 00:11:55 +00:00
parent afa125ccfd
commit ff6ef4a430
7 changed files with 421 additions and 22 deletions

View File

@ -127,6 +127,7 @@ public class AuthenticationFilter implements Filter {
public static final String SIGNATURE_PROVIDER_ATTRIBUTE = public static final String SIGNATURE_PROVIDER_ATTRIBUTE =
"org.apache.hadoop.security.authentication.util.SignerSecretProvider"; "org.apache.hadoop.security.authentication.util.SignerSecretProvider";
private Properties config;
private Signer signer; private Signer signer;
private SignerSecretProvider secretProvider; private SignerSecretProvider secretProvider;
private AuthenticationHandler authHandler; private AuthenticationHandler authHandler;
@ -150,7 +151,7 @@ public class AuthenticationFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException { public void init(FilterConfig filterConfig) throws ServletException {
String configPrefix = filterConfig.getInitParameter(CONFIG_PREFIX); String configPrefix = filterConfig.getInitParameter(CONFIG_PREFIX);
configPrefix = (configPrefix != null) ? configPrefix + "." : ""; configPrefix = (configPrefix != null) ? configPrefix + "." : "";
Properties config = getConfiguration(configPrefix, filterConfig); config = getConfiguration(configPrefix, filterConfig);
String authHandlerName = config.getProperty(AUTH_TYPE, null); String authHandlerName = config.getProperty(AUTH_TYPE, null);
String authHandlerClassName; String authHandlerClassName;
if (authHandlerName == null) { if (authHandlerName == null) {
@ -224,6 +225,17 @@ public class AuthenticationFilter implements Filter {
cookiePath = config.getProperty(COOKIE_PATH, null); 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. * Returns the authentication handler being used.
* *
@ -457,7 +469,7 @@ public class AuthenticationFilter implements Filter {
createAuthCookie(httpResponse, signedToken, getCookieDomain(), createAuthCookie(httpResponse, signedToken, getCookieDomain(),
getCookiePath(), token.getExpires(), isHttps); getCookiePath(), token.getExpires(), isHttps);
} }
filterChain.doFilter(httpRequest, httpResponse); doFilter(filterChain, httpRequest, httpResponse);
} }
} else { } else {
unauthorizedResponse = false; 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. * Creates the Hadoop authentication HTTP cookie.
* *

View File

@ -63,7 +63,11 @@ Release 2.6.0 - UNRELEASED
HADOOP-10791. AuthenticationFilter should support externalizing the HADOOP-10791. AuthenticationFilter should support externalizing the
secret for signing and provide rotation support. (rkanter via tucu) 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 OPTIMIZATIONS

View File

@ -34,6 +34,7 @@ import java.io.IOException;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.URL; import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -60,6 +61,13 @@ import java.util.Map;
@InterfaceStability.Unstable @InterfaceStability.Unstable
public class DelegationTokenAuthenticatedURL extends AuthenticatedURL { 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. * 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); url = augmentURL(url, extraParams);
return super.openConnection(url, token); return super.openConnection(url, token);
} }

View File

@ -17,17 +17,39 @@
*/ */
package org.apache.hadoop.security.token.delegation.web; 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.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability; 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.AuthenticationFilter;
import org.apache.hadoop.security.authentication.server.AuthenticationHandler; 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.KerberosAuthenticationHandler;
import org.apache.hadoop.security.authentication.server.PseudoAuthenticationHandler; 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.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.FilterConfig;
import javax.servlet.ServletContext; import javax.servlet.ServletContext;
import javax.servlet.ServletException; 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; import java.util.Properties;
/** /**
@ -49,6 +71,10 @@ import java.util.Properties;
public class DelegationTokenAuthenticationFilter public class DelegationTokenAuthenticationFilter
extends AuthenticationFilter { 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 * Sets an external <code>DelegationTokenSecretManager</code> instance to
* manage creation and verification of Delegation Tokens. * manage creation and verification of Delegation Tokens.
@ -60,6 +86,14 @@ public class DelegationTokenAuthenticationFilter
public static final String DELEGATION_TOKEN_SECRET_MANAGER_ATTR = public static final String DELEGATION_TOKEN_SECRET_MANAGER_ATTR =
"hadoop.http.delegation-token-secret-manager"; "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 * It delegates to
* {@link AuthenticationFilter#getConfiguration(String, FilterConfig)} and * {@link AuthenticationFilter#getConfiguration(String, FilterConfig)} and
@ -86,17 +120,155 @@ public class DelegationTokenAuthenticationFilter
return props; 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 @Override
public void init(FilterConfig filterConfig) throws ServletException { public void init(FilterConfig filterConfig) throws ServletException {
super.init(filterConfig); super.init(filterConfig);
AuthenticationHandler handler = getAuthenticationHandler();
AbstractDelegationTokenSecretManager dtSecretManager = AbstractDelegationTokenSecretManager dtSecretManager =
(AbstractDelegationTokenSecretManager) filterConfig.getServletContext(). (AbstractDelegationTokenSecretManager) filterConfig.getServletContext().
getAttribute(DELEGATION_TOKEN_SECRET_MANAGER_ATTR); getAttribute(DELEGATION_TOKEN_SECRET_MANAGER_ATTR);
if (dtSecretManager != null && getAuthenticationHandler() if (dtSecretManager != null && handler
instanceof DelegationTokenAuthenticationHandler) { instanceof DelegationTokenAuthenticationHandler) {
DelegationTokenAuthenticationHandler handler = DelegationTokenAuthenticationHandler dtHandler =
(DelegationTokenAuthenticationHandler) getAuthenticationHandler(); (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();
}
} }
} }
} }

View File

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

View File

@ -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();
}
}

View File

@ -72,6 +72,10 @@ import java.util.UUID;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
public class TestWebDelegationToken { 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; private Server jetty;
public static class DummyAuthenticationHandler public static class DummyAuthenticationHandler
@ -330,13 +334,13 @@ public class TestWebDelegationToken {
new DelegationTokenAuthenticatedURL(); new DelegationTokenAuthenticatedURL();
try { try {
aUrl.getDelegationToken(nonAuthURL, token, "foo"); aUrl.getDelegationToken(nonAuthURL, token, FOO_USER);
Assert.fail(); Assert.fail();
} catch (Exception ex) { } catch (Exception ex) {
Assert.assertTrue(ex.getMessage().contains("401")); Assert.assertTrue(ex.getMessage().contains("401"));
} }
aUrl.getDelegationToken(authURL, token, "foo"); aUrl.getDelegationToken(authURL, token, FOO_USER);
Assert.assertNotNull(token.getDelegationToken()); Assert.assertNotNull(token.getDelegationToken());
Assert.assertEquals(new Text("token-kind"), Assert.assertEquals(new Text("token-kind"),
token.getDelegationToken().getKind()); token.getDelegationToken().getKind());
@ -350,7 +354,7 @@ public class TestWebDelegationToken {
Assert.assertTrue(ex.getMessage().contains("401")); Assert.assertTrue(ex.getMessage().contains("401"));
} }
aUrl.getDelegationToken(authURL, token, "foo"); aUrl.getDelegationToken(authURL, token, FOO_USER);
try { try {
aUrl.renewDelegationToken(authURL2, token); aUrl.renewDelegationToken(authURL2, token);
@ -359,15 +363,15 @@ public class TestWebDelegationToken {
Assert.assertTrue(ex.getMessage().contains("403")); Assert.assertTrue(ex.getMessage().contains("403"));
} }
aUrl.getDelegationToken(authURL, token, "foo"); aUrl.getDelegationToken(authURL, token, FOO_USER);
aUrl.cancelDelegationToken(authURL, token); aUrl.cancelDelegationToken(authURL, token);
aUrl.getDelegationToken(authURL, token, "foo"); aUrl.getDelegationToken(authURL, token, FOO_USER);
aUrl.cancelDelegationToken(nonAuthURL, token); aUrl.cancelDelegationToken(nonAuthURL, token);
aUrl.getDelegationToken(authURL, token, "foo"); aUrl.getDelegationToken(authURL, token, FOO_USER);
try { try {
aUrl.renewDelegationToken(nonAuthURL, token); aUrl.renewDelegationToken(nonAuthURL, token);
@ -416,7 +420,7 @@ public class TestWebDelegationToken {
DelegationTokenAuthenticatedURL aUrl = DelegationTokenAuthenticatedURL aUrl =
new DelegationTokenAuthenticatedURL(); new DelegationTokenAuthenticatedURL();
aUrl.getDelegationToken(authURL, token, "foo"); aUrl.getDelegationToken(authURL, token, FOO_USER);
Assert.assertNotNull(token.getDelegationToken()); Assert.assertNotNull(token.getDelegationToken());
Assert.assertEquals(new Text("fooKind"), Assert.assertEquals(new Text("fooKind"),
token.getDelegationToken().getKind()); token.getDelegationToken().getKind());
@ -488,7 +492,7 @@ public class TestWebDelegationToken {
jetty.start(); jetty.start();
final URL url = new URL(getJettyURL() + "/foo/bar"); final URL url = new URL(getJettyURL() + "/foo/bar");
UserGroupInformation ugi = UserGroupInformation.createRemoteUser("foo"); UserGroupInformation ugi = UserGroupInformation.createRemoteUser(FOO_USER);
ugi.doAs(new PrivilegedExceptionAction<Void>() { ugi.doAs(new PrivilegedExceptionAction<Void>() {
@Override @Override
public Void run() throws Exception { public Void run() throws Exception {
@ -501,10 +505,10 @@ public class TestWebDelegationToken {
conn.getResponseCode()); conn.getResponseCode());
List<String> ret = IOUtils.readLines(conn.getInputStream()); List<String> ret = IOUtils.readLines(conn.getInputStream());
Assert.assertEquals(1, ret.size()); Assert.assertEquals(1, ret.size());
Assert.assertEquals("foo", ret.get(0)); Assert.assertEquals(FOO_USER, ret.get(0));
try { try {
aUrl.getDelegationToken(url, token, "foo"); aUrl.getDelegationToken(url, token, FOO_USER);
Assert.fail(); Assert.fail();
} catch (AuthenticationException ex) { } catch (AuthenticationException ex) {
Assert.assertTrue(ex.getMessage().contains( Assert.assertTrue(ex.getMessage().contains(
@ -531,6 +535,16 @@ public class TestWebDelegationToken {
"token-kind"); "token-kind");
return conf; 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 @Test
@ -547,7 +561,7 @@ public class TestWebDelegationToken {
jetty.start(); jetty.start();
final URL url = new URL(getJettyURL() + "/foo/bar"); final URL url = new URL(getJettyURL() + "/foo/bar");
UserGroupInformation ugi = UserGroupInformation.createRemoteUser("foo"); UserGroupInformation ugi = UserGroupInformation.createRemoteUser(FOO_USER);
ugi.doAs(new PrivilegedExceptionAction<Void>() { ugi.doAs(new PrivilegedExceptionAction<Void>() {
@Override @Override
public Void run() throws Exception { public Void run() throws Exception {
@ -560,9 +574,9 @@ public class TestWebDelegationToken {
conn.getResponseCode()); conn.getResponseCode());
List<String> ret = IOUtils.readLines(conn.getInputStream()); List<String> ret = IOUtils.readLines(conn.getInputStream());
Assert.assertEquals(1, ret.size()); 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.assertNotNull(token.getDelegationToken());
Assert.assertEquals(new Text("token-kind"), Assert.assertEquals(new Text("token-kind"),
token.getDelegationToken().getKind()); token.getDelegationToken().getKind());
@ -684,7 +698,7 @@ public class TestWebDelegationToken {
final URL url = new URL(getJettyURL() + "/foo/bar"); final URL url = new URL(getJettyURL() + "/foo/bar");
try { try {
aUrl.getDelegationToken(url, token, "foo"); aUrl.getDelegationToken(url, token, FOO_USER);
Assert.fail(); Assert.fail();
} catch (AuthenticationException ex) { } catch (AuthenticationException ex) {
Assert.assertTrue(ex.getMessage().contains("GSSException")); Assert.assertTrue(ex.getMessage().contains("GSSException"));
@ -700,7 +714,7 @@ public class TestWebDelegationToken {
aUrl.renewDelegationToken(url, token); aUrl.renewDelegationToken(url, token);
Assert.assertNotNull(token.getDelegationToken()); Assert.assertNotNull(token.getDelegationToken());
aUrl.getDelegationToken(url, token, "foo"); aUrl.getDelegationToken(url, token, FOO_USER);
Assert.assertNotNull(token.getDelegationToken()); Assert.assertNotNull(token.getDelegationToken());
try { try {
@ -710,7 +724,7 @@ public class TestWebDelegationToken {
Assert.assertTrue(ex.getMessage().contains("403")); Assert.assertTrue(ex.getMessage().contains("403"));
} }
aUrl.getDelegationToken(url, token, "foo"); aUrl.getDelegationToken(url, token, FOO_USER);
aUrl.cancelDelegationToken(url, token); aUrl.cancelDelegationToken(url, token);
Assert.assertNull(token.getDelegationToken()); 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();
}
}
} }