You are viewing a plain text version of this content. The canonical link for it is here.
Posted to common-commits@hadoop.apache.org by qu...@apache.org on 2022/05/20 08:49:07 UTC
[hadoop] branch trunk updated: HADOOP-18120. Hadoop auth does not handle HTTP Headers in a case-insensitive way. Contributed by Janos Makai.
This is an automated email from the ASF dual-hosted git repository.
quapaw pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/hadoop.git
The following commit(s) were added to refs/heads/trunk by this push:
new 0773fae3929 HADOOP-18120. Hadoop auth does not handle HTTP Headers in a case-insensitive way. Contributed by Janos Makai.
0773fae3929 is described below
commit 0773fae3929ddfe91329928c97ee908e4e0da2fa
Author: 9uapaw <gy...@gmail.com>
AuthorDate: Fri May 20 10:08:19 2022 +0200
HADOOP-18120. Hadoop auth does not handle HTTP Headers in a case-insensitive way. Contributed by Janos Makai.
---
.../examples/RequestLoggerFilter.java | 1 +
.../authentication/client/AuthenticatedURL.java | 3 +
.../client/KerberosAuthenticator.java | 6 ++
.../server/AuthenticationFilter.java | 4 +-
.../client/TestAuthenticatedURL.java | 38 ++++++++++
.../client/TestKerberosAuthenticator.java | 82 ++++++++++++++++++++++
.../server/TestAuthenticationFilter.java | 38 ++++++++++
7 files changed, 171 insertions(+), 1 deletion(-)
diff --git a/hadoop-common-project/hadoop-auth-examples/src/main/java/org/apache/hadoop/security/authentication/examples/RequestLoggerFilter.java b/hadoop-common-project/hadoop-auth-examples/src/main/java/org/apache/hadoop/security/authentication/examples/RequestLoggerFilter.java
index 80489917e08..e96e5062919 100644
--- a/hadoop-common-project/hadoop-auth-examples/src/main/java/org/apache/hadoop/security/authentication/examples/RequestLoggerFilter.java
+++ b/hadoop-common-project/hadoop-auth-examples/src/main/java/org/apache/hadoop/security/authentication/examples/RequestLoggerFilter.java
@@ -116,6 +116,7 @@ public class RequestLoggerFilter implements Filter {
public void addCookie(Cookie cookie) {
super.addCookie(cookie);
List<String> cookies = getHeaderValues("Set-Cookie", false);
+ cookies.addAll(getHeaderValues("set-cookie", false));
cookies.add(cookie.getName() + "=" + cookie.getValue());
}
diff --git a/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/client/AuthenticatedURL.java b/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/client/AuthenticatedURL.java
index 32f4edfbc57..cb7d36368aa 100644
--- a/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/client/AuthenticatedURL.java
+++ b/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/client/AuthenticatedURL.java
@@ -92,6 +92,9 @@ public class AuthenticatedURL {
@Override
public void put(URI uri, Map<String, List<String>> responseHeaders) {
List<String> headers = responseHeaders.get("Set-Cookie");
+ if (headers == null) {
+ headers = responseHeaders.get("set-cookie");
+ }
if (headers != null) {
for (String header : headers) {
List<HttpCookie> cookies;
diff --git a/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/client/KerberosAuthenticator.java b/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/client/KerberosAuthenticator.java
index 06b63c1b991..30e65efe10c 100644
--- a/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/client/KerberosAuthenticator.java
+++ b/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/client/KerberosAuthenticator.java
@@ -280,6 +280,9 @@ public class KerberosAuthenticator implements Authenticator {
boolean negotiate = false;
if (conn.getResponseCode() == HttpURLConnection.HTTP_UNAUTHORIZED) {
String authHeader = conn.getHeaderField(WWW_AUTHENTICATE);
+ if (authHeader == null) {
+ authHeader = conn.getHeaderField(WWW_AUTHENTICATE.toLowerCase());
+ }
negotiate = authHeader != null && authHeader.trim().startsWith(NEGOTIATE);
}
return negotiate;
@@ -388,6 +391,9 @@ public class KerberosAuthenticator implements Authenticator {
int status = conn.getResponseCode();
if (status == HttpURLConnection.HTTP_OK || status == HttpURLConnection.HTTP_UNAUTHORIZED) {
String authHeader = conn.getHeaderField(WWW_AUTHENTICATE);
+ if (authHeader == null) {
+ authHeader = conn.getHeaderField(WWW_AUTHENTICATE.toLowerCase());
+ }
if (authHeader == null || !authHeader.trim().startsWith(NEGOTIATE)) {
throw new AuthenticationException("Invalid SPNEGO sequence, '" + WWW_AUTHENTICATE +
"' header incorrect: " + authHeader);
diff --git a/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/AuthenticationFilter.java b/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/AuthenticationFilter.java
index 3658bd8b8ec..7cc70c493c0 100644
--- a/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/AuthenticationFilter.java
+++ b/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/AuthenticationFilter.java
@@ -616,7 +616,9 @@ public class AuthenticationFilter implements Filter {
// present.. reset to 403 if not found..
if ((errCode == HttpServletResponse.SC_UNAUTHORIZED)
&& (!httpResponse.containsHeader(
- KerberosAuthenticator.WWW_AUTHENTICATE))) {
+ KerberosAuthenticator.WWW_AUTHENTICATE)
+ && !httpResponse.containsHeader(
+ KerberosAuthenticator.WWW_AUTHENTICATE.toLowerCase()))) {
errCode = HttpServletResponse.SC_FORBIDDEN;
}
// After Jetty 9.4.21, sendError() no longer allows a custom message.
diff --git a/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/client/TestAuthenticatedURL.java b/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/client/TestAuthenticatedURL.java
index b56fc65b25b..5b3de5208f4 100644
--- a/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/client/TestAuthenticatedURL.java
+++ b/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/client/TestAuthenticatedURL.java
@@ -89,6 +89,44 @@ public class TestAuthenticatedURL {
}
}
+ @Test
+ public void testExtractTokenCookieHeader() throws Exception {
+ HttpURLConnection conn = Mockito.mock(HttpURLConnection.class);
+
+ Mockito.when(conn.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK);
+
+ String tokenStr = "foo";
+ Map<String, List<String>> headers = new HashMap<>();
+ List<String> cookies = new ArrayList<>();
+ cookies.add(AuthenticatedURL.AUTH_COOKIE + "=" + tokenStr);
+ headers.put("Set-Cookie", cookies);
+ Mockito.when(conn.getHeaderFields()).thenReturn(headers);
+
+ AuthenticatedURL.Token token = new AuthenticatedURL.Token();
+ AuthenticatedURL.extractToken(conn, token);
+
+ Assert.assertTrue(token.isSet());
+ }
+
+ @Test
+ public void testExtractTokenLowerCaseCookieHeader() throws Exception {
+ HttpURLConnection conn = Mockito.mock(HttpURLConnection.class);
+
+ Mockito.when(conn.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK);
+
+ String tokenStr = "foo";
+ Map<String, List<String>> headers = new HashMap<>();
+ List<String> cookies = new ArrayList<>();
+ cookies.add(AuthenticatedURL.AUTH_COOKIE + "=" + tokenStr);
+ headers.put("set-cookie", cookies);
+ Mockito.when(conn.getHeaderFields()).thenReturn(headers);
+
+ AuthenticatedURL.Token token = new AuthenticatedURL.Token();
+ AuthenticatedURL.extractToken(conn, token);
+
+ Assert.assertTrue(token.isSet());
+ }
+
@Test
public void testConnectionConfigurator() throws Exception {
HttpURLConnection conn = Mockito.mock(HttpURLConnection.class);
diff --git a/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/client/TestKerberosAuthenticator.java b/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/client/TestKerberosAuthenticator.java
index 177bcb4547e..0d8f1c04137 100644
--- a/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/client/TestKerberosAuthenticator.java
+++ b/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/client/TestKerberosAuthenticator.java
@@ -21,8 +21,13 @@ import static org.apache.hadoop.security.authentication.server.KerberosAuthentic
import static org.apache.hadoop.security.authentication.server.KerberosAuthenticationHandler.NAME_RULES;
import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.nio.charset.CharacterCodingException;
import javax.security.sasl.AuthenticationException;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.lang.reflect.FieldUtils;
import org.apache.hadoop.minikdc.KerberosSecurityTestcase;
import org.apache.hadoop.security.authentication.KerberosTestUtils;
import org.apache.hadoop.security.authentication.server.AuthenticationFilter;
@@ -32,10 +37,12 @@ import org.apache.hadoop.security.authentication.server.KerberosAuthenticationHa
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
+import org.mockito.Mockito;
import java.io.File;
import java.net.HttpURLConnection;
import java.net.URL;
+import java.util.Arrays;
import java.util.Properties;
import java.util.concurrent.Callable;
@@ -248,4 +255,79 @@ public class TestKerberosAuthenticator extends KerberosSecurityTestcase {
Assert.assertTrue(ex.equals(ex2));
}
+ @Test(timeout = 60000)
+ public void testNegotiate() throws NoSuchMethodException, InvocationTargetException,
+ IllegalAccessException, IOException {
+ KerberosAuthenticator kerberosAuthenticator = new KerberosAuthenticator();
+
+ HttpURLConnection conn = Mockito.mock(HttpURLConnection.class);
+ Mockito.when(conn.getHeaderField(KerberosAuthenticator.WWW_AUTHENTICATE)).
+ thenReturn(KerberosAuthenticator.NEGOTIATE);
+ Mockito.when(conn.getResponseCode()).thenReturn(HttpURLConnection.HTTP_UNAUTHORIZED);
+
+ Method method = KerberosAuthenticator.class.getDeclaredMethod("isNegotiate",
+ HttpURLConnection.class);
+ method.setAccessible(true);
+
+ Assert.assertTrue((boolean)method.invoke(kerberosAuthenticator, conn));
+ }
+
+ @Test(timeout = 60000)
+ public void testNegotiateLowerCase() throws NoSuchMethodException, InvocationTargetException,
+ IllegalAccessException, IOException {
+ KerberosAuthenticator kerberosAuthenticator = new KerberosAuthenticator();
+
+ HttpURLConnection conn = Mockito.mock(HttpURLConnection.class);
+ Mockito.when(conn.getHeaderField("www-authenticate"))
+ .thenReturn(KerberosAuthenticator.NEGOTIATE);
+ Mockito.when(conn.getResponseCode()).thenReturn(HttpURLConnection.HTTP_UNAUTHORIZED);
+
+ Method method = KerberosAuthenticator.class.getDeclaredMethod("isNegotiate",
+ HttpURLConnection.class);
+ method.setAccessible(true);
+
+ Assert.assertTrue((boolean)method.invoke(kerberosAuthenticator, conn));
+ }
+
+ @Test(timeout = 60000)
+ public void testReadToken() throws NoSuchMethodException, IOException, IllegalAccessException,
+ InvocationTargetException {
+ KerberosAuthenticator kerberosAuthenticator = new KerberosAuthenticator();
+ FieldUtils.writeField(kerberosAuthenticator, "base64", new Base64(), true);
+
+ Base64 base64 = new Base64();
+
+ HttpURLConnection conn = Mockito.mock(HttpURLConnection.class);
+ Mockito.when(conn.getResponseCode()).thenReturn(HttpURLConnection.HTTP_UNAUTHORIZED);
+ Mockito.when(conn.getHeaderField(KerberosAuthenticator.WWW_AUTHENTICATE))
+ .thenReturn(KerberosAuthenticator.NEGOTIATE + " " +
+ Arrays.toString(base64.encode("foobar".getBytes())));
+
+ Method method = KerberosAuthenticator.class.getDeclaredMethod("readToken",
+ HttpURLConnection.class);
+ method.setAccessible(true);
+
+ method.invoke(kerberosAuthenticator, conn); // expecting this not to throw an exception
+ }
+
+ @Test(timeout = 60000)
+ public void testReadTokenLowerCase() throws NoSuchMethodException, IOException,
+ IllegalAccessException, InvocationTargetException {
+ KerberosAuthenticator kerberosAuthenticator = new KerberosAuthenticator();
+ FieldUtils.writeField(kerberosAuthenticator, "base64", new Base64(), true);
+
+ Base64 base64 = new Base64();
+
+ HttpURLConnection conn = Mockito.mock(HttpURLConnection.class);
+ Mockito.when(conn.getResponseCode()).thenReturn(HttpURLConnection.HTTP_UNAUTHORIZED);
+ Mockito.when(conn.getHeaderField("www-authenticate"))
+ .thenReturn(KerberosAuthenticator.NEGOTIATE +
+ Arrays.toString(base64.encode("foobar".getBytes())));
+
+ Method method = KerberosAuthenticator.class.getDeclaredMethod("readToken",
+ HttpURLConnection.class);
+ method.setAccessible(true);
+
+ method.invoke(kerberosAuthenticator, conn); // expecting this not to throw an exception
+ }
}
diff --git a/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/server/TestAuthenticationFilter.java b/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/server/TestAuthenticationFilter.java
index 4f4a4521b2f..b0066abbdd3 100644
--- a/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/server/TestAuthenticationFilter.java
+++ b/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/server/TestAuthenticationFilter.java
@@ -574,6 +574,44 @@ public class TestAuthenticationFilter {
}
}
+ @Test
+ public void testDoFilterNotAuthenticatedLowerCase() throws Exception {
+ AuthenticationFilter filter = new AuthenticationFilter();
+ try {
+ FilterConfig config = Mockito.mock(FilterConfig.class);
+ Mockito.when(config.getInitParameter("management.operation.return")).
+ thenReturn("true");
+ Mockito.when(config.getInitParameter(AuthenticationFilter.AUTH_TYPE)).thenReturn(
+ DummyAuthenticationHandler.class.getName());
+ Mockito.when(config.getInitParameterNames()).thenReturn(
+ new Vector<>(
+ Arrays.asList(AuthenticationFilter.AUTH_TYPE,
+ "management.operation.return")).elements());
+ getMockedServletContextWithStringSigner(config);
+ filter.init(config);
+
+ HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
+ Mockito.when(request.getRequestURL()).thenReturn(new StringBuffer("http://foo:8080/bar"));
+
+ HttpServletResponse response = Mockito.mock(HttpServletResponse.class);
+
+ FilterChain chain = Mockito.mock(FilterChain.class);
+
+ Mockito.doAnswer((Answer<Object>) invocation -> {
+ Assert.fail();
+ return null;
+ }).when(chain).doFilter(any(), any());
+
+ Mockito.when(response.containsHeader("www-authenticate")).thenReturn(true);
+ filter.doFilter(request, response, chain);
+
+ Mockito.verify(response).sendError(
+ HttpServletResponse.SC_UNAUTHORIZED, "Authentication required");
+ } finally {
+ filter.destroy();
+ }
+ }
+
private void _testDoFilterAuthentication(boolean withDomainPath,
boolean invalidToken,
boolean expired) throws Exception {
---------------------------------------------------------------------
To unsubscribe, e-mail: common-commits-unsubscribe@hadoop.apache.org
For additional commands, e-mail: common-commits-help@hadoop.apache.org