From 7d2070493e07198896bc49135bc84ef00499a375 Mon Sep 17 00:00:00 2001 From: Andrew Wang Date: Mon, 27 Jun 2016 18:46:33 -0700 Subject: [PATCH] HADOOP-13316. Enforce Kerberos authentication for required ops in DelegationTokenAuthenticator. Contributed by Xiao Chen. --- .../DelegationTokenAuthenticationHandler.java | 3 +- ...onTokenAuthenticationHandlerWithMocks.java | 102 +++++++++++++++++- 2 files changed, 103 insertions(+), 2 deletions(-) diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/token/delegation/web/DelegationTokenAuthenticationHandler.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/token/delegation/web/DelegationTokenAuthenticationHandler.java index 3f191de2fb..50c3eb585e 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/token/delegation/web/DelegationTokenAuthenticationHandler.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/token/delegation/web/DelegationTokenAuthenticationHandler.java @@ -179,7 +179,8 @@ public boolean managementOperation(AuthenticationToken token, if (dtOp.getHttpMethod().equals(request.getMethod())) { boolean doManagement; if (dtOp.requiresKerberosCredentials() && token == null) { - token = authenticate(request, response); + // Don't authenticate via DT for DT ops. + token = authHandler.authenticate(request, response); if (token == null) { requestContinues = false; doManagement = false; diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/token/delegation/web/TestDelegationTokenAuthenticationHandlerWithMocks.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/token/delegation/web/TestDelegationTokenAuthenticationHandlerWithMocks.java index 600078964e..d9c4f0239c 100644 --- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/token/delegation/web/TestDelegationTokenAuthenticationHandlerWithMocks.java +++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/token/delegation/web/TestDelegationTokenAuthenticationHandlerWithMocks.java @@ -25,12 +25,13 @@ import org.apache.hadoop.security.authentication.server.AuthenticationToken; import org.apache.hadoop.security.token.SecretManager; import org.apache.hadoop.security.token.Token; -import org.apache.hadoop.util.HttpExceptionUtils; import org.codehaus.jackson.map.ObjectMapper; import org.junit.After; import org.junit.Assert; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.Timeout; import org.mockito.Mockito; import javax.servlet.ServletException; @@ -87,6 +88,9 @@ public AuthenticationToken authenticate(HttpServletRequest request, private DelegationTokenAuthenticationHandler handler; + @Rule + public Timeout testTimeout = new Timeout(120000); + @Before public void setUp() throws Exception { Properties conf = new Properties(); @@ -358,4 +362,100 @@ private void testInvalidDelegationTokenHeader() throws Exception { Assert.assertTrue(writer.toString().contains("AuthenticationException")); } + private String getToken() throws Exception { + DelegationTokenAuthenticator.DelegationTokenOperation op = + DelegationTokenAuthenticator.DelegationTokenOperation. + GETDELEGATIONTOKEN; + HttpServletRequest request = Mockito.mock(HttpServletRequest.class); + HttpServletResponse response = Mockito.mock(HttpServletResponse.class); + Mockito.when(request.getQueryString()). + thenReturn(DelegationTokenAuthenticator.OP_PARAM + "=" + op.toString()); + Mockito.when(request.getMethod()).thenReturn(op.getHttpMethod()); + + AuthenticationToken token = Mockito.mock(AuthenticationToken.class); + Mockito.when(token.getUserName()).thenReturn("user"); + Mockito.when(response.getWriter()).thenReturn(new PrintWriter( + new StringWriter())); + Assert.assertFalse(handler.managementOperation(token, request, response)); + + Mockito.when(request.getQueryString()). + thenReturn(DelegationTokenAuthenticator.OP_PARAM + "=" + op.toString() + + "&" + DelegationTokenAuthenticator.RENEWER_PARAM + "=" + null); + + Mockito.reset(response); + Mockito.reset(token); + Mockito.when(token.getUserName()).thenReturn("user"); + StringWriter writer = new StringWriter(); + PrintWriter pwriter = new PrintWriter(writer); + Mockito.when(response.getWriter()).thenReturn(pwriter); + Assert.assertFalse(handler.managementOperation(token, request, response)); + Mockito.verify(token).getUserName(); + Mockito.verify(response).setStatus(HttpServletResponse.SC_OK); + Mockito.verify(response).setContentType(MediaType.APPLICATION_JSON); + pwriter.close(); + String responseOutput = writer.toString(); + String tokenLabel = DelegationTokenAuthenticator. + DELEGATION_TOKEN_JSON; + Assert.assertTrue(responseOutput.contains(tokenLabel)); + Assert.assertTrue(responseOutput.contains( + DelegationTokenAuthenticator.DELEGATION_TOKEN_URL_STRING_JSON)); + ObjectMapper jsonMapper = new ObjectMapper(); + Map json = jsonMapper.readValue(responseOutput, Map.class); + json = (Map) json.get(tokenLabel); + String tokenStr; + tokenStr = (String) json.get(DelegationTokenAuthenticator. + DELEGATION_TOKEN_URL_STRING_JSON); + Token dt = new Token(); + dt.decodeFromUrlString(tokenStr); + handler.getTokenManager().verifyToken(dt); + return tokenStr; + } + + @Test + public void testCannotGetTokenUsingToken() throws Exception { + DelegationTokenAuthenticator.DelegationTokenOperation op = + DelegationTokenAuthenticator.DelegationTokenOperation. + GETDELEGATIONTOKEN; + HttpServletRequest request = Mockito.mock(HttpServletRequest.class); + Mockito.when(request.getMethod()).thenReturn(op.getHttpMethod()); + HttpServletResponse response = Mockito.mock(HttpServletResponse.class); + Mockito.when(response.getWriter()).thenReturn(new PrintWriter( + new StringWriter())); + String tokenStr = getToken(); + // Try get a new token using the fetched token, should get 401. + Mockito.when(request.getQueryString()). + thenReturn(DelegationTokenAuthenticator.OP_PARAM + "=" + op.toString() + + "&" + DelegationTokenAuthenticator.RENEWER_PARAM + "=" + null + + "&" + DelegationTokenAuthenticator.DELEGATION_PARAM + "=" + tokenStr); + Mockito.reset(response); + StringWriter writer = new StringWriter(); + PrintWriter pwriter = new PrintWriter(writer); + Mockito.when(response.getWriter()).thenReturn(pwriter); + Assert.assertFalse(handler.managementOperation(null, request, response)); + Mockito.verify(response).setStatus(HttpServletResponse.SC_UNAUTHORIZED); + } + + @Test + public void testCannotRenewTokenUsingToken() throws Exception { + DelegationTokenAuthenticator.DelegationTokenOperation op = + DelegationTokenAuthenticator.DelegationTokenOperation. + RENEWDELEGATIONTOKEN; + HttpServletRequest request = Mockito.mock(HttpServletRequest.class); + Mockito.when(request.getMethod()).thenReturn(op.getHttpMethod()); + HttpServletResponse response = Mockito.mock(HttpServletResponse.class); + Mockito.when(response.getWriter()).thenReturn(new PrintWriter( + new StringWriter())); + String tokenStr = getToken(); + // Try renew a token using itself, should get 401. + Mockito.when(request.getQueryString()). + thenReturn(DelegationTokenAuthenticator.OP_PARAM + "=" + op.toString() + + "&" + DelegationTokenAuthenticator.TOKEN_PARAM + "=" + tokenStr + + "&" + DelegationTokenAuthenticator.DELEGATION_PARAM + "=" + tokenStr); + Mockito.reset(response); + StringWriter writer = new StringWriter(); + PrintWriter pwriter = new PrintWriter(writer); + Mockito.when(response.getWriter()).thenReturn(pwriter); + Assert.assertFalse(handler.managementOperation(null, request, response)); + Mockito.verify(response).setStatus(HttpServletResponse.SC_UNAUTHORIZED); + } }