HADOOP-13346. DelegationTokenAuthenticationHandler writes via closed writer. Contributed by Gregory Chanan and Hrishikesh Gadre.
This commit is contained in:
parent
c619e9b43f
commit
822ae88f7d
|
@ -48,6 +48,8 @@ import org.apache.hadoop.security.token.delegation.AbstractDelegationTokenIdenti
|
||||||
import org.apache.hadoop.security.token.delegation.AbstractDelegationTokenSecretManager;
|
import org.apache.hadoop.security.token.delegation.AbstractDelegationTokenSecretManager;
|
||||||
import org.apache.hadoop.util.HttpExceptionUtils;
|
import org.apache.hadoop.util.HttpExceptionUtils;
|
||||||
import org.apache.hadoop.util.StringUtils;
|
import org.apache.hadoop.util.StringUtils;
|
||||||
|
import org.codehaus.jackson.JsonFactory;
|
||||||
|
import org.codehaus.jackson.JsonGenerator;
|
||||||
import org.codehaus.jackson.map.ObjectMapper;
|
import org.codehaus.jackson.map.ObjectMapper;
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
@ -89,6 +91,8 @@ public abstract class DelegationTokenAuthenticationHandler
|
||||||
public static final String DELEGATION_TOKEN_UGI_ATTRIBUTE =
|
public static final String DELEGATION_TOKEN_UGI_ATTRIBUTE =
|
||||||
"hadoop.security.delegation-token.ugi";
|
"hadoop.security.delegation-token.ugi";
|
||||||
|
|
||||||
|
public static final String JSON_MAPPER_PREFIX = PREFIX + "json-mapper.";
|
||||||
|
|
||||||
static {
|
static {
|
||||||
DELEGATION_TOKEN_OPS.add(KerberosDelegationTokenAuthenticator.
|
DELEGATION_TOKEN_OPS.add(KerberosDelegationTokenAuthenticator.
|
||||||
DelegationTokenOperation.GETDELEGATIONTOKEN.toString());
|
DelegationTokenOperation.GETDELEGATIONTOKEN.toString());
|
||||||
|
@ -101,6 +105,7 @@ public abstract class DelegationTokenAuthenticationHandler
|
||||||
private AuthenticationHandler authHandler;
|
private AuthenticationHandler authHandler;
|
||||||
private DelegationTokenManager tokenManager;
|
private DelegationTokenManager tokenManager;
|
||||||
private String authType;
|
private String authType;
|
||||||
|
private JsonFactory jsonFactory;
|
||||||
|
|
||||||
public DelegationTokenAuthenticationHandler(AuthenticationHandler handler) {
|
public DelegationTokenAuthenticationHandler(AuthenticationHandler handler) {
|
||||||
authHandler = handler;
|
authHandler = handler;
|
||||||
|
@ -120,6 +125,7 @@ public abstract class DelegationTokenAuthenticationHandler
|
||||||
public void init(Properties config) throws ServletException {
|
public void init(Properties config) throws ServletException {
|
||||||
authHandler.init(config);
|
authHandler.init(config);
|
||||||
initTokenManager(config);
|
initTokenManager(config);
|
||||||
|
initJsonFactory(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -153,6 +159,30 @@ public abstract class DelegationTokenAuthenticationHandler
|
||||||
tokenManager.init();
|
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
|
@Override
|
||||||
public void destroy() {
|
public void destroy() {
|
||||||
tokenManager.destroy();
|
tokenManager.destroy();
|
||||||
|
@ -298,7 +328,7 @@ public abstract class DelegationTokenAuthenticationHandler
|
||||||
if (map != null) {
|
if (map != null) {
|
||||||
response.setContentType(MediaType.APPLICATION_JSON);
|
response.setContentType(MediaType.APPLICATION_JSON);
|
||||||
Writer writer = response.getWriter();
|
Writer writer = response.getWriter();
|
||||||
ObjectMapper jsonMapper = new ObjectMapper();
|
ObjectMapper jsonMapper = new ObjectMapper(jsonFactory);
|
||||||
jsonMapper.writeValue(writer, map);
|
jsonMapper.writeValue(writer, map);
|
||||||
writer.write(ENTER);
|
writer.write(ENTER);
|
||||||
writer.flush();
|
writer.flush();
|
||||||
|
|
|
@ -17,6 +17,9 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.hadoop.security.token.delegation.web;
|
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.io.Text;
|
||||||
import org.apache.hadoop.security.UserGroupInformation;
|
import org.apache.hadoop.security.UserGroupInformation;
|
||||||
import org.apache.hadoop.security.authentication.client.AuthenticationException;
|
import org.apache.hadoop.security.authentication.client.AuthenticationException;
|
||||||
|
@ -458,4 +461,51 @@ public class TestDelegationTokenAuthenticationHandlerWithMocks {
|
||||||
Assert.assertFalse(handler.managementOperation(null, request, response));
|
Assert.assertFalse(handler.managementOperation(null, request, response));
|
||||||
Mockito.verify(response).setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue