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:
Jing Zhao 2014-03-28 21:22:39 +00:00
parent d8c11dc781
commit 0da50f6074
4 changed files with 113 additions and 22 deletions

View File

@ -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());
}
} }
} }
} }

View File

@ -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();
} }

View File

@ -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);

View File

@ -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)