/* * 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.hive.ql.security; import static org.apache.hadoop.fs.permission.AclEntryScope.ACCESS; import static org.apache.hadoop.fs.permission.AclEntryType.GROUP; import static org.apache.hadoop.fs.permission.AclEntryType.OTHER; import static org.apache.hadoop.fs.permission.AclEntryType.USER; import java.lang.reflect.Method; import java.net.URI; import java.security.PrivilegedExceptionAction; import java.util.Arrays; import java.util.List; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.permission.AclEntry; import org.apache.hadoop.fs.permission.AclEntryScope; import org.apache.hadoop.fs.permission.AclEntryType; import org.apache.hadoop.fs.permission.FsAction; import org.apache.hadoop.hive.conf.HiveConf; import org.apache.hadoop.hive.shims.ShimLoader; import org.apache.hadoop.hive.shims.Utils; import org.apache.hadoop.hive.shims.HadoopShims.MiniDFSShim; import org.apache.hadoop.security.UserGroupInformation; import com.google.common.collect.Lists; public class TestStorageBasedMetastoreAuthorizationProviderWithACL extends TestStorageBasedMetastoreAuthorizationProvider { protected static MiniDFSShim dfs = null; protected static Path warehouseDir = null; protected UserGroupInformation userUgi = null; protected String testUserName = "test_user"; @Override protected boolean isTestEnabled() { // This test with HDFS ACLs will only work if FileSystem.access() is available in the // version of hadoop-2 used to build Hive. return doesAccessAPIExist(); } private static boolean doesAccessAPIExist() { boolean foundMethod = false; try { Method method = FileSystem.class.getMethod("access", Path.class, FsAction.class); foundMethod = true; } catch (NoSuchMethodException err) { } return foundMethod; } @Override protected HiveConf createHiveConf() throws Exception { userUgi = UserGroupInformation.createUserForTesting(testUserName, new String[] {}); // Hadoop FS ACLs do not work with LocalFileSystem, so set up MiniDFS. HiveConf conf = super.createHiveConf(); String currentUserName = Utils.getUGI().getShortUserName(); conf.set("dfs.namenode.acls.enabled", "true"); conf.set("hadoop.proxyuser." + currentUserName + ".groups", "*"); conf.set("hadoop.proxyuser." + currentUserName + ".hosts", "*"); dfs = ShimLoader.getHadoopShims().getMiniDfs(conf, 4, true, null); FileSystem fs = dfs.getFileSystem(); warehouseDir = new Path(new Path(fs.getUri()), "/warehouse"); fs.mkdirs(warehouseDir); conf.setVar(HiveConf.ConfVars.METASTOREWAREHOUSE, warehouseDir.toString()); // Set up scratch directory Path scratchDir = new Path(new Path(fs.getUri()), "/scratchdir"); conf.setVar(HiveConf.ConfVars.SCRATCHDIR, scratchDir.toString()); return conf; } protected String setupUser() { // Using MiniDFS, the permissions don't work properly because // the current user gets treated as a superuser. // For this test, specify a different (non-super) user. InjectableDummyAuthenticator.injectUserName(userUgi.getShortUserName()); InjectableDummyAuthenticator.injectGroupNames(Arrays.asList(userUgi.getGroupNames())); InjectableDummyAuthenticator.injectMode(true); return userUgi.getShortUserName(); } @Override protected void tearDown() throws Exception { super.tearDown(); if (dfs != null) { dfs.shutdown(); dfs = null; } } protected void allowWriteAccessViaAcl(String userName, String location) throws Exception { // Set the FS perms to read-only access, and create ACL entries allowing write access. List<AclEntry> aclSpec = Lists.newArrayList( aclEntry(ACCESS, USER, FsAction.READ_EXECUTE), aclEntry(ACCESS, GROUP, FsAction.READ_EXECUTE), aclEntry(ACCESS, OTHER, FsAction.READ_EXECUTE), aclEntry(ACCESS, USER, userName, FsAction.ALL) ); FileSystem fs = FileSystem.get(new URI(location), clientHiveConf); fs.setAcl(new Path(location), aclSpec); } protected void disallowWriteAccessViaAcl(String userName, String location) throws Exception { FileSystem fs = FileSystem.get(new URI(location), clientHiveConf); fs.removeAcl(new Path(location)); setPermissions(location,"-r-xr-xr-x"); } /** * Create a new AclEntry with scope, type and permission (no name). * Borrowed from TestExtendedAcls * * @param scope * AclEntryScope scope of the ACL entry * @param type * AclEntryType ACL entry type * @param permission * FsAction set of permissions in the ACL entry * @return AclEntry new AclEntry */ private AclEntry aclEntry(AclEntryScope scope, AclEntryType type, FsAction permission) { return new AclEntry.Builder().setScope(scope).setType(type) .setPermission(permission).build(); } /** * Create a new AclEntry with scope, type, name and permission. * Borrowed from TestExtendedAcls * * @param scope * AclEntryScope scope of the ACL entry * @param type * AclEntryType ACL entry type * @param name * String optional ACL entry name * @param permission * FsAction set of permissions in the ACL entry * @return AclEntry new AclEntry */ private AclEntry aclEntry(AclEntryScope scope, AclEntryType type, String name, FsAction permission) { return new AclEntry.Builder().setScope(scope).setType(type).setName(name) .setPermission(permission).build(); } protected void allowCreateDatabase(String userName) throws Exception { allowWriteAccessViaAcl(userName, warehouseDir.toString()); } @Override protected void allowCreateInDb(String dbName, String userName, String location) throws Exception { allowWriteAccessViaAcl(userName, location); } @Override protected void disallowCreateInDb(String dbName, String userName, String location) throws Exception { disallowWriteAccessViaAcl(userName, location); } @Override protected void allowCreateInTbl(String tableName, String userName, String location) throws Exception{ allowWriteAccessViaAcl(userName, location); } @Override protected void disallowCreateInTbl(String tableName, String userName, String location) throws Exception { disallowWriteAccessViaAcl(userName, location); } @Override protected void allowDropOnTable(String tblName, String userName, String location) throws Exception { allowWriteAccessViaAcl(userName, location); } @Override protected void disallowDropOnTable(String tblName, String userName, String location) throws Exception { disallowWriteAccessViaAcl(userName, location); } @Override protected void allowDropOnDb(String dbName, String userName, String location) throws Exception { allowWriteAccessViaAcl(userName, location); } }