HADOOP-16527. Add a whitelist of endpoints to skip Kerberos authentication (#1336) Contributed by Akira Ajisaka.

This commit is contained in:
Akira Ajisaka 2019-08-28 14:28:41 +09:00 committed by Takanobu Asanuma
parent 5d31a4eff7
commit 55cc115878
3 changed files with 74 additions and 0 deletions

View File

@ -13,6 +13,7 @@
*/
package org.apache.hadoop.security.authentication.server;
import com.google.common.annotations.VisibleForTesting;
import org.apache.hadoop.security.authentication.client.AuthenticationException;
import org.apache.hadoop.security.authentication.client.KerberosAuthenticator;
import org.apache.commons.codec.binary.Base64;
@ -38,6 +39,8 @@ import java.io.IOException;
import java.security.Principal;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.Collection;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Pattern;
@ -94,10 +97,18 @@ public class KerberosAuthenticationHandler implements AuthenticationHandler {
*/
public static final String RULE_MECHANISM = TYPE + ".name.rules.mechanism";
/**
* Constant for the list of endpoints that skips Kerberos authentication.
*/
@VisibleForTesting
static final String ENDPOINT_WHITELIST = TYPE + ".endpoint.whitelist";
private static final Pattern ENDPOINT_PATTERN = Pattern.compile("^/[\\w]+");
private String type;
private String keytab;
private GSSManager gssManager;
private Subject serverSubject = new Subject();
private final Collection<String> whitelist = new HashSet<>();
/**
* Creates a Kerberos SPNEGO authentication handler with the default
@ -173,6 +184,22 @@ public class KerberosAuthenticationHandler implements AuthenticationHandler {
if (ruleMechanism != null) {
KerberosName.setRuleMechanism(ruleMechanism);
}
final String whitelistStr = config.getProperty(ENDPOINT_WHITELIST, null);
if (whitelistStr != null) {
final String[] strs = whitelistStr.trim().split("\\s*[,\n]\\s*");
for (String s: strs) {
if (s.isEmpty()) continue;
if (ENDPOINT_PATTERN.matcher(s).matches()) {
whitelist.add(s);
} else {
throw new ServletException(
"The element of the whitelist: " + s + " must start with '/'"
+ " and must not contain special characters afterwards");
}
}
}
try {
gssManager = Subject.doAs(serverSubject,
new PrivilegedExceptionAction<GSSManager>() {
@ -269,6 +296,16 @@ public class KerberosAuthenticationHandler implements AuthenticationHandler {
public AuthenticationToken authenticate(HttpServletRequest request,
final HttpServletResponse response)
throws IOException, AuthenticationException {
// If the request servlet path is in the whitelist,
// skip Kerberos authentication and return anonymous token.
final String path = request.getServletPath();
for(final String endpoint: whitelist) {
if (endpoint.equals(path)) {
return AuthenticationToken.ANONYMOUS;
}
}
AuthenticationToken token = null;
String authorization = request.getHeader(
KerberosAuthenticator.AUTHORIZATION);

View File

@ -89,6 +89,9 @@ public class TestKerberosAuthenticationHandler
// handler
handler = getNewAuthenticationHandler();
Properties props = getDefaultProperties();
// Set whitelist for testing
props.setProperty(KerberosAuthenticationHandler.ENDPOINT_WHITELIST,
"/white,/white2,/white3");
try {
handler.init(props);
} catch (Exception ex) {
@ -371,6 +374,27 @@ public class TestKerberosAuthenticationHandler
}
}
@Test
public void testRequestToWhitelist() throws Exception {
final String token = new Base64(0).encodeToString(new byte[]{0, 1, 2});
final HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
final HttpServletResponse response =
Mockito.mock(HttpServletResponse.class);
Mockito.when(request.getHeader(KerberosAuthenticator.AUTHORIZATION))
.thenReturn(KerberosAuthenticator.NEGOTIATE + token);
Mockito.when(request.getServletPath()).thenReturn("/white");
handler.authenticate(request, response);
Mockito.when(request.getServletPath()).thenReturn("/white4");
try {
handler.authenticate(request, response);
Assert.fail();
} catch (AuthenticationException ex) {
// Expected
} catch (Exception ex) {
Assert.fail();
}
}
@After
public void tearDown() throws Exception {
if (handler != null) {

View File

@ -2495,6 +2495,19 @@
</description>
</property>
<property>
<name>hadoop.http.authentication.kerberos.endpoint.whitelist</name>
<value></value>
<description>
The comma-separated list of the endpoints that skips Kerberos
authentication. The endpoint must start with '/' and must not
contain special characters afterwards. This parameter is for
the monitoring tools that do not support Kerberos authentication.
Administrator must configure this parameter very carefully
because it allows unauthenticated access to the daemons.
</description>
</property>
<!-- HTTP CORS support -->
<property>
<name>hadoop.http.cross-origin.enabled</name>