From f77ebcf191b1daf4ad412d83502b8666b225174e Mon Sep 17 00:00:00 2001 From: Andrew Purtell Date: Wed, 3 Sep 2014 18:30:52 -0700 Subject: [PATCH] HBASE-11886 The creator of the table should have all permissions on the table (Devaraj Das and Andrew Purtell) --- .../master/handler/CreateTableHandler.java | 23 +++- .../access/TestAccessController2.java | 102 ++++++++++++++++++ 2 files changed, 123 insertions(+), 2 deletions(-) create mode 100644 hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessController2.java diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/CreateTableHandler.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/CreateTableHandler.java index 4c20dc508fc..3a86128063d 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/CreateTableHandler.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/CreateTableHandler.java @@ -20,6 +20,7 @@ package org.apache.hadoop.hbase.master.handler; import java.io.IOException; import java.io.InterruptedIOException; +import java.security.PrivilegedExceptionAction; import java.util.ArrayList; import java.util.List; @@ -40,6 +41,7 @@ import org.apache.hadoop.hbase.client.RegionReplicaUtil; import org.apache.hadoop.hbase.MetaTableAccessor; import org.apache.hadoop.hbase.executor.EventHandler; import org.apache.hadoop.hbase.executor.EventType; +import org.apache.hadoop.hbase.ipc.RequestContext; import org.apache.hadoop.hbase.master.AssignmentManager; import org.apache.hadoop.hbase.master.HMaster; import org.apache.hadoop.hbase.master.MasterCoprocessorHost; @@ -48,6 +50,8 @@ import org.apache.hadoop.hbase.master.MasterServices; import org.apache.hadoop.hbase.master.TableLockManager; import org.apache.hadoop.hbase.master.TableLockManager.TableLock; import org.apache.hadoop.hbase.protobuf.generated.ZooKeeperProtos; +import org.apache.hadoop.hbase.security.User; +import org.apache.hadoop.hbase.security.UserProvider; import org.apache.hadoop.hbase.util.FSTableDescriptors; import org.apache.hadoop.hbase.util.FSUtils; import org.apache.hadoop.hbase.util.ModifyRegionUtils; @@ -66,6 +70,7 @@ public class CreateTableHandler extends EventHandler { private final TableLockManager tableLockManager; private final HRegionInfo [] newRegions; private final TableLock tableLock; + private User activeUser; public CreateTableHandler(Server server, MasterFileSystem fileSystemManager, HTableDescriptor hTableDescriptor, Configuration conf, HRegionInfo [] newRegions, @@ -93,6 +98,14 @@ public class CreateTableHandler extends EventHandler { server.getZooKeeper(), timeout) == null) { throw new NotAllMetaRegionsOnlineException(); } + // If we are creating the table in service to an RPC request, record the + // active user for later, so proper permissions will be applied to the + // new table by the AccessController if it is active + if (RequestContext.isInRequestContext()) { + this.activeUser = RequestContext.getRequestUser(); + } else { + this.activeUser = UserProvider.instantiate(conf).getCurrent(); + } } catch (InterruptedException e) { LOG.warn("Interrupted waiting for meta availability", e); InterruptedIOException ie = new InterruptedIOException(e.getMessage()); @@ -176,14 +189,20 @@ public class CreateTableHandler extends EventHandler { LOG.info("Create table " + tableName); try { - MasterCoprocessorHost cpHost = ((HMaster) this.server).getMasterCoprocessorHost(); + final MasterCoprocessorHost cpHost = ((HMaster) this.server).getMasterCoprocessorHost(); if (cpHost != null) { cpHost.preCreateTableHandler(this.hTableDescriptor, this.newRegions); } handleCreateTable(tableName); completed(null); if (cpHost != null) { - cpHost.postCreateTableHandler(this.hTableDescriptor, this.newRegions); + this.activeUser.runAs(new PrivilegedExceptionAction() { + @Override + public Void run() throws Exception { + cpHost.postCreateTableHandler(hTableDescriptor, newRegions); + return null; + } + }); } } catch (Throwable e) { LOG.error("Error trying to create the table " + tableName, e); diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessController2.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessController2.java new file mode 100644 index 00000000000..864739cd834 --- /dev/null +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessController2.java @@ -0,0 +1,102 @@ +/* + * 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.hbase.security.access; + +import static org.junit.Assert.*; + +import java.util.List; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.hbase.HBaseTestingUtility; +import org.apache.hadoop.hbase.HColumnDescriptor; +import org.apache.hadoop.hbase.HTableDescriptor; +import org.apache.hadoop.hbase.LargeTests; +import org.apache.hadoop.hbase.client.HBaseAdmin; +import org.apache.hadoop.hbase.security.User; +import org.apache.hadoop.hbase.security.access.Permission.Action; +import org.apache.hadoop.hbase.util.Bytes; +import org.apache.hadoop.hbase.util.TestTableName; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +@Category(LargeTests.class) +public class TestAccessController2 extends SecureTestUtil { + + private static final byte[] TEST_FAMILY = Bytes.toBytes("f"); + private static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility(); + private static Configuration conf; + + @Rule public TestTableName TEST_TABLE = new TestTableName(); + + @BeforeClass + public static void setupBeforeClass() throws Exception { + conf = TEST_UTIL.getConfiguration(); + // Enable security + enableSecurity(conf); + // Verify enableSecurity sets up what we require + verifyConfiguration(conf); + TEST_UTIL.startMiniCluster(); + // Wait for the ACL table to become available + TEST_UTIL.waitTableEnabled(AccessControlLists.ACL_TABLE_NAME.getName()); + } + + @AfterClass + public static void tearDownAfterClass() throws Exception { + TEST_UTIL.shutdownMiniCluster(); + } + + @Test + public void testCreateWithCorrectOwner() throws Exception { + // Create a test user + User testUser = User.createUserForTesting(TEST_UTIL.getConfiguration(), "TestUser", + new String[0]); + // Grant the test user the ability to create tables + SecureTestUtil.grantGlobal(TEST_UTIL, testUser.getShortName(), Action.CREATE); + verifyAllowed(new AccessTestAction() { + @Override + public Object run() throws Exception { + HTableDescriptor desc = new HTableDescriptor(TEST_TABLE.getTableName()); + desc.addFamily(new HColumnDescriptor(TEST_FAMILY)); + HBaseAdmin admin = new HBaseAdmin(conf); + try { + admin.createTable(desc); + } finally { + admin.close(); + } + return null; + } + }, testUser); + TEST_UTIL.waitTableEnabled(TEST_TABLE.getTableName().getName()); + // Verify that owner permissions have been granted to the test user on the + // table just created + List perms = AccessControlLists.getTablePermissions(conf, TEST_TABLE.getTableName()) + .get(testUser.getShortName()); + assertNotNull(perms); + assertFalse(perms.isEmpty()); + // Should be RWXCA + assertTrue(perms.get(0).implies(Permission.Action.READ)); + assertTrue(perms.get(0).implies(Permission.Action.WRITE)); + assertTrue(perms.get(0).implies(Permission.Action.EXEC)); + assertTrue(perms.get(0).implies(Permission.Action.CREATE)); + assertTrue(perms.get(0).implies(Permission.Action.ADMIN)); + } + +}