|
13 | 13 | */
|
14 | 14 | package org.apache.hadoop.security.authentication.server;
|
15 | 15 |
|
| 16 | +import com.google.common.annotations.VisibleForTesting; |
16 | 17 | import org.apache.hadoop.security.authentication.client.AuthenticationException;
|
17 | 18 | import org.apache.hadoop.security.authentication.client.KerberosAuthenticator;
|
18 | 19 | import org.apache.commons.codec.binary.Base64;
|
|
38 | 39 | import java.security.Principal;
|
39 | 40 | import java.security.PrivilegedActionException;
|
40 | 41 | import java.security.PrivilegedExceptionAction;
|
| 42 | +import java.util.Collection; |
| 43 | +import java.util.HashSet; |
41 | 44 | import java.util.Properties;
|
42 | 45 | import java.util.Set;
|
43 | 46 | import java.util.regex.Pattern;
|
@@ -94,10 +97,18 @@ public class KerberosAuthenticationHandler implements AuthenticationHandler {
|
94 | 97 | */
|
95 | 98 | public static final String RULE_MECHANISM = TYPE + ".name.rules.mechanism";
|
96 | 99 |
|
| 100 | + /** |
| 101 | + * Constant for the list of endpoints that skips Kerberos authentication. |
| 102 | + */ |
| 103 | + @VisibleForTesting |
| 104 | + static final String ENDPOINT_WHITELIST = TYPE + ".endpoint.whitelist"; |
| 105 | + private static final Pattern ENDPOINT_PATTERN = Pattern.compile("^/[\\w]+"); |
| 106 | + |
97 | 107 | private String type;
|
98 | 108 | private String keytab;
|
99 | 109 | private GSSManager gssManager;
|
100 | 110 | private Subject serverSubject = new Subject();
|
| 111 | + private final Collection<String> whitelist = new HashSet<>(); |
101 | 112 |
|
102 | 113 | /**
|
103 | 114 | * Creates a Kerberos SPNEGO authentication handler with the default
|
@@ -173,6 +184,22 @@ public void init(Properties config) throws ServletException {
|
173 | 184 | if (ruleMechanism != null) {
|
174 | 185 | KerberosName.setRuleMechanism(ruleMechanism);
|
175 | 186 | }
|
| 187 | + |
| 188 | + final String whitelistStr = config.getProperty(ENDPOINT_WHITELIST, null); |
| 189 | + if (whitelistStr != null) { |
| 190 | + final String[] strs = whitelistStr.trim().split("\\s*[,\n]\\s*"); |
| 191 | + for (String s: strs) { |
| 192 | + if (s.isEmpty()) continue; |
| 193 | + if (ENDPOINT_PATTERN.matcher(s).matches()) { |
| 194 | + whitelist.add(s); |
| 195 | + } else { |
| 196 | + throw new ServletException( |
| 197 | + "The element of the whitelist: " + s + " must start with '/'" |
| 198 | + + " and must not contain special characters afterwards"); |
| 199 | + } |
| 200 | + } |
| 201 | + } |
| 202 | + |
176 | 203 | try {
|
177 | 204 | gssManager = Subject.doAs(serverSubject,
|
178 | 205 | new PrivilegedExceptionAction<GSSManager>() {
|
@@ -269,6 +296,16 @@ public boolean managementOperation(AuthenticationToken token,
|
269 | 296 | public AuthenticationToken authenticate(HttpServletRequest request,
|
270 | 297 | final HttpServletResponse response)
|
271 | 298 | throws IOException, AuthenticationException {
|
| 299 | + |
| 300 | + // If the request servlet path is in the whitelist, |
| 301 | + // skip Kerberos authentication and return anonymous token. |
| 302 | + final String path = request.getServletPath(); |
| 303 | + for(final String endpoint: whitelist) { |
| 304 | + if (endpoint.equals(path)) { |
| 305 | + return AuthenticationToken.ANONYMOUS; |
| 306 | + } |
| 307 | + } |
| 308 | + |
272 | 309 | AuthenticationToken token = null;
|
273 | 310 | String authorization = request.getHeader(
|
274 | 311 | KerberosAuthenticator.AUTHORIZATION);
|
|
0 commit comments