diff --git a/hadoop-common-project/hadoop-auth/pom.xml b/hadoop-common-project/hadoop-auth/pom.xml index 2ff51d6ffe..564518c540 100644 --- a/hadoop-common-project/hadoop-auth/pom.xml +++ b/hadoop-common-project/hadoop-auth/pom.xml @@ -61,6 +61,16 @@ org.mortbay.jetty jetty test + + + org.apache.tomcat.embed + tomcat-embed-core + test + + + org.apache.tomcat.embed + tomcat-embed-logging-juli + test javax.servlet 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 316cd60a25..9330444c46 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 @@ -519,9 +519,7 @@ public static void createAuthCookie(HttpServletResponse resp, String token, StringBuilder sb = new StringBuilder(AuthenticatedURL.AUTH_COOKIE) .append("="); if (token != null && token.length() > 0) { - sb.append("\"") - .append(token) - .append("\""); + sb.append(token); } sb.append("; Version=1"); diff --git a/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/client/AuthenticatorTestCase.java b/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/client/AuthenticatorTestCase.java index 4e4ecc483e..8f35e13e66 100644 --- a/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/client/AuthenticatorTestCase.java +++ b/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/client/AuthenticatorTestCase.java @@ -13,7 +13,22 @@ */ package org.apache.hadoop.security.authentication.client; +import org.apache.catalina.deploy.FilterDef; +import org.apache.catalina.deploy.FilterMap; +import org.apache.catalina.startup.Tomcat; import org.apache.hadoop.security.authentication.server.AuthenticationFilter; +import org.apache.http.HttpResponse; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.Credentials; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.client.params.AuthPolicy; +import org.apache.http.entity.InputStreamEntity; +import org.apache.http.impl.auth.SPNegoSchemeFactory; +import org.apache.http.impl.client.SystemDefaultHttpClient; +import org.apache.http.util.EntityUtils; import org.mortbay.jetty.Server; import org.mortbay.jetty.servlet.Context; import org.mortbay.jetty.servlet.FilterHolder; @@ -24,16 +39,19 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; -import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.Writer; import java.net.HttpURLConnection; import java.net.ServerSocket; import java.net.URL; +import java.security.Principal; import java.util.Properties; import org.junit.Assert; @@ -41,10 +59,18 @@ public class AuthenticatorTestCase { private Server server; private String host = null; private int port = -1; + private boolean useTomcat = false; + private Tomcat tomcat = null; Context context; private static Properties authenticatorConfig; + public AuthenticatorTestCase() {} + + public AuthenticatorTestCase(boolean useTomcat) { + this.useTomcat = useTomcat; + } + protected static void setAuthenticationHandlerConfig(Properties config) { authenticatorConfig = config; } @@ -80,7 +106,19 @@ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws S } } + protected int getLocalPort() throws Exception { + ServerSocket ss = new ServerSocket(0); + int ret = ss.getLocalPort(); + ss.close(); + return ret; + } + protected void start() throws Exception { + if (useTomcat) startTomcat(); + else startJetty(); + } + + protected void startJetty() throws Exception { server = new Server(0); context = new Context(); context.setContextPath("/foo"); @@ -88,16 +126,42 @@ protected void start() throws Exception { context.addFilter(new FilterHolder(TestFilter.class), "/*", 0); context.addServlet(new ServletHolder(TestServlet.class), "/bar"); host = "localhost"; - ServerSocket ss = new ServerSocket(0); - port = ss.getLocalPort(); - ss.close(); + port = getLocalPort(); server.getConnectors()[0].setHost(host); server.getConnectors()[0].setPort(port); server.start(); System.out.println("Running embedded servlet container at: http://" + host + ":" + port); } + protected void startTomcat() throws Exception { + tomcat = new Tomcat(); + File base = new File(System.getProperty("java.io.tmpdir")); + org.apache.catalina.Context ctx = + tomcat.addContext("/foo",base.getAbsolutePath()); + FilterDef fd = new FilterDef(); + fd.setFilterClass(TestFilter.class.getName()); + fd.setFilterName("TestFilter"); + FilterMap fm = new FilterMap(); + fm.setFilterName("TestFilter"); + fm.addURLPattern("/*"); + fm.addServletName("/bar"); + ctx.addFilterDef(fd); + ctx.addFilterMap(fm); + tomcat.addServlet(ctx, "/bar", TestServlet.class.getName()); + ctx.addServletMapping("/bar", "/bar"); + host = "localhost"; + port = getLocalPort(); + tomcat.setHostname(host); + tomcat.setPort(port); + tomcat.start(); + } + protected void stop() throws Exception { + if (useTomcat) stopTomcat(); + else stopJetty(); + } + + protected void stopJetty() throws Exception { try { server.stop(); } catch (Exception e) { @@ -109,6 +173,18 @@ protected void stop() throws Exception { } } + protected void stopTomcat() throws Exception { + try { + tomcat.stop(); + } catch (Exception e) { + } + + try { + tomcat.destroy(); + } catch (Exception e) { + } + } + protected String getBaseURL() { return "http://" + host + ":" + port + "/foo/bar"; } @@ -165,4 +241,57 @@ protected void _testAuthentication(Authenticator authenticator, boolean doPost) } } + private SystemDefaultHttpClient getHttpClient() { + final SystemDefaultHttpClient httpClient = new SystemDefaultHttpClient(); + httpClient.getAuthSchemes().register(AuthPolicy.SPNEGO, new SPNegoSchemeFactory(true)); + Credentials use_jaas_creds = new Credentials() { + public String getPassword() { + return null; + } + + public Principal getUserPrincipal() { + return null; + } + }; + + httpClient.getCredentialsProvider().setCredentials( + AuthScope.ANY, use_jaas_creds); + return httpClient; + } + + private void doHttpClientRequest(HttpClient httpClient, HttpUriRequest request) throws Exception { + HttpResponse response = null; + try { + response = httpClient.execute(request); + final int httpStatus = response.getStatusLine().getStatusCode(); + Assert.assertEquals(HttpURLConnection.HTTP_OK, httpStatus); + } finally { + if (response != null) EntityUtils.consumeQuietly(response.getEntity()); + } + } + + protected void _testAuthenticationHttpClient(Authenticator authenticator, boolean doPost) throws Exception { + start(); + try { + SystemDefaultHttpClient httpClient = getHttpClient(); + doHttpClientRequest(httpClient, new HttpGet(getBaseURL())); + + // Always do a GET before POST to trigger the SPNego negotiation + if (doPost) { + HttpPost post = new HttpPost(getBaseURL()); + byte [] postBytes = POST.getBytes(); + ByteArrayInputStream bis = new ByteArrayInputStream(postBytes); + InputStreamEntity entity = new InputStreamEntity(bis, postBytes.length); + + // Important that the entity is not repeatable -- this means if + // we have to renegotiate (e.g. b/c the cookie wasn't handled properly) + // the test will fail. + Assert.assertFalse(entity.isRepeatable()); + post.setEntity(entity); + doHttpClientRequest(httpClient, post); + } + } finally { + stop(); + } + } } 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 53d23c467a..6c49d15f09 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 @@ -20,16 +20,36 @@ import org.apache.hadoop.security.authentication.server.KerberosAuthenticationHandler; import org.junit.Assert; import org.junit.Before; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; +import org.junit.runner.RunWith; import org.junit.Test; import java.io.File; import java.net.HttpURLConnection; import java.net.URL; +import java.util.Arrays; +import java.util.Collection; import java.util.Properties; import java.util.concurrent.Callable; +@RunWith(Parameterized.class) public class TestKerberosAuthenticator extends KerberosSecurityTestcase { + private boolean useTomcat = false; + + public TestKerberosAuthenticator(boolean useTomcat) { + this.useTomcat = useTomcat; + } + + @Parameterized.Parameters + public static Collection booleans() { + return Arrays.asList(new Object[][] { + { false }, + { true } + }); + } + @Before public void setup() throws Exception { // create keytab @@ -53,7 +73,7 @@ private Properties getAuthenticationHandlerConfiguration() { @Test(timeout=60000) public void testFallbacktoPseudoAuthenticator() throws Exception { - AuthenticatorTestCase auth = new AuthenticatorTestCase(); + AuthenticatorTestCase auth = new AuthenticatorTestCase(useTomcat); Properties props = new Properties(); props.setProperty(AuthenticationFilter.AUTH_TYPE, "simple"); props.setProperty(PseudoAuthenticationHandler.ANONYMOUS_ALLOWED, "false"); @@ -63,7 +83,7 @@ public void testFallbacktoPseudoAuthenticator() throws Exception { @Test(timeout=60000) public void testFallbacktoPseudoAuthenticatorAnonymous() throws Exception { - AuthenticatorTestCase auth = new AuthenticatorTestCase(); + AuthenticatorTestCase auth = new AuthenticatorTestCase(useTomcat); Properties props = new Properties(); props.setProperty(AuthenticationFilter.AUTH_TYPE, "simple"); props.setProperty(PseudoAuthenticationHandler.ANONYMOUS_ALLOWED, "true"); @@ -73,7 +93,7 @@ public void testFallbacktoPseudoAuthenticatorAnonymous() throws Exception { @Test(timeout=60000) public void testNotAuthenticated() throws Exception { - AuthenticatorTestCase auth = new AuthenticatorTestCase(); + AuthenticatorTestCase auth = new AuthenticatorTestCase(useTomcat); AuthenticatorTestCase.setAuthenticationHandlerConfig(getAuthenticationHandlerConfiguration()); auth.start(); try { @@ -89,7 +109,7 @@ public void testNotAuthenticated() throws Exception { @Test(timeout=60000) public void testAuthentication() throws Exception { - final AuthenticatorTestCase auth = new AuthenticatorTestCase(); + final AuthenticatorTestCase auth = new AuthenticatorTestCase(useTomcat); AuthenticatorTestCase.setAuthenticationHandlerConfig( getAuthenticationHandlerConfiguration()); KerberosTestUtils.doAsClient(new Callable() { @@ -103,7 +123,7 @@ public Void call() throws Exception { @Test(timeout=60000) public void testAuthenticationPost() throws Exception { - final AuthenticatorTestCase auth = new AuthenticatorTestCase(); + final AuthenticatorTestCase auth = new AuthenticatorTestCase(useTomcat); AuthenticatorTestCase.setAuthenticationHandlerConfig( getAuthenticationHandlerConfiguration()); KerberosTestUtils.doAsClient(new Callable() { @@ -114,4 +134,32 @@ public Void call() throws Exception { } }); } + + @Test(timeout=60000) + public void testAuthenticationHttpClient() throws Exception { + final AuthenticatorTestCase auth = new AuthenticatorTestCase(useTomcat); + AuthenticatorTestCase.setAuthenticationHandlerConfig( + getAuthenticationHandlerConfiguration()); + KerberosTestUtils.doAsClient(new Callable() { + @Override + public Void call() throws Exception { + auth._testAuthenticationHttpClient(new KerberosAuthenticator(), false); + return null; + } + }); + } + + @Test(timeout=60000) + public void testAuthenticationHttpClientPost() throws Exception { + final AuthenticatorTestCase auth = new AuthenticatorTestCase(useTomcat); + AuthenticatorTestCase.setAuthenticationHandlerConfig( + getAuthenticationHandlerConfiguration()); + KerberosTestUtils.doAsClient(new Callable() { + @Override + public Void call() throws Exception { + auth._testAuthenticationHttpClient(new KerberosAuthenticator(), true); + return null; + } + }); + } } diff --git a/hadoop-common-project/hadoop-common/CHANGES.txt b/hadoop-common-project/hadoop-common/CHANGES.txt index 717bd24978..637636479f 100644 --- a/hadoop-common-project/hadoop-common/CHANGES.txt +++ b/hadoop-common-project/hadoop-common/CHANGES.txt @@ -710,6 +710,9 @@ Release 2.6.0 - UNRELEASED loaded. (umamahesh) -- + HADOOP-10911. hadoop.auth cookie after HADOOP-10710 still not proper + according to RFC2109. (gchanan via tucu) + Release 2.5.1 - UNRELEASED INCOMPATIBLE CHANGES diff --git a/hadoop-project/pom.xml b/hadoop-project/pom.xml index beaeec63a7..e9adc31592 100644 --- a/hadoop-project/pom.xml +++ b/hadoop-project/pom.xml @@ -398,6 +398,16 @@ jetty-util 6.1.26 + + org.apache.tomcat.embed + tomcat-embed-core + 7.0.55 + + + org.apache.tomcat.embed + tomcat-embed-logging-juli + 7.0.55 + javax.servlet.jsp jsp-api