Skip to content

Commit

Permalink
HADOOP-16527. Add a whitelist of endpoints to skip Kerberos authentic…
Browse files Browse the repository at this point in the history
…ation (#1336) Contributed by Akira Ajisaka.
  • Loading branch information
aajisaka authored and tasanuma committed Aug 28, 2019
1 parent 5d31a4e commit 55cc115
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -38,6 +39,8 @@
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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -173,6 +184,22 @@ public void init(Properties config) throws ServletException {
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>() {
Expand Down Expand Up @@ -269,6 +296,16 @@ public boolean managementOperation(AuthenticationToken token,
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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ public void setup() throws Exception {
// 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) {
Expand Down Expand Up @@ -371,6 +374,27 @@ public void testRequestWithInvalidKerberosAuthorization() {
}
}

@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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down

0 comments on commit 55cc115

Please sign in to comment.