Added: hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/token/delegation/web/PseudoDelegationTokenAuthenticationHandler.java URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/token/delegation/web/PseudoDelegationTokenAuthenticationHandler.java?rev=1616672&view=auto ============================================================================== --- hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/token/delegation/web/PseudoDelegationTokenAuthenticationHandler.java (added) +++ hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/token/delegation/web/PseudoDelegationTokenAuthenticationHandler.java Fri Aug 8 04:58:58 2014 @@ -0,0 +1,55 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.security.token.delegation.web; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.classification.InterfaceStability; +import org.apache.hadoop.security.authentication.server.AuthenticationHandler; +import org.apache.hadoop.security.authentication.server.KerberosAuthenticationHandler; +import org.apache.hadoop.security.authentication.server.PseudoAuthenticationHandler; + +/** + * An {@link AuthenticationHandler} that implements Kerberos SPNEGO mechanism + * for HTTP and supports Delegation Token functionality. + * <p/> + * In addition to the {@link KerberosAuthenticationHandler} configuration + * properties, this handler supports: + * <ul> + * <li>simple.delegation-token.token-kind: the token kind for generated tokens + * (no default, required property).</li> + * <li>simple.delegation-token.update-interval.sec: secret manager master key + * update interval in seconds (default 1 day).</li> + * <li>simple.delegation-token.max-lifetime.sec: maximum life of a delegation + * token in seconds (default 7 days).</li> + * <li>simple.delegation-token.renewal-interval.sec: renewal interval for + * delegation tokens in seconds (default 1 day).</li> + * <li>simple.delegation-token.removal-scan-interval.sec: delegation tokens + * removal scan interval in seconds (default 1 hour).</li> + * </ul> + */ [email protected] [email protected] +public class PseudoDelegationTokenAuthenticationHandler + extends DelegationTokenAuthenticationHandler { + + public PseudoDelegationTokenAuthenticationHandler() { + super(new PseudoAuthenticationHandler(PseudoAuthenticationHandler.TYPE + + TYPE_POSTFIX)); + } + +}
Modified: hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/token/delegation/web/PseudoDelegationTokenAuthenticator.java URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/token/delegation/web/PseudoDelegationTokenAuthenticator.java?rev=1616672&r1=1616671&r2=1616672&view=diff ============================================================================== --- hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/token/delegation/web/PseudoDelegationTokenAuthenticator.java (original) +++ hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/token/delegation/web/PseudoDelegationTokenAuthenticator.java Fri Aug 8 04:58:58 2014 @@ -15,33 +15,40 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -package org.apache.hadoop.fs.http.client; +package org.apache.hadoop.security.token.delegation.web; import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.classification.InterfaceStability; import org.apache.hadoop.security.UserGroupInformation; import org.apache.hadoop.security.authentication.client.PseudoAuthenticator; import java.io.IOException; /** - * A <code>PseudoAuthenticator</code> subclass that uses FileSystemAccess's - * <code>UserGroupInformation</code> to obtain the client user name (the UGI's login user). + * The <code>PseudoDelegationTokenAuthenticator</code> provides support for + * Hadoop's pseudo authentication mechanism that accepts + * the user name specified as a query string parameter and support for Hadoop + * Delegation Token operations. + * <p/> + * This mimics the model of Hadoop Simple authentication trusting the + * {@link UserGroupInformation#getCurrentUser()} value. */ [email protected] -public class HttpFSPseudoAuthenticator extends PseudoAuthenticator { [email protected] [email protected] +public class PseudoDelegationTokenAuthenticator + extends DelegationTokenAuthenticator { - /** - * Return the client user name. - * - * @return the client user name. - */ - @Override - protected String getUserName() { - try { - return UserGroupInformation.getLoginUser().getUserName(); - } catch (IOException ex) { - throw new SecurityException("Could not obtain current user, " + ex.getMessage(), ex); - } + public PseudoDelegationTokenAuthenticator() { + super(new PseudoAuthenticator() { + @Override + protected String getUserName() { + try { + return UserGroupInformation.getCurrentUser().getShortUserName(); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } + }); } + } Added: hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/token/delegation/web/ServletUtils.java URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/token/delegation/web/ServletUtils.java?rev=1616672&view=auto ============================================================================== --- hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/token/delegation/web/ServletUtils.java (added) +++ hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/token/delegation/web/ServletUtils.java Fri Aug 8 04:58:58 2014 @@ -0,0 +1,59 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.security.token.delegation.web; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.http.NameValuePair; +import org.apache.http.client.utils.URLEncodedUtils; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.List; + +/** + * Servlet utility methods. + */ [email protected] +class ServletUtils { + private static final Charset UTF8_CHARSET = Charset.forName("UTF-8"); + + /** + * Extract a query string parameter without triggering http parameters + * processing by the servlet container. + * + * @param request the request + * @param name the parameter to get the value. + * @return the parameter value, or <code>NULL</code> if the parameter is not + * defined. + * @throws IOException thrown if there was an error parsing the query string. + */ + public static String getParameter(HttpServletRequest request, String name) + throws IOException { + List<NameValuePair> list = URLEncodedUtils.parse(request.getQueryString(), + UTF8_CHARSET); + if (list != null) { + for (NameValuePair nv : list) { + if (name.equals(nv.getName())) { + return nv.getValue(); + } + } + } + return null; + } +} Modified: hadoop/common/trunk/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/token/delegation/web/TestDelegationTokenAuthenticationHandlerWithMocks.java URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/token/delegation/web/TestDelegationTokenAuthenticationHandlerWithMocks.java?rev=1616672&r1=1616671&r2=1616672&view=diff ============================================================================== --- hadoop/common/trunk/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/token/delegation/web/TestDelegationTokenAuthenticationHandlerWithMocks.java (original) +++ hadoop/common/trunk/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/token/delegation/web/TestDelegationTokenAuthenticationHandlerWithMocks.java Fri Aug 8 04:58:58 2014 @@ -15,141 +15,162 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +package org.apache.hadoop.security.token.delegation.web; -package org.apache.hadoop.fs.http.server; - -import org.apache.hadoop.conf.Configuration; -import org.apache.hadoop.fs.http.client.HttpFSFileSystem; -import org.apache.hadoop.fs.http.client.HttpFSKerberosAuthenticator; -import org.apache.hadoop.fs.http.client.HttpFSKerberosAuthenticator.DelegationTokenOperation; -import org.apache.hadoop.hdfs.web.SWebHdfsFileSystem; -import org.apache.hadoop.hdfs.web.WebHdfsFileSystem; import org.apache.hadoop.io.Text; -import org.apache.hadoop.lib.service.DelegationTokenIdentifier; -import org.apache.hadoop.lib.service.DelegationTokenManager; -import org.apache.hadoop.lib.service.DelegationTokenManagerException; -import org.apache.hadoop.lib.servlet.ServerWebApp; import org.apache.hadoop.security.UserGroupInformation; import org.apache.hadoop.security.authentication.client.AuthenticationException; +import org.apache.hadoop.security.authentication.client.KerberosAuthenticator; import org.apache.hadoop.security.authentication.server.AuthenticationHandler; import org.apache.hadoop.security.authentication.server.AuthenticationToken; +import org.apache.hadoop.security.token.SecretManager; import org.apache.hadoop.security.token.Token; -import org.apache.hadoop.test.HFSTestCase; -import org.apache.hadoop.test.TestDir; -import org.apache.hadoop.test.TestDirHelper; -import org.json.simple.JSONObject; -import org.json.simple.parser.JSONParser; +import org.codehaus.jackson.map.ObjectMapper; +import org.junit.After; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; +import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.ws.rs.core.MediaType; +import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; -import java.net.InetAddress; -import java.net.InetSocketAddress; +import java.util.Map; +import java.util.Properties; -public class TestHttpFSKerberosAuthenticationHandler extends HFSTestCase { +public class TestDelegationTokenAuthenticationHandlerWithMocks { - @Test - @TestDir - public void testManagementOperationsWebHdfsFileSystem() throws Exception { - testManagementOperations(WebHdfsFileSystem.TOKEN_KIND); - } + public static class MockDelegationTokenAuthenticationHandler + extends DelegationTokenAuthenticationHandler { - @Test - @TestDir - public void testManagementOperationsSWebHdfsFileSystem() throws Exception { - try { - System.setProperty(HttpFSServerWebApp.NAME + - ServerWebApp.SSL_ENABLED, "true"); - testManagementOperations(SWebHdfsFileSystem.TOKEN_KIND); - } finally { - System.getProperties().remove(HttpFSServerWebApp.NAME + - ServerWebApp.SSL_ENABLED); + public MockDelegationTokenAuthenticationHandler() { + super(new AuthenticationHandler() { + @Override + public String getType() { + return "T"; + } + + @Override + public void init(Properties config) throws ServletException { + + } + + @Override + public void destroy() { + + } + + @Override + public boolean managementOperation(AuthenticationToken token, + HttpServletRequest request, HttpServletResponse response) + throws IOException, AuthenticationException { + return false; + } + + @Override + public AuthenticationToken authenticate(HttpServletRequest request, + HttpServletResponse response) + throws IOException, AuthenticationException { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + response.setHeader(KerberosAuthenticator.WWW_AUTHENTICATE, "mock"); + return null; + } + }); } + } - private void testManagementOperations(Text expectedTokenKind) throws Exception { - String dir = TestDirHelper.getTestDir().getAbsolutePath(); + private DelegationTokenAuthenticationHandler handler; - Configuration httpfsConf = new Configuration(false); - HttpFSServerWebApp server = - new HttpFSServerWebApp(dir, dir, dir, dir, httpfsConf); - server.setAuthority(new InetSocketAddress(InetAddress.getLocalHost(), - 14000)); - AuthenticationHandler handler = - new HttpFSKerberosAuthenticationHandlerForTesting(); - try { - server.init(); - handler.init(null); + @Before + public void setUp() throws Exception { + Properties conf = new Properties(); - testNonManagementOperation(handler); - testManagementOperationErrors(handler); - testGetToken(handler, null, expectedTokenKind); - testGetToken(handler, "foo", expectedTokenKind); - testCancelToken(handler); - testRenewToken(handler); - - } finally { - if (handler != null) { - handler.destroy(); - } - server.destroy(); - } + conf.put(KerberosDelegationTokenAuthenticationHandler.TOKEN_KIND, "foo"); + handler = new MockDelegationTokenAuthenticationHandler(); + handler.initTokenManager(conf); } - private void testNonManagementOperation(AuthenticationHandler handler) - throws Exception { + @After + public void cleanUp() { + handler.destroy(); + } + + @Test + public void testManagementOperations() throws Exception { + testNonManagementOperation(); + testManagementOperationErrors(); + testGetToken(null, new Text("foo")); + testGetToken("bar", new Text("foo")); + testCancelToken(); + testRenewToken(); + } + + private void testNonManagementOperation() throws Exception { HttpServletRequest request = Mockito.mock(HttpServletRequest.class); - Mockito.when(request.getParameter(HttpFSFileSystem.OP_PARAM)). - thenReturn(null); + Mockito.when(request.getParameter( + DelegationTokenAuthenticator.OP_PARAM)).thenReturn(null); Assert.assertTrue(handler.managementOperation(null, request, null)); - Mockito.when(request.getParameter(HttpFSFileSystem.OP_PARAM)). - thenReturn(HttpFSFileSystem.Operation.CREATE.toString()); + Mockito.when(request.getParameter( + DelegationTokenAuthenticator.OP_PARAM)).thenReturn("CREATE"); Assert.assertTrue(handler.managementOperation(null, request, null)); } - private void testManagementOperationErrors(AuthenticationHandler handler) - throws Exception { + private void testManagementOperationErrors() throws Exception { HttpServletRequest request = Mockito.mock(HttpServletRequest.class); HttpServletResponse response = Mockito.mock(HttpServletResponse.class); - Mockito.when(request.getParameter(HttpFSFileSystem.OP_PARAM)). - thenReturn(DelegationTokenOperation.GETDELEGATIONTOKEN.toString()); + Mockito.when(request.getQueryString()).thenReturn( + DelegationTokenAuthenticator.OP_PARAM + "=" + + DelegationTokenAuthenticator.DelegationTokenOperation. + GETDELEGATIONTOKEN.toString() + ); Mockito.when(request.getMethod()).thenReturn("FOO"); Assert.assertFalse(handler.managementOperation(null, request, response)); Mockito.verify(response).sendError( - Mockito.eq(HttpServletResponse.SC_BAD_REQUEST), - Mockito.startsWith("Wrong HTTP method")); + Mockito.eq(HttpServletResponse.SC_BAD_REQUEST), + Mockito.startsWith("Wrong HTTP method")); Mockito.reset(response); - Mockito.when(request.getMethod()). - thenReturn(DelegationTokenOperation.GETDELEGATIONTOKEN.getHttpMethod()); + Mockito.when(request.getMethod()).thenReturn( + DelegationTokenAuthenticator.DelegationTokenOperation. + GETDELEGATIONTOKEN.getHttpMethod() + ); Assert.assertFalse(handler.managementOperation(null, request, response)); - Mockito.verify(response).sendError( - Mockito.eq(HttpServletResponse.SC_UNAUTHORIZED), - Mockito.contains("requires SPNEGO")); + Mockito.verify(response).setStatus( + Mockito.eq(HttpServletResponse.SC_UNAUTHORIZED)); + Mockito.verify(response).setHeader( + Mockito.eq(KerberosAuthenticator.WWW_AUTHENTICATE), + Mockito.eq("mock")); } - private void testGetToken(AuthenticationHandler handler, String renewer, - Text expectedTokenKind) throws Exception { - DelegationTokenOperation op = DelegationTokenOperation.GETDELEGATIONTOKEN; + private void testGetToken(String renewer, Text expectedTokenKind) + throws Exception { + DelegationTokenAuthenticator.DelegationTokenOperation op = + DelegationTokenAuthenticator.DelegationTokenOperation. + GETDELEGATIONTOKEN; HttpServletRequest request = Mockito.mock(HttpServletRequest.class); HttpServletResponse response = Mockito.mock(HttpServletResponse.class); - Mockito.when(request.getParameter(HttpFSFileSystem.OP_PARAM)). - thenReturn(op.toString()); - Mockito.when(request.getMethod()). - thenReturn(op.getHttpMethod()); + Mockito.when(request.getQueryString()). + thenReturn(DelegationTokenAuthenticator.OP_PARAM + "=" + op.toString()); + Mockito.when(request.getMethod()).thenReturn(op.getHttpMethod()); AuthenticationToken token = Mockito.mock(AuthenticationToken.class); Mockito.when(token.getUserName()).thenReturn("user"); - Assert.assertFalse(handler.managementOperation(null, request, response)); - Mockito.when(request.getParameter(HttpFSKerberosAuthenticator.RENEWER_PARAM)). - thenReturn(renewer); + Mockito.when(response.getWriter()).thenReturn(new PrintWriter( + new StringWriter())); + Assert.assertFalse(handler.managementOperation(token, request, response)); + + Mockito.when(request.getQueryString()). + thenReturn(DelegationTokenAuthenticator.OP_PARAM + "=" + op.toString() + + "&" + DelegationTokenAuthenticator.RENEWER_PARAM + "=" + renewer); Mockito.reset(response); + Mockito.reset(token); + Mockito.when(token.getUserName()).thenReturn("user"); StringWriter writer = new StringWriter(); PrintWriter pwriter = new PrintWriter(writer); Mockito.when(response.getWriter()).thenReturn(pwriter); @@ -157,151 +178,140 @@ public class TestHttpFSKerberosAuthentic if (renewer == null) { Mockito.verify(token).getUserName(); } else { - Mockito.verify(token, Mockito.never()).getUserName(); + Mockito.verify(token).getUserName(); } Mockito.verify(response).setStatus(HttpServletResponse.SC_OK); Mockito.verify(response).setContentType(MediaType.APPLICATION_JSON); pwriter.close(); String responseOutput = writer.toString(); - String tokenLabel = HttpFSKerberosAuthenticator.DELEGATION_TOKEN_JSON; + String tokenLabel = DelegationTokenAuthenticator. + DELEGATION_TOKEN_JSON; Assert.assertTrue(responseOutput.contains(tokenLabel)); Assert.assertTrue(responseOutput.contains( - HttpFSKerberosAuthenticator.DELEGATION_TOKEN_URL_STRING_JSON)); - JSONObject json = (JSONObject) new JSONParser().parse(responseOutput); - json = (JSONObject) json.get(tokenLabel); + DelegationTokenAuthenticator.DELEGATION_TOKEN_URL_STRING_JSON)); + ObjectMapper jsonMapper = new ObjectMapper(); + Map json = jsonMapper.readValue(responseOutput, Map.class); + json = (Map) json.get(tokenLabel); String tokenStr; - tokenStr = (String) - json.get(HttpFSKerberosAuthenticator.DELEGATION_TOKEN_URL_STRING_JSON); + tokenStr = (String) json.get(DelegationTokenAuthenticator. + DELEGATION_TOKEN_URL_STRING_JSON); Token<DelegationTokenIdentifier> dt = new Token<DelegationTokenIdentifier>(); dt.decodeFromUrlString(tokenStr); - HttpFSServerWebApp.get().get(DelegationTokenManager.class).verifyToken(dt); + handler.getTokenManager().verifyToken(dt); Assert.assertEquals(expectedTokenKind, dt.getKind()); } - private void testCancelToken(AuthenticationHandler handler) - throws Exception { - DelegationTokenOperation op = - DelegationTokenOperation.CANCELDELEGATIONTOKEN; + private void testCancelToken() throws Exception { + DelegationTokenAuthenticator.DelegationTokenOperation op = + DelegationTokenAuthenticator.DelegationTokenOperation. + CANCELDELEGATIONTOKEN; HttpServletRequest request = Mockito.mock(HttpServletRequest.class); HttpServletResponse response = Mockito.mock(HttpServletResponse.class); - Mockito.when(request.getParameter(HttpFSFileSystem.OP_PARAM)). - thenReturn(op.toString()); + Mockito.when(request.getQueryString()).thenReturn( + DelegationTokenAuthenticator.OP_PARAM + "=" + op.toString()); Mockito.when(request.getMethod()). - thenReturn(op.getHttpMethod()); + thenReturn(op.getHttpMethod()); Assert.assertFalse(handler.managementOperation(null, request, response)); Mockito.verify(response).sendError( - Mockito.eq(HttpServletResponse.SC_BAD_REQUEST), - Mockito.contains("requires the parameter [token]")); + Mockito.eq(HttpServletResponse.SC_BAD_REQUEST), + Mockito.contains("requires the parameter [token]")); Mockito.reset(response); Token<DelegationTokenIdentifier> token = - HttpFSServerWebApp.get().get(DelegationTokenManager.class).createToken( - UserGroupInformation.getCurrentUser(), "foo"); - Mockito.when(request.getParameter(HttpFSKerberosAuthenticator.TOKEN_PARAM)). - thenReturn(token.encodeToUrlString()); + handler.getTokenManager().createToken( + UserGroupInformation.getCurrentUser(), "foo"); + Mockito.when(request.getQueryString()).thenReturn( + DelegationTokenAuthenticator.OP_PARAM + "=" + op.toString() + "&" + + DelegationTokenAuthenticator.TOKEN_PARAM + "=" + + token.encodeToUrlString()); Assert.assertFalse(handler.managementOperation(null, request, response)); Mockito.verify(response).setStatus(HttpServletResponse.SC_OK); try { - HttpFSServerWebApp.get().get(DelegationTokenManager.class).verifyToken(token); + handler.getTokenManager().verifyToken(token); + Assert.fail(); + } catch (SecretManager.InvalidToken ex) { + //NOP + } catch (Throwable ex) { Assert.fail(); - } - catch (DelegationTokenManagerException ex) { - Assert.assertTrue(ex.toString().contains("DT01")); } } - private void testRenewToken(AuthenticationHandler handler) - throws Exception { - DelegationTokenOperation op = - DelegationTokenOperation.RENEWDELEGATIONTOKEN; + private void testRenewToken() throws Exception { + DelegationTokenAuthenticator.DelegationTokenOperation op = + DelegationTokenAuthenticator.DelegationTokenOperation. + RENEWDELEGATIONTOKEN; HttpServletRequest request = Mockito.mock(HttpServletRequest.class); HttpServletResponse response = Mockito.mock(HttpServletResponse.class); - Mockito.when(request.getParameter(HttpFSFileSystem.OP_PARAM)). - thenReturn(op.toString()); + Mockito.when(request.getQueryString()). + thenReturn(DelegationTokenAuthenticator.OP_PARAM + "=" + op.toString()); Mockito.when(request.getMethod()). - thenReturn(op.getHttpMethod()); + thenReturn(op.getHttpMethod()); Assert.assertFalse(handler.managementOperation(null, request, response)); - Mockito.verify(response).sendError( - Mockito.eq(HttpServletResponse.SC_UNAUTHORIZED), - Mockito.contains("equires SPNEGO authentication established")); + Mockito.verify(response).setStatus( + Mockito.eq(HttpServletResponse.SC_UNAUTHORIZED)); + Mockito.verify(response).setHeader(Mockito.eq( + KerberosAuthenticator.WWW_AUTHENTICATE), + Mockito.eq("mock") + ); Mockito.reset(response); AuthenticationToken token = Mockito.mock(AuthenticationToken.class); Mockito.when(token.getUserName()).thenReturn("user"); Assert.assertFalse(handler.managementOperation(token, request, response)); Mockito.verify(response).sendError( - Mockito.eq(HttpServletResponse.SC_BAD_REQUEST), - Mockito.contains("requires the parameter [token]")); + Mockito.eq(HttpServletResponse.SC_BAD_REQUEST), + Mockito.contains("requires the parameter [token]")); Mockito.reset(response); StringWriter writer = new StringWriter(); PrintWriter pwriter = new PrintWriter(writer); Mockito.when(response.getWriter()).thenReturn(pwriter); Token<DelegationTokenIdentifier> dToken = - HttpFSServerWebApp.get().get(DelegationTokenManager.class).createToken( - UserGroupInformation.getCurrentUser(), "user"); - Mockito.when(request.getParameter(HttpFSKerberosAuthenticator.TOKEN_PARAM)). - thenReturn(dToken.encodeToUrlString()); + handler.getTokenManager().createToken( + UserGroupInformation.getCurrentUser(), "user"); + Mockito.when(request.getQueryString()). + thenReturn(DelegationTokenAuthenticator.OP_PARAM + "=" + op.toString() + + "&" + DelegationTokenAuthenticator.TOKEN_PARAM + "=" + + dToken.encodeToUrlString()); Assert.assertFalse(handler.managementOperation(token, request, response)); Mockito.verify(response).setStatus(HttpServletResponse.SC_OK); pwriter.close(); Assert.assertTrue(writer.toString().contains("long")); - HttpFSServerWebApp.get().get(DelegationTokenManager.class).verifyToken(dToken); + handler.getTokenManager().verifyToken(dToken); } @Test - @TestDir public void testAuthenticate() throws Exception { - String dir = TestDirHelper.getTestDir().getAbsolutePath(); - - Configuration httpfsConf = new Configuration(false); - HttpFSServerWebApp server = - new HttpFSServerWebApp(dir, dir, dir, dir, httpfsConf); - server.setAuthority(new InetSocketAddress(InetAddress.getLocalHost(), - 14000)); - AuthenticationHandler handler = - new HttpFSKerberosAuthenticationHandlerForTesting(); - try { - server.init(); - handler.init(null); - - testValidDelegationToken(handler); - testInvalidDelegationToken(handler); - } finally { - if (handler != null) { - handler.destroy(); - } - server.destroy(); - } + testValidDelegationToken(); + testInvalidDelegationToken(); } - private void testValidDelegationToken(AuthenticationHandler handler) - throws Exception { + private void testValidDelegationToken() throws Exception { HttpServletRequest request = Mockito.mock(HttpServletRequest.class); HttpServletResponse response = Mockito.mock(HttpServletResponse.class); Token<DelegationTokenIdentifier> dToken = - HttpFSServerWebApp.get().get(DelegationTokenManager.class).createToken( - UserGroupInformation.getCurrentUser(), "user"); - Mockito.when(request.getParameter(HttpFSKerberosAuthenticator.DELEGATION_PARAM)). - thenReturn(dToken.encodeToUrlString()); + handler.getTokenManager().createToken( + UserGroupInformation.getCurrentUser(), "user"); + Mockito.when(request.getQueryString()).thenReturn( + DelegationTokenAuthenticator.DELEGATION_PARAM + "=" + + dToken.encodeToUrlString()); AuthenticationToken token = handler.authenticate(request, response); - Assert.assertEquals(UserGroupInformation.getCurrentUser().getShortUserName(), - token.getUserName()); + Assert.assertEquals(UserGroupInformation.getCurrentUser(). + getShortUserName(), token.getUserName()); Assert.assertEquals(0, token.getExpires()); - Assert.assertEquals(HttpFSKerberosAuthenticationHandler.TYPE, - token.getType()); + Assert.assertEquals(handler.getType(), + token.getType()); Assert.assertTrue(token.isExpired()); } - private void testInvalidDelegationToken(AuthenticationHandler handler) - throws Exception { + private void testInvalidDelegationToken() throws Exception { HttpServletRequest request = Mockito.mock(HttpServletRequest.class); HttpServletResponse response = Mockito.mock(HttpServletResponse.class); - Mockito.when(request.getParameter(HttpFSKerberosAuthenticator.DELEGATION_PARAM)). - thenReturn("invalid"); + Mockito.when(request.getQueryString()).thenReturn( + DelegationTokenAuthenticator.DELEGATION_PARAM + "=invalid"); try { handler.authenticate(request, response); Modified: hadoop/common/trunk/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/token/delegation/web/TestDelegationTokenManager.java URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/token/delegation/web/TestDelegationTokenManager.java?rev=1616672&r1=1616671&r2=1616672&view=diff ============================================================================== --- hadoop/common/trunk/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/token/delegation/web/TestDelegationTokenManager.java (original) +++ hadoop/common/trunk/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/token/delegation/web/TestDelegationTokenManager.java Fri Aug 8 04:58:58 2014 @@ -15,62 +15,32 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -package org.apache.hadoop.lib.service.security; +package org.apache.hadoop.security.token.delegation.web; import org.apache.hadoop.conf.Configuration; -import org.apache.hadoop.fs.http.server.HttpFSServerWebApp; -import org.apache.hadoop.lib.server.Server; -import org.apache.hadoop.lib.service.DelegationTokenManager; -import org.apache.hadoop.lib.service.DelegationTokenManagerException; -import org.apache.hadoop.lib.service.hadoop.FileSystemAccessService; -import org.apache.hadoop.lib.service.instrumentation.InstrumentationService; -import org.apache.hadoop.lib.service.scheduler.SchedulerService; +import org.apache.hadoop.io.Text; import org.apache.hadoop.security.UserGroupInformation; import org.apache.hadoop.security.token.Token; -import org.apache.hadoop.test.HTestCase; -import org.apache.hadoop.test.TestDir; -import org.apache.hadoop.test.TestDirHelper; import org.apache.hadoop.util.StringUtils; import org.junit.Assert; import org.junit.Test; +import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.util.Arrays; -public class TestDelegationTokenManagerService extends HTestCase { +public class TestDelegationTokenManager { - @Test - @TestDir - public void service() throws Exception { - String dir = TestDirHelper.getTestDir().getAbsolutePath(); - Configuration conf = new Configuration(false); - conf.set("httpfs.services", StringUtils.join(",", - Arrays.asList(InstrumentationService.class.getName(), - SchedulerService.class.getName(), - FileSystemAccessService.class.getName(), - DelegationTokenManagerService.class.getName()))); - Server server = new HttpFSServerWebApp(dir, dir, dir, dir, conf); - server.init(); - DelegationTokenManager tm = server.get(DelegationTokenManager.class); - Assert.assertNotNull(tm); - server.destroy(); - } + private static final long DAY_IN_SECS = 86400; @Test - @TestDir - @SuppressWarnings("unchecked") - public void tokens() throws Exception { - String dir = TestDirHelper.getTestDir().getAbsolutePath(); - Configuration conf = new Configuration(false); - conf.set("server.services", StringUtils.join(",", - Arrays.asList(DelegationTokenManagerService.class.getName()))); - HttpFSServerWebApp server = new HttpFSServerWebApp(dir, dir, dir, dir, conf); - server.setAuthority(new InetSocketAddress(InetAddress.getLocalHost(), 14000)); - server.init(); - DelegationTokenManager tm = server.get(DelegationTokenManager.class); - Token token = tm.createToken(UserGroupInformation.getCurrentUser(), "foo"); + public void testDTManager() throws Exception { + DelegationTokenManager tm = new DelegationTokenManager(new Text("foo"), + DAY_IN_SECS, DAY_IN_SECS, DAY_IN_SECS, DAY_IN_SECS); + tm.init(); + Token<DelegationTokenIdentifier> token = + tm.createToken(UserGroupInformation.getCurrentUser(), "foo"); Assert.assertNotNull(token); tm.verifyToken(token); Assert.assertTrue(tm.renewToken(token, "foo") > System.currentTimeMillis()); @@ -78,12 +48,12 @@ public class TestDelegationTokenManagerS try { tm.verifyToken(token); Assert.fail(); - } catch (DelegationTokenManagerException ex) { + } catch (IOException ex) { //NOP } catch (Exception ex) { Assert.fail(); } - server.destroy(); + tm.destroy(); } } Added: hadoop/common/trunk/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/token/delegation/web/TestWebDelegationToken.java URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/token/delegation/web/TestWebDelegationToken.java?rev=1616672&view=auto ============================================================================== --- hadoop/common/trunk/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/token/delegation/web/TestWebDelegationToken.java (added) +++ hadoop/common/trunk/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/token/delegation/web/TestWebDelegationToken.java Fri Aug 8 04:58:58 2014 @@ -0,0 +1,727 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.security.token.delegation.web; + +import org.apache.commons.io.IOUtils; +import org.apache.hadoop.io.Text; +import org.apache.hadoop.minikdc.MiniKdc; +import org.apache.hadoop.security.UserGroupInformation; +import org.apache.hadoop.security.authentication.client.AuthenticationException; +import org.apache.hadoop.security.authentication.client.KerberosAuthenticator; +import org.apache.hadoop.security.authentication.server.AuthenticationFilter; +import org.apache.hadoop.security.authentication.server.AuthenticationHandler; +import org.apache.hadoop.security.authentication.server.AuthenticationToken; +import org.apache.hadoop.security.authentication.server.KerberosAuthenticationHandler; +import org.apache.hadoop.security.authentication.server.PseudoAuthenticationHandler; +import org.apache.hadoop.security.authentication.util.KerberosUtil; +import org.apache.hadoop.security.token.delegation.AbstractDelegationTokenSecretManager; +import org.codehaus.jackson.map.ObjectMapper; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mortbay.jetty.Connector; +import org.mortbay.jetty.Server; +import org.mortbay.jetty.servlet.Context; +import org.mortbay.jetty.servlet.FilterHolder; +import org.mortbay.jetty.servlet.ServletHolder; + +import javax.security.auth.Subject; +import javax.security.auth.kerberos.KerberosPrincipal; +import javax.security.auth.login.AppConfigurationEntry; +import javax.security.auth.login.Configuration; +import javax.security.auth.login.LoginContext; +import javax.servlet.Filter; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.io.IOException; +import java.io.Writer; +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.URL; +import java.security.Principal; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.Callable; + +public class TestWebDelegationToken { + private Server jetty; + + public static class DummyAuthenticationHandler + implements AuthenticationHandler { + @Override + public String getType() { + return "dummy"; + } + + @Override + public void init(Properties config) throws ServletException { + } + + @Override + public void destroy() { + } + + @Override + public boolean managementOperation(AuthenticationToken token, + HttpServletRequest request, HttpServletResponse response) + throws IOException, AuthenticationException { + return false; + } + + @Override + public AuthenticationToken authenticate(HttpServletRequest request, + HttpServletResponse response) + throws IOException, AuthenticationException { + AuthenticationToken token = null; + if (request.getParameter("authenticated") != null) { + token = new AuthenticationToken(request.getParameter("authenticated"), + "U", "test"); + } else { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + response.setHeader(KerberosAuthenticator.WWW_AUTHENTICATE, "dummy"); + } + return token; + } + } + + public static class DummyDelegationTokenAuthenticationHandler extends + DelegationTokenAuthenticationHandler { + public DummyDelegationTokenAuthenticationHandler() { + super(new DummyAuthenticationHandler()); + } + + @Override + public void init(Properties config) throws ServletException { + Properties conf = new Properties(config); + conf.setProperty(TOKEN_KIND, "token-kind"); + initTokenManager(conf); + } + } + + public static class AFilter extends DelegationTokenAuthenticationFilter { + + @Override + protected Properties getConfiguration(String configPrefix, + FilterConfig filterConfig) { + Properties conf = new Properties(); + conf.setProperty(AUTH_TYPE, + DummyDelegationTokenAuthenticationHandler.class.getName()); + return conf; + } + } + + public static class PingServlet extends HttpServlet { + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + resp.setStatus(HttpServletResponse.SC_OK); + resp.getWriter().write("ping"); + } + + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + Writer writer = resp.getWriter(); + writer.write("ping: "); + IOUtils.copy(req.getReader(), writer); + resp.setStatus(HttpServletResponse.SC_OK); + } + } + + protected Server createJettyServer() { + try { + InetAddress localhost = InetAddress.getLocalHost(); + ServerSocket ss = new ServerSocket(0, 50, localhost); + int port = ss.getLocalPort(); + ss.close(); + jetty = new Server(0); + jetty.getConnectors()[0].setHost("localhost"); + jetty.getConnectors()[0].setPort(port); + return jetty; + } catch (Exception ex) { + throw new RuntimeException("Could not setup Jetty: " + ex.getMessage(), + ex); + } + } + + protected String getJettyURL() { + Connector c = jetty.getConnectors()[0]; + return "http://" + c.getHost() + ":" + c.getPort(); + } + + @Before + public void setUp() throws Exception { + // resetting hadoop security to simple + org.apache.hadoop.conf.Configuration conf = + new org.apache.hadoop.conf.Configuration(); + UserGroupInformation.setConfiguration(conf); + + jetty = createJettyServer(); + } + + @After + public void cleanUp() throws Exception { + jetty.stop(); + + // resetting hadoop security to simple + org.apache.hadoop.conf.Configuration conf = + new org.apache.hadoop.conf.Configuration(); + UserGroupInformation.setConfiguration(conf); + } + + protected Server getJetty() { + return jetty; + } + + @Test + public void testRawHttpCalls() throws Exception { + final Server jetty = createJettyServer(); + Context context = new Context(); + context.setContextPath("/foo"); + jetty.setHandler(context); + context.addFilter(new FilterHolder(AFilter.class), "/*", 0); + context.addServlet(new ServletHolder(PingServlet.class), "/bar"); + try { + jetty.start(); + URL nonAuthURL = new URL(getJettyURL() + "/foo/bar"); + URL authURL = new URL(getJettyURL() + "/foo/bar?authenticated=foo"); + + // unauthenticated access to URL + HttpURLConnection conn = (HttpURLConnection) nonAuthURL.openConnection(); + Assert.assertEquals(HttpURLConnection.HTTP_UNAUTHORIZED, + conn.getResponseCode()); + + // authenticated access to URL + conn = (HttpURLConnection) authURL.openConnection(); + Assert.assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode()); + + // unauthenticated access to get delegation token + URL url = new URL(nonAuthURL.toExternalForm() + "?op=GETDELEGATIONTOKEN"); + conn = (HttpURLConnection) url.openConnection(); + Assert.assertEquals(HttpURLConnection.HTTP_UNAUTHORIZED, + conn.getResponseCode()); + + // authenticated access to get delegation token + url = new URL(authURL.toExternalForm() + + "&op=GETDELEGATIONTOKEN&renewer=foo"); + conn = (HttpURLConnection) url.openConnection(); + Assert.assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode()); + ObjectMapper mapper = new ObjectMapper(); + Map map = mapper.readValue(conn.getInputStream(), Map.class); + String dt = (String) ((Map) map.get("Token")).get("urlString"); + Assert.assertNotNull(dt); + + // delegation token access to URL + url = new URL(nonAuthURL.toExternalForm() + "?delegation=" + dt); + conn = (HttpURLConnection) url.openConnection(); + Assert.assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode()); + + // delegation token and authenticated access to URL + url = new URL(authURL.toExternalForm() + "&delegation=" + dt); + conn = (HttpURLConnection) url.openConnection(); + Assert.assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode()); + + // renewew delegation token, unauthenticated access to URL + url = new URL(nonAuthURL.toExternalForm() + + "?op=RENEWDELEGATIONTOKEN&token=" + dt); + conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("PUT"); + Assert.assertEquals(HttpURLConnection.HTTP_UNAUTHORIZED, + conn.getResponseCode()); + + // renewew delegation token, authenticated access to URL + url = new URL(authURL.toExternalForm() + + "&op=RENEWDELEGATIONTOKEN&token=" + dt); + conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("PUT"); + Assert.assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode()); + + // renewew delegation token, authenticated access to URL, not renewer + url = new URL(getJettyURL() + + "/foo/bar?authenticated=bar&op=RENEWDELEGATIONTOKEN&token=" + dt); + conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("PUT"); + Assert.assertEquals(HttpURLConnection.HTTP_FORBIDDEN, + conn.getResponseCode()); + + // cancel delegation token, nonauthenticated access to URL + url = new URL(nonAuthURL.toExternalForm() + + "?op=CANCELDELEGATIONTOKEN&token=" + dt); + conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("PUT"); + Assert.assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode()); + + // cancel canceled delegation token, nonauthenticated access to URL + url = new URL(nonAuthURL.toExternalForm() + + "?op=CANCELDELEGATIONTOKEN&token=" + dt); + conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("PUT"); + Assert.assertEquals(HttpURLConnection.HTTP_NOT_FOUND, + conn.getResponseCode()); + + // get new delegation token + url = new URL(authURL.toExternalForm() + + "&op=GETDELEGATIONTOKEN&renewer=foo"); + conn = (HttpURLConnection) url.openConnection(); + Assert.assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode()); + mapper = new ObjectMapper(); + map = mapper.readValue(conn.getInputStream(), Map.class); + dt = (String) ((Map) map.get("Token")).get("urlString"); + Assert.assertNotNull(dt); + + // cancel delegation token, authenticated access to URL + url = new URL(authURL.toExternalForm() + + "&op=CANCELDELEGATIONTOKEN&token=" + dt); + conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("PUT"); + Assert.assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode()); + } finally { + jetty.stop(); + } + } + + @Test + public void testDelegationTokenAuthenticatorCalls() throws Exception { + final Server jetty = createJettyServer(); + Context context = new Context(); + context.setContextPath("/foo"); + jetty.setHandler(context); + context.addFilter(new FilterHolder(AFilter.class), "/*", 0); + context.addServlet(new ServletHolder(PingServlet.class), "/bar"); + + try { + jetty.start(); + URL nonAuthURL = new URL(getJettyURL() + "/foo/bar"); + URL authURL = new URL(getJettyURL() + "/foo/bar?authenticated=foo"); + URL authURL2 = new URL(getJettyURL() + "/foo/bar?authenticated=bar"); + + DelegationTokenAuthenticatedURL.Token token = + new DelegationTokenAuthenticatedURL.Token(); + DelegationTokenAuthenticatedURL aUrl = + new DelegationTokenAuthenticatedURL(); + + try { + aUrl.getDelegationToken(nonAuthURL, token, "foo"); + Assert.fail(); + } catch (Exception ex) { + Assert.assertTrue(ex.getMessage().contains("401")); + } + + aUrl.getDelegationToken(authURL, token, "foo"); + Assert.assertNotNull(token.getDelegationToken()); + Assert.assertEquals(new Text("token-kind"), + token.getDelegationToken().getKind()); + + aUrl.renewDelegationToken(authURL, token); + + try { + aUrl.renewDelegationToken(nonAuthURL, token); + Assert.fail(); + } catch (Exception ex) { + Assert.assertTrue(ex.getMessage().contains("401")); + } + + aUrl.getDelegationToken(authURL, token, "foo"); + + try { + aUrl.renewDelegationToken(authURL2, token); + Assert.fail(); + } catch (Exception ex) { + Assert.assertTrue(ex.getMessage().contains("403")); + } + + aUrl.getDelegationToken(authURL, token, "foo"); + + aUrl.cancelDelegationToken(authURL, token); + + aUrl.getDelegationToken(authURL, token, "foo"); + + aUrl.cancelDelegationToken(nonAuthURL, token); + + aUrl.getDelegationToken(authURL, token, "foo"); + + try { + aUrl.renewDelegationToken(nonAuthURL, token); + } catch (Exception ex) { + Assert.assertTrue(ex.getMessage().contains("401")); + } + + } finally { + jetty.stop(); + } + } + + private static class DummyDelegationTokenSecretManager + extends AbstractDelegationTokenSecretManager<DelegationTokenIdentifier> { + + public DummyDelegationTokenSecretManager() { + super(10000, 10000, 10000, 10000); + } + + @Override + public DelegationTokenIdentifier createIdentifier() { + return new DelegationTokenIdentifier(new Text("fooKind")); + } + + } + + @Test + public void testExternalDelegationTokenSecretManager() throws Exception { + DummyDelegationTokenSecretManager secretMgr + = new DummyDelegationTokenSecretManager(); + final Server jetty = createJettyServer(); + Context context = new Context(); + context.setContextPath("/foo"); + jetty.setHandler(context); + context.addFilter(new FilterHolder(AFilter.class), "/*", 0); + context.addServlet(new ServletHolder(PingServlet.class), "/bar"); + try { + secretMgr.startThreads(); + context.setAttribute(DelegationTokenAuthenticationFilter. + DELEGATION_TOKEN_SECRET_MANAGER_ATTR, secretMgr); + jetty.start(); + URL authURL = new URL(getJettyURL() + "/foo/bar?authenticated=foo"); + + DelegationTokenAuthenticatedURL.Token token = + new DelegationTokenAuthenticatedURL.Token(); + DelegationTokenAuthenticatedURL aUrl = + new DelegationTokenAuthenticatedURL(); + + aUrl.getDelegationToken(authURL, token, "foo"); + Assert.assertNotNull(token.getDelegationToken()); + Assert.assertEquals(new Text("fooKind"), + token.getDelegationToken().getKind()); + + } finally { + jetty.stop(); + secretMgr.stopThreads(); + } + } + + public static class NoDTFilter extends AuthenticationFilter { + + @Override + protected Properties getConfiguration(String configPrefix, + FilterConfig filterConfig) { + Properties conf = new Properties(); + conf.setProperty(AUTH_TYPE, PseudoAuthenticationHandler.TYPE); + return conf; + } + } + + + public static class NoDTHandlerDTAFilter + extends DelegationTokenAuthenticationFilter { + + @Override + protected Properties getConfiguration(String configPrefix, + FilterConfig filterConfig) { + Properties conf = new Properties(); + conf.setProperty(AUTH_TYPE, PseudoAuthenticationHandler.TYPE); + return conf; + } + } + + public static class UserServlet extends HttpServlet { + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + resp.setStatus(HttpServletResponse.SC_OK); + resp.getWriter().write(req.getUserPrincipal().getName()); + } + } + + @Test + public void testDelegationTokenAuthenticationURLWithNoDTFilter() + throws Exception { + testDelegationTokenAuthenticatedURLWithNoDT(NoDTFilter.class); + } + + @Test + public void testDelegationTokenAuthenticationURLWithNoDTHandler() + throws Exception { + testDelegationTokenAuthenticatedURLWithNoDT(NoDTHandlerDTAFilter.class); + } + + // we are, also, implicitly testing KerberosDelegationTokenAuthenticator + // fallback here + private void testDelegationTokenAuthenticatedURLWithNoDT( + Class<? extends Filter> filterClass) throws Exception { + final Server jetty = createJettyServer(); + Context context = new Context(); + context.setContextPath("/foo"); + jetty.setHandler(context); + context.addFilter(new FilterHolder(filterClass), "/*", 0); + context.addServlet(new ServletHolder(UserServlet.class), "/bar"); + + try { + jetty.start(); + final URL url = new URL(getJettyURL() + "/foo/bar"); + + UserGroupInformation ugi = UserGroupInformation.createRemoteUser("foo"); + ugi.doAs(new PrivilegedExceptionAction<Void>() { + @Override + public Void run() throws Exception { + DelegationTokenAuthenticatedURL.Token token = + new DelegationTokenAuthenticatedURL.Token(); + DelegationTokenAuthenticatedURL aUrl = + new DelegationTokenAuthenticatedURL(); + HttpURLConnection conn = aUrl.openConnection(url, token); + Assert.assertEquals(HttpURLConnection.HTTP_OK, + conn.getResponseCode()); + List<String> ret = IOUtils.readLines(conn.getInputStream()); + Assert.assertEquals(1, ret.size()); + Assert.assertEquals("foo", ret.get(0)); + + try { + aUrl.getDelegationToken(url, token, "foo"); + Assert.fail(); + } catch (AuthenticationException ex) { + Assert.assertTrue(ex.getMessage().contains( + "delegation token operation")); + } + return null; + } + }); + } finally { + jetty.stop(); + } + } + + public static class PseudoDTAFilter + extends DelegationTokenAuthenticationFilter { + + @Override + protected Properties getConfiguration(String configPrefix, + FilterConfig filterConfig) { + Properties conf = new Properties(); + conf.setProperty(AUTH_TYPE, + PseudoDelegationTokenAuthenticationHandler.class.getName()); + conf.setProperty(DelegationTokenAuthenticationHandler.TOKEN_KIND, + "token-kind"); + return conf; + } + } + + @Test + public void testFallbackToPseudoDelegationTokenAuthenticator() + throws Exception { + final Server jetty = createJettyServer(); + Context context = new Context(); + context.setContextPath("/foo"); + jetty.setHandler(context); + context.addFilter(new FilterHolder(PseudoDTAFilter.class), "/*", 0); + context.addServlet(new ServletHolder(UserServlet.class), "/bar"); + + try { + jetty.start(); + final URL url = new URL(getJettyURL() + "/foo/bar"); + + UserGroupInformation ugi = UserGroupInformation.createRemoteUser("foo"); + ugi.doAs(new PrivilegedExceptionAction<Void>() { + @Override + public Void run() throws Exception { + DelegationTokenAuthenticatedURL.Token token = + new DelegationTokenAuthenticatedURL.Token(); + DelegationTokenAuthenticatedURL aUrl = + new DelegationTokenAuthenticatedURL(); + HttpURLConnection conn = aUrl.openConnection(url, token); + Assert.assertEquals(HttpURLConnection.HTTP_OK, + conn.getResponseCode()); + List<String> ret = IOUtils.readLines(conn.getInputStream()); + Assert.assertEquals(1, ret.size()); + Assert.assertEquals("foo", ret.get(0)); + + aUrl.getDelegationToken(url, token, "foo"); + Assert.assertNotNull(token.getDelegationToken()); + Assert.assertEquals(new Text("token-kind"), + token.getDelegationToken().getKind()); + return null; + } + }); + } finally { + jetty.stop(); + } + } + + public static class KDTAFilter extends DelegationTokenAuthenticationFilter { + static String keytabFile; + + @Override + protected Properties getConfiguration(String configPrefix, + FilterConfig filterConfig) { + Properties conf = new Properties(); + conf.setProperty(AUTH_TYPE, + KerberosDelegationTokenAuthenticationHandler.class.getName()); + conf.setProperty(KerberosAuthenticationHandler.KEYTAB, keytabFile); + conf.setProperty(KerberosAuthenticationHandler.PRINCIPAL, + "HTTP/localhost"); + conf.setProperty(KerberosDelegationTokenAuthenticationHandler.TOKEN_KIND, + "token-kind"); + return conf; + } + } + + private static class KerberosConfiguration extends Configuration { + private String principal; + private String keytab; + + public KerberosConfiguration(String principal, String keytab) { + this.principal = principal; + this.keytab = keytab; + } + + @Override + public AppConfigurationEntry[] getAppConfigurationEntry(String name) { + Map<String, String> options = new HashMap<String, String>(); + options.put("principal", principal); + options.put("keyTab", keytab); + options.put("useKeyTab", "true"); + options.put("storeKey", "true"); + options.put("doNotPrompt", "true"); + options.put("useTicketCache", "true"); + options.put("renewTGT", "true"); + options.put("refreshKrb5Config", "true"); + options.put("isInitiator", "true"); + String ticketCache = System.getenv("KRB5CCNAME"); + if (ticketCache != null) { + options.put("ticketCache", ticketCache); + } + options.put("debug", "true"); + + return new AppConfigurationEntry[]{ + new AppConfigurationEntry(KerberosUtil.getKrb5LoginModuleName(), + AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, + options),}; + } + } + + public static <T> T doAsKerberosUser(String principal, String keytab, + final Callable<T> callable) throws Exception { + LoginContext loginContext = null; + try { + Set<Principal> principals = new HashSet<Principal>(); + principals.add(new KerberosPrincipal(principal)); + Subject subject = new Subject(false, principals, new HashSet<Object>(), + new HashSet<Object>()); + loginContext = new LoginContext("", subject, null, + new KerberosConfiguration(principal, keytab)); + loginContext.login(); + subject = loginContext.getSubject(); + return Subject.doAs(subject, new PrivilegedExceptionAction<T>() { + @Override + public T run() throws Exception { + return callable.call(); + } + }); + } catch (PrivilegedActionException ex) { + throw ex.getException(); + } finally { + if (loginContext != null) { + loginContext.logout(); + } + } + } + + @Test + public void testKerberosDelegationTokenAuthenticator() throws Exception { + // setting hadoop security to kerberos + org.apache.hadoop.conf.Configuration conf = + new org.apache.hadoop.conf.Configuration(); + conf.set("hadoop.security.authentication", "kerberos"); + UserGroupInformation.setConfiguration(conf); + + File testDir = new File("target/" + UUID.randomUUID().toString()); + Assert.assertTrue(testDir.mkdirs()); + MiniKdc kdc = new MiniKdc(MiniKdc.createConf(), testDir); + final Server jetty = createJettyServer(); + Context context = new Context(); + context.setContextPath("/foo"); + jetty.setHandler(context); + context.addFilter(new FilterHolder(KDTAFilter.class), "/*", 0); + context.addServlet(new ServletHolder(UserServlet.class), "/bar"); + try { + kdc.start(); + File keytabFile = new File(testDir, "test.keytab"); + kdc.createPrincipal(keytabFile, "client", "HTTP/localhost"); + KDTAFilter.keytabFile = keytabFile.getAbsolutePath(); + jetty.start(); + + final DelegationTokenAuthenticatedURL.Token token = + new DelegationTokenAuthenticatedURL.Token(); + final DelegationTokenAuthenticatedURL aUrl = + new DelegationTokenAuthenticatedURL(); + final URL url = new URL(getJettyURL() + "/foo/bar"); + + try { + aUrl.getDelegationToken(url, token, "foo"); + Assert.fail(); + } catch (AuthenticationException ex) { + Assert.assertTrue(ex.getMessage().contains("GSSException")); + } + + doAsKerberosUser("client", keytabFile.getAbsolutePath(), + new Callable<Void>() { + @Override + public Void call() throws Exception { + aUrl.getDelegationToken(url, token, "client"); + Assert.assertNotNull(token.getDelegationToken()); + + aUrl.renewDelegationToken(url, token); + Assert.assertNotNull(token.getDelegationToken()); + + aUrl.getDelegationToken(url, token, "foo"); + Assert.assertNotNull(token.getDelegationToken()); + + try { + aUrl.renewDelegationToken(url, token); + Assert.fail(); + } catch (Exception ex) { + Assert.assertTrue(ex.getMessage().contains("403")); + } + + aUrl.getDelegationToken(url, token, "foo"); + + aUrl.cancelDelegationToken(url, token); + Assert.assertNull(token.getDelegationToken()); + + return null; + } + }); + } finally { + jetty.stop(); + kdc.stop(); + } + } + +}
