From 822ae88f7da638e15a25747f6965caee8198aca6 Mon Sep 17 00:00:00 2001 From: Xiao Chen Date: Wed, 9 Nov 2016 09:32:15 -0800 Subject: [PATCH] HADOOP-13346. DelegationTokenAuthenticationHandler writes via closed writer. Contributed by Gregory Chanan and Hrishikesh Gadre. --- .../DelegationTokenAuthenticationHandler.java | 32 +++++++++++- ...onTokenAuthenticationHandlerWithMocks.java | 50 +++++++++++++++++++ 2 files changed, 81 insertions(+), 1 deletion(-) 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 c23a94f078..315c9d6994 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 @@ -48,6 +48,8 @@ import org.apache.hadoop.security.token.delegation.AbstractDelegationTokenSecretManager; import org.apache.hadoop.util.HttpExceptionUtils; import org.apache.hadoop.util.StringUtils; +import org.codehaus.jackson.JsonFactory; +import org.codehaus.jackson.JsonGenerator; import org.codehaus.jackson.map.ObjectMapper; import com.google.common.annotations.VisibleForTesting; @@ -89,6 +91,8 @@ public abstract class DelegationTokenAuthenticationHandler public static final String DELEGATION_TOKEN_UGI_ATTRIBUTE = "hadoop.security.delegation-token.ugi"; + public static final String JSON_MAPPER_PREFIX = PREFIX + "json-mapper."; + static { DELEGATION_TOKEN_OPS.add(KerberosDelegationTokenAuthenticator. DelegationTokenOperation.GETDELEGATIONTOKEN.toString()); @@ -101,6 +105,7 @@ public abstract class DelegationTokenAuthenticationHandler private AuthenticationHandler authHandler; private DelegationTokenManager tokenManager; private String authType; + private JsonFactory jsonFactory; public DelegationTokenAuthenticationHandler(AuthenticationHandler handler) { authHandler = handler; @@ -120,6 +125,7 @@ AuthenticationHandler getAuthHandler() { public void init(Properties config) throws ServletException { authHandler.init(config); initTokenManager(config); + initJsonFactory(config); } /** @@ -153,6 +159,30 @@ public void initTokenManager(Properties config) { tokenManager.init(); } + @VisibleForTesting + public void initJsonFactory(Properties config) { + boolean hasFeature = false; + JsonFactory tmpJsonFactory = new JsonFactory(); + + for (Map.Entry entry : config.entrySet()) { + String key = (String)entry.getKey(); + if (key.startsWith(JSON_MAPPER_PREFIX)) { + JsonGenerator.Feature feature = + JsonGenerator.Feature.valueOf(key.substring(JSON_MAPPER_PREFIX + .length())); + if (feature != null) { + hasFeature = true; + boolean enabled = Boolean.parseBoolean((String)entry.getValue()); + tmpJsonFactory.configure(feature, enabled); + } + } + } + + if (hasFeature) { + jsonFactory = tmpJsonFactory; + } + } + @Override public void destroy() { tokenManager.destroy(); @@ -298,7 +328,7 @@ public boolean managementOperation(AuthenticationToken token, if (map != null) { response.setContentType(MediaType.APPLICATION_JSON); Writer writer = response.getWriter(); - ObjectMapper jsonMapper = new ObjectMapper(); + ObjectMapper jsonMapper = new ObjectMapper(jsonFactory); jsonMapper.writeValue(writer, map); writer.write(ENTER); writer.flush(); 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 d9c4f0239c..361d7fdb00 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 @@ -17,6 +17,9 @@ */ package org.apache.hadoop.security.token.delegation.web; +import static org.apache.hadoop.security.token.delegation.web.DelegationTokenAuthenticator.DelegationTokenOperation.*; + +import org.apache.commons.lang.mutable.MutableBoolean; import org.apache.hadoop.io.Text; import org.apache.hadoop.security.UserGroupInformation; import org.apache.hadoop.security.authentication.client.AuthenticationException; @@ -458,4 +461,51 @@ public void testCannotRenewTokenUsingToken() throws Exception { Assert.assertFalse(handler.managementOperation(null, request, response)); Mockito.verify(response).setStatus(HttpServletResponse.SC_UNAUTHORIZED); } + + @Test + public void testWriterNotClosed() throws Exception { + Properties conf = new Properties(); + conf.put(KerberosDelegationTokenAuthenticationHandler.TOKEN_KIND, "foo"); + conf.put(DelegationTokenAuthenticationHandler.JSON_MAPPER_PREFIX + + "AUTO_CLOSE_TARGET", "false"); + DelegationTokenAuthenticationHandler noAuthCloseHandler = + new MockDelegationTokenAuthenticationHandler(); + try { + noAuthCloseHandler.initTokenManager(conf); + noAuthCloseHandler.initJsonFactory(conf); + + DelegationTokenAuthenticator.DelegationTokenOperation op = + 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"); + final MutableBoolean closed = new MutableBoolean(); + PrintWriter printWriterCloseCount = new PrintWriter(new StringWriter()) { + @Override + public void close() { + closed.setValue(true); + super.close(); + } + + @Override + public void write(String str) { + if (closed.booleanValue()) { + throw new RuntimeException("already closed!"); + } + super.write(str); + } + + }; + Mockito.when(response.getWriter()).thenReturn(printWriterCloseCount); + Assert.assertFalse(noAuthCloseHandler.managementOperation(token, request, + response)); + } finally { + noAuthCloseHandler.destroy(); + } + } }