Java tutorial
/** * 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 * <p> * http://www.apache.org/licenses/LICENSE-2.0 * <p> * 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.http; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.CommonConfigurationKeys; import org.apache.hadoop.minikdc.MiniKdc; import org.apache.hadoop.net.NetUtils; import org.apache.hadoop.security.AuthenticationFilterInitializer; import org.apache.hadoop.security.UserGroupInformation; import org.apache.hadoop.security.authentication.KerberosTestUtils; import org.apache.hadoop.security.authentication.client.AuthenticatedURL; import org.apache.hadoop.security.authentication.server.AuthenticationFilter; import org.apache.hadoop.security.authentication.server.AuthenticationToken; import org.apache.hadoop.security.authentication.util.Signer; import org.apache.hadoop.security.authentication.util.SignerSecretProvider; import org.apache.hadoop.security.authentication.util.StringSignerSecretProviderCreator; import org.apache.hadoop.security.authorize.AccessControlList; import org.apache.hadoop.security.authorize.ProxyUsers; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.junit.Assert; import java.io.File; import java.io.FileWriter; import java.io.Writer; import java.net.HttpURLConnection; import java.net.URI; import java.net.URL; import java.util.Properties; import static org.junit.Assert.assertTrue; /** * This class is tested for http server with SPENGO authentication. */ public class TestHttpServerWithSpengo { static final Log LOG = LogFactory.getLog(TestHttpServerWithSpengo.class); private static final String SECRET_STR = "secret"; private static final String HTTP_USER = "HTTP"; private static final String PREFIX = "hadoop.http.authentication."; private static final long TIMEOUT = 20000; private static File httpSpnegoKeytabFile = new File(KerberosTestUtils.getKeytabFile()); private static String httpSpnegoPrincipal = KerberosTestUtils.getServerPrincipal(); private static String realm = KerberosTestUtils.getRealm(); private static File testRootDir = new File("target", TestHttpServerWithSpengo.class.getName() + "-root"); private static MiniKdc testMiniKDC; private static File secretFile = new File(testRootDir, SECRET_STR); @BeforeClass public static void setUp() throws Exception { try { testMiniKDC = new MiniKdc(MiniKdc.createConf(), testRootDir); testMiniKDC.start(); testMiniKDC.createPrincipal(httpSpnegoKeytabFile, HTTP_USER + "/localhost"); } catch (Exception e) { assertTrue("Couldn't setup MiniKDC", false); } Writer w = new FileWriter(secretFile); w.write("secret"); w.close(); } @AfterClass public static void tearDown() { if (testMiniKDC != null) { testMiniKDC.stop(); } } /** * groupA * - userA * groupB * - userA, userB * groupC * - userC * SPNEGO filter has been enabled. * userA has the privilege to impersonate users in groupB. * userA has admin access to all default servlets, but userB * and userC don't have. So "/logs" can only be accessed by userA. * @throws Exception */ @Test public void testAuthenticationWithProxyUser() throws Exception { Configuration spengoConf = getSpengoConf(new Configuration()); //setup logs dir System.setProperty("hadoop.log.dir", testRootDir.getAbsolutePath()); // Setup user group UserGroupInformation.createUserForTesting("userA", new String[] { "groupA", "groupB" }); UserGroupInformation.createUserForTesting("userB", new String[] { "groupB" }); UserGroupInformation.createUserForTesting("userC", new String[] { "groupC" }); // Make userA impersonate users in groupB spengoConf.set("hadoop.proxyuser.userA.hosts", "*"); spengoConf.set("hadoop.proxyuser.userA.groups", "groupB"); ProxyUsers.refreshSuperUserGroupsConfiguration(spengoConf); HttpServer2 httpServer = null; try { // Create http server to test. httpServer = getCommonBuilder().setConf(spengoConf).setACL(new AccessControlList("userA groupA")) .build(); httpServer.start(); // Get signer to encrypt token Signer signer = getSignerToEncrypt(); // setup auth token for userA AuthenticatedURL.Token token = getEncryptedAuthToken(signer, "userA"); String serverURL = "http://" + NetUtils.getHostPortString(httpServer.getConnectorAddress(0)) + "/"; // The default authenticator is kerberos. AuthenticatedURL authUrl = new AuthenticatedURL(); // userA impersonates userB, it's allowed. for (String servlet : new String[] { "stacks", "jmx", "conf" }) { HttpURLConnection conn = authUrl.openConnection(new URL(serverURL + servlet + "?doAs=userB"), token); Assert.assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode()); } // userA cannot impersonate userC, it fails. for (String servlet : new String[] { "stacks", "jmx", "conf" }) { HttpURLConnection conn = authUrl.openConnection(new URL(serverURL + servlet + "?doAs=userC"), token); Assert.assertEquals(HttpURLConnection.HTTP_FORBIDDEN, conn.getResponseCode()); } // "/logs" and "/logLevel" require admin authorization, // only userA has the access. for (String servlet : new String[] { "logLevel", "logs" }) { HttpURLConnection conn = authUrl.openConnection(new URL(serverURL + servlet), token); Assert.assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode()); } // Setup token for userB token = getEncryptedAuthToken(signer, "userB"); // userB cannot access these servlets. for (String servlet : new String[] { "logLevel", "logs" }) { HttpURLConnection conn = authUrl.openConnection(new URL(serverURL + servlet), token); Assert.assertEquals(HttpURLConnection.HTTP_FORBIDDEN, conn.getResponseCode()); } } finally { if (httpServer != null) { httpServer.stop(); } } } private AuthenticatedURL.Token getEncryptedAuthToken(Signer signer, String user) throws Exception { AuthenticationToken token = new AuthenticationToken(user, user, "kerberos"); token.setExpires(System.currentTimeMillis() + TIMEOUT); return new AuthenticatedURL.Token(signer.sign(token.toString())); } private Signer getSignerToEncrypt() throws Exception { SignerSecretProvider secretProvider = StringSignerSecretProviderCreator.newStringSignerSecretProvider(); Properties secretProviderProps = new Properties(); secretProviderProps.setProperty(AuthenticationFilter.SIGNATURE_SECRET, SECRET_STR); secretProvider.init(secretProviderProps, null, TIMEOUT); return new Signer(secretProvider); } private Configuration getSpengoConf(Configuration conf) { conf = new Configuration(); conf.set(HttpServer2.FILTER_INITIALIZER_PROPERTY, AuthenticationFilterInitializer.class.getName()); conf.set(PREFIX + "type", "kerberos"); conf.setBoolean(PREFIX + "simple.anonymous.allowed", false); conf.set(PREFIX + "signature.secret.file", secretFile.getAbsolutePath()); conf.set(PREFIX + "kerberos.keytab", httpSpnegoKeytabFile.getAbsolutePath()); conf.set(PREFIX + "kerberos.principal", httpSpnegoPrincipal); conf.set(PREFIX + "cookie.domain", realm); conf.setBoolean(CommonConfigurationKeys.HADOOP_SECURITY_AUTHORIZATION, true); return conf; } private HttpServer2.Builder getCommonBuilder() throws Exception { return new HttpServer2.Builder().setName("test").addEndpoint(new URI("http://localhost:0")) .setFindPort(true); } }