Return-Path: X-Original-To: apmail-hadoop-common-commits-archive@www.apache.org Delivered-To: apmail-hadoop-common-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id E07FD11A53 for ; Fri, 28 Mar 2014 21:31:23 +0000 (UTC) Received: (qmail 96476 invoked by uid 500); 28 Mar 2014 21:31:22 -0000 Delivered-To: apmail-hadoop-common-commits-archive@hadoop.apache.org Received: (qmail 96417 invoked by uid 500); 28 Mar 2014 21:31:21 -0000 Mailing-List: contact common-commits-help@hadoop.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: common-dev@hadoop.apache.org Delivered-To: mailing list common-commits@hadoop.apache.org Received: (qmail 96408 invoked by uid 99); 28 Mar 2014 21:31:20 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 28 Mar 2014 21:31:20 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 28 Mar 2014 21:31:19 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 0C41323888FE; Fri, 28 Mar 2014 21:30:59 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1582888 - in /hadoop/common/branches/branch-2.4/hadoop-common-project: hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/ hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/client/ hadoop-auth/src/... Date: Fri, 28 Mar 2014 21:30:58 -0000 To: common-commits@hadoop.apache.org From: jing9@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20140328213059.0C41323888FE@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: jing9 Date: Fri Mar 28 21:30:58 2014 New Revision: 1582888 URL: http://svn.apache.org/r1582888 Log: HADOOP-10301. Merge r1582884 from branch-2. Modified: hadoop/common/branches/branch-2.4/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/AuthenticationFilter.java hadoop/common/branches/branch-2.4/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/client/TestPseudoAuthenticator.java hadoop/common/branches/branch-2.4/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/server/TestAuthenticationFilter.java hadoop/common/branches/branch-2.4/hadoop-common-project/hadoop-common/CHANGES.txt Modified: hadoop/common/branches/branch-2.4/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/AuthenticationFilter.java URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-2.4/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/AuthenticationFilter.java?rev=1582888&r1=1582887&r2=1582888&view=diff ============================================================================== --- hadoop/common/branches/branch-2.4/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/AuthenticationFilter.java (original) +++ hadoop/common/branches/branch-2.4/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/AuthenticationFilter.java Fri Mar 28 21:30:58 2014 @@ -332,7 +332,8 @@ public class AuthenticationFilter implem public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException { boolean unauthorizedResponse = true; - String unauthorizedMsg = ""; + int errCode = HttpServletResponse.SC_UNAUTHORIZED; + AuthenticationException authenticationEx = null; HttpServletRequest httpRequest = (HttpServletRequest) request; HttpServletResponse httpResponse = (HttpServletResponse) response; boolean isHttps = "https".equals(httpRequest.getScheme()); @@ -344,6 +345,8 @@ public class AuthenticationFilter implem } catch (AuthenticationException ex) { LOG.warn("AuthenticationToken ignored: " + ex.getMessage()); + // will be sent back in a 401 unless filter authenticates + authenticationEx = ex; token = null; } if (authHandler.managementOperation(token, httpRequest, httpResponse)) { @@ -392,15 +395,20 @@ public class AuthenticationFilter implem unauthorizedResponse = false; } } 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); } if (unauthorizedResponse) { if (!httpResponse.isCommitted()) { createAuthCookie(httpResponse, "", getCookieDomain(), getCookiePath(), 0, isHttps); - httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, - unauthorizedMsg); + if (authenticationEx == null) { + httpResponse.sendError(errCode, "Authentication required"); + } else { + httpResponse.sendError(errCode, authenticationEx.getMessage()); + } } } } Modified: hadoop/common/branches/branch-2.4/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/client/TestPseudoAuthenticator.java URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-2.4/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/client/TestPseudoAuthenticator.java?rev=1582888&r1=1582887&r2=1582888&view=diff ============================================================================== --- hadoop/common/branches/branch-2.4/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/client/TestPseudoAuthenticator.java (original) +++ hadoop/common/branches/branch-2.4/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/client/TestPseudoAuthenticator.java Fri Mar 28 21:30:58 2014 @@ -63,7 +63,8 @@ public class TestPseudoAuthenticator { URL url = new URL(auth.getBaseURL()); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 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 { auth.stop(); } Modified: hadoop/common/branches/branch-2.4/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/server/TestAuthenticationFilter.java URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-2.4/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/server/TestAuthenticationFilter.java?rev=1582888&r1=1582887&r2=1582888&view=diff ============================================================================== --- hadoop/common/branches/branch-2.4/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/server/TestAuthenticationFilter.java (original) +++ hadoop/common/branches/branch-2.4/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/server/TestAuthenticationFilter.java Fri Mar 28 21:30:58 2014 @@ -14,8 +14,10 @@ package org.apache.hadoop.security.authentication.server; import java.io.IOException; +import java.net.HttpCookie; import java.util.Arrays; import java.util.HashMap; +import java.util.List; import java.util.Properties; import java.util.Vector; @@ -130,7 +132,11 @@ public class TestAuthenticationFilter { token = new AuthenticationToken("u", "p", "t"); token.setExpires((expired) ? 0 : System.currentTimeMillis() + TOKEN_VALIDITY_SEC); } 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; } @@ -303,7 +309,8 @@ public class TestAuthenticationFilter { "management.operation.return")).elements()); 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); Signer signer = new Signer("secret".getBytes()); String tokenSigned = signer.sign(token.toString()); @@ -312,13 +319,14 @@ public class TestAuthenticationFilter { HttpServletRequest request = Mockito.mock(HttpServletRequest.class); Mockito.when(request.getCookies()).thenReturn(new Cookie[]{cookie}); + boolean failed = false; try { filter.getToken(request); - Assert.fail(); } catch (AuthenticationException ex) { - // Expected - } catch (Exception ex) { - Assert.fail(); + Assert.assertEquals("AuthenticationToken expired", ex.getMessage()); + failed = true; + } finally { + Assert.assertTrue("token not expired", failed); } } finally { filter.destroy(); @@ -351,13 +359,14 @@ public class TestAuthenticationFilter { HttpServletRequest request = Mockito.mock(HttpServletRequest.class); Mockito.when(request.getCookies()).thenReturn(new Cookie[]{cookie}); + boolean failed = false; try { filter.getToken(request); - Assert.fail(); } catch (AuthenticationException ex) { - // Expected - } catch (Exception ex) { - Assert.fail(); + Assert.assertEquals("Invalid AuthenticationToken type", ex.getMessage()); + failed = true; + } finally { + Assert.assertTrue("token not invalid type", failed); } } finally { filter.destroy(); @@ -398,7 +407,9 @@ public class TestAuthenticationFilter { 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 { filter.destroy(); } @@ -468,10 +479,10 @@ public class TestAuthenticationFilter { if (expired) { Mockito.verify(response, Mockito.never()). - addCookie(Mockito.any(Cookie.class)); + addHeader(Mockito.eq("Set-Cookie"), Mockito.anyString()); } else { 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 ("t=") && v.contains("e=") && v.contains("s=")); Mockito.verify(chain).doFilter(Mockito.any(ServletRequest.class), @@ -586,7 +597,67 @@ public class TestAuthenticationFilter { } @Test + public void testDoFilterAuthenticationFailure() 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()); + 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 cookieMap = new HashMap(); + Mockito.doAnswer( + new Answer() { + @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() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + Assert.fail("shouldn't get here"); + return null; + } + } + ).when(chain).doFilter(Mockito.anyObject(), Mockito.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); @@ -594,9 +665,12 @@ public class TestAuthenticationFilter { 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( Arrays.asList(AuthenticationFilter.AUTH_TYPE, + AuthenticationFilter.SIGNATURE_SECRET, "management.operation.return")).elements()); filter.init(config); @@ -605,7 +679,7 @@ public class TestAuthenticationFilter { AuthenticationToken token = new AuthenticationToken("u", "p", DummyAuthenticationHandler.TYPE); 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()); Cookie cookie = new Cookie(AuthenticatedURL.AUTH_COOKIE, tokenSigned); @@ -643,12 +717,14 @@ public class TestAuthenticationFilter { Mockito.verify(chain, Mockito.never()).doFilter(Mockito.any (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)); } @Test public void testDoFilterAuthenticatedInvalidType() throws Exception { + String secret = "secret"; AuthenticationFilter filter = new AuthenticationFilter(); try { FilterConfig config = Mockito.mock(FilterConfig.class); @@ -656,9 +732,12 @@ public class TestAuthenticationFilter { 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( Arrays.asList(AuthenticationFilter.AUTH_TYPE, + AuthenticationFilter.SIGNATURE_SECRET, "management.operation.return")).elements()); filter.init(config); @@ -667,7 +746,7 @@ public class TestAuthenticationFilter { AuthenticationToken token = new AuthenticationToken("u", "p", "invalidtype"); 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()); Cookie cookie = new Cookie(AuthenticatedURL.AUTH_COOKIE, tokenSigned); Modified: hadoop/common/branches/branch-2.4/hadoop-common-project/hadoop-common/CHANGES.txt URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-2.4/hadoop-common-project/hadoop-common/CHANGES.txt?rev=1582888&r1=1582887&r2=1582888&view=diff ============================================================================== --- hadoop/common/branches/branch-2.4/hadoop-common-project/hadoop-common/CHANGES.txt (original) +++ hadoop/common/branches/branch-2.4/hadoop-common-project/hadoop-common/CHANGES.txt Fri Mar 28 21:30:58 2014 @@ -140,6 +140,9 @@ Release 2.4.0 - UNRELEASED HADOOP-10450. Build zlib native code bindings in hadoop.dll for Windows. (cnauroth) + HADOOP-10301. AuthenticationFilter should return Forbidden for failed + authentication. (Daryn Sharp via jing9) + BREAKDOWN OF HADOOP-10184 SUBTASKS AND RELATED JIRAS HADOOP-10185. FileSystem API for ACLs. (cnauroth)