HADOOP-16527. Add a whitelist of endpoints to skip Kerberos authentication (#1336) Contributed by Akira Ajisaka.
This commit is contained in:
parent
5d31a4eff7
commit
55cc115878
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue