HADOOP-10301. Merge r1582883 from trunk.
git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/branches/branch-2@1582884 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
d8c11dc781
commit
0da50f6074
|
@ -332,7 +332,8 @@ public class AuthenticationFilter implements Filter {
|
||||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
|
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
|
||||||
throws IOException, ServletException {
|
throws IOException, ServletException {
|
||||||
boolean unauthorizedResponse = true;
|
boolean unauthorizedResponse = true;
|
||||||
String unauthorizedMsg = "";
|
int errCode = HttpServletResponse.SC_UNAUTHORIZED;
|
||||||
|
AuthenticationException authenticationEx = null;
|
||||||
HttpServletRequest httpRequest = (HttpServletRequest) request;
|
HttpServletRequest httpRequest = (HttpServletRequest) request;
|
||||||
HttpServletResponse httpResponse = (HttpServletResponse) response;
|
HttpServletResponse httpResponse = (HttpServletResponse) response;
|
||||||
boolean isHttps = "https".equals(httpRequest.getScheme());
|
boolean isHttps = "https".equals(httpRequest.getScheme());
|
||||||
|
@ -344,6 +345,8 @@ public class AuthenticationFilter implements Filter {
|
||||||
}
|
}
|
||||||
catch (AuthenticationException ex) {
|
catch (AuthenticationException ex) {
|
||||||
LOG.warn("AuthenticationToken ignored: " + ex.getMessage());
|
LOG.warn("AuthenticationToken ignored: " + ex.getMessage());
|
||||||
|
// will be sent back in a 401 unless filter authenticates
|
||||||
|
authenticationEx = ex;
|
||||||
token = null;
|
token = null;
|
||||||
}
|
}
|
||||||
if (authHandler.managementOperation(token, httpRequest, httpResponse)) {
|
if (authHandler.managementOperation(token, httpRequest, httpResponse)) {
|
||||||
|
@ -392,15 +395,20 @@ public class AuthenticationFilter implements Filter {
|
||||||
unauthorizedResponse = false;
|
unauthorizedResponse = false;
|
||||||
}
|
}
|
||||||
} catch (AuthenticationException ex) {
|
} catch (AuthenticationException ex) {
|
||||||
unauthorizedMsg = ex.toString();
|
// exception from the filter itself is fatal
|
||||||
|
errCode = HttpServletResponse.SC_FORBIDDEN;
|
||||||
|
authenticationEx = ex;
|
||||||
LOG.warn("Authentication exception: " + ex.getMessage(), ex);
|
LOG.warn("Authentication exception: " + ex.getMessage(), ex);
|
||||||
}
|
}
|
||||||
if (unauthorizedResponse) {
|
if (unauthorizedResponse) {
|
||||||
if (!httpResponse.isCommitted()) {
|
if (!httpResponse.isCommitted()) {
|
||||||
createAuthCookie(httpResponse, "", getCookieDomain(),
|
createAuthCookie(httpResponse, "", getCookieDomain(),
|
||||||
getCookiePath(), 0, isHttps);
|
getCookiePath(), 0, isHttps);
|
||||||
httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED,
|
if (authenticationEx == null) {
|
||||||
unauthorizedMsg);
|
httpResponse.sendError(errCode, "Authentication required");
|
||||||
|
} else {
|
||||||
|
httpResponse.sendError(errCode, authenticationEx.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,8 @@ public class TestPseudoAuthenticator {
|
||||||
URL url = new URL(auth.getBaseURL());
|
URL url = new URL(auth.getBaseURL());
|
||||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||||
conn.connect();
|
conn.connect();
|
||||||
Assert.assertEquals(HttpURLConnection.HTTP_UNAUTHORIZED, conn.getResponseCode());
|
Assert.assertEquals(HttpURLConnection.HTTP_FORBIDDEN, conn.getResponseCode());
|
||||||
|
Assert.assertEquals("Anonymous requests are disallowed", conn.getResponseMessage());
|
||||||
} finally {
|
} finally {
|
||||||
auth.stop();
|
auth.stop();
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,10 @@
|
||||||
package org.apache.hadoop.security.authentication.server;
|
package org.apache.hadoop.security.authentication.server;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.HttpCookie;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.Vector;
|
import java.util.Vector;
|
||||||
|
|
||||||
|
@ -130,7 +132,11 @@ public class TestAuthenticationFilter {
|
||||||
token = new AuthenticationToken("u", "p", "t");
|
token = new AuthenticationToken("u", "p", "t");
|
||||||
token.setExpires((expired) ? 0 : System.currentTimeMillis() + TOKEN_VALIDITY_SEC);
|
token.setExpires((expired) ? 0 : System.currentTimeMillis() + TOKEN_VALIDITY_SEC);
|
||||||
} else {
|
} else {
|
||||||
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
if (request.getHeader("WWW-Authenticate") == null) {
|
||||||
|
response.setHeader("WWW-Authenticate", "dummyauth");
|
||||||
|
} else {
|
||||||
|
throw new AuthenticationException("AUTH FAILED");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
@ -303,7 +309,8 @@ public class TestAuthenticationFilter {
|
||||||
"management.operation.return")).elements());
|
"management.operation.return")).elements());
|
||||||
filter.init(config);
|
filter.init(config);
|
||||||
|
|
||||||
AuthenticationToken token = new AuthenticationToken("u", "p", "invalidtype");
|
AuthenticationToken token =
|
||||||
|
new AuthenticationToken("u", "p", DummyAuthenticationHandler.TYPE);
|
||||||
token.setExpires(System.currentTimeMillis() - TOKEN_VALIDITY_SEC);
|
token.setExpires(System.currentTimeMillis() - TOKEN_VALIDITY_SEC);
|
||||||
Signer signer = new Signer("secret".getBytes());
|
Signer signer = new Signer("secret".getBytes());
|
||||||
String tokenSigned = signer.sign(token.toString());
|
String tokenSigned = signer.sign(token.toString());
|
||||||
|
@ -312,13 +319,14 @@ public class TestAuthenticationFilter {
|
||||||
HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
|
HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
|
||||||
Mockito.when(request.getCookies()).thenReturn(new Cookie[]{cookie});
|
Mockito.when(request.getCookies()).thenReturn(new Cookie[]{cookie});
|
||||||
|
|
||||||
|
boolean failed = false;
|
||||||
try {
|
try {
|
||||||
filter.getToken(request);
|
filter.getToken(request);
|
||||||
Assert.fail();
|
|
||||||
} catch (AuthenticationException ex) {
|
} catch (AuthenticationException ex) {
|
||||||
// Expected
|
Assert.assertEquals("AuthenticationToken expired", ex.getMessage());
|
||||||
} catch (Exception ex) {
|
failed = true;
|
||||||
Assert.fail();
|
} finally {
|
||||||
|
Assert.assertTrue("token not expired", failed);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
filter.destroy();
|
filter.destroy();
|
||||||
|
@ -351,13 +359,14 @@ public class TestAuthenticationFilter {
|
||||||
HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
|
HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
|
||||||
Mockito.when(request.getCookies()).thenReturn(new Cookie[]{cookie});
|
Mockito.when(request.getCookies()).thenReturn(new Cookie[]{cookie});
|
||||||
|
|
||||||
|
boolean failed = false;
|
||||||
try {
|
try {
|
||||||
filter.getToken(request);
|
filter.getToken(request);
|
||||||
Assert.fail();
|
|
||||||
} catch (AuthenticationException ex) {
|
} catch (AuthenticationException ex) {
|
||||||
// Expected
|
Assert.assertEquals("Invalid AuthenticationToken type", ex.getMessage());
|
||||||
} catch (Exception ex) {
|
failed = true;
|
||||||
Assert.fail();
|
} finally {
|
||||||
|
Assert.assertTrue("token not invalid type", failed);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
filter.destroy();
|
filter.destroy();
|
||||||
|
@ -398,7 +407,9 @@ public class TestAuthenticationFilter {
|
||||||
|
|
||||||
filter.doFilter(request, response, chain);
|
filter.doFilter(request, response, chain);
|
||||||
|
|
||||||
Mockito.verify(response).setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
Mockito.verify(response).sendError(
|
||||||
|
HttpServletResponse.SC_UNAUTHORIZED, "Authentication required");
|
||||||
|
Mockito.verify(response).setHeader("WWW-Authenticate", "dummyauth");
|
||||||
} finally {
|
} finally {
|
||||||
filter.destroy();
|
filter.destroy();
|
||||||
}
|
}
|
||||||
|
@ -468,10 +479,10 @@ public class TestAuthenticationFilter {
|
||||||
|
|
||||||
if (expired) {
|
if (expired) {
|
||||||
Mockito.verify(response, Mockito.never()).
|
Mockito.verify(response, Mockito.never()).
|
||||||
addCookie(Mockito.any(Cookie.class));
|
addHeader(Mockito.eq("Set-Cookie"), Mockito.anyString());
|
||||||
} else {
|
} else {
|
||||||
String v = cookieMap.get(AuthenticatedURL.AUTH_COOKIE);
|
String v = cookieMap.get(AuthenticatedURL.AUTH_COOKIE);
|
||||||
Assert.assertNotNull(v);
|
Assert.assertNotNull("cookie missing", v);
|
||||||
Assert.assertTrue(v.contains("u=") && v.contains("p=") && v.contains
|
Assert.assertTrue(v.contains("u=") && v.contains("p=") && v.contains
|
||||||
("t=") && v.contains("e=") && v.contains("s="));
|
("t=") && v.contains("e=") && v.contains("s="));
|
||||||
Mockito.verify(chain).doFilter(Mockito.any(ServletRequest.class),
|
Mockito.verify(chain).doFilter(Mockito.any(ServletRequest.class),
|
||||||
|
@ -586,7 +597,7 @@ public class TestAuthenticationFilter {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDoFilterAuthenticatedExpired() throws Exception {
|
public void testDoFilterAuthenticationFailure() throws Exception {
|
||||||
AuthenticationFilter filter = new AuthenticationFilter();
|
AuthenticationFilter filter = new AuthenticationFilter();
|
||||||
try {
|
try {
|
||||||
FilterConfig config = Mockito.mock(FilterConfig.class);
|
FilterConfig config = Mockito.mock(FilterConfig.class);
|
||||||
|
@ -600,12 +611,75 @@ public class TestAuthenticationFilter {
|
||||||
"management.operation.return")).elements());
|
"management.operation.return")).elements());
|
||||||
filter.init(config);
|
filter.init(config);
|
||||||
|
|
||||||
|
HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
|
||||||
|
Mockito.when(request.getRequestURL()).thenReturn(new StringBuffer("http://foo:8080/bar"));
|
||||||
|
Mockito.when(request.getCookies()).thenReturn(new Cookie[]{});
|
||||||
|
Mockito.when(request.getHeader("WWW-Authenticate")).thenReturn("dummyauth");
|
||||||
|
HttpServletResponse response = Mockito.mock(HttpServletResponse.class);
|
||||||
|
|
||||||
|
FilterChain chain = Mockito.mock(FilterChain.class);
|
||||||
|
|
||||||
|
final HashMap<String, String> cookieMap = new HashMap<String, String>();
|
||||||
|
Mockito.doAnswer(
|
||||||
|
new Answer<Object>() {
|
||||||
|
@Override
|
||||||
|
public Object answer(InvocationOnMock invocation) throws Throwable {
|
||||||
|
Object[] args = invocation.getArguments();
|
||||||
|
parseCookieMap((String) args[1], cookieMap);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).when(response).addHeader(Mockito.eq("Set-Cookie"), Mockito.anyString());
|
||||||
|
|
||||||
|
Mockito.doAnswer(
|
||||||
|
new Answer<Object>() {
|
||||||
|
@Override
|
||||||
|
public Object answer(InvocationOnMock invocation) throws Throwable {
|
||||||
|
Assert.fail("shouldn't get here");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).when(chain).doFilter(Mockito.<ServletRequest>anyObject(), Mockito.<ServletResponse>anyObject());
|
||||||
|
|
||||||
|
filter.doFilter(request, response, chain);
|
||||||
|
|
||||||
|
Mockito.verify(response).sendError(
|
||||||
|
HttpServletResponse.SC_FORBIDDEN, "AUTH FAILED");
|
||||||
|
Mockito.verify(response, Mockito.never()).setHeader(Mockito.eq("WWW-Authenticate"), Mockito.anyString());
|
||||||
|
|
||||||
|
String value = cookieMap.get(AuthenticatedURL.AUTH_COOKIE);
|
||||||
|
Assert.assertNotNull("cookie missing", value);
|
||||||
|
Assert.assertEquals("", value);
|
||||||
|
} finally {
|
||||||
|
filter.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDoFilterAuthenticatedExpired() throws Exception {
|
||||||
|
String secret = "secret";
|
||||||
|
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.getInitParameter(AuthenticationFilter.SIGNATURE_SECRET)).thenReturn(
|
||||||
|
secret);
|
||||||
|
Mockito.when(config.getInitParameterNames()).thenReturn(
|
||||||
|
new Vector<String>(
|
||||||
|
Arrays.asList(AuthenticationFilter.AUTH_TYPE,
|
||||||
|
AuthenticationFilter.SIGNATURE_SECRET,
|
||||||
|
"management.operation.return")).elements());
|
||||||
|
filter.init(config);
|
||||||
|
|
||||||
HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
|
HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
|
||||||
Mockito.when(request.getRequestURL()).thenReturn(new StringBuffer("http://foo:8080/bar"));
|
Mockito.when(request.getRequestURL()).thenReturn(new StringBuffer("http://foo:8080/bar"));
|
||||||
|
|
||||||
AuthenticationToken token = new AuthenticationToken("u", "p", DummyAuthenticationHandler.TYPE);
|
AuthenticationToken token = new AuthenticationToken("u", "p", DummyAuthenticationHandler.TYPE);
|
||||||
token.setExpires(System.currentTimeMillis() - TOKEN_VALIDITY_SEC);
|
token.setExpires(System.currentTimeMillis() - TOKEN_VALIDITY_SEC);
|
||||||
Signer signer = new Signer("secret".getBytes());
|
Signer signer = new Signer(secret.getBytes());
|
||||||
String tokenSigned = signer.sign(token.toString());
|
String tokenSigned = signer.sign(token.toString());
|
||||||
|
|
||||||
Cookie cookie = new Cookie(AuthenticatedURL.AUTH_COOKIE, tokenSigned);
|
Cookie cookie = new Cookie(AuthenticatedURL.AUTH_COOKIE, tokenSigned);
|
||||||
|
@ -643,12 +717,14 @@ public class TestAuthenticationFilter {
|
||||||
Mockito.verify(chain, Mockito.never()).doFilter(Mockito.any
|
Mockito.verify(chain, Mockito.never()).doFilter(Mockito.any
|
||||||
(ServletRequest.class), Mockito.any(ServletResponse.class));
|
(ServletRequest.class), Mockito.any(ServletResponse.class));
|
||||||
|
|
||||||
Assert.assertTrue(cookieMap.containsKey(AuthenticatedURL.AUTH_COOKIE));
|
Assert.assertTrue("cookie is missing",
|
||||||
|
cookieMap.containsKey(AuthenticatedURL.AUTH_COOKIE));
|
||||||
Assert.assertEquals("", cookieMap.get(AuthenticatedURL.AUTH_COOKIE));
|
Assert.assertEquals("", cookieMap.get(AuthenticatedURL.AUTH_COOKIE));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDoFilterAuthenticatedInvalidType() throws Exception {
|
public void testDoFilterAuthenticatedInvalidType() throws Exception {
|
||||||
|
String secret = "secret";
|
||||||
AuthenticationFilter filter = new AuthenticationFilter();
|
AuthenticationFilter filter = new AuthenticationFilter();
|
||||||
try {
|
try {
|
||||||
FilterConfig config = Mockito.mock(FilterConfig.class);
|
FilterConfig config = Mockito.mock(FilterConfig.class);
|
||||||
|
@ -656,9 +732,12 @@ public class TestAuthenticationFilter {
|
||||||
thenReturn("true");
|
thenReturn("true");
|
||||||
Mockito.when(config.getInitParameter(AuthenticationFilter.AUTH_TYPE)).thenReturn(
|
Mockito.when(config.getInitParameter(AuthenticationFilter.AUTH_TYPE)).thenReturn(
|
||||||
DummyAuthenticationHandler.class.getName());
|
DummyAuthenticationHandler.class.getName());
|
||||||
|
Mockito.when(config.getInitParameter(AuthenticationFilter.SIGNATURE_SECRET)).thenReturn(
|
||||||
|
secret);
|
||||||
Mockito.when(config.getInitParameterNames()).thenReturn(
|
Mockito.when(config.getInitParameterNames()).thenReturn(
|
||||||
new Vector<String>(
|
new Vector<String>(
|
||||||
Arrays.asList(AuthenticationFilter.AUTH_TYPE,
|
Arrays.asList(AuthenticationFilter.AUTH_TYPE,
|
||||||
|
AuthenticationFilter.SIGNATURE_SECRET,
|
||||||
"management.operation.return")).elements());
|
"management.operation.return")).elements());
|
||||||
filter.init(config);
|
filter.init(config);
|
||||||
|
|
||||||
|
@ -667,7 +746,7 @@ public class TestAuthenticationFilter {
|
||||||
|
|
||||||
AuthenticationToken token = new AuthenticationToken("u", "p", "invalidtype");
|
AuthenticationToken token = new AuthenticationToken("u", "p", "invalidtype");
|
||||||
token.setExpires(System.currentTimeMillis() + TOKEN_VALIDITY_SEC);
|
token.setExpires(System.currentTimeMillis() + TOKEN_VALIDITY_SEC);
|
||||||
Signer signer = new Signer("secret".getBytes());
|
Signer signer = new Signer(secret.getBytes());
|
||||||
String tokenSigned = signer.sign(token.toString());
|
String tokenSigned = signer.sign(token.toString());
|
||||||
|
|
||||||
Cookie cookie = new Cookie(AuthenticatedURL.AUTH_COOKIE, tokenSigned);
|
Cookie cookie = new Cookie(AuthenticatedURL.AUTH_COOKIE, tokenSigned);
|
||||||
|
|
|
@ -167,6 +167,9 @@ Release 2.4.0 - UNRELEASED
|
||||||
HADOOP-10450. Build zlib native code bindings in hadoop.dll for Windows.
|
HADOOP-10450. Build zlib native code bindings in hadoop.dll for Windows.
|
||||||
(cnauroth)
|
(cnauroth)
|
||||||
|
|
||||||
|
HADOOP-10301. AuthenticationFilter should return Forbidden for failed
|
||||||
|
authentication. (Daryn Sharp via jing9)
|
||||||
|
|
||||||
BREAKDOWN OF HADOOP-10184 SUBTASKS AND RELATED JIRAS
|
BREAKDOWN OF HADOOP-10184 SUBTASKS AND RELATED JIRAS
|
||||||
|
|
||||||
HADOOP-10185. FileSystem API for ACLs. (cnauroth)
|
HADOOP-10185. FileSystem API for ACLs. (cnauroth)
|
||||||
|
|
Loading…
Reference in New Issue