| /** |
| * 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.fs.http.server; |
| |
| import org.apache.hadoop.conf.Configuration; |
| import org.apache.hadoop.fs.CommonConfigurationKeysPublic; |
| import org.apache.hadoop.fs.FileSystem; |
| import org.apache.hadoop.fs.Path; |
| import org.apache.hadoop.hdfs.DFSConfigKeys; |
| import org.apache.hadoop.hdfs.MiniDFSCluster; |
| import org.apache.hadoop.test.HTestCase; |
| import org.apache.hadoop.test.HadoopUsersConfTestHelper; |
| import org.apache.hadoop.test.TestDir; |
| import org.apache.hadoop.test.TestDirHelper; |
| import org.apache.hadoop.test.TestJetty; |
| import org.apache.hadoop.test.TestJettyHelper; |
| import org.junit.Assert; |
| import org.junit.Test; |
| import org.mortbay.jetty.Server; |
| import org.mortbay.jetty.webapp.WebAppContext; |
| |
| import java.io.BufferedReader; |
| import java.io.File; |
| import java.io.FileOutputStream; |
| import java.io.FileWriter; |
| import java.io.IOException; |
| import java.io.InputStreamReader; |
| import java.io.OutputStream; |
| import java.io.Writer; |
| import java.net.HttpURLConnection; |
| import java.net.URL; |
| import java.text.MessageFormat; |
| |
| /** |
| * This test class ensures that everything works as expected when ACL |
| * support is turned off HDFS. This is the default configuration. The other |
| * tests operate with ACL support turned on. |
| */ |
| public class TestHttpFSServerNoACLs extends HTestCase { |
| |
| private MiniDFSCluster miniDfs; |
| private Configuration nnConf; |
| |
| /** |
| * Fire up our own hand-rolled MiniDFSCluster. We do this here instead |
| * of relying on TestHdfsHelper because we don't want to turn on ACL |
| * support. |
| * |
| * @throws Exception |
| */ |
| private void startMiniDFS() throws Exception { |
| |
| File testDirRoot = TestDirHelper.getTestDir(); |
| |
| if (System.getProperty("hadoop.log.dir") == null) { |
| System.setProperty("hadoop.log.dir", |
| new File(testDirRoot, "hadoop-log").getAbsolutePath()); |
| } |
| if (System.getProperty("test.build.data") == null) { |
| System.setProperty("test.build.data", |
| new File(testDirRoot, "hadoop-data").getAbsolutePath()); |
| } |
| |
| Configuration conf = HadoopUsersConfTestHelper.getBaseConf(); |
| HadoopUsersConfTestHelper.addUserConf(conf); |
| conf.set("fs.hdfs.impl.disable.cache", "true"); |
| conf.set("dfs.block.access.token.enable", "false"); |
| conf.set("dfs.permissions", "true"); |
| conf.set("hadoop.security.authentication", "simple"); |
| |
| // Explicitly turn off ACL support |
| conf.setBoolean(DFSConfigKeys.DFS_NAMENODE_ACLS_ENABLED_KEY, false); |
| |
| MiniDFSCluster.Builder builder = new MiniDFSCluster.Builder(conf); |
| builder.numDataNodes(2); |
| miniDfs = builder.build(); |
| nnConf = miniDfs.getConfiguration(0); |
| } |
| |
| /** |
| * Create an HttpFS Server to talk to the MiniDFSCluster we created. |
| * @throws Exception |
| */ |
| private void createHttpFSServer() throws Exception { |
| File homeDir = TestDirHelper.getTestDir(); |
| Assert.assertTrue(new File(homeDir, "conf").mkdir()); |
| Assert.assertTrue(new File(homeDir, "log").mkdir()); |
| Assert.assertTrue(new File(homeDir, "temp").mkdir()); |
| HttpFSServerWebApp.setHomeDirForCurrentThread(homeDir.getAbsolutePath()); |
| |
| File secretFile = new File(new File(homeDir, "conf"), "secret"); |
| Writer w = new FileWriter(secretFile); |
| w.write("secret"); |
| w.close(); |
| |
| // HDFS configuration |
| File hadoopConfDir = new File(new File(homeDir, "conf"), "hadoop-conf"); |
| if ( !hadoopConfDir.mkdirs() ) { |
| throw new IOException(); |
| } |
| |
| String fsDefaultName = |
| nnConf.get(CommonConfigurationKeysPublic.FS_DEFAULT_NAME_KEY); |
| Configuration conf = new Configuration(false); |
| conf.set(CommonConfigurationKeysPublic.FS_DEFAULT_NAME_KEY, fsDefaultName); |
| |
| // Explicitly turn off ACLs, just in case the default becomes true later |
| conf.setBoolean(DFSConfigKeys.DFS_NAMENODE_ACLS_ENABLED_KEY, false); |
| |
| File hdfsSite = new File(hadoopConfDir, "hdfs-site.xml"); |
| OutputStream os = new FileOutputStream(hdfsSite); |
| conf.writeXml(os); |
| os.close(); |
| |
| // HTTPFS configuration |
| conf = new Configuration(false); |
| conf.set("httpfs.hadoop.config.dir", hadoopConfDir.toString()); |
| conf.set("httpfs.proxyuser." + |
| HadoopUsersConfTestHelper.getHadoopProxyUser() + ".groups", |
| HadoopUsersConfTestHelper.getHadoopProxyUserGroups()); |
| conf.set("httpfs.proxyuser." + |
| HadoopUsersConfTestHelper.getHadoopProxyUser() + ".hosts", |
| HadoopUsersConfTestHelper.getHadoopProxyUserHosts()); |
| conf.set("httpfs.authentication.signature.secret.file", |
| secretFile.getAbsolutePath()); |
| |
| File httpfsSite = new File(new File(homeDir, "conf"), "httpfs-site.xml"); |
| os = new FileOutputStream(httpfsSite); |
| conf.writeXml(os); |
| os.close(); |
| |
| ClassLoader cl = Thread.currentThread().getContextClassLoader(); |
| URL url = cl.getResource("webapp"); |
| if ( url == null ) { |
| throw new IOException(); |
| } |
| WebAppContext context = new WebAppContext(url.getPath(), "/webhdfs"); |
| Server server = TestJettyHelper.getJettyServer(); |
| server.addHandler(context); |
| server.start(); |
| } |
| |
| /** |
| * Talks to the http interface to get the json output of a *STATUS command |
| * on the given file. |
| * |
| * @param filename The file to query. |
| * @param command Either GETFILESTATUS, LISTSTATUS, or ACLSTATUS |
| * @param expectOK Is this operation expected to succeed? |
| * @throws Exception |
| */ |
| private void getStatus(String filename, String command, boolean expectOK) |
| throws Exception { |
| String user = HadoopUsersConfTestHelper.getHadoopUsers()[0]; |
| // Remove leading / from filename |
| if ( filename.charAt(0) == '/' ) { |
| filename = filename.substring(1); |
| } |
| String pathOps = MessageFormat.format( |
| "/webhdfs/v1/{0}?user.name={1}&op={2}", |
| filename, user, command); |
| URL url = new URL(TestJettyHelper.getJettyURL(), pathOps); |
| HttpURLConnection conn = (HttpURLConnection) url.openConnection(); |
| conn.connect(); |
| int resp = conn.getResponseCode(); |
| BufferedReader reader; |
| if ( expectOK ) { |
| Assert.assertEquals(HttpURLConnection.HTTP_OK, resp); |
| reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); |
| String res = reader.readLine(); |
| Assert.assertTrue(!res.contains("aclBit")); |
| Assert.assertTrue(res.contains("owner")); // basic sanity check |
| } else { |
| Assert.assertEquals(HttpURLConnection.HTTP_INTERNAL_ERROR, resp); |
| reader = new BufferedReader(new InputStreamReader(conn.getErrorStream())); |
| String res = reader.readLine(); |
| Assert.assertTrue(res.contains("AclException")); |
| Assert.assertTrue(res.contains("Support for ACLs has been disabled")); |
| } |
| } |
| |
| /** |
| * General-purpose http PUT command to the httpfs server. |
| * @param filename The file to operate upon |
| * @param command The command to perform (SETACL, etc) |
| * @param params Parameters, like "aclspec=..." |
| */ |
| private void putCmd(String filename, String command, |
| String params, boolean expectOK) throws Exception { |
| String user = HadoopUsersConfTestHelper.getHadoopUsers()[0]; |
| // Remove leading / from filename |
| if ( filename.charAt(0) == '/' ) { |
| filename = filename.substring(1); |
| } |
| String pathOps = MessageFormat.format( |
| "/webhdfs/v1/{0}?user.name={1}{2}{3}&op={4}", |
| filename, user, (params == null) ? "" : "&", |
| (params == null) ? "" : params, command); |
| URL url = new URL(TestJettyHelper.getJettyURL(), pathOps); |
| HttpURLConnection conn = (HttpURLConnection) url.openConnection(); |
| conn.setRequestMethod("PUT"); |
| conn.connect(); |
| int resp = conn.getResponseCode(); |
| if ( expectOK ) { |
| Assert.assertEquals(HttpURLConnection.HTTP_OK, resp); |
| } else { |
| Assert.assertEquals(HttpURLConnection.HTTP_INTERNAL_ERROR, resp); |
| BufferedReader reader; |
| reader = new BufferedReader(new InputStreamReader(conn.getErrorStream())); |
| String err = reader.readLine(); |
| Assert.assertTrue(err.contains("AclException")); |
| Assert.assertTrue(err.contains("Support for ACLs has been disabled")); |
| } |
| } |
| |
| /** |
| * Ensure that |
| * <ol> |
| * <li>GETFILESTATUS and LISTSTATUS work happily</li> |
| * <li>ACLSTATUS throws an exception</li> |
| * <li>The ACL SET, REMOVE, etc calls all fail</li> |
| * </ol> |
| * |
| * @throws Exception |
| */ |
| @Test |
| @TestDir |
| @TestJetty |
| public void testWithNoAcls() throws Exception { |
| final String aclUser1 = "user:foo:rw-"; |
| final String rmAclUser1 = "user:foo:"; |
| final String aclUser2 = "user:bar:r--"; |
| final String aclGroup1 = "group::r--"; |
| final String aclSpec = "aclspec=user::rwx," + aclUser1 + "," |
| + aclGroup1 + ",other::---"; |
| final String modAclSpec = "aclspec=" + aclUser2; |
| final String remAclSpec = "aclspec=" + rmAclUser1; |
| final String defUser1 = "default:user:glarch:r-x"; |
| final String defSpec1 = "aclspec=" + defUser1; |
| final String dir = "/noACLs"; |
| final String path = dir + "/foo"; |
| |
| startMiniDFS(); |
| createHttpFSServer(); |
| |
| FileSystem fs = FileSystem.get(nnConf); |
| fs.mkdirs(new Path(dir)); |
| OutputStream os = fs.create(new Path(path)); |
| os.write(1); |
| os.close(); |
| |
| /* The normal status calls work as expected; GETACLSTATUS fails */ |
| getStatus(path, "GETFILESTATUS", true); |
| getStatus(dir, "LISTSTATUS", true); |
| getStatus(path, "GETACLSTATUS", false); |
| |
| /* All the ACL-based PUT commands fail with ACL exceptions */ |
| putCmd(path, "SETACL", aclSpec, false); |
| putCmd(path, "MODIFYACLENTRIES", modAclSpec, false); |
| putCmd(path, "REMOVEACLENTRIES", remAclSpec, false); |
| putCmd(path, "REMOVEACL", null, false); |
| putCmd(dir, "SETACL", defSpec1, false); |
| putCmd(dir, "REMOVEDEFAULTACL", null, false); |
| |
| miniDfs.shutdown(); |
| } |
| } |