From 298b9168e6c309efe1db83b16f12143ae6a99077 Mon Sep 17 00:00:00 2001 From: Akira Ajisaka Date: Wed, 28 Aug 2019 14:28:41 +0900 Subject: [PATCH] HADOOP-16527. Add a whitelist of endpoints to skip Kerberos authentication (#1336) Contributed by Akira Ajisaka. --- .../server/KerberosAuthenticationHandler.java | 37 +++++++++++++++++++ .../TestKerberosAuthenticationHandler.java | 24 ++++++++++++ .../src/main/resources/core-default.xml | 13 +++++++ 3 files changed, 74 insertions(+) diff --git a/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/KerberosAuthenticationHandler.java b/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/KerberosAuthenticationHandler.java index 7a918b20bb606..50eeb2a965e27 100644 --- a/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/KerberosAuthenticationHandler.java +++ b/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/KerberosAuthenticationHandler.java @@ -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.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 whitelist = new HashSet<>(); /** * Creates a Kerberos SPNEGO authentication handler with the default @@ -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() { @@ -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); diff --git a/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/server/TestKerberosAuthenticationHandler.java b/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/server/TestKerberosAuthenticationHandler.java index bef3018ca4a70..629b68bffbbd9 100644 --- a/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/server/TestKerberosAuthenticationHandler.java +++ b/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/server/TestKerberosAuthenticationHandler.java @@ -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) { @@ -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) { diff --git a/hadoop-common-project/hadoop-common/src/main/resources/core-default.xml b/hadoop-common-project/hadoop-common/src/main/resources/core-default.xml index 2b78ede7568b1..7ed3e8a32dac6 100644 --- a/hadoop-common-project/hadoop-common/src/main/resources/core-default.xml +++ b/hadoop-common-project/hadoop-common/src/main/resources/core-default.xml @@ -2495,6 +2495,19 @@ + + hadoop.http.authentication.kerberos.endpoint.whitelist + + + 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. + + + hadoop.http.cross-origin.enabled