From 7532922cfe60ec8cfadf6f4c4c607cd03f6fdc8d Mon Sep 17 00:00:00 2001 From: meiyi Date: Wed, 10 Apr 2019 09:47:33 +0800 Subject: [PATCH] HBASE-22084 Rename AccessControlLists to PermissionStorage --- .../hadoop/hbase/coprocessor/TestSecureExport.java | 10 +- .../snapshot/TestMobSecureExportSnapshot.java | 5 +- .../hbase/snapshot/TestSecureExportSnapshot.java | 4 +- .../hadoop/hbase/rsgroup/TestRSGroupsWithACL.java | 12 +- .../hbase/tmpl/master/MasterStatusTmpl.jamon | 4 +- .../hadoop/hbase/master/MasterRpcServices.java | 18 +- .../hbase/security/access/AccessControlLists.java | 910 --------------------- .../hbase/security/access/AccessController.java | 78 +- .../hadoop/hbase/security/access/AuthManager.java | 14 +- .../hbase/security/access/PermissionStorage.java | 910 +++++++++++++++++++++ .../hbase/security/access/ZKPermissionWatcher.java | 10 +- .../hbase/snapshot/SnapshotDescriptionUtils.java | 6 +- .../hadoop/hbase/TestJMXConnectorServer.java | 2 - .../hbase/client/SnapshotWithAclTestBase.java | 4 +- .../client/TestAsyncAccessControlAdminApi.java | 4 +- .../hbase/security/access/SecureTestUtil.java | 2 +- .../security/access/TestAccessControlFilter.java | 2 +- .../security/access/TestAccessController.java | 29 +- .../security/access/TestAccessController2.java | 21 +- .../security/access/TestAccessController3.java | 12 +- .../access/TestCellACLWithMultipleVersions.java | 4 +- .../hadoop/hbase/security/access/TestCellACLs.java | 4 +- .../security/access/TestNamespaceCommands.java | 14 +- .../hbase/security/access/TestRpcAccessChecks.java | 2 +- .../security/access/TestScanEarlyTermination.java | 4 +- .../security/access/TestTablePermissions.java | 56 +- .../access/TestWithDisabledAuthorization.java | 12 +- .../security/access/TestZKPermissionWatcher.java | 4 +- .../visibility/TestVisibilityLabelsWithACL.java | 4 +- .../tool/TestSecureLoadIncrementalHFiles.java | 4 +- ...stSecureLoadIncrementalHFilesSplitRecovery.java | 4 +- hbase-shell/src/main/ruby/hbase/security.rb | 2 +- src/main/asciidoc/_chapters/security.adoc | 23 +- 33 files changed, 1086 insertions(+), 1108 deletions(-) delete mode 100644 hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessControlLists.java create mode 100644 hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/PermissionStorage.java diff --git a/hbase-endpoint/src/test/java/org/apache/hadoop/hbase/coprocessor/TestSecureExport.java b/hbase-endpoint/src/test/java/org/apache/hadoop/hbase/coprocessor/TestSecureExport.java index 31bfd37..71175c4 100644 --- a/hbase-endpoint/src/test/java/org/apache/hadoop/hbase/coprocessor/TestSecureExport.java +++ b/hbase-endpoint/src/test/java/org/apache/hadoop/hbase/coprocessor/TestSecureExport.java @@ -54,8 +54,8 @@ import org.apache.hadoop.hbase.security.HadoopSecurityEnabledUserProviderForTest import org.apache.hadoop.hbase.security.User; import org.apache.hadoop.hbase.security.UserProvider; import org.apache.hadoop.hbase.security.access.AccessControlConstants; -import org.apache.hadoop.hbase.security.access.AccessControlLists; import org.apache.hadoop.hbase.security.access.Permission; +import org.apache.hadoop.hbase.security.access.PermissionStorage; import org.apache.hadoop.hbase.security.access.SecureTestUtil; import org.apache.hadoop.hbase.security.access.SecureTestUtil.AccessTestAction; import org.apache.hadoop.hbase.security.visibility.Authorizations; @@ -204,9 +204,9 @@ public class TestSecureExport { SecureTestUtil.verifyConfiguration(UTIL.getConfiguration()); setUpClusterKdc(); UTIL.startMiniCluster(); - UTIL.waitUntilAllRegionsAssigned(AccessControlLists.ACL_TABLE_NAME); + UTIL.waitUntilAllRegionsAssigned(PermissionStorage.ACL_TABLE_NAME); UTIL.waitUntilAllRegionsAssigned(VisibilityConstants.LABELS_TABLE_NAME); - UTIL.waitTableEnabled(AccessControlLists.ACL_TABLE_NAME, 50000); + UTIL.waitTableEnabled(PermissionStorage.ACL_TABLE_NAME, 50000); UTIL.waitTableEnabled(VisibilityConstants.LABELS_TABLE_NAME, 50000); SecureTestUtil.grantGlobal(UTIL, USER_ADMIN, Permission.Action.ADMIN, @@ -249,8 +249,8 @@ public class TestSecureExport { SecureTestUtil.grantOnTable(UTIL, USER_XO, TableName.valueOf(exportTable), null, null, Permission.Action.EXEC); - assertEquals(4, AccessControlLists.getTablePermissions(UTIL.getConfiguration(), - TableName.valueOf(exportTable)).size()); + assertEquals(4, PermissionStorage + .getTablePermissions(UTIL.getConfiguration(), TableName.valueOf(exportTable)).size()); AccessTestAction putAction = () -> { Put p = new Put(ROW1); p.addColumn(FAMILYA, Bytes.toBytes("qual_0"), NOW, QUAL); diff --git a/hbase-mapreduce/src/test/java/org/apache/hadoop/hbase/snapshot/TestMobSecureExportSnapshot.java b/hbase-mapreduce/src/test/java/org/apache/hadoop/hbase/snapshot/TestMobSecureExportSnapshot.java index 1a5756b..484f88a 100644 --- a/hbase-mapreduce/src/test/java/org/apache/hadoop/hbase/snapshot/TestMobSecureExportSnapshot.java +++ b/hbase-mapreduce/src/test/java/org/apache/hadoop/hbase/snapshot/TestMobSecureExportSnapshot.java @@ -20,13 +20,12 @@ package org.apache.hadoop.hbase.snapshot; import org.apache.hadoop.hbase.HBaseClassTestRule; import org.apache.hadoop.hbase.security.HadoopSecurityEnabledUserProviderForTesting; import org.apache.hadoop.hbase.security.UserProvider; -import org.apache.hadoop.hbase.security.access.AccessControlLists; +import org.apache.hadoop.hbase.security.access.PermissionStorage; import org.apache.hadoop.hbase.security.access.SecureTestUtil; import org.apache.hadoop.hbase.testclassification.LargeTests; import org.apache.hadoop.hbase.testclassification.VerySlowRegionServerTests; import org.junit.BeforeClass; import org.junit.ClassRule; -import org.junit.Ignore; import org.junit.experimental.categories.Category; /** @@ -57,6 +56,6 @@ public class TestMobSecureExportSnapshot extends TestMobExportSnapshot { TEST_UTIL.startMiniMapReduceCluster(); // Wait for the ACL table to become available - TEST_UTIL.waitTableEnabled(AccessControlLists.ACL_TABLE_NAME); + TEST_UTIL.waitTableEnabled(PermissionStorage.ACL_TABLE_NAME); } } diff --git a/hbase-mapreduce/src/test/java/org/apache/hadoop/hbase/snapshot/TestSecureExportSnapshot.java b/hbase-mapreduce/src/test/java/org/apache/hadoop/hbase/snapshot/TestSecureExportSnapshot.java index 77da0d5..ce1c4cb 100644 --- a/hbase-mapreduce/src/test/java/org/apache/hadoop/hbase/snapshot/TestSecureExportSnapshot.java +++ b/hbase-mapreduce/src/test/java/org/apache/hadoop/hbase/snapshot/TestSecureExportSnapshot.java @@ -20,7 +20,7 @@ package org.apache.hadoop.hbase.snapshot; import org.apache.hadoop.hbase.HBaseClassTestRule; import org.apache.hadoop.hbase.security.HadoopSecurityEnabledUserProviderForTesting; import org.apache.hadoop.hbase.security.UserProvider; -import org.apache.hadoop.hbase.security.access.AccessControlLists; +import org.apache.hadoop.hbase.security.access.PermissionStorage; import org.apache.hadoop.hbase.security.access.SecureTestUtil; import org.apache.hadoop.hbase.testclassification.LargeTests; import org.apache.hadoop.hbase.testclassification.VerySlowRegionServerTests; @@ -56,6 +56,6 @@ public class TestSecureExportSnapshot extends TestExportSnapshot { TEST_UTIL.startMiniMapReduceCluster(); // Wait for the ACL table to become available - TEST_UTIL.waitTableEnabled(AccessControlLists.ACL_TABLE_NAME); + TEST_UTIL.waitTableEnabled(PermissionStorage.ACL_TABLE_NAME); } } diff --git a/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsWithACL.java b/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsWithACL.java index 59e5601..4b23f18 100644 --- a/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsWithACL.java +++ b/hbase-rsgroup/src/test/java/org/apache/hadoop/hbase/rsgroup/TestRSGroupsWithACL.java @@ -34,9 +34,9 @@ import org.apache.hadoop.hbase.client.TableDescriptorBuilder; import org.apache.hadoop.hbase.coprocessor.CoprocessorHost; import org.apache.hadoop.hbase.security.User; import org.apache.hadoop.hbase.security.access.AccessControlClient; -import org.apache.hadoop.hbase.security.access.AccessControlLists; import org.apache.hadoop.hbase.security.access.AuthManager; import org.apache.hadoop.hbase.security.access.Permission; +import org.apache.hadoop.hbase.security.access.PermissionStorage; import org.apache.hadoop.hbase.security.access.SecureTestUtil; import org.apache.hadoop.hbase.testclassification.MediumTests; import org.apache.hadoop.hbase.testclassification.SecurityTests; @@ -113,7 +113,7 @@ public class TestRSGroupsWithACL extends SecureTestUtil{ rsGroupAdminEndpoint = (RSGroupAdminEndpoint) TEST_UTIL.getMiniHBaseCluster().getMaster(). getMasterCoprocessorHost().findCoprocessor(RSGroupAdminEndpoint.class.getName()); // Wait for the ACL table to become available - TEST_UTIL.waitUntilAllRegionsAssigned(AccessControlLists.ACL_TABLE_NAME); + TEST_UTIL.waitUntilAllRegionsAssigned(PermissionStorage.ACL_TABLE_NAME); // create a set of test users SUPERUSER = User.createUserForTesting(conf, "admin", new String[] { "supergroup" }); @@ -174,7 +174,7 @@ public class TestRSGroupsWithACL extends SecureTestUtil{ grantGlobal(TEST_UTIL, toGroupEntry(GROUP_READ), Permission.Action.READ); grantGlobal(TEST_UTIL, toGroupEntry(GROUP_WRITE), Permission.Action.WRITE); - assertEquals(4, AccessControlLists.getTablePermissions(conf, TEST_TABLE).size()); + assertEquals(4, PermissionStorage.getTablePermissions(conf, TEST_TABLE).size()); try { assertEquals(4, AccessControlClient.getUserPermissions(systemUserConnection, TEST_TABLE.toString()).size()); @@ -194,9 +194,9 @@ public class TestRSGroupsWithACL extends SecureTestUtil{ LOG.info("Test deleted table " + TEST_TABLE); } // Verify all table/namespace permissions are erased - assertEquals(0, AccessControlLists.getTablePermissions(conf, TEST_TABLE).size()); - assertEquals(0, AccessControlLists.getNamespacePermissions(conf, - TEST_TABLE.getNamespaceAsString()).size()); + assertEquals(0, PermissionStorage.getTablePermissions(conf, TEST_TABLE).size()); + assertEquals(0, + PermissionStorage.getNamespacePermissions(conf, TEST_TABLE.getNamespaceAsString()).size()); } @AfterClass diff --git a/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/master/MasterStatusTmpl.jamon b/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/master/MasterStatusTmpl.jamon index f6ea764..06fe2c9 100644 --- a/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/master/MasterStatusTmpl.jamon +++ b/hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/master/MasterStatusTmpl.jamon @@ -52,7 +52,7 @@ org.apache.hadoop.hbase.master.RegionState; org.apache.hadoop.hbase.master.ServerManager; org.apache.hadoop.hbase.protobuf.ProtobufUtil; org.apache.hadoop.hbase.quotas.QuotaUtil; -org.apache.hadoop.hbase.security.access.AccessControlLists; +org.apache.hadoop.hbase.security.access.PermissionStorage; org.apache.hadoop.hbase.security.visibility.VisibilityConstants; org.apache.hadoop.hbase.shaded.protobuf.generated.SnapshotProtos.SnapshotDescription; org.apache.hadoop.hbase.tool.Canary; @@ -444,7 +444,7 @@ AssignmentManager assignmentManager = master.getAssignmentManager(); } else if (tableName.equals(Canary.DEFAULT_WRITE_TABLE_NAME)){ description = "The hbase:canary table is used to sniff the write availbility of" + " each regionserver."; - } else if (tableName.equals(AccessControlLists.ACL_TABLE_NAME)){ + } else if (tableName.equals(PermissionStorage.ACL_TABLE_NAME)){ description = "The hbase:acl table holds information about acl."; } else if (tableName.equals(VisibilityConstants.LABELS_TABLE_NAME)){ description = "The hbase:labels table holds information about visibility labels."; diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java index 6a5b508..222a686 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java @@ -102,10 +102,10 @@ import org.apache.hadoop.hbase.security.Superusers; import org.apache.hadoop.hbase.security.User; import org.apache.hadoop.hbase.security.access.AccessChecker; import org.apache.hadoop.hbase.security.access.AccessChecker.InputUser; -import org.apache.hadoop.hbase.security.access.AccessControlLists; import org.apache.hadoop.hbase.security.access.AccessController; import org.apache.hadoop.hbase.security.access.Permission; import org.apache.hadoop.hbase.security.access.Permission.Action; +import org.apache.hadoop.hbase.security.access.PermissionStorage; import org.apache.hadoop.hbase.security.access.ShadedAccessControlUtil; import org.apache.hadoop.hbase.security.access.UserPermission; import org.apache.hadoop.hbase.security.visibility.VisibilityController; @@ -2712,8 +2712,8 @@ public class MasterRpcServices extends RSRpcServices if (master.cpHost != null) { master.cpHost.preGrant(perm, mergeExistingPermissions); } - try (Table table = master.getConnection().getTable(AccessControlLists.ACL_TABLE_NAME)) { - AccessControlLists.addUserPermission(getConfiguration(), perm, table, + try (Table table = master.getConnection().getTable(PermissionStorage.ACL_TABLE_NAME)) { + PermissionStorage.addUserPermission(getConfiguration(), perm, table, mergeExistingPermissions); } if (master.cpHost != null) { @@ -2734,8 +2734,8 @@ public class MasterRpcServices extends RSRpcServices if (master.cpHost != null) { master.cpHost.preRevoke(userPermission); } - try (Table table = master.getConnection().getTable(AccessControlLists.ACL_TABLE_NAME)) { - AccessControlLists.removeUserPermission(master.getConfiguration(), userPermission, table); + try (Table table = master.getConnection().getTable(PermissionStorage.ACL_TABLE_NAME)) { + PermissionStorage.removeUserPermission(master.getConfiguration(), userPermission, table); } if (master.cpHost != null) { master.cpHost.postRevoke(userPermission); @@ -2765,17 +2765,17 @@ public class MasterRpcServices extends RSRpcServices List perms = null; if (permissionType == Type.Table) { boolean filter = (cf != null || userName != null) ? true : false; - perms = AccessControlLists.getUserTablePermissions(master.getConfiguration(), table, cf, cq, + perms = PermissionStorage.getUserTablePermissions(master.getConfiguration(), table, cf, cq, userName, filter); } else if (permissionType == Type.Namespace) { - perms = AccessControlLists.getUserNamespacePermissions(master.getConfiguration(), namespace, + perms = PermissionStorage.getUserNamespacePermissions(master.getConfiguration(), namespace, userName, userName != null ? true : false); } else { - perms = AccessControlLists.getUserPermissions(master.getConfiguration(), null, null, null, + perms = PermissionStorage.getUserPermissions(master.getConfiguration(), null, null, null, userName, userName != null ? true : false); // Skip super users when filter user is specified if (userName == null) { - // Adding superusers explicitly to the result set as AccessControlLists do not store + // Adding superusers explicitly to the result set as PermissionStorage do not store // them. Also using acl as table name to be inline with the results of global admin and // will help in avoiding any leakage of information about being superusers. for (String user : Superusers.getSuperUsers()) { diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessControlLists.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessControlLists.java deleted file mode 100644 index 1182baa..0000000 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessControlLists.java +++ /dev/null @@ -1,910 +0,0 @@ -/* - * 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 java.io.ByteArrayInputStream; -import java.io.DataInput; -import java.io.DataInputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; -import java.util.TreeSet; - -import org.apache.commons.lang3.StringUtils; -import org.apache.hadoop.conf.Configuration; -import org.apache.hadoop.hbase.AuthUtil; -import org.apache.hadoop.hbase.Cell; -import org.apache.hadoop.hbase.Cell.Type; -import org.apache.hadoop.hbase.CellBuilderFactory; -import org.apache.hadoop.hbase.CellBuilderType; -import org.apache.hadoop.hbase.CellUtil; -import org.apache.hadoop.hbase.CompareOperator; -import org.apache.hadoop.hbase.NamespaceDescriptor; -import org.apache.hadoop.hbase.PrivateCellUtil; -import org.apache.hadoop.hbase.TableName; -import org.apache.hadoop.hbase.Tag; -import org.apache.hadoop.hbase.TagType; -import org.apache.hadoop.hbase.client.Connection; -import org.apache.hadoop.hbase.client.ConnectionFactory; -import org.apache.hadoop.hbase.client.Delete; -import org.apache.hadoop.hbase.client.Get; -import org.apache.hadoop.hbase.client.Put; -import org.apache.hadoop.hbase.client.Result; -import org.apache.hadoop.hbase.client.ResultScanner; -import org.apache.hadoop.hbase.client.Scan; -import org.apache.hadoop.hbase.client.Table; -import org.apache.hadoop.hbase.client.TableDescriptor; -import org.apache.hadoop.hbase.exceptions.DeserializationException; -import org.apache.hadoop.hbase.filter.QualifierFilter; -import org.apache.hadoop.hbase.filter.RegexStringComparator; -import org.apache.hadoop.hbase.protobuf.ProtobufUtil; -import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos; -import org.apache.hadoop.hbase.regionserver.InternalScanner; -import org.apache.hadoop.hbase.regionserver.Region; -import org.apache.hadoop.hbase.security.User; -import org.apache.hbase.thirdparty.com.google.common.annotations.VisibleForTesting; -import org.apache.hbase.thirdparty.com.google.common.collect.ArrayListMultimap; -import org.apache.hbase.thirdparty.com.google.common.collect.ListMultimap; -import org.apache.hbase.thirdparty.com.google.common.collect.Lists; -import org.apache.hadoop.hbase.util.Bytes; -import org.apache.hadoop.hbase.util.Pair; -import org.apache.hadoop.io.Text; -import org.apache.hadoop.io.Writable; -import org.apache.hadoop.io.WritableFactories; -import org.apache.hadoop.io.WritableUtils; -import org.apache.yetus.audience.InterfaceAudience; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Maintains lists of permission grants to users and groups to allow for - * authorization checks by {@link AccessController}. - * - *

- * Access control lists are stored in an "internal" metadata table named - * {@code _acl_}. Each table's permission grants are stored as a separate row, - * keyed by the table name. KeyValues for permissions assignments are stored - * in one of the formats: - *

- * Key                      Desc
- * --------                 --------
- * user                     table level permissions for a user [R=read, W=write]
- * group                    table level permissions for a group
- * user,family              column family level permissions for a user
- * group,family             column family level permissions for a group
- * user,family,qualifier    column qualifier level permissions for a user
- * group,family,qualifier   column qualifier level permissions for a group
- * 
- *

- * All values are encoded as byte arrays containing the codes from the - * org.apache.hadoop.hbase.security.access.TablePermission.Action enum. - *

- */ -@InterfaceAudience.Private -public class AccessControlLists { - /** Internal storage table for access control lists */ - public static final TableName ACL_TABLE_NAME = - TableName.valueOf(NamespaceDescriptor.SYSTEM_NAMESPACE_NAME_STR, "acl"); - public static final byte[] ACL_GLOBAL_NAME = ACL_TABLE_NAME.getName(); - /** Column family used to store ACL grants */ - public static final String ACL_LIST_FAMILY_STR = "l"; - public static final byte[] ACL_LIST_FAMILY = Bytes.toBytes(ACL_LIST_FAMILY_STR); - /** KV tag to store per cell access control lists */ - public static final byte ACL_TAG_TYPE = TagType.ACL_TAG_TYPE; - - public static final char NAMESPACE_PREFIX = '@'; - - /** - * Delimiter to separate user, column family, and qualifier in - * _acl_ table info: column keys */ - public static final char ACL_KEY_DELIMITER = ','; - - private static final Logger LOG = LoggerFactory.getLogger(AccessControlLists.class); - - /** - * Stores a new user permission grant in the access control lists table. - * @param conf the configuration - * @param userPerm the details of the permission to be granted - * @param t acl table instance. It is closed upon method return. - * @throws IOException in the case of an error accessing the metadata table - */ - public static void addUserPermission(Configuration conf, UserPermission userPerm, Table t, - boolean mergeExistingPermissions) throws IOException { - Permission permission = userPerm.getPermission(); - Permission.Action[] actions = permission.getActions(); - byte[] rowKey = userPermissionRowKey(permission); - Put p = new Put(rowKey); - byte[] key = userPermissionKey(userPerm); - - if ((actions == null) || (actions.length == 0)) { - String msg = "No actions associated with user '" + userPerm.getUser() + "'"; - LOG.warn(msg); - throw new IOException(msg); - } - - Set actionSet = new TreeSet(); - if(mergeExistingPermissions){ - List perms = getUserPermissions(conf, rowKey, null, null, null, false); - UserPermission currentPerm = null; - for (UserPermission perm : perms) { - if (userPerm.equalsExceptActions(perm)) { - currentPerm = perm; - break; - } - } - - if (currentPerm != null && currentPerm.getPermission().getActions() != null){ - actionSet.addAll(Arrays.asList(currentPerm.getPermission().getActions())); - } - } - - // merge current action with new action. - actionSet.addAll(Arrays.asList(actions)); - - // serialize to byte array. - byte[] value = new byte[actionSet.size()]; - int index = 0; - for (Permission.Action action : actionSet) { - value[index++] = action.code(); - } - p.add(CellBuilderFactory.create(CellBuilderType.SHALLOW_COPY) - .setRow(p.getRow()) - .setFamily(ACL_LIST_FAMILY) - .setQualifier(key) - .setTimestamp(p.getTimestamp()) - .setType(Type.Put) - .setValue(value) - .build()); - if (LOG.isDebugEnabled()) { - LOG.debug("Writing permission with rowKey "+ - Bytes.toString(rowKey)+" "+ - Bytes.toString(key)+": "+Bytes.toStringBinary(value) - ); - } - try { - t.put(p); - } finally { - t.close(); - } - } - - static void addUserPermission(Configuration conf, UserPermission userPerm, Table t) - throws IOException{ - addUserPermission(conf, userPerm, t, false); - } - - /** - * Removes a previously granted permission from the stored access control - * lists. The {@link TablePermission} being removed must exactly match what - * is stored -- no wildcard matching is attempted. Ie, if user "bob" has - * been granted "READ" access to the "data" table, but only to column family - * plus qualifier "info:colA", then trying to call this method with only - * user "bob" and the table name "data" (but without specifying the - * column qualifier "info:colA") will have no effect. - * - * @param conf the configuration - * @param userPerm the details of the permission to be revoked - * @param t acl table - * @throws IOException if there is an error accessing the metadata table - */ - public static void removeUserPermission(Configuration conf, UserPermission userPerm, Table t) - throws IOException { - if (null == userPerm.getPermission().getActions() || - userPerm.getPermission().getActions().length == 0) { - removePermissionRecord(conf, userPerm, t); - } else { - // Get all the global user permissions from the acl table - List permsList = - getUserPermissions(conf, userPermissionRowKey(userPerm.getPermission()), - null, null, null, false); - List remainingActions = new ArrayList<>(); - List dropActions = Arrays.asList(userPerm.getPermission().getActions()); - for (UserPermission perm : permsList) { - // Find the user and remove only the requested permissions - if (perm.getUser().equals(userPerm.getUser())) { - for (Permission.Action oldAction : perm.getPermission().getActions()) { - if (!dropActions.contains(oldAction)) { - remainingActions.add(oldAction); - } - } - if (!remainingActions.isEmpty()) { - perm.getPermission().setActions( - remainingActions.toArray(new Permission.Action[remainingActions.size()])); - addUserPermission(conf, perm, t); - } else { - removePermissionRecord(conf, userPerm, t); - } - break; - } - } - } - if (LOG.isDebugEnabled()) { - LOG.debug("Removed permission "+ userPerm.toString()); - } - } - - private static void removePermissionRecord(Configuration conf, UserPermission userPerm, Table t) - throws IOException { - Delete d = new Delete(userPermissionRowKey(userPerm.getPermission())); - d.addColumns(ACL_LIST_FAMILY, userPermissionKey(userPerm)); - try { - t.delete(d); - } finally { - t.close(); - } - } - - /** - * Remove specified table from the _acl_ table. - */ - static void removeTablePermissions(Configuration conf, TableName tableName, Table t) - throws IOException{ - Delete d = new Delete(tableName.getName()); - - if (LOG.isDebugEnabled()) { - LOG.debug("Removing permissions of removed table "+ tableName); - } - try { - t.delete(d); - } finally { - t.close(); - } - } - - /** - * Remove specified namespace from the acl table. - */ - static void removeNamespacePermissions(Configuration conf, String namespace, Table t) - throws IOException{ - Delete d = new Delete(Bytes.toBytes(toNamespaceEntry(namespace))); - - if (LOG.isDebugEnabled()) { - LOG.debug("Removing permissions of removed namespace "+ namespace); - } - - try { - t.delete(d); - } finally { - t.close(); - } - } - - static private void removeTablePermissions(TableName tableName, byte[] column, Table table, - boolean closeTable) throws IOException { - Scan scan = new Scan(); - scan.addFamily(ACL_LIST_FAMILY); - - String columnName = Bytes.toString(column); - scan.setFilter(new QualifierFilter(CompareOperator.EQUAL, new RegexStringComparator( - String.format("(%s%s%s)|(%s%s)$", - ACL_KEY_DELIMITER, columnName, ACL_KEY_DELIMITER, - ACL_KEY_DELIMITER, columnName)))); - - Set qualifierSet = new TreeSet<>(Bytes.BYTES_COMPARATOR); - ResultScanner scanner = null; - try { - scanner = table.getScanner(scan); - for (Result res : scanner) { - for (byte[] q : res.getFamilyMap(ACL_LIST_FAMILY).navigableKeySet()) { - qualifierSet.add(q); - } - } - - if (qualifierSet.size() > 0) { - Delete d = new Delete(tableName.getName()); - for (byte[] qualifier : qualifierSet) { - d.addColumns(ACL_LIST_FAMILY, qualifier); - } - table.delete(d); - } - } finally { - if (scanner != null) scanner.close(); - if (closeTable) table.close(); - } - } - - /** - * Remove specified table column from the acl table. - */ - static void removeTablePermissions(Configuration conf, TableName tableName, byte[] column, - Table t) throws IOException { - if (LOG.isDebugEnabled()) { - LOG.debug("Removing permissions of removed column " + Bytes.toString(column) + - " from table "+ tableName); - } - removeTablePermissions(tableName, column, t, true); - } - - static byte[] userPermissionRowKey(Permission permission) { - byte[] row; - if (permission instanceof TablePermission) { - TablePermission tablePerm = (TablePermission) permission; - row = tablePerm.getTableName().getName(); - } else if (permission instanceof NamespacePermission) { - NamespacePermission nsPerm = (NamespacePermission) permission; - row = Bytes.toBytes(toNamespaceEntry(nsPerm.getNamespace())); - } else { - // permission instanceof TablePermission - row = ACL_GLOBAL_NAME; - } - return row; - } - - /** - * Build qualifier key from user permission: - * username - * username,family - * username,family,qualifier - */ - static byte[] userPermissionKey(UserPermission permission) { - byte[] key = Bytes.toBytes(permission.getUser()); - byte[] qualifier = null; - byte[] family = null; - if (permission.getPermission().getAccessScope() == Permission.Scope.TABLE) { - TablePermission tablePermission = (TablePermission) permission.getPermission(); - family = tablePermission.getFamily(); - qualifier = tablePermission.getQualifier(); - } - - if (family != null && family.length > 0) { - key = Bytes.add(key, Bytes.add(new byte[]{ACL_KEY_DELIMITER}, family)); - if (qualifier != null && qualifier.length > 0) { - key = Bytes.add(key, Bytes.add(new byte[]{ACL_KEY_DELIMITER}, qualifier)); - } - } - - return key; - } - - /** - * Returns {@code true} if the given region is part of the {@code _acl_} - * metadata table. - */ - static boolean isAclRegion(Region region) { - return ACL_TABLE_NAME.equals(region.getTableDescriptor().getTableName()); - } - - /** - * Returns {@code true} if the given table is {@code _acl_} metadata table. - */ - static boolean isAclTable(TableDescriptor desc) { - return ACL_TABLE_NAME.equals(desc.getTableName()); - } - - /** - * Loads all of the permission grants stored in a region of the {@code _acl_} - * table. - * - * @param aclRegion - * @return a map of the permissions for this table. - * @throws IOException - */ - static Map> loadAll(Region aclRegion) - throws IOException { - - if (!isAclRegion(aclRegion)) { - throw new IOException("Can only load permissions from "+ACL_TABLE_NAME); - } - - Map> allPerms = - new TreeMap<>(Bytes.BYTES_RAWCOMPARATOR); - - // do a full scan of _acl_ table - - Scan scan = new Scan(); - scan.addFamily(ACL_LIST_FAMILY); - - InternalScanner iScanner = null; - try { - iScanner = aclRegion.getScanner(scan); - - while (true) { - List row = new ArrayList<>(); - - boolean hasNext = iScanner.next(row); - ListMultimap perms = ArrayListMultimap.create(); - byte[] entry = null; - for (Cell kv : row) { - if (entry == null) { - entry = CellUtil.cloneRow(kv); - } - Pair permissionsOfUserOnTable = - parsePermissionRecord(entry, kv, null, null, false, null); - if (permissionsOfUserOnTable != null) { - String username = permissionsOfUserOnTable.getFirst(); - Permission permission = permissionsOfUserOnTable.getSecond(); - perms.put(username, new UserPermission(username, permission)); - } - } - if (entry != null) { - allPerms.put(entry, perms); - } - if (!hasNext) { - break; - } - } - } finally { - if (iScanner != null) { - iScanner.close(); - } - } - - return allPerms; - } - - /** - * Load all permissions from the region server holding {@code _acl_}, - * primarily intended for testing purposes. - */ - static Map> loadAll( - Configuration conf) throws IOException { - Map> allPerms = - new TreeMap<>(Bytes.BYTES_RAWCOMPARATOR); - - // do a full scan of _acl_, filtering on only first table region rows - - Scan scan = new Scan(); - scan.addFamily(ACL_LIST_FAMILY); - - ResultScanner scanner = null; - // TODO: Pass in a Connection rather than create one each time. - try (Connection connection = ConnectionFactory.createConnection(conf)) { - try (Table table = connection.getTable(ACL_TABLE_NAME)) { - scanner = table.getScanner(scan); - try { - for (Result row : scanner) { - ListMultimap resultPerms = - parsePermissions(row.getRow(), row, null, null, null, false); - allPerms.put(row.getRow(), resultPerms); - } - } finally { - if (scanner != null) scanner.close(); - } - } - } - - return allPerms; - } - - public static ListMultimap getTablePermissions(Configuration conf, - TableName tableName) throws IOException { - return getPermissions(conf, tableName != null ? tableName.getName() : null, null, null, null, - null, false); - } - - @VisibleForTesting - public static ListMultimap getNamespacePermissions(Configuration conf, - String namespace) throws IOException { - return getPermissions(conf, Bytes.toBytes(toNamespaceEntry(namespace)), null, null, null, null, - false); - } - - /** - * Reads user permission assignments stored in the l: column family of the first - * table row in _acl_. - *

- * See {@link AccessControlLists class documentation} for the key structure used for storage. - *

- */ - static ListMultimap getPermissions(Configuration conf, byte[] entryName, - Table t, byte[] cf, byte[] cq, String user, boolean hasFilterUser) throws IOException { - if (entryName == null) entryName = ACL_GLOBAL_NAME; - // for normal user tables, we just read the table row from _acl_ - ListMultimap perms = ArrayListMultimap.create(); - Get get = new Get(entryName); - get.addFamily(ACL_LIST_FAMILY); - Result row = null; - if (t == null) { - try (Connection connection = ConnectionFactory.createConnection(conf)) { - try (Table table = connection.getTable(ACL_TABLE_NAME)) { - row = table.get(get); - } - } - } else { - row = t.get(get); - } - if (!row.isEmpty()) { - perms = parsePermissions(entryName, row, cf, cq, user, hasFilterUser); - } else { - LOG.info("No permissions found in " + ACL_TABLE_NAME + " for acl entry " - + Bytes.toString(entryName)); - } - - return perms; - } - - /** - * Returns the currently granted permissions for a given table as the specified user plus - * associated permissions. - */ - public static List getUserTablePermissions(Configuration conf, - TableName tableName, byte[] cf, byte[] cq, String userName, boolean hasFilterUser) - throws IOException { - return getUserPermissions(conf, tableName == null ? null : tableName.getName(), cf, cq, - userName, hasFilterUser); - } - - /** - * Returns the currently granted permissions for a given namespace as the specified user plus - * associated permissions. - */ - public static List getUserNamespacePermissions(Configuration conf, - String namespace, String user, boolean hasFilterUser) throws IOException { - return getUserPermissions(conf, Bytes.toBytes(toNamespaceEntry(namespace)), null, null, user, - hasFilterUser); - } - - /** - * Returns the currently granted permissions for a given table/namespace with associated - * permissions based on the specified column family, column qualifier and user name. - * @param conf the configuration - * @param entryName Table name or the namespace - * @param cf Column family - * @param cq Column qualifier - * @param user User name to be filtered from permission as requested - * @param hasFilterUser true if filter user is provided, otherwise false. - * @return List of UserPermissions - * @throws IOException on failure - */ - public static List getUserPermissions(Configuration conf, byte[] entryName, - byte[] cf, byte[] cq, String user, boolean hasFilterUser) throws IOException { - ListMultimap allPerms = - getPermissions(conf, entryName, null, cf, cq, user, hasFilterUser); - List perms = new ArrayList<>(); - for (Map.Entry entry : allPerms.entries()) { - perms.add(entry.getValue()); - } - return perms; - } - - /** - * Parse and filter permission based on the specified column family, column qualifier and user - * name. - */ - private static ListMultimap parsePermissions(byte[] entryName, - Result result, byte[] cf, byte[] cq, String user, boolean hasFilterUser) { - ListMultimap perms = ArrayListMultimap.create(); - if (result != null && result.size() > 0) { - for (Cell kv : result.rawCells()) { - Pair permissionsOfUserOnTable = - parsePermissionRecord(entryName, kv, cf, cq, hasFilterUser, user); - - if (permissionsOfUserOnTable != null) { - String username = permissionsOfUserOnTable.getFirst(); - Permission permission = permissionsOfUserOnTable.getSecond(); - perms.put(username, new UserPermission(username, permission)); - } - } - } - return perms; - } - - private static Pair parsePermissionRecord(byte[] entryName, Cell kv, - byte[] cf, byte[] cq, boolean filterPerms, String filterUser) { - // return X given a set of permissions encoded in the permissionRecord kv. - byte[] family = CellUtil.cloneFamily(kv); - if (!Bytes.equals(family, ACL_LIST_FAMILY)) { - return null; - } - - byte[] key = CellUtil.cloneQualifier(kv); - byte[] value = CellUtil.cloneValue(kv); - if (LOG.isDebugEnabled()) { - LOG.debug("Read acl: entry[" + - Bytes.toStringBinary(entryName) + "], kv [" + - Bytes.toStringBinary(key) + ": " + - Bytes.toStringBinary(value)+"]"); - } - - // check for a column family appended to the key - // TODO: avoid the string conversion to make this more efficient - String username = Bytes.toString(key); - - // Retrieve group list for the filterUser if cell key is a group. - // Group list is not required when filterUser itself a group - List filterUserGroups = null; - if (filterPerms) { - if (username.charAt(0) == '@' && !StringUtils.isEmpty(filterUser) - && filterUser.charAt(0) != '@') { - filterUserGroups = AccessChecker.getUserGroups(filterUser); - } - } - - // Handle namespace entry - if (isNamespaceEntry(entryName)) { - // Filter the permissions cell record if client query - if (filterPerms && !validateFilterUser(username, filterUser, filterUserGroups)) { - return null; - } - - return new Pair<>(username, - Permission.newBuilder(Bytes.toString(fromNamespaceEntry(entryName))) - .withActionCodes(value).build()); - } - - // Handle global entry - if (isGlobalEntry(entryName)) { - // Filter the permissions cell record if client query - if (filterPerms && !validateFilterUser(username, filterUser, filterUserGroups)) { - return null; - } - - return new Pair<>(username, Permission.newBuilder().withActionCodes(value).build()); - } - - // Handle table entry - int idx = username.indexOf(ACL_KEY_DELIMITER); - byte[] permFamily = null; - byte[] permQualifier = null; - if (idx > 0 && idx < username.length()-1) { - String remainder = username.substring(idx+1); - username = username.substring(0, idx); - idx = remainder.indexOf(ACL_KEY_DELIMITER); - if (idx > 0 && idx < remainder.length()-1) { - permFamily = Bytes.toBytes(remainder.substring(0, idx)); - permQualifier = Bytes.toBytes(remainder.substring(idx+1)); - } else { - permFamily = Bytes.toBytes(remainder); - } - } - - // Filter the permissions cell record if client query - if (filterPerms) { - // ACL table contain 3 types of cell key entries; hbase:Acl, namespace and table. So to filter - // the permission cell records additional validations are required at CF, CQ and username. - // Here we can proceed based on client input whether it contain filterUser. - // Validate the filterUser when specified - if (filterUser != null && !validateFilterUser(username, filterUser, filterUserGroups)) { - return null; - } - if (!validateCFAndCQ(permFamily, cf, permQualifier, cq)) { - return null; - } - } - - return new Pair<>(username, Permission.newBuilder(TableName.valueOf(entryName)) - .withFamily(permFamily).withQualifier(permQualifier).withActionCodes(value).build()); - } - - /* - * Validate the cell key with the client filterUser if specified in the query input. 1. If cell - * key (username) is not a group then check whether client filterUser is equal to username 2. If - * cell key (username) is a group then check whether client filterUser belongs to the cell key - * group (username) 3. In case when both filterUser and username are group names then cell will be - * filtered if not equal. - */ - private static boolean validateFilterUser(String username, String filterUser, - List filterUserGroups) { - if (filterUserGroups == null) { - // Validate user name or group names whether equal - if (filterUser.equals(username)) { - return true; - } - } else { - // Check whether filter user belongs to the cell key group. - return filterUserGroups.contains(username.substring(1)); - } - return false; - } - - /* - * Validate the cell with client CF and CQ if specified in the query input. 1. If CF is NULL, then - * no need of further validation, result should include all CF and CQ. 2. IF CF specified and - * equal then validation required at CQ level if CF specified in client input, otherwise return - * all CQ records. - */ - private static boolean validateCFAndCQ(byte[] permFamily, byte[] cf, byte[] permQualifier, - byte[] cq) { - boolean include = true; - if (cf != null) { - if (Bytes.equals(cf, permFamily)) { - if (cq != null && !Bytes.equals(cq, permQualifier)) { - // if CQ specified and didn't match then ignore this cell - include = false; - } - } else { - // if CF specified and didn't match then ignore this cell - include = false; - } - } - return include; - } - - /** - * Writes a set of permissions as {@link org.apache.hadoop.io.Writable} instances and returns the - * resulting byte array. Writes a set of permission [user: table permission] - */ - public static byte[] writePermissionsAsBytes(ListMultimap perms, - Configuration conf) { - return ProtobufUtil.prependPBMagic(AccessControlUtil.toUserTablePermissions(perms).toByteArray()); - } - - // This is part of the old HbaseObjectWritableFor96Migration. - private static final int LIST_CODE = 61; - - private static final int WRITABLE_CODE = 14; - - private static final int WRITABLE_NOT_ENCODED = 0; - - private static List readWritableUserPermission(DataInput in, - Configuration conf) throws IOException, ClassNotFoundException { - assert WritableUtils.readVInt(in) == LIST_CODE; - int length = in.readInt(); - List list = new ArrayList<>(length); - for (int i = 0; i < length; i++) { - assert WritableUtils.readVInt(in) == WRITABLE_CODE; - assert WritableUtils.readVInt(in) == WRITABLE_NOT_ENCODED; - String className = Text.readString(in); - Class clazz = conf.getClassByName(className).asSubclass(Writable.class); - Writable instance = WritableFactories.newInstance(clazz, conf); - instance.readFields(in); - list.add((Permission) instance); - } - return list; - } - - @VisibleForTesting - public static ListMultimap readUserPermission(byte[] data, - Configuration conf) throws DeserializationException { - if (ProtobufUtil.isPBMagicPrefix(data)) { - int pblen = ProtobufUtil.lengthOfPBMagic(); - try { - AccessControlProtos.UsersAndPermissions.Builder builder = - AccessControlProtos.UsersAndPermissions.newBuilder(); - ProtobufUtil.mergeFrom(builder, data, pblen, data.length - pblen); - return AccessControlUtil.toUserPermission(builder.build()); - } catch (IOException e) { - throw new DeserializationException(e); - } - } else { - // TODO: We have to re-write non-PB data as PB encoded. Otherwise we will carry old Writables - // forever (here and a couple of other places). - ListMultimap userPermission = ArrayListMultimap.create(); - try { - DataInput in = new DataInputStream(new ByteArrayInputStream(data)); - int length = in.readInt(); - for (int i = 0; i < length; i++) { - String user = Text.readString(in); - List perms = readWritableUserPermission(in, conf); - for (Permission p : perms) { - userPermission.put(user, new UserPermission(user, p)); - } - } - } catch (IOException | ClassNotFoundException e) { - throw new DeserializationException(e); - } - return userPermission; - } - } - - public static ListMultimap readPermissions(byte[] data, - Configuration conf) throws DeserializationException { - if (ProtobufUtil.isPBMagicPrefix(data)) { - int pblen = ProtobufUtil.lengthOfPBMagic(); - try { - AccessControlProtos.UsersAndPermissions.Builder builder = - AccessControlProtos.UsersAndPermissions.newBuilder(); - ProtobufUtil.mergeFrom(builder, data, pblen, data.length - pblen); - return AccessControlUtil.toPermission(builder.build()); - } catch (IOException e) { - throw new DeserializationException(e); - } - } else { - // TODO: We have to re-write non-PB data as PB encoded. Otherwise we will carry old Writables - // forever (here and a couple of other places). - ListMultimap perms = ArrayListMultimap.create(); - try { - DataInput in = new DataInputStream(new ByteArrayInputStream(data)); - int length = in.readInt(); - for (int i = 0; i < length; i++) { - String user = Text.readString(in); - perms.putAll(user, readWritableUserPermission(in, conf)); - } - } catch (IOException | ClassNotFoundException e) { - throw new DeserializationException(e); - } - return perms; - } - } - - public static boolean isGlobalEntry(byte[] entryName) { - return entryName != null && TableName.valueOf(entryName).equals(ACL_TABLE_NAME); - } - - public static boolean isNamespaceEntry(String entryName) { - return entryName != null && entryName.charAt(0) == NAMESPACE_PREFIX; - } - - public static boolean isNamespaceEntry(byte[] entryName) { - return entryName != null && entryName.length !=0 && entryName[0] == NAMESPACE_PREFIX; - } - - public static String toNamespaceEntry(String namespace) { - return NAMESPACE_PREFIX + namespace; - } - - public static String fromNamespaceEntry(String namespace) { - if(namespace.charAt(0) != NAMESPACE_PREFIX) - throw new IllegalArgumentException("Argument is not a valid namespace entry"); - return namespace.substring(1); - } - - public static byte[] toNamespaceEntry(byte[] namespace) { - byte[] ret = new byte[namespace.length+1]; - ret[0] = NAMESPACE_PREFIX; - System.arraycopy(namespace, 0, ret, 1, namespace.length); - return ret; - } - - public static byte[] fromNamespaceEntry(byte[] namespace) { - if(namespace[0] != NAMESPACE_PREFIX) { - throw new IllegalArgumentException("Argument is not a valid namespace entry: " + - Bytes.toString(namespace)); - } - return Arrays.copyOfRange(namespace, 1, namespace.length); - } - - public static List getCellPermissionsForUser(User user, Cell cell) - throws IOException { - // Save an object allocation where we can - if (cell.getTagsLength() == 0) { - return null; - } - List results = Lists.newArrayList(); - Iterator tagsIterator = PrivateCellUtil.tagsIterator(cell); - while (tagsIterator.hasNext()) { - Tag tag = tagsIterator.next(); - if (tag.getType() == ACL_TAG_TYPE) { - // Deserialize the table permissions from the KV - // TODO: This can be improved. Don't build UsersAndPermissions just to unpack it again, - // use the builder - AccessControlProtos.UsersAndPermissions.Builder builder = - AccessControlProtos.UsersAndPermissions.newBuilder(); - if (tag.hasArray()) { - ProtobufUtil.mergeFrom(builder, tag.getValueArray(), tag.getValueOffset(), tag.getValueLength()); - } else { - ProtobufUtil.mergeFrom(builder, Tag.cloneValue(tag)); - } - ListMultimap kvPerms = - AccessControlUtil.toUsersAndPermissions(builder.build()); - // Are there permissions for this user? - List userPerms = kvPerms.get(user.getShortName()); - if (userPerms != null) { - results.addAll(userPerms); - } - // Are there permissions for any of the groups this user belongs to? - String groupNames[] = user.getGroupNames(); - if (groupNames != null) { - for (String group : groupNames) { - List groupPerms = kvPerms.get(AuthUtil.toGroupEntry(group)); - if (results != null) { - results.addAll(groupPerms); - } - } - } - } - } - return results; - } -} diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java index a5ee794..0949207 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java @@ -244,14 +244,14 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, private void initialize(RegionCoprocessorEnvironment e) throws IOException { final Region region = e.getRegion(); Configuration conf = e.getConfiguration(); - Map> tables = AccessControlLists.loadAll(region); + Map> tables = PermissionStorage.loadAll(region); // For each table, write out the table's permissions to the respective // znode for that table. for (Map.Entry> t: tables.entrySet()) { byte[] entry = t.getKey(); ListMultimap perms = t.getValue(); - byte[] serialized = AccessControlLists.writePermissionsAsBytes(perms, conf); + byte[] serialized = PermissionStorage.writePermissionsAsBytes(perms, conf); getAuthManager().getZKPermissionWatcher().writeToZookeeper(entry, serialized); } initialized = true; @@ -268,7 +268,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, for (Map.Entry> f : familyMap.entrySet()) { List cells = f.getValue(); for (Cell cell: cells) { - if (CellUtil.matchingFamily(cell, AccessControlLists.ACL_LIST_FAMILY)) { + if (CellUtil.matchingFamily(cell, PermissionStorage.ACL_LIST_FAMILY)) { entries.add(CellUtil.cloneRow(cell)); } } @@ -283,12 +283,12 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, // to and fro conversion overhead. get req is converted to PB req // and results are converted to PB results 1st and then to POJOs // again. We could have avoided such at least in ACL table context.. - try (Table t = e.getConnection().getTable(AccessControlLists.ACL_TABLE_NAME)) { + try (Table t = e.getConnection().getTable(PermissionStorage.ACL_TABLE_NAME)) { for (byte[] entry : entries) { currentEntry = entry; ListMultimap perms = - AccessControlLists.getPermissions(conf, entry, t, null, null, null, false); - byte[] serialized = AccessControlLists.writePermissionsAsBytes(perms, conf); + PermissionStorage.getPermissions(conf, entry, t, null, null, null, false); + byte[] serialized = PermissionStorage.writePermissionsAsBytes(perms, conf); zkw.writeToZookeeper(entry, serialized); } } catch(IOException ex) { @@ -624,7 +624,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, for (Cell cell: e.getValue()) { // Prepend the supplied perms in a new ACL tag to an update list of tags for the cell List tags = new ArrayList<>(); - tags.add(new ArrayBackedTag(AccessControlLists.ACL_TAG_TYPE, perms)); + tags.add(new ArrayBackedTag(PermissionStorage.ACL_TAG_TYPE, perms)); Iterator tagIterator = PrivateCellUtil.tagsIterator(cell); while (tagIterator.hasNext()) { tags.add(tagIterator.next()); @@ -656,7 +656,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, for (CellScanner cellScanner = m.cellScanner(); cellScanner.advance();) { Iterator tagsItr = PrivateCellUtil.tagsIterator(cellScanner.current()); while (tagsItr.hasNext()) { - if (tagsItr.next().getType() == AccessControlLists.ACL_TAG_TYPE) { + if (tagsItr.next().getType() == PermissionStorage.ACL_TAG_TYPE) { throw new AccessDeniedException("Mutation contains cell with reserved type tag"); } } @@ -786,12 +786,12 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, // creating acl table, getting delayed and by that time another table creation got over and // this hook is getting called. In such a case, we will need a wait logic here which will // wait till the acl table is created. - if (AccessControlLists.isAclTable(desc)) { + if (PermissionStorage.isAclTable(desc)) { this.aclTabAvailable = true; } else { if (!aclTabAvailable) { LOG.warn("Not adding owner permission for table " + desc.getTableName() + ". " - + AccessControlLists.ACL_TABLE_NAME + " is not yet created. " + + PermissionStorage.ACL_TABLE_NAME + " is not yet created. " + getClass().getSimpleName() + " should be configured as the first Coprocessor"); } else { String owner = desc.getOwnerString(); @@ -804,9 +804,9 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, User.runAsLoginUser(new PrivilegedExceptionAction() { @Override public Void run() throws Exception { - try (Table table = c.getEnvironment().getConnection(). - getTable(AccessControlLists.ACL_TABLE_NAME)) { - AccessControlLists.addUserPermission(c.getEnvironment().getConfiguration(), + try (Table table = + c.getEnvironment().getConnection().getTable(PermissionStorage.ACL_TABLE_NAME)) { + PermissionStorage.addUserPermission(c.getEnvironment().getConfiguration(), userPermission, table); } return null; @@ -830,9 +830,9 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, User.runAsLoginUser(new PrivilegedExceptionAction() { @Override public Void run() throws Exception { - try (Table table = c.getEnvironment().getConnection(). - getTable(AccessControlLists.ACL_TABLE_NAME)) { - AccessControlLists.removeTablePermissions(conf, tableName, table); + try (Table table = + c.getEnvironment().getConnection().getTable(PermissionStorage.ACL_TABLE_NAME)) { + PermissionStorage.removeTablePermissions(conf, tableName, table); } return null; } @@ -851,7 +851,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, @Override public Void run() throws Exception { List acls = - AccessControlLists.getUserTablePermissions(conf, tableName, null, null, null, false); + PermissionStorage.getUserTablePermissions(conf, tableName, null, null, null, false); if (acls != null) { tableAcls.put(tableName, acls); } @@ -870,9 +870,9 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, List perms = tableAcls.get(tableName); if (perms != null) { for (UserPermission perm : perms) { - try (Table table = ctx.getEnvironment().getConnection(). - getTable(AccessControlLists.ACL_TABLE_NAME)) { - AccessControlLists.addUserPermission(conf, perm, table); + try (Table table = + ctx.getEnvironment().getConnection().getTable(PermissionStorage.ACL_TABLE_NAME)) { + PermissionStorage.addUserPermission(conf, perm, table); } } } @@ -903,9 +903,9 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, public Void run() throws Exception { UserPermission userperm = new UserPermission(owner, Permission.newBuilder(currentDesc.getTableName()).withActions(Action.values()).build()); - try (Table table = c.getEnvironment().getConnection(). - getTable(AccessControlLists.ACL_TABLE_NAME)) { - AccessControlLists.addUserPermission(conf, userperm, table); + try (Table table = + c.getEnvironment().getConnection().getTable(PermissionStorage.ACL_TABLE_NAME)) { + PermissionStorage.addUserPermission(conf, userperm, table); } return null; } @@ -922,13 +922,13 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, @Override public void preDisableTable(ObserverContext c, TableName tableName) throws IOException { - if (Bytes.equals(tableName.getName(), AccessControlLists.ACL_GLOBAL_NAME)) { + if (Bytes.equals(tableName.getName(), PermissionStorage.ACL_GLOBAL_NAME)) { // We have to unconditionally disallow disable of the ACL table when we are installed, // even if not enforcing authorizations. We are still allowing grants and revocations, // checking permissions and logging audit messages, etc. If the ACL table is not // available we will fail random actions all over the place. - throw new AccessDeniedException("Not allowed to disable " - + AccessControlLists.ACL_TABLE_NAME + " table with AccessController installed"); + throw new AccessDeniedException("Not allowed to disable " + PermissionStorage.ACL_TABLE_NAME + + " table with AccessController installed"); } requirePermission(c, "disableTable", tableName, null, null, Action.ADMIN, Action.CREATE); @@ -1022,7 +1022,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, public void postStartMaster(ObserverContext ctx) throws IOException { try (Admin admin = ctx.getEnvironment().getConnection().getAdmin()) { - if (!admin.tableExists(AccessControlLists.ACL_TABLE_NAME)) { + if (!admin.tableExists(PermissionStorage.ACL_TABLE_NAME)) { createACLTable(admin); } else { this.aclTabAvailable = true; @@ -1036,7 +1036,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, private static void createACLTable(Admin admin) throws IOException { /** Table descriptor for ACL table */ ColumnFamilyDescriptor cfd = - ColumnFamilyDescriptorBuilder.newBuilder(AccessControlLists.ACL_LIST_FAMILY). + ColumnFamilyDescriptorBuilder.newBuilder(PermissionStorage.ACL_LIST_FAMILY). setMaxVersions(1). setInMemory(true). setBlockCacheEnabled(true). @@ -1044,7 +1044,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, setBloomFilterType(BloomType.NONE). setScope(HConstants.REPLICATION_SCOPE_LOCAL).build(); TableDescriptor td = - TableDescriptorBuilder.newBuilder(AccessControlLists.ACL_TABLE_NAME). + TableDescriptorBuilder.newBuilder(PermissionStorage.ACL_TABLE_NAME). setColumnFamily(cfd).build(); admin.createTable(td); } @@ -1140,15 +1140,15 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, User.runAsLoginUser(new PrivilegedExceptionAction() { @Override public Void run() throws Exception { - try (Table table = ctx.getEnvironment().getConnection(). - getTable(AccessControlLists.ACL_TABLE_NAME)) { - AccessControlLists.removeNamespacePermissions(conf, namespace, table); + try (Table table = + ctx.getEnvironment().getConnection().getTable(PermissionStorage.ACL_TABLE_NAME)) { + PermissionStorage.removeNamespacePermissions(conf, namespace, table); } return null; } }); getAuthManager().getZKPermissionWatcher().deleteNamespaceACLNode(namespace); - LOG.info(namespace + " entry deleted in " + AccessControlLists.ACL_TABLE_NAME + " table."); + LOG.info(namespace + " entry deleted in " + PermissionStorage.ACL_TABLE_NAME + " table."); } @Override @@ -1253,7 +1253,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, LOG.error("NULL region from RegionCoprocessorEnvironment in postOpen()"); return; } - if (AccessControlLists.isAclRegion(region)) { + if (PermissionStorage.isAclRegion(region)) { aclRegion = true; try { initialize(env); @@ -1798,7 +1798,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, Iterator tagIterator = PrivateCellUtil.tagsIterator(oldCell); while (tagIterator.hasNext()) { Tag tag = tagIterator.next(); - if (tag.getType() != AccessControlLists.ACL_TAG_TYPE) { + if (tag.getType() != PermissionStorage.ACL_TAG_TYPE) { // Not an ACL tag, just carry it through if (LOG.isTraceEnabled()) { LOG.trace("Carrying forward tag from " + oldCell + ": type " + tag.getType() @@ -1815,7 +1815,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, byte[] aclBytes = mutation.getACL(); if (aclBytes != null) { // Yes, use it - tags.add(new ArrayBackedTag(AccessControlLists.ACL_TAG_TYPE, aclBytes)); + tags.add(new ArrayBackedTag(PermissionStorage.ACL_TAG_TYPE, aclBytes)); } else { // No, use what we carried forward if (perms != null) { @@ -1997,7 +1997,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, } } else { throw new CoprocessorException(AccessController.class, "This method " - + "can only execute at " + AccessControlLists.ACL_TABLE_NAME + " table."); + + "can only execute at " + PermissionStorage.ACL_TABLE_NAME + " table."); } response = AccessControlProtos.GrantResponse.getDefaultInstance(); } catch (IOException ioe) { @@ -2037,7 +2037,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, } } else { throw new CoprocessorException(AccessController.class, "This method " - + "can only execute at " + AccessControlLists.ACL_TABLE_NAME + " table."); + + "can only execute at " + PermissionStorage.ACL_TABLE_NAME + " table."); } response = AccessControlProtos.RevokeResponse.getDefaultInstance(); } catch (IOException ioe) { @@ -2089,7 +2089,7 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, response = AccessControlUtil.buildGetUserPermissionsResponse(perms); } else { throw new CoprocessorException(AccessController.class, "This method " - + "can only execute at " + AccessControlLists.ACL_TABLE_NAME + " table."); + + "can only execute at " + PermissionStorage.ACL_TABLE_NAME + " table."); } } catch (IOException ioe) { // pass exception back up diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AuthManager.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AuthManager.java index 8719f62..e374a1b 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AuthManager.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AuthManager.java @@ -147,10 +147,9 @@ public final class AuthManager implements Closeable { public void refreshTableCacheFromWritable(TableName table, byte[] data) throws IOException { if (data != null && data.length > 0) { try { - ListMultimap perms = - AccessControlLists.readPermissions(data, conf); + ListMultimap perms = PermissionStorage.readPermissions(data, conf); if (perms != null) { - if (Bytes.equals(table.getName(), AccessControlLists.ACL_GLOBAL_NAME)) { + if (Bytes.equals(table.getName(), PermissionStorage.ACL_GLOBAL_NAME)) { updateGlobalCache(perms); } else { updateTableCache(table, perms); @@ -173,8 +172,7 @@ public final class AuthManager implements Closeable { public void refreshNamespaceCacheFromWritable(String namespace, byte[] data) throws IOException { if (data != null && data.length > 0) { try { - ListMultimap perms = - AccessControlLists.readPermissions(data, conf); + ListMultimap perms = PermissionStorage.readPermissions(data, conf); if (perms != null) { updateNamespaceCache(namespace, perms); } @@ -324,7 +322,7 @@ public final class AuthManager implements Closeable { return false; } if (table == null) { - table = AccessControlLists.ACL_TABLE_NAME; + table = PermissionStorage.ACL_TABLE_NAME; } if (authorizeUserNamespace(user, table.getNamespaceAsString(), action)) { return true; @@ -393,7 +391,7 @@ public final class AuthManager implements Closeable { return false; } if (table == null) { - table = AccessControlLists.ACL_TABLE_NAME; + table = PermissionStorage.ACL_TABLE_NAME; } if (authorizeUserNamespace(user, table.getNamespaceAsString(), action)) { return true; @@ -473,7 +471,7 @@ public final class AuthManager implements Closeable { */ public boolean authorizeCell(User user, TableName table, Cell cell, Permission.Action action) { try { - List perms = AccessControlLists.getCellPermissionsForUser(user, cell); + List perms = PermissionStorage.getCellPermissionsForUser(user, cell); if (LOG.isTraceEnabled()) { LOG.trace("Perms for user {} in table {} in cell {}: {}", user.getShortName(), table, cell, (perms != null ? perms : "")); diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/PermissionStorage.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/PermissionStorage.java new file mode 100644 index 0000000..491c933 --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/PermissionStorage.java @@ -0,0 +1,910 @@ +/* + * 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 java.io.ByteArrayInputStream; +import java.io.DataInput; +import java.io.DataInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; + +import org.apache.commons.lang3.StringUtils; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.hbase.AuthUtil; +import org.apache.hadoop.hbase.Cell; +import org.apache.hadoop.hbase.Cell.Type; +import org.apache.hadoop.hbase.CellBuilderFactory; +import org.apache.hadoop.hbase.CellBuilderType; +import org.apache.hadoop.hbase.CellUtil; +import org.apache.hadoop.hbase.CompareOperator; +import org.apache.hadoop.hbase.NamespaceDescriptor; +import org.apache.hadoop.hbase.PrivateCellUtil; +import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.Tag; +import org.apache.hadoop.hbase.TagType; +import org.apache.hadoop.hbase.client.Connection; +import org.apache.hadoop.hbase.client.ConnectionFactory; +import org.apache.hadoop.hbase.client.Delete; +import org.apache.hadoop.hbase.client.Get; +import org.apache.hadoop.hbase.client.Put; +import org.apache.hadoop.hbase.client.Result; +import org.apache.hadoop.hbase.client.ResultScanner; +import org.apache.hadoop.hbase.client.Scan; +import org.apache.hadoop.hbase.client.Table; +import org.apache.hadoop.hbase.client.TableDescriptor; +import org.apache.hadoop.hbase.exceptions.DeserializationException; +import org.apache.hadoop.hbase.filter.QualifierFilter; +import org.apache.hadoop.hbase.filter.RegexStringComparator; +import org.apache.hadoop.hbase.protobuf.ProtobufUtil; +import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos; +import org.apache.hadoop.hbase.regionserver.InternalScanner; +import org.apache.hadoop.hbase.regionserver.Region; +import org.apache.hadoop.hbase.security.User; +import org.apache.hbase.thirdparty.com.google.common.annotations.VisibleForTesting; +import org.apache.hbase.thirdparty.com.google.common.collect.ArrayListMultimap; +import org.apache.hbase.thirdparty.com.google.common.collect.ListMultimap; +import org.apache.hbase.thirdparty.com.google.common.collect.Lists; +import org.apache.hadoop.hbase.util.Bytes; +import org.apache.hadoop.hbase.util.Pair; +import org.apache.hadoop.io.Text; +import org.apache.hadoop.io.Writable; +import org.apache.hadoop.io.WritableFactories; +import org.apache.hadoop.io.WritableUtils; +import org.apache.yetus.audience.InterfaceAudience; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Maintains lists of permission grants to users and groups to allow for + * authorization checks by {@link AccessController}. + * + *

+ * Access control lists are stored in an "internal" metadata table named + * {@code _acl_}. Each table's permission grants are stored as a separate row, + * keyed by the table name. KeyValues for permissions assignments are stored + * in one of the formats: + *

+ * Key                      Desc
+ * --------                 --------
+ * user                     table level permissions for a user [R=read, W=write]
+ * group                    table level permissions for a group
+ * user,family              column family level permissions for a user
+ * group,family             column family level permissions for a group
+ * user,family,qualifier    column qualifier level permissions for a user
+ * group,family,qualifier   column qualifier level permissions for a group
+ * 
+ *

+ * All values are encoded as byte arrays containing the codes from the + * org.apache.hadoop.hbase.security.access.TablePermission.Action enum. + *

+ */ +@InterfaceAudience.Private +public class PermissionStorage { + /** Internal storage table for access control lists */ + public static final TableName ACL_TABLE_NAME = + TableName.valueOf(NamespaceDescriptor.SYSTEM_NAMESPACE_NAME_STR, "acl"); + public static final byte[] ACL_GLOBAL_NAME = ACL_TABLE_NAME.getName(); + /** Column family used to store ACL grants */ + public static final String ACL_LIST_FAMILY_STR = "l"; + public static final byte[] ACL_LIST_FAMILY = Bytes.toBytes(ACL_LIST_FAMILY_STR); + /** KV tag to store per cell access control lists */ + public static final byte ACL_TAG_TYPE = TagType.ACL_TAG_TYPE; + + public static final char NAMESPACE_PREFIX = '@'; + + /** + * Delimiter to separate user, column family, and qualifier in + * _acl_ table info: column keys */ + public static final char ACL_KEY_DELIMITER = ','; + + private static final Logger LOG = LoggerFactory.getLogger(PermissionStorage.class); + + /** + * Stores a new user permission grant in the access control lists table. + * @param conf the configuration + * @param userPerm the details of the permission to be granted + * @param t acl table instance. It is closed upon method return. + * @throws IOException in the case of an error accessing the metadata table + */ + public static void addUserPermission(Configuration conf, UserPermission userPerm, Table t, + boolean mergeExistingPermissions) throws IOException { + Permission permission = userPerm.getPermission(); + Permission.Action[] actions = permission.getActions(); + byte[] rowKey = userPermissionRowKey(permission); + Put p = new Put(rowKey); + byte[] key = userPermissionKey(userPerm); + + if ((actions == null) || (actions.length == 0)) { + String msg = "No actions associated with user '" + userPerm.getUser() + "'"; + LOG.warn(msg); + throw new IOException(msg); + } + + Set actionSet = new TreeSet(); + if(mergeExistingPermissions){ + List perms = getUserPermissions(conf, rowKey, null, null, null, false); + UserPermission currentPerm = null; + for (UserPermission perm : perms) { + if (userPerm.equalsExceptActions(perm)) { + currentPerm = perm; + break; + } + } + + if (currentPerm != null && currentPerm.getPermission().getActions() != null){ + actionSet.addAll(Arrays.asList(currentPerm.getPermission().getActions())); + } + } + + // merge current action with new action. + actionSet.addAll(Arrays.asList(actions)); + + // serialize to byte array. + byte[] value = new byte[actionSet.size()]; + int index = 0; + for (Permission.Action action : actionSet) { + value[index++] = action.code(); + } + p.add(CellBuilderFactory.create(CellBuilderType.SHALLOW_COPY) + .setRow(p.getRow()) + .setFamily(ACL_LIST_FAMILY) + .setQualifier(key) + .setTimestamp(p.getTimestamp()) + .setType(Type.Put) + .setValue(value) + .build()); + if (LOG.isDebugEnabled()) { + LOG.debug("Writing permission with rowKey "+ + Bytes.toString(rowKey)+" "+ + Bytes.toString(key)+": "+Bytes.toStringBinary(value) + ); + } + try { + t.put(p); + } finally { + t.close(); + } + } + + static void addUserPermission(Configuration conf, UserPermission userPerm, Table t) + throws IOException{ + addUserPermission(conf, userPerm, t, false); + } + + /** + * Removes a previously granted permission from the stored access control + * lists. The {@link TablePermission} being removed must exactly match what + * is stored -- no wildcard matching is attempted. Ie, if user "bob" has + * been granted "READ" access to the "data" table, but only to column family + * plus qualifier "info:colA", then trying to call this method with only + * user "bob" and the table name "data" (but without specifying the + * column qualifier "info:colA") will have no effect. + * + * @param conf the configuration + * @param userPerm the details of the permission to be revoked + * @param t acl table + * @throws IOException if there is an error accessing the metadata table + */ + public static void removeUserPermission(Configuration conf, UserPermission userPerm, Table t) + throws IOException { + if (null == userPerm.getPermission().getActions() || + userPerm.getPermission().getActions().length == 0) { + removePermissionRecord(conf, userPerm, t); + } else { + // Get all the global user permissions from the acl table + List permsList = + getUserPermissions(conf, userPermissionRowKey(userPerm.getPermission()), + null, null, null, false); + List remainingActions = new ArrayList<>(); + List dropActions = Arrays.asList(userPerm.getPermission().getActions()); + for (UserPermission perm : permsList) { + // Find the user and remove only the requested permissions + if (perm.getUser().equals(userPerm.getUser())) { + for (Permission.Action oldAction : perm.getPermission().getActions()) { + if (!dropActions.contains(oldAction)) { + remainingActions.add(oldAction); + } + } + if (!remainingActions.isEmpty()) { + perm.getPermission().setActions( + remainingActions.toArray(new Permission.Action[remainingActions.size()])); + addUserPermission(conf, perm, t); + } else { + removePermissionRecord(conf, userPerm, t); + } + break; + } + } + } + if (LOG.isDebugEnabled()) { + LOG.debug("Removed permission "+ userPerm.toString()); + } + } + + private static void removePermissionRecord(Configuration conf, UserPermission userPerm, Table t) + throws IOException { + Delete d = new Delete(userPermissionRowKey(userPerm.getPermission())); + d.addColumns(ACL_LIST_FAMILY, userPermissionKey(userPerm)); + try { + t.delete(d); + } finally { + t.close(); + } + } + + /** + * Remove specified table from the _acl_ table. + */ + static void removeTablePermissions(Configuration conf, TableName tableName, Table t) + throws IOException{ + Delete d = new Delete(tableName.getName()); + + if (LOG.isDebugEnabled()) { + LOG.debug("Removing permissions of removed table "+ tableName); + } + try { + t.delete(d); + } finally { + t.close(); + } + } + + /** + * Remove specified namespace from the acl table. + */ + static void removeNamespacePermissions(Configuration conf, String namespace, Table t) + throws IOException{ + Delete d = new Delete(Bytes.toBytes(toNamespaceEntry(namespace))); + + if (LOG.isDebugEnabled()) { + LOG.debug("Removing permissions of removed namespace "+ namespace); + } + + try { + t.delete(d); + } finally { + t.close(); + } + } + + static private void removeTablePermissions(TableName tableName, byte[] column, Table table, + boolean closeTable) throws IOException { + Scan scan = new Scan(); + scan.addFamily(ACL_LIST_FAMILY); + + String columnName = Bytes.toString(column); + scan.setFilter(new QualifierFilter(CompareOperator.EQUAL, new RegexStringComparator( + String.format("(%s%s%s)|(%s%s)$", + ACL_KEY_DELIMITER, columnName, ACL_KEY_DELIMITER, + ACL_KEY_DELIMITER, columnName)))); + + Set qualifierSet = new TreeSet<>(Bytes.BYTES_COMPARATOR); + ResultScanner scanner = null; + try { + scanner = table.getScanner(scan); + for (Result res : scanner) { + for (byte[] q : res.getFamilyMap(ACL_LIST_FAMILY).navigableKeySet()) { + qualifierSet.add(q); + } + } + + if (qualifierSet.size() > 0) { + Delete d = new Delete(tableName.getName()); + for (byte[] qualifier : qualifierSet) { + d.addColumns(ACL_LIST_FAMILY, qualifier); + } + table.delete(d); + } + } finally { + if (scanner != null) scanner.close(); + if (closeTable) table.close(); + } + } + + /** + * Remove specified table column from the acl table. + */ + static void removeTablePermissions(Configuration conf, TableName tableName, byte[] column, + Table t) throws IOException { + if (LOG.isDebugEnabled()) { + LOG.debug("Removing permissions of removed column " + Bytes.toString(column) + + " from table "+ tableName); + } + removeTablePermissions(tableName, column, t, true); + } + + static byte[] userPermissionRowKey(Permission permission) { + byte[] row; + if (permission instanceof TablePermission) { + TablePermission tablePerm = (TablePermission) permission; + row = tablePerm.getTableName().getName(); + } else if (permission instanceof NamespacePermission) { + NamespacePermission nsPerm = (NamespacePermission) permission; + row = Bytes.toBytes(toNamespaceEntry(nsPerm.getNamespace())); + } else { + // permission instanceof TablePermission + row = ACL_GLOBAL_NAME; + } + return row; + } + + /** + * Build qualifier key from user permission: + * username + * username,family + * username,family,qualifier + */ + static byte[] userPermissionKey(UserPermission permission) { + byte[] key = Bytes.toBytes(permission.getUser()); + byte[] qualifier = null; + byte[] family = null; + if (permission.getPermission().getAccessScope() == Permission.Scope.TABLE) { + TablePermission tablePermission = (TablePermission) permission.getPermission(); + family = tablePermission.getFamily(); + qualifier = tablePermission.getQualifier(); + } + + if (family != null && family.length > 0) { + key = Bytes.add(key, Bytes.add(new byte[]{ACL_KEY_DELIMITER}, family)); + if (qualifier != null && qualifier.length > 0) { + key = Bytes.add(key, Bytes.add(new byte[]{ACL_KEY_DELIMITER}, qualifier)); + } + } + + return key; + } + + /** + * Returns {@code true} if the given region is part of the {@code _acl_} + * metadata table. + */ + static boolean isAclRegion(Region region) { + return ACL_TABLE_NAME.equals(region.getTableDescriptor().getTableName()); + } + + /** + * Returns {@code true} if the given table is {@code _acl_} metadata table. + */ + static boolean isAclTable(TableDescriptor desc) { + return ACL_TABLE_NAME.equals(desc.getTableName()); + } + + /** + * Loads all of the permission grants stored in a region of the {@code _acl_} + * table. + * + * @param aclRegion + * @return a map of the permissions for this table. + * @throws IOException + */ + static Map> loadAll(Region aclRegion) + throws IOException { + + if (!isAclRegion(aclRegion)) { + throw new IOException("Can only load permissions from "+ACL_TABLE_NAME); + } + + Map> allPerms = + new TreeMap<>(Bytes.BYTES_RAWCOMPARATOR); + + // do a full scan of _acl_ table + + Scan scan = new Scan(); + scan.addFamily(ACL_LIST_FAMILY); + + InternalScanner iScanner = null; + try { + iScanner = aclRegion.getScanner(scan); + + while (true) { + List row = new ArrayList<>(); + + boolean hasNext = iScanner.next(row); + ListMultimap perms = ArrayListMultimap.create(); + byte[] entry = null; + for (Cell kv : row) { + if (entry == null) { + entry = CellUtil.cloneRow(kv); + } + Pair permissionsOfUserOnTable = + parsePermissionRecord(entry, kv, null, null, false, null); + if (permissionsOfUserOnTable != null) { + String username = permissionsOfUserOnTable.getFirst(); + Permission permission = permissionsOfUserOnTable.getSecond(); + perms.put(username, new UserPermission(username, permission)); + } + } + if (entry != null) { + allPerms.put(entry, perms); + } + if (!hasNext) { + break; + } + } + } finally { + if (iScanner != null) { + iScanner.close(); + } + } + + return allPerms; + } + + /** + * Load all permissions from the region server holding {@code _acl_}, + * primarily intended for testing purposes. + */ + static Map> loadAll( + Configuration conf) throws IOException { + Map> allPerms = + new TreeMap<>(Bytes.BYTES_RAWCOMPARATOR); + + // do a full scan of _acl_, filtering on only first table region rows + + Scan scan = new Scan(); + scan.addFamily(ACL_LIST_FAMILY); + + ResultScanner scanner = null; + // TODO: Pass in a Connection rather than create one each time. + try (Connection connection = ConnectionFactory.createConnection(conf)) { + try (Table table = connection.getTable(ACL_TABLE_NAME)) { + scanner = table.getScanner(scan); + try { + for (Result row : scanner) { + ListMultimap resultPerms = + parsePermissions(row.getRow(), row, null, null, null, false); + allPerms.put(row.getRow(), resultPerms); + } + } finally { + if (scanner != null) scanner.close(); + } + } + } + + return allPerms; + } + + public static ListMultimap getTablePermissions(Configuration conf, + TableName tableName) throws IOException { + return getPermissions(conf, tableName != null ? tableName.getName() : null, null, null, null, + null, false); + } + + @VisibleForTesting + public static ListMultimap getNamespacePermissions(Configuration conf, + String namespace) throws IOException { + return getPermissions(conf, Bytes.toBytes(toNamespaceEntry(namespace)), null, null, null, null, + false); + } + + /** + * Reads user permission assignments stored in the l: column family of the first + * table row in _acl_. + *

+ * See {@link PermissionStorage class documentation} for the key structure used for storage. + *

+ */ + static ListMultimap getPermissions(Configuration conf, byte[] entryName, + Table t, byte[] cf, byte[] cq, String user, boolean hasFilterUser) throws IOException { + if (entryName == null) entryName = ACL_GLOBAL_NAME; + // for normal user tables, we just read the table row from _acl_ + ListMultimap perms = ArrayListMultimap.create(); + Get get = new Get(entryName); + get.addFamily(ACL_LIST_FAMILY); + Result row = null; + if (t == null) { + try (Connection connection = ConnectionFactory.createConnection(conf)) { + try (Table table = connection.getTable(ACL_TABLE_NAME)) { + row = table.get(get); + } + } + } else { + row = t.get(get); + } + if (!row.isEmpty()) { + perms = parsePermissions(entryName, row, cf, cq, user, hasFilterUser); + } else { + LOG.info("No permissions found in " + ACL_TABLE_NAME + " for acl entry " + + Bytes.toString(entryName)); + } + + return perms; + } + + /** + * Returns the currently granted permissions for a given table as the specified user plus + * associated permissions. + */ + public static List getUserTablePermissions(Configuration conf, + TableName tableName, byte[] cf, byte[] cq, String userName, boolean hasFilterUser) + throws IOException { + return getUserPermissions(conf, tableName == null ? null : tableName.getName(), cf, cq, + userName, hasFilterUser); + } + + /** + * Returns the currently granted permissions for a given namespace as the specified user plus + * associated permissions. + */ + public static List getUserNamespacePermissions(Configuration conf, + String namespace, String user, boolean hasFilterUser) throws IOException { + return getUserPermissions(conf, Bytes.toBytes(toNamespaceEntry(namespace)), null, null, user, + hasFilterUser); + } + + /** + * Returns the currently granted permissions for a given table/namespace with associated + * permissions based on the specified column family, column qualifier and user name. + * @param conf the configuration + * @param entryName Table name or the namespace + * @param cf Column family + * @param cq Column qualifier + * @param user User name to be filtered from permission as requested + * @param hasFilterUser true if filter user is provided, otherwise false. + * @return List of UserPermissions + * @throws IOException on failure + */ + public static List getUserPermissions(Configuration conf, byte[] entryName, + byte[] cf, byte[] cq, String user, boolean hasFilterUser) throws IOException { + ListMultimap allPerms = + getPermissions(conf, entryName, null, cf, cq, user, hasFilterUser); + List perms = new ArrayList<>(); + for (Map.Entry entry : allPerms.entries()) { + perms.add(entry.getValue()); + } + return perms; + } + + /** + * Parse and filter permission based on the specified column family, column qualifier and user + * name. + */ + private static ListMultimap parsePermissions(byte[] entryName, + Result result, byte[] cf, byte[] cq, String user, boolean hasFilterUser) { + ListMultimap perms = ArrayListMultimap.create(); + if (result != null && result.size() > 0) { + for (Cell kv : result.rawCells()) { + Pair permissionsOfUserOnTable = + parsePermissionRecord(entryName, kv, cf, cq, hasFilterUser, user); + + if (permissionsOfUserOnTable != null) { + String username = permissionsOfUserOnTable.getFirst(); + Permission permission = permissionsOfUserOnTable.getSecond(); + perms.put(username, new UserPermission(username, permission)); + } + } + } + return perms; + } + + private static Pair parsePermissionRecord(byte[] entryName, Cell kv, + byte[] cf, byte[] cq, boolean filterPerms, String filterUser) { + // return X given a set of permissions encoded in the permissionRecord kv. + byte[] family = CellUtil.cloneFamily(kv); + if (!Bytes.equals(family, ACL_LIST_FAMILY)) { + return null; + } + + byte[] key = CellUtil.cloneQualifier(kv); + byte[] value = CellUtil.cloneValue(kv); + if (LOG.isDebugEnabled()) { + LOG.debug("Read acl: entry[" + + Bytes.toStringBinary(entryName) + "], kv [" + + Bytes.toStringBinary(key) + ": " + + Bytes.toStringBinary(value)+"]"); + } + + // check for a column family appended to the key + // TODO: avoid the string conversion to make this more efficient + String username = Bytes.toString(key); + + // Retrieve group list for the filterUser if cell key is a group. + // Group list is not required when filterUser itself a group + List filterUserGroups = null; + if (filterPerms) { + if (username.charAt(0) == '@' && !StringUtils.isEmpty(filterUser) + && filterUser.charAt(0) != '@') { + filterUserGroups = AccessChecker.getUserGroups(filterUser); + } + } + + // Handle namespace entry + if (isNamespaceEntry(entryName)) { + // Filter the permissions cell record if client query + if (filterPerms && !validateFilterUser(username, filterUser, filterUserGroups)) { + return null; + } + + return new Pair<>(username, + Permission.newBuilder(Bytes.toString(fromNamespaceEntry(entryName))) + .withActionCodes(value).build()); + } + + // Handle global entry + if (isGlobalEntry(entryName)) { + // Filter the permissions cell record if client query + if (filterPerms && !validateFilterUser(username, filterUser, filterUserGroups)) { + return null; + } + + return new Pair<>(username, Permission.newBuilder().withActionCodes(value).build()); + } + + // Handle table entry + int idx = username.indexOf(ACL_KEY_DELIMITER); + byte[] permFamily = null; + byte[] permQualifier = null; + if (idx > 0 && idx < username.length()-1) { + String remainder = username.substring(idx+1); + username = username.substring(0, idx); + idx = remainder.indexOf(ACL_KEY_DELIMITER); + if (idx > 0 && idx < remainder.length()-1) { + permFamily = Bytes.toBytes(remainder.substring(0, idx)); + permQualifier = Bytes.toBytes(remainder.substring(idx+1)); + } else { + permFamily = Bytes.toBytes(remainder); + } + } + + // Filter the permissions cell record if client query + if (filterPerms) { + // ACL table contain 3 types of cell key entries; hbase:Acl, namespace and table. So to filter + // the permission cell records additional validations are required at CF, CQ and username. + // Here we can proceed based on client input whether it contain filterUser. + // Validate the filterUser when specified + if (filterUser != null && !validateFilterUser(username, filterUser, filterUserGroups)) { + return null; + } + if (!validateCFAndCQ(permFamily, cf, permQualifier, cq)) { + return null; + } + } + + return new Pair<>(username, Permission.newBuilder(TableName.valueOf(entryName)) + .withFamily(permFamily).withQualifier(permQualifier).withActionCodes(value).build()); + } + + /* + * Validate the cell key with the client filterUser if specified in the query input. 1. If cell + * key (username) is not a group then check whether client filterUser is equal to username 2. If + * cell key (username) is a group then check whether client filterUser belongs to the cell key + * group (username) 3. In case when both filterUser and username are group names then cell will be + * filtered if not equal. + */ + private static boolean validateFilterUser(String username, String filterUser, + List filterUserGroups) { + if (filterUserGroups == null) { + // Validate user name or group names whether equal + if (filterUser.equals(username)) { + return true; + } + } else { + // Check whether filter user belongs to the cell key group. + return filterUserGroups.contains(username.substring(1)); + } + return false; + } + + /* + * Validate the cell with client CF and CQ if specified in the query input. 1. If CF is NULL, then + * no need of further validation, result should include all CF and CQ. 2. IF CF specified and + * equal then validation required at CQ level if CF specified in client input, otherwise return + * all CQ records. + */ + private static boolean validateCFAndCQ(byte[] permFamily, byte[] cf, byte[] permQualifier, + byte[] cq) { + boolean include = true; + if (cf != null) { + if (Bytes.equals(cf, permFamily)) { + if (cq != null && !Bytes.equals(cq, permQualifier)) { + // if CQ specified and didn't match then ignore this cell + include = false; + } + } else { + // if CF specified and didn't match then ignore this cell + include = false; + } + } + return include; + } + + /** + * Writes a set of permissions as {@link org.apache.hadoop.io.Writable} instances and returns the + * resulting byte array. Writes a set of permission [user: table permission] + */ + public static byte[] writePermissionsAsBytes(ListMultimap perms, + Configuration conf) { + return ProtobufUtil.prependPBMagic(AccessControlUtil.toUserTablePermissions(perms).toByteArray()); + } + + // This is part of the old HbaseObjectWritableFor96Migration. + private static final int LIST_CODE = 61; + + private static final int WRITABLE_CODE = 14; + + private static final int WRITABLE_NOT_ENCODED = 0; + + private static List readWritableUserPermission(DataInput in, + Configuration conf) throws IOException, ClassNotFoundException { + assert WritableUtils.readVInt(in) == LIST_CODE; + int length = in.readInt(); + List list = new ArrayList<>(length); + for (int i = 0; i < length; i++) { + assert WritableUtils.readVInt(in) == WRITABLE_CODE; + assert WritableUtils.readVInt(in) == WRITABLE_NOT_ENCODED; + String className = Text.readString(in); + Class clazz = conf.getClassByName(className).asSubclass(Writable.class); + Writable instance = WritableFactories.newInstance(clazz, conf); + instance.readFields(in); + list.add((Permission) instance); + } + return list; + } + + @VisibleForTesting + public static ListMultimap readUserPermission(byte[] data, + Configuration conf) throws DeserializationException { + if (ProtobufUtil.isPBMagicPrefix(data)) { + int pblen = ProtobufUtil.lengthOfPBMagic(); + try { + AccessControlProtos.UsersAndPermissions.Builder builder = + AccessControlProtos.UsersAndPermissions.newBuilder(); + ProtobufUtil.mergeFrom(builder, data, pblen, data.length - pblen); + return AccessControlUtil.toUserPermission(builder.build()); + } catch (IOException e) { + throw new DeserializationException(e); + } + } else { + // TODO: We have to re-write non-PB data as PB encoded. Otherwise we will carry old Writables + // forever (here and a couple of other places). + ListMultimap userPermission = ArrayListMultimap.create(); + try { + DataInput in = new DataInputStream(new ByteArrayInputStream(data)); + int length = in.readInt(); + for (int i = 0; i < length; i++) { + String user = Text.readString(in); + List perms = readWritableUserPermission(in, conf); + for (Permission p : perms) { + userPermission.put(user, new UserPermission(user, p)); + } + } + } catch (IOException | ClassNotFoundException e) { + throw new DeserializationException(e); + } + return userPermission; + } + } + + public static ListMultimap readPermissions(byte[] data, + Configuration conf) throws DeserializationException { + if (ProtobufUtil.isPBMagicPrefix(data)) { + int pblen = ProtobufUtil.lengthOfPBMagic(); + try { + AccessControlProtos.UsersAndPermissions.Builder builder = + AccessControlProtos.UsersAndPermissions.newBuilder(); + ProtobufUtil.mergeFrom(builder, data, pblen, data.length - pblen); + return AccessControlUtil.toPermission(builder.build()); + } catch (IOException e) { + throw new DeserializationException(e); + } + } else { + // TODO: We have to re-write non-PB data as PB encoded. Otherwise we will carry old Writables + // forever (here and a couple of other places). + ListMultimap perms = ArrayListMultimap.create(); + try { + DataInput in = new DataInputStream(new ByteArrayInputStream(data)); + int length = in.readInt(); + for (int i = 0; i < length; i++) { + String user = Text.readString(in); + perms.putAll(user, readWritableUserPermission(in, conf)); + } + } catch (IOException | ClassNotFoundException e) { + throw new DeserializationException(e); + } + return perms; + } + } + + public static boolean isGlobalEntry(byte[] entryName) { + return entryName != null && TableName.valueOf(entryName).equals(ACL_TABLE_NAME); + } + + public static boolean isNamespaceEntry(String entryName) { + return entryName != null && entryName.charAt(0) == NAMESPACE_PREFIX; + } + + public static boolean isNamespaceEntry(byte[] entryName) { + return entryName != null && entryName.length !=0 && entryName[0] == NAMESPACE_PREFIX; + } + + public static String toNamespaceEntry(String namespace) { + return NAMESPACE_PREFIX + namespace; + } + + public static String fromNamespaceEntry(String namespace) { + if(namespace.charAt(0) != NAMESPACE_PREFIX) + throw new IllegalArgumentException("Argument is not a valid namespace entry"); + return namespace.substring(1); + } + + public static byte[] toNamespaceEntry(byte[] namespace) { + byte[] ret = new byte[namespace.length+1]; + ret[0] = NAMESPACE_PREFIX; + System.arraycopy(namespace, 0, ret, 1, namespace.length); + return ret; + } + + public static byte[] fromNamespaceEntry(byte[] namespace) { + if(namespace[0] != NAMESPACE_PREFIX) { + throw new IllegalArgumentException("Argument is not a valid namespace entry: " + + Bytes.toString(namespace)); + } + return Arrays.copyOfRange(namespace, 1, namespace.length); + } + + public static List getCellPermissionsForUser(User user, Cell cell) + throws IOException { + // Save an object allocation where we can + if (cell.getTagsLength() == 0) { + return null; + } + List results = Lists.newArrayList(); + Iterator tagsIterator = PrivateCellUtil.tagsIterator(cell); + while (tagsIterator.hasNext()) { + Tag tag = tagsIterator.next(); + if (tag.getType() == ACL_TAG_TYPE) { + // Deserialize the table permissions from the KV + // TODO: This can be improved. Don't build UsersAndPermissions just to unpack it again, + // use the builder + AccessControlProtos.UsersAndPermissions.Builder builder = + AccessControlProtos.UsersAndPermissions.newBuilder(); + if (tag.hasArray()) { + ProtobufUtil.mergeFrom(builder, tag.getValueArray(), tag.getValueOffset(), tag.getValueLength()); + } else { + ProtobufUtil.mergeFrom(builder, Tag.cloneValue(tag)); + } + ListMultimap kvPerms = + AccessControlUtil.toUsersAndPermissions(builder.build()); + // Are there permissions for this user? + List userPerms = kvPerms.get(user.getShortName()); + if (userPerms != null) { + results.addAll(userPerms); + } + // Are there permissions for any of the groups this user belongs to? + String groupNames[] = user.getGroupNames(); + if (groupNames != null) { + for (String group : groupNames) { + List groupPerms = kvPerms.get(AuthUtil.toGroupEntry(group)); + if (results != null) { + results.addAll(groupPerms); + } + } + } + } + } + return results; + } +} diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/ZKPermissionWatcher.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/ZKPermissionWatcher.java index fa3c30f..b410719 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/ZKPermissionWatcher.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/ZKPermissionWatcher.java @@ -146,7 +146,7 @@ public class ZKPermissionWatcher extends ZKListener implements Closeable { @Override public void run() { String table = ZKUtil.getNodeName(path); - if(AccessControlLists.isNamespaceEntry(table)) { + if (PermissionStorage.isNamespaceEntry(table)) { authManager.removeNamespace(Bytes.toBytes(table)); } else { authManager.removeTable(TableName.valueOf(table)); @@ -245,9 +245,9 @@ public class ZKPermissionWatcher extends ZKListener implements Closeable { LOG.debug("Updating permissions cache from {} with data {}", entry, Bytes.toStringBinary(nodeData)); } - if(AccessControlLists.isNamespaceEntry(entry)) { - authManager.refreshNamespaceCacheFromWritable( - AccessControlLists.fromNamespaceEntry(entry), nodeData); + if (PermissionStorage.isNamespaceEntry(entry)) { + authManager.refreshNamespaceCacheFromWritable(PermissionStorage.fromNamespaceEntry(entry), + nodeData); } else { authManager.refreshTableCacheFromWritable(TableName.valueOf(entry), nodeData); } @@ -296,7 +296,7 @@ public class ZKPermissionWatcher extends ZKListener implements Closeable { */ public void deleteNamespaceACLNode(final String namespace) { String zkNode = ZNodePaths.joinZNode(watcher.getZNodePaths().baseZNode, ACL_NODE); - zkNode = ZNodePaths.joinZNode(zkNode, AccessControlLists.NAMESPACE_PREFIX + namespace); + zkNode = ZNodePaths.joinZNode(zkNode, PermissionStorage.NAMESPACE_PREFIX + namespace); try { ZKUtil.deleteNode(watcher, zkNode); diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/snapshot/SnapshotDescriptionUtils.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/snapshot/SnapshotDescriptionUtils.java index 203a58b..5c25526 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/snapshot/SnapshotDescriptionUtils.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/snapshot/SnapshotDescriptionUtils.java @@ -33,7 +33,7 @@ import org.apache.hadoop.hbase.client.Admin; import org.apache.hadoop.hbase.client.Connection; import org.apache.hadoop.hbase.client.ConnectionFactory; import org.apache.hadoop.hbase.security.User; -import org.apache.hadoop.hbase.security.access.AccessControlLists; +import org.apache.hadoop.hbase.security.access.PermissionStorage; import org.apache.hadoop.hbase.security.access.ShadedAccessControlUtil; import org.apache.hadoop.hbase.security.access.UserPermission; import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; @@ -418,7 +418,7 @@ public final class SnapshotDescriptionUtils { public static boolean isSecurityAvailable(Configuration conf) throws IOException { try (Connection conn = ConnectionFactory.createConnection(conf)) { try (Admin admin = conn.getAdmin()) { - return admin.tableExists(AccessControlLists.ACL_TABLE_NAME); + return admin.tableExists(PermissionStorage.ACL_TABLE_NAME); } } } @@ -429,7 +429,7 @@ public final class SnapshotDescriptionUtils { User.runAsLoginUser(new PrivilegedExceptionAction>() { @Override public ListMultimap run() throws Exception { - return AccessControlLists.getTablePermissions(conf, + return PermissionStorage.getTablePermissions(conf, TableName.valueOf(snapshot.getTable())); } }); diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/TestJMXConnectorServer.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/TestJMXConnectorServer.java index 4c48347..2b94b7f 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/TestJMXConnectorServer.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/TestJMXConnectorServer.java @@ -28,11 +28,9 @@ import org.apache.hadoop.hbase.coprocessor.MasterCoprocessorEnvironment; import org.apache.hadoop.hbase.coprocessor.ObserverContext; import org.apache.hadoop.hbase.coprocessor.RegionServerCoprocessorEnvironment; import org.apache.hadoop.hbase.security.AccessDeniedException; -import org.apache.hadoop.hbase.security.access.AccessControlLists; import org.apache.hadoop.hbase.security.access.AccessController; import org.apache.hadoop.hbase.testclassification.MediumTests; import org.apache.hadoop.hbase.testclassification.MiscTests; -import org.apache.hadoop.hbase.util.Threads; import org.junit.After; import org.junit.Assert; import org.junit.Before; diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/SnapshotWithAclTestBase.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/SnapshotWithAclTestBase.java index 9359fcc..98c84d5 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/SnapshotWithAclTestBase.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/SnapshotWithAclTestBase.java @@ -26,9 +26,9 @@ import org.apache.hadoop.hbase.coprocessor.CoprocessorHost; import org.apache.hadoop.hbase.master.MasterCoprocessorHost; import org.apache.hadoop.hbase.security.User; import org.apache.hadoop.hbase.security.access.AccessControlConstants; -import org.apache.hadoop.hbase.security.access.AccessControlLists; import org.apache.hadoop.hbase.security.access.AccessController; import org.apache.hadoop.hbase.security.access.Permission; +import org.apache.hadoop.hbase.security.access.PermissionStorage; import org.apache.hadoop.hbase.security.access.SecureTestUtil; import org.apache.hadoop.hbase.util.Bytes; import org.junit.AfterClass; @@ -108,7 +108,7 @@ public abstract class SnapshotWithAclTestBase extends SecureTestUtil { // Enable EXEC permission checking conf.setBoolean(AccessControlConstants.EXEC_PERMISSION_CHECKS_KEY, true); TEST_UTIL.startMiniCluster(); - TEST_UTIL.waitUntilAllRegionsAssigned(AccessControlLists.ACL_TABLE_NAME); + TEST_UTIL.waitUntilAllRegionsAssigned(PermissionStorage.ACL_TABLE_NAME); MasterCoprocessorHost cpHost = TEST_UTIL.getMiniHBaseCluster().getMaster().getMasterCoprocessorHost(); cpHost.load(AccessController.class, Coprocessor.PRIORITY_HIGHEST, conf); diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAsyncAccessControlAdminApi.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAsyncAccessControlAdminApi.java index fbb08c6..9182e6f 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAsyncAccessControlAdminApi.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAsyncAccessControlAdminApi.java @@ -20,9 +20,9 @@ import java.util.List; import org.apache.hadoop.hbase.HBaseClassTestRule; import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.security.User; -import org.apache.hadoop.hbase.security.access.AccessControlLists; import org.apache.hadoop.hbase.security.access.GetUserPermissionsRequest; import org.apache.hadoop.hbase.security.access.Permission; +import org.apache.hadoop.hbase.security.access.PermissionStorage; import org.apache.hadoop.hbase.security.access.SecureTestUtil; import org.apache.hadoop.hbase.security.access.SecureTestUtil.AccessTestAction; import org.apache.hadoop.hbase.security.access.UserPermission; @@ -48,7 +48,7 @@ public class TestAsyncAccessControlAdminApi extends TestAsyncAdminBase { public static void setUpBeforeClass() throws Exception { SecureTestUtil.enableSecurity(TEST_UTIL.getConfiguration()); TEST_UTIL.startMiniCluster(1); - TEST_UTIL.waitTableAvailable(AccessControlLists.ACL_TABLE_NAME); + TEST_UTIL.waitTableAvailable(PermissionStorage.ACL_TABLE_NAME); ASYNC_CONN = ConnectionFactory.createAsyncConnection(TEST_UTIL.getConfiguration()).get(); } diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/SecureTestUtil.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/SecureTestUtil.java index 341e7df..a84b492 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/SecureTestUtil.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/SecureTestUtil.java @@ -808,7 +808,7 @@ public class SecureTestUtil { } public static String convertToNamespace(String namespace) { - return AccessControlLists.NAMESPACE_PREFIX + namespace; + return PermissionStorage.NAMESPACE_PREFIX + namespace; } public static void checkGlobalPerms(HBaseTestingUtility testUtil, Permission.Action... actions) diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessControlFilter.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessControlFilter.java index 3dc915b..ed38d91 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessControlFilter.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessControlFilter.java @@ -86,7 +86,7 @@ public class TestAccessControlFilter extends SecureTestUtil { conf.setBoolean(AccessControlConstants.CF_ATTRIBUTE_EARLY_OUT, false); TEST_UTIL.startMiniCluster(); - TEST_UTIL.waitTableEnabled(AccessControlLists.ACL_TABLE_NAME.getName(), 50000); + TEST_UTIL.waitTableEnabled(PermissionStorage.ACL_TABLE_NAME.getName(), 50000); READER = User.createUserForTesting(conf, "reader", new String[0]); LIMITED = User.createUserForTesting(conf, "limited", new String[0]); diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessController.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessController.java index a5a8a04..a87a838 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessController.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessController.java @@ -245,7 +245,7 @@ public class TestAccessController extends SecureTestUtil { RSCP_ENV = rsCpHost.createEnvironment(ACCESS_CONTROLLER, Coprocessor.PRIORITY_HIGHEST, 1, conf); // Wait for the ACL table to become available - TEST_UTIL.waitUntilAllRegionsAssigned(AccessControlLists.ACL_TABLE_NAME); + TEST_UTIL.waitUntilAllRegionsAssigned(PermissionStorage.ACL_TABLE_NAME); // create a set of test users SUPERUSER = User.createUserForTesting(conf, "admin", new String[] { "supergroup" }); @@ -323,7 +323,7 @@ public class TestAccessController extends SecureTestUtil { grantGlobal(TEST_UTIL, toGroupEntry(GROUP_READ), Permission.Action.READ); grantGlobal(TEST_UTIL, toGroupEntry(GROUP_WRITE), Permission.Action.WRITE); - assertEquals(5, AccessControlLists.getTablePermissions(conf, TEST_TABLE).size()); + assertEquals(5, PermissionStorage.getTablePermissions(conf, TEST_TABLE).size()); int size = 0; try { size = AccessControlClient.getUserPermissions(systemUserConnection, TEST_TABLE.toString()) @@ -344,11 +344,9 @@ public class TestAccessController extends SecureTestUtil { LOG.info("Test deleted table " + TEST_TABLE); } // Verify all table/namespace permissions are erased - assertEquals(0, AccessControlLists.getTablePermissions(conf, TEST_TABLE).size()); - assertEquals( - 0, - AccessControlLists.getNamespacePermissions(conf, - TEST_TABLE.getNamespaceAsString()).size()); + assertEquals(0, PermissionStorage.getTablePermissions(conf, TEST_TABLE).size()); + assertEquals(0, + PermissionStorage.getNamespacePermissions(conf, TEST_TABLE.getNamespaceAsString()).size()); } @Test @@ -477,7 +475,7 @@ public class TestAccessController extends SecureTestUtil { @Override public Object run() throws Exception { ACCESS_CONTROLLER.preDisableTable(ObserverContextImpl.createAndPrepare(CP_ENV), - AccessControlLists.ACL_TABLE_NAME); + PermissionStorage.ACL_TABLE_NAME); return null; } }; @@ -1204,8 +1202,7 @@ public class TestAccessController extends SecureTestUtil { AccessTestAction getGlobalPermissionsAction = new AccessTestAction() { @Override public Object run() throws Exception { - try (Connection conn = ConnectionFactory.createConnection(conf); - Table acl = conn.getTable(AccessControlLists.ACL_TABLE_NAME)) { + try (Connection conn = ConnectionFactory.createConnection(conf)) { conn.getAdmin().getUserPermissions(GetUserPermissionsRequest.newBuilder().build()); } return null; @@ -1237,7 +1234,7 @@ public class TestAccessController extends SecureTestUtil { @Override public Object run() throws Exception { try (Connection conn = ConnectionFactory.createConnection(conf); - Table acl = conn.getTable(AccessControlLists.ACL_TABLE_NAME)) { + Table acl = conn.getTable(PermissionStorage.ACL_TABLE_NAME)) { BlockingRpcChannel service = acl.coprocessorService(TEST_TABLE.getName()); AccessControlService.BlockingInterface protocol = AccessControlService.newBlockingStub(service); @@ -1252,7 +1249,7 @@ public class TestAccessController extends SecureTestUtil { @Override public Object run() throws Exception { try (Connection conn = ConnectionFactory.createConnection(conf); - Table acl = conn.getTable(AccessControlLists.ACL_TABLE_NAME)) { + Table acl = conn.getTable(PermissionStorage.ACL_TABLE_NAME)) { BlockingRpcChannel service = acl.coprocessorService(TEST_TABLE.getName()); AccessControlService.BlockingInterface protocol = AccessControlService.newBlockingStub(service); @@ -1914,7 +1911,7 @@ public class TestAccessController extends SecureTestUtil { AccessControlProtos.TablePermission.newBuilder() .setTableName(ProtobufUtil.toProtoTableName(TEST_TABLE)) .addAction(AccessControlProtos.Permission.Action.CREATE))).build(); - Table acl = systemUserConnection.getTable(AccessControlLists.ACL_TABLE_NAME); + Table acl = systemUserConnection.getTable(PermissionStorage.ACL_TABLE_NAME); try { BlockingRpcChannel channel = acl.coprocessorService(new byte[0]); AccessControlService.BlockingInterface protocol = @@ -2770,7 +2767,7 @@ public class TestAccessController extends SecureTestUtil { int expectedAmount, String expectedNamespace) throws HBaseException { try { List namespacePermissions = AccessControlClient.getUserPermissions( - systemUserConnection, AccessControlLists.toNamespaceEntry(namespaceRegexWithoutPrefix)); + systemUserConnection, PermissionStorage.toNamespaceEntry(namespaceRegexWithoutPrefix)); assertTrue(namespacePermissions != null); assertEquals(expectedAmount, namespacePermissions.size()); for (UserPermission namespacePermission : namespacePermissions) { @@ -2862,7 +2859,7 @@ public class TestAccessController extends SecureTestUtil { createTable(TEST_UTIL, htd); // Verify that we can read sys-tables - String aclTableName = AccessControlLists.ACL_TABLE_NAME.getNameAsString(); + String aclTableName = PermissionStorage.ACL_TABLE_NAME.getNameAsString(); assertEquals(5, SUPERUSER.runAs(getPrivilegedAction(aclTableName)).size()); assertEquals(0, testRegexHandler.runAs(getPrivilegedAction(aclTableName)).size()); @@ -3336,7 +3333,7 @@ public class TestAccessController extends SecureTestUtil { @Override public Object run() throws Exception { try (Connection conn = ConnectionFactory.createConnection(conf); - Table acl = conn.getTable(AccessControlLists.ACL_TABLE_NAME)) { + Table acl = conn.getTable(PermissionStorage.ACL_TABLE_NAME)) { BlockingRpcChannel service = acl.coprocessorService(TEST_TABLE.getName()); AccessControlService.BlockingInterface protocol = AccessControlService.newBlockingStub(service); 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 index eb2a5ac..dc8136c 100644 --- 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 @@ -122,7 +122,7 @@ public class TestAccessController2 extends SecureTestUtil { verifyConfiguration(conf); TEST_UTIL.startMiniCluster(); // Wait for the ACL table to become available - TEST_UTIL.waitUntilAllRegionsAssigned(AccessControlLists.ACL_TABLE_NAME); + TEST_UTIL.waitUntilAllRegionsAssigned(PermissionStorage.ACL_TABLE_NAME); TESTGROUP_1_NAME = toGroupEntry(TESTGROUP_1); TESTGROUP1_USER1 = @@ -146,7 +146,7 @@ public class TestAccessController2 extends SecureTestUtil { new Put(TEST_ROW_3).addColumn(TEST_FAMILY_2, Q1, value1))); } - assertEquals(1, AccessControlLists.getTablePermissions(conf, tableName).size()); + assertEquals(1, PermissionStorage.getTablePermissions(conf, tableName).size()); try { assertEquals(1, AccessControlClient.getUserPermissions(systemUserConnection, tableName.toString()).size()); @@ -173,8 +173,8 @@ public class TestAccessController2 extends SecureTestUtil { } deleteNamespace(TEST_UTIL, namespace); // Verify all table/namespace permissions are erased - assertEquals(0, AccessControlLists.getTablePermissions(conf, tableName).size()); - assertEquals(0, AccessControlLists.getNamespacePermissions(conf, namespace).size()); + assertEquals(0, PermissionStorage.getTablePermissions(conf, tableName).size()); + assertEquals(0, PermissionStorage.getNamespacePermissions(conf, namespace).size()); } @Test @@ -201,9 +201,8 @@ public class TestAccessController2 extends SecureTestUtil { TEST_UTIL.waitTableAvailable(TEST_TABLE.getTableName()); // 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()); + List perms = PermissionStorage + .getTablePermissions(conf, TEST_TABLE.getTableName()).get(testUser.getShortName()); assertNotNull(perms); assertFalse(perms.isEmpty()); // Should be RWXCA @@ -293,9 +292,9 @@ public class TestAccessController2 extends SecureTestUtil { public Object run() throws Exception { try (Connection conn = ConnectionFactory.createConnection(conf); - Table t = conn.getTable(AccessControlLists.ACL_TABLE_NAME)) { - t.put(new Put(TEST_ROW).addColumn(AccessControlLists.ACL_LIST_FAMILY, - TEST_QUALIFIER, TEST_VALUE)); + Table t = conn.getTable(PermissionStorage.ACL_TABLE_NAME)) { + t.put(new Put(TEST_ROW).addColumn(PermissionStorage.ACL_LIST_FAMILY, TEST_QUALIFIER, + TEST_VALUE)); return null; } finally { } @@ -320,7 +319,7 @@ public class TestAccessController2 extends SecureTestUtil { @Override public Object run() throws Exception { try (Connection conn = ConnectionFactory.createConnection(conf); - Table t = conn.getTable(AccessControlLists.ACL_TABLE_NAME)) { + Table t = conn.getTable(PermissionStorage.ACL_TABLE_NAME)) { ResultScanner s = t.getScanner(new Scan()); try { for (Result r = s.next(); r != null; r = s.next()) { diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessController3.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessController3.java index 7b10e3f..864928c 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessController3.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessController3.java @@ -168,7 +168,7 @@ public class TestAccessController3 extends SecureTestUtil { RSCP_ENV = rsHost.createEnvironment(ACCESS_CONTROLLER, Coprocessor.PRIORITY_HIGHEST, 1, conf); // Wait for the ACL table to become available - TEST_UTIL.waitUntilAllRegionsAssigned(AccessControlLists.ACL_TABLE_NAME); + TEST_UTIL.waitUntilAllRegionsAssigned(PermissionStorage.ACL_TABLE_NAME); // create a set of test users SUPERUSER = User.createUserForTesting(conf, "admin", new String[] { "supergroup" }); @@ -250,7 +250,7 @@ public class TestAccessController3 extends SecureTestUtil { grantGlobal(TEST_UTIL, toGroupEntry(GROUP_READ), Permission.Action.READ); grantGlobal(TEST_UTIL, toGroupEntry(GROUP_WRITE), Permission.Action.WRITE); - assertEquals(5, AccessControlLists.getTablePermissions(conf, TEST_TABLE).size()); + assertEquals(5, PermissionStorage.getTablePermissions(conf, TEST_TABLE).size()); try { assertEquals(5, AccessControlClient.getUserPermissions(systemUserConnection, TEST_TABLE.toString()).size()); @@ -271,11 +271,9 @@ public class TestAccessController3 extends SecureTestUtil { LOG.info("Test deleted table " + TEST_TABLE); } // Verify all table/namespace permissions are erased - assertEquals(0, AccessControlLists.getTablePermissions(conf, TEST_TABLE).size()); - assertEquals( - 0, - AccessControlLists.getNamespacePermissions(conf, - TEST_TABLE.getNamespaceAsString()).size()); + assertEquals(0, PermissionStorage.getTablePermissions(conf, TEST_TABLE).size()); + assertEquals(0, + PermissionStorage.getNamespacePermissions(conf, TEST_TABLE.getNamespaceAsString()).size()); } @Test diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestCellACLWithMultipleVersions.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestCellACLWithMultipleVersions.java index 88d0314..b4dd8c6 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestCellACLWithMultipleVersions.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestCellACLWithMultipleVersions.java @@ -115,7 +115,7 @@ public class TestCellACLWithMultipleVersions extends SecureTestUtil { rsHost.createEnvironment(ac, Coprocessor.PRIORITY_HIGHEST, 1, conf); // Wait for the ACL table to become available - TEST_UTIL.waitTableEnabled(AccessControlLists.ACL_TABLE_NAME); + TEST_UTIL.waitTableEnabled(PermissionStorage.ACL_TABLE_NAME); // create a set of test users USER_OWNER = User.createUserForTesting(conf, "owner", new String[0]); @@ -976,6 +976,6 @@ public class TestCellACLWithMultipleVersions extends SecureTestUtil { // Test deleted the table, no problem LOG.info("Test deleted table " + TEST_TABLE.getTableName()); } - assertEquals(0, AccessControlLists.getTablePermissions(conf, TEST_TABLE.getTableName()).size()); + assertEquals(0, PermissionStorage.getTablePermissions(conf, TEST_TABLE.getTableName()).size()); } } diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestCellACLs.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestCellACLs.java index ec741fb..24dbaee 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestCellACLs.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestCellACLs.java @@ -118,7 +118,7 @@ public class TestCellACLs extends SecureTestUtil { rsHost.createEnvironment(ac, Coprocessor.PRIORITY_HIGHEST, 1, conf); // Wait for the ACL table to become available - TEST_UTIL.waitTableEnabled(AccessControlLists.ACL_TABLE_NAME); + TEST_UTIL.waitTableEnabled(PermissionStorage.ACL_TABLE_NAME); // create a set of test users USER_OWNER = User.createUserForTesting(conf, "owner", new String[0]); @@ -460,6 +460,6 @@ public class TestCellACLs extends SecureTestUtil { // Test deleted the table, no problem LOG.info("Test deleted table " + TEST_TABLE.getTableName()); } - assertEquals(0, AccessControlLists.getTablePermissions(conf, TEST_TABLE.getTableName()).size()); + assertEquals(0, PermissionStorage.getTablePermissions(conf, TEST_TABLE.getTableName()).size()); } } diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestNamespaceCommands.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestNamespaceCommands.java index f6b018e..752b4be 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestNamespaceCommands.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestNamespaceCommands.java @@ -156,7 +156,7 @@ public class TestNamespaceCommands extends SecureTestUtil { UTIL.getConfiguration().setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 2); UTIL.startMiniCluster(); // Wait for the ACL table to become available - UTIL.waitTableAvailable(AccessControlLists.ACL_TABLE_NAME.getName(), 30 * 1000); + UTIL.waitTableAvailable(PermissionStorage.ACL_TABLE_NAME.getName(), 30 * 1000); // Find the Access Controller CP. Could be on master or if master is not serving regions, is // on an arbitrary server. @@ -204,10 +204,10 @@ public class TestNamespaceCommands extends SecureTestUtil { @Test public void testAclTableEntries() throws Exception { String userTestNamespace = "userTestNsp"; - Table acl = UTIL.getConnection().getTable(AccessControlLists.ACL_TABLE_NAME); + Table acl = UTIL.getConnection().getTable(PermissionStorage.ACL_TABLE_NAME); try { ListMultimap perms = - AccessControlLists.getNamespacePermissions(conf, TEST_NAMESPACE); + PermissionStorage.getNamespacePermissions(conf, TEST_NAMESPACE); for (Map.Entry entry : perms.entries()) { LOG.debug(Objects.toString(entry)); } @@ -219,7 +219,7 @@ public class TestNamespaceCommands extends SecureTestUtil { Result result = acl.get(new Get(Bytes.toBytes(userTestNamespace))); assertTrue(result != null); - perms = AccessControlLists.getNamespacePermissions(conf, TEST_NAMESPACE); + perms = PermissionStorage.getNamespacePermissions(conf, TEST_NAMESPACE); assertEquals(7, perms.size()); List namespacePerms = perms.get(userTestNamespace); assertTrue(perms.containsKey(userTestNamespace)); @@ -233,7 +233,7 @@ public class TestNamespaceCommands extends SecureTestUtil { revokeFromNamespace(UTIL, userTestNamespace, TEST_NAMESPACE, Permission.Action.WRITE); - perms = AccessControlLists.getNamespacePermissions(conf, TEST_NAMESPACE); + perms = PermissionStorage.getNamespacePermissions(conf, TEST_NAMESPACE); assertEquals(6, perms.size()); } finally { acl.close(); @@ -438,7 +438,7 @@ public class TestNamespaceCommands extends SecureTestUtil { @Override public Object run() throws Exception { try (Connection connection = ConnectionFactory.createConnection(conf); - Table acl = connection.getTable(AccessControlLists.ACL_TABLE_NAME)) { + Table acl = connection.getTable(PermissionStorage.ACL_TABLE_NAME)) { BlockingRpcChannel service = acl.coprocessorService(HConstants.EMPTY_START_ROW); AccessControlService.BlockingInterface protocol = AccessControlService.newBlockingStub(service); @@ -451,7 +451,7 @@ public class TestNamespaceCommands extends SecureTestUtil { @Override public Object run() throws Exception { try (Connection connection = ConnectionFactory.createConnection(conf); - Table acl = connection.getTable(AccessControlLists.ACL_TABLE_NAME)) { + Table acl = connection.getTable(PermissionStorage.ACL_TABLE_NAME)) { BlockingRpcChannel service = acl.coprocessorService(HConstants.EMPTY_START_ROW); AccessControlService.BlockingInterface protocol = AccessControlService.newBlockingStub(service); diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestRpcAccessChecks.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestRpcAccessChecks.java index b95c776..1b3712c 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestRpcAccessChecks.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestRpcAccessChecks.java @@ -153,7 +153,7 @@ public class TestRpcAccessChecks { TEST_UTIL.startMiniCluster(); // Wait for the ACL table to become available - TEST_UTIL.waitUntilAllRegionsAssigned(AccessControlLists.ACL_TABLE_NAME); + TEST_UTIL.waitUntilAllRegionsAssigned(PermissionStorage.ACL_TABLE_NAME); // Assign permissions to groups SecureTestUtil.grantGlobal(TEST_UTIL, toGroupEntry(GROUP_ADMIN), diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestScanEarlyTermination.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestScanEarlyTermination.java index 9284cc9..0e6c66a 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestScanEarlyTermination.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestScanEarlyTermination.java @@ -101,7 +101,7 @@ public class TestScanEarlyTermination extends SecureTestUtil { rsHost.createEnvironment(ac, Coprocessor.PRIORITY_HIGHEST, 1, conf); // Wait for the ACL table to become available - TEST_UTIL.waitTableEnabled(AccessControlLists.ACL_TABLE_NAME); + TEST_UTIL.waitTableEnabled(PermissionStorage.ACL_TABLE_NAME); // create a set of test users USER_OWNER = User.createUserForTesting(conf, "owner", new String[0]); @@ -142,7 +142,7 @@ public class TestScanEarlyTermination extends SecureTestUtil { // Test deleted the table, no problem LOG.info("Test deleted table " + TEST_TABLE.getTableName()); } - assertEquals(0, AccessControlLists.getTablePermissions(conf, TEST_TABLE.getTableName()).size()); + assertEquals(0, PermissionStorage.getTablePermissions(conf, TEST_TABLE.getTableName()).size()); } @Test diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestTablePermissions.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestTablePermissions.java index 8363665..962db9f 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestTablePermissions.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestTablePermissions.java @@ -101,7 +101,7 @@ public class TestTablePermissions { UTIL.startMiniCluster(); // Wait for the ACL table to become available - UTIL.waitTableEnabled(AccessControlLists.ACL_TABLE_NAME); + UTIL.waitTableEnabled(PermissionStorage.ACL_TABLE_NAME); ZKW = new ZKWatcher(UTIL.getConfiguration(), "TestTablePermissions", ABORTABLE); @@ -119,19 +119,19 @@ public class TestTablePermissions { public void tearDown() throws Exception { Configuration conf = UTIL.getConfiguration(); try (Connection connection = ConnectionFactory.createConnection(conf); - Table table = connection.getTable(AccessControlLists.ACL_TABLE_NAME)) { - AccessControlLists.removeTablePermissions(conf, TEST_TABLE, table); - AccessControlLists.removeTablePermissions(conf, TEST_TABLE2, table); - AccessControlLists.removeTablePermissions(conf, AccessControlLists.ACL_TABLE_NAME, table); + Table table = connection.getTable(PermissionStorage.ACL_TABLE_NAME)) { + PermissionStorage.removeTablePermissions(conf, TEST_TABLE, table); + PermissionStorage.removeTablePermissions(conf, TEST_TABLE2, table); + PermissionStorage.removeTablePermissions(conf, PermissionStorage.ACL_TABLE_NAME, table); } } /** - * The AccessControlLists.addUserPermission may throw exception before closing the table. + * The PermissionStorage.addUserPermission may throw exception before closing the table. */ private void addUserPermission(Configuration conf, UserPermission userPerm, Table t) throws IOException { try { - AccessControlLists.addUserPermission(conf, userPerm, t); + PermissionStorage.addUserPermission(conf, userPerm, t); } finally { t.close(); } @@ -146,20 +146,20 @@ public class TestTablePermissions { new UserPermission("george", Permission.newBuilder(TEST_TABLE) .withActions(Permission.Action.READ, Permission.Action.WRITE).build()), - connection.getTable(AccessControlLists.ACL_TABLE_NAME)); + connection.getTable(PermissionStorage.ACL_TABLE_NAME)); addUserPermission(conf, new UserPermission("hubert", Permission.newBuilder(TEST_TABLE).withActions(Permission.Action.READ).build()), - connection.getTable(AccessControlLists.ACL_TABLE_NAME)); + connection.getTable(PermissionStorage.ACL_TABLE_NAME)); addUserPermission(conf, new UserPermission("humphrey", Permission.newBuilder(TEST_TABLE).withFamily(TEST_FAMILY).withQualifier(TEST_QUALIFIER) .withActions(Permission.Action.READ).build()), - connection.getTable(AccessControlLists.ACL_TABLE_NAME)); + connection.getTable(PermissionStorage.ACL_TABLE_NAME)); } // retrieve the same ListMultimap perms = - AccessControlLists.getTablePermissions(conf, TEST_TABLE); + PermissionStorage.getTablePermissions(conf, TEST_TABLE); List userPerms = perms.get("george"); assertNotNull("Should have permissions for george", userPerms); assertEquals("Should have 1 permission for george", 1, userPerms.size()); @@ -213,15 +213,14 @@ public class TestTablePermissions { // table 2 permissions try (Connection connection = ConnectionFactory.createConnection(conf); - Table table = connection.getTable(AccessControlLists.ACL_TABLE_NAME)) { - AccessControlLists.addUserPermission(conf, + Table table = connection.getTable(PermissionStorage.ACL_TABLE_NAME)) { + PermissionStorage.addUserPermission(conf, new UserPermission("hubert", Permission.newBuilder(TEST_TABLE2) .withActions(Permission.Action.READ, Permission.Action.WRITE).build()), table); } // check full load - Map> allPerms = - AccessControlLists.loadAll(conf); + Map> allPerms = PermissionStorage.loadAll(conf); assertEquals("Full permission map should have entries for both test tables", 2, allPerms.size()); @@ -253,26 +252,26 @@ public class TestTablePermissions { addUserPermission(conf, new UserPermission("albert", Permission.newBuilder(TEST_TABLE).withActions(Permission.Action.READ).build()), - connection.getTable(AccessControlLists.ACL_TABLE_NAME)); + connection.getTable(PermissionStorage.ACL_TABLE_NAME)); addUserPermission(conf, new UserPermission("betty", Permission.newBuilder(TEST_TABLE) .withActions(Permission.Action.READ, Permission.Action.WRITE).build()), - connection.getTable(AccessControlLists.ACL_TABLE_NAME)); + connection.getTable(PermissionStorage.ACL_TABLE_NAME)); addUserPermission(conf, new UserPermission("clark", Permission.newBuilder(TEST_TABLE).withFamily(TEST_FAMILY) .withActions(Permission.Action.READ).build()), - connection.getTable(AccessControlLists.ACL_TABLE_NAME)); + connection.getTable(PermissionStorage.ACL_TABLE_NAME)); addUserPermission(conf, new UserPermission("dwight", Permission.newBuilder(TEST_TABLE).withFamily(TEST_FAMILY).withQualifier(TEST_QUALIFIER) .withActions(Permission.Action.WRITE).build()), - connection.getTable(AccessControlLists.ACL_TABLE_NAME)); + connection.getTable(PermissionStorage.ACL_TABLE_NAME)); } // verify permissions survive changes in table metadata ListMultimap preperms = - AccessControlLists.getTablePermissions(conf, TEST_TABLE); + PermissionStorage.getTablePermissions(conf, TEST_TABLE); Table table = UTIL.getConnection().getTable(TEST_TABLE); table.put( @@ -295,7 +294,7 @@ public class TestTablePermissions { Thread.sleep(10000); ListMultimap postperms = - AccessControlLists.getTablePermissions(conf, TEST_TABLE); + PermissionStorage.getTablePermissions(conf, TEST_TABLE); checkMultimapEqual(preperms, postperms); } @@ -304,10 +303,10 @@ public class TestTablePermissions { public void testSerialization() throws Exception { Configuration conf = UTIL.getConfiguration(); ListMultimap permissions = createPermissions(); - byte[] permsData = AccessControlLists.writePermissionsAsBytes(permissions, conf); + byte[] permsData = PermissionStorage.writePermissionsAsBytes(permissions, conf); ListMultimap copy = - AccessControlLists.readUserPermission(permsData, conf); + PermissionStorage.readUserPermission(permsData, conf); checkMultimapEqual(permissions, copy); } @@ -410,21 +409,20 @@ public class TestTablePermissions { addUserPermission(conf, new UserPermission("user1", Permission.newBuilder() .withActions(Permission.Action.READ, Permission.Action.WRITE).build()), - connection.getTable(AccessControlLists.ACL_TABLE_NAME)); + connection.getTable(PermissionStorage.ACL_TABLE_NAME)); addUserPermission(conf, new UserPermission("user2", Permission.newBuilder().withActions(Permission.Action.CREATE).build()), - connection.getTable(AccessControlLists.ACL_TABLE_NAME)); + connection.getTable(PermissionStorage.ACL_TABLE_NAME)); addUserPermission(conf, new UserPermission("user3", Permission.newBuilder() .withActions(Permission.Action.ADMIN, Permission.Action.READ, Permission.Action.CREATE) .build()), - connection.getTable(AccessControlLists.ACL_TABLE_NAME)); + connection.getTable(PermissionStorage.ACL_TABLE_NAME)); } - ListMultimap perms = - AccessControlLists.getTablePermissions(conf, null); + ListMultimap perms = PermissionStorage.getTablePermissions(conf, null); List user1Perms = perms.get("user1"); assertEquals("Should have 1 permission for user1", 1, user1Perms.size()); assertEquals("user1 should have WRITE permission", @@ -465,7 +463,7 @@ public class TestTablePermissions { .withActions(Permission.Action.ADMIN, Permission.Action.READ, Permission.Action.WRITE) .build()), - connection.getTable(AccessControlLists.ACL_TABLE_NAME)); + connection.getTable(PermissionStorage.ACL_TABLE_NAME)); // make sure the system user still shows as authorized assertTrue("Failed current user auth check on iter "+i, authManager.authorizeUserGlobal(currentUser, Permission.Action.ADMIN)); diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestWithDisabledAuthorization.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestWithDisabledAuthorization.java index 8bc5718..3e930c5 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestWithDisabledAuthorization.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestWithDisabledAuthorization.java @@ -155,7 +155,7 @@ public class TestWithDisabledAuthorization extends SecureTestUtil { RSCP_ENV = rsHost.createEnvironment(ACCESS_CONTROLLER, Coprocessor.PRIORITY_HIGHEST, 1, conf); // Wait for the ACL table to become available - TEST_UTIL.waitUntilAllRegionsAssigned(AccessControlLists.ACL_TABLE_NAME); + TEST_UTIL.waitUntilAllRegionsAssigned(PermissionStorage.ACL_TABLE_NAME); // create a set of test users SUPERUSER = User.createUserForTesting(conf, "admin", new String[] { "supergroup" }); @@ -219,8 +219,8 @@ public class TestWithDisabledAuthorization extends SecureTestUtil { Permission.Action.READ, Permission.Action.WRITE); - assertEquals(5, AccessControlLists.getTablePermissions(TEST_UTIL.getConfiguration(), - TEST_TABLE.getTableName()).size()); + assertEquals(5, PermissionStorage + .getTablePermissions(TEST_UTIL.getConfiguration(), TEST_TABLE.getTableName()).size()); } @After @@ -233,9 +233,9 @@ public class TestWithDisabledAuthorization extends SecureTestUtil { LOG.info("Test deleted table " + TEST_TABLE.getTableName()); } // Verify all table/namespace permissions are erased - assertEquals(0, AccessControlLists.getTablePermissions(TEST_UTIL.getConfiguration(), - TEST_TABLE.getTableName()).size()); - assertEquals(0, AccessControlLists.getNamespacePermissions(TEST_UTIL.getConfiguration(), + assertEquals(0, PermissionStorage + .getTablePermissions(TEST_UTIL.getConfiguration(), TEST_TABLE.getTableName()).size()); + assertEquals(0, PermissionStorage.getNamespacePermissions(TEST_UTIL.getConfiguration(), TEST_TABLE.getTableName().getNamespaceAsString()).size()); } diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestZKPermissionWatcher.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestZKPermissionWatcher.java index 327c49d..3c182d8 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestZKPermissionWatcher.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestZKPermissionWatcher.java @@ -117,7 +117,7 @@ public class TestZKPermissionWatcher { .withActions(Permission.Action.READ, Permission.Action.WRITE).build())); ListMultimap multimap = ArrayListMultimap.create(); multimap.putAll(george.getShortName(), acl); - byte[] serialized = AccessControlLists.writePermissionsAsBytes(multimap, conf); + byte[] serialized = PermissionStorage.writePermissionsAsBytes(multimap, conf); AUTH_A.getZKPermissionWatcher().writeToZookeeper(TEST_TABLE.getName(), serialized); final long mtimeB = AUTH_B.getMTime(); // Wait for the update to propagate @@ -145,7 +145,7 @@ public class TestZKPermissionWatcher { Permission.newBuilder(TEST_TABLE).withActions(TablePermission.Action.READ).build())); final long mtimeA = AUTH_A.getMTime(); multimap.putAll(hubert.getShortName(), acl2); - byte[] serialized2 = AccessControlLists.writePermissionsAsBytes(multimap, conf); + byte[] serialized2 = PermissionStorage.writePermissionsAsBytes(multimap, conf); AUTH_B.getZKPermissionWatcher().writeToZookeeper(TEST_TABLE.getName(), serialized2); // Wait for the update to propagate UTIL.waitFor(10000, 100, new Predicate() { diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/visibility/TestVisibilityLabelsWithACL.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/visibility/TestVisibilityLabelsWithACL.java index e36e451..bb4ca21 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/visibility/TestVisibilityLabelsWithACL.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/visibility/TestVisibilityLabelsWithACL.java @@ -43,9 +43,9 @@ import org.apache.hadoop.hbase.client.Table; import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.GetAuthsResponse; import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.VisibilityLabelsResponse; import org.apache.hadoop.hbase.security.User; -import org.apache.hadoop.hbase.security.access.AccessControlLists; import org.apache.hadoop.hbase.security.access.AccessController; import org.apache.hadoop.hbase.security.access.Permission; +import org.apache.hadoop.hbase.security.access.PermissionStorage; import org.apache.hadoop.hbase.security.access.SecureTestUtil; import org.apache.hadoop.hbase.testclassification.MediumTests; import org.apache.hadoop.hbase.testclassification.SecurityTests; @@ -92,7 +92,7 @@ public class TestVisibilityLabelsWithACL { + VisibilityController.class.getName()); TEST_UTIL.startMiniCluster(2); - TEST_UTIL.waitTableEnabled(AccessControlLists.ACL_TABLE_NAME.getName(), 50000); + TEST_UTIL.waitTableEnabled(PermissionStorage.ACL_TABLE_NAME.getName(), 50000); // Wait for the labels table to become available TEST_UTIL.waitTableEnabled(LABELS_TABLE_NAME.getName(), 50000); addLabels(); diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/tool/TestSecureLoadIncrementalHFiles.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/tool/TestSecureLoadIncrementalHFiles.java index 4e10f01..e09b9ac 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/tool/TestSecureLoadIncrementalHFiles.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/tool/TestSecureLoadIncrementalHFiles.java @@ -22,7 +22,7 @@ import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.codec.KeyValueCodecWithTags; import org.apache.hadoop.hbase.security.HadoopSecurityEnabledUserProviderForTesting; import org.apache.hadoop.hbase.security.UserProvider; -import org.apache.hadoop.hbase.security.access.AccessControlLists; +import org.apache.hadoop.hbase.security.access.PermissionStorage; import org.apache.hadoop.hbase.security.access.SecureTestUtil; import org.apache.hadoop.hbase.testclassification.LargeTests; import org.apache.hadoop.hbase.testclassification.MiscTests; @@ -62,7 +62,7 @@ public class TestSecureLoadIncrementalHFiles extends TestLoadIncrementalHFiles { util.startMiniCluster(); // Wait for the ACL table to become available - util.waitTableEnabled(AccessControlLists.ACL_TABLE_NAME); + util.waitTableEnabled(PermissionStorage.ACL_TABLE_NAME); setupNamespace(); } diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/tool/TestSecureLoadIncrementalHFilesSplitRecovery.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/tool/TestSecureLoadIncrementalHFilesSplitRecovery.java index 7fe79a9..03b9380 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/tool/TestSecureLoadIncrementalHFilesSplitRecovery.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/tool/TestSecureLoadIncrementalHFilesSplitRecovery.java @@ -21,7 +21,7 @@ import org.apache.hadoop.hbase.HBaseClassTestRule; import org.apache.hadoop.hbase.HBaseTestingUtility; import org.apache.hadoop.hbase.security.HadoopSecurityEnabledUserProviderForTesting; import org.apache.hadoop.hbase.security.UserProvider; -import org.apache.hadoop.hbase.security.access.AccessControlLists; +import org.apache.hadoop.hbase.security.access.PermissionStorage; import org.apache.hadoop.hbase.security.access.SecureTestUtil; import org.apache.hadoop.hbase.testclassification.LargeTests; import org.apache.hadoop.hbase.testclassification.MiscTests; @@ -61,7 +61,7 @@ public class TestSecureLoadIncrementalHFilesSplitRecovery util.startMiniCluster(); // Wait for the ACL table to become available - util.waitTableEnabled(AccessControlLists.ACL_TABLE_NAME); + util.waitTableEnabled(PermissionStorage.ACL_TABLE_NAME); } // Disabling this test as it does not work in secure mode diff --git a/hbase-shell/src/main/ruby/hbase/security.rb b/hbase-shell/src/main/ruby/hbase/security.rb index 4639c71..f07eaa3 100644 --- a/hbase-shell/src/main/ruby/hbase/security.rb +++ b/hbase-shell/src/main/ruby/hbase/security.rb @@ -202,7 +202,7 @@ module Hbase # If we are unable to use getSecurityCapabilities, fall back with a check for # deployment of the ACL table raise(ArgumentError, 'DISABLED: Security features are not available') unless \ - exists?(org.apache.hadoop.hbase.security.access.AccessControlLists::ACL_TABLE_NAME.getNameAsString) + exists?(org.apache.hadoop.hbase.security.access.PermissionStorage::ACL_TABLE_NAME.getNameAsString) return end raise(ArgumentError, 'DISABLED: Security features are not available') unless \ diff --git a/src/main/asciidoc/_chapters/security.adoc b/src/main/asciidoc/_chapters/security.adoc index 56f6566..2c76285 100644 --- a/src/main/asciidoc/_chapters/security.adoc +++ b/src/main/asciidoc/_chapters/security.adoc @@ -1036,12 +1036,10 @@ public static void grantOnTable(final HBaseTestingUtility util, final String use SecureTestUtil.updateACLs(util, new Callable() { @Override public Void call() throws Exception { - try (Connection connection = ConnectionFactory.createConnection(util.getConfiguration()); - Table acl = connection.getTable(AccessControlLists.ACL_TABLE_NAME)) { - BlockingRpcChannel service = acl.coprocessorService(HConstants.EMPTY_START_ROW); - AccessControlService.BlockingInterface protocol = - AccessControlService.newBlockingStub(service); - AccessControlUtil.grant(null, protocol, user, table, family, qualifier, false, actions); + try (Connection connection = ConnectionFactory.createConnection(util.getConfiguration())) { + connection.getAdmin().grant(new UserPermission(user, Permission.newBuilder(table) + .withFamily(family).withQualifier(qualifier).withActions(actions).build()), + false); } return null; } @@ -1084,16 +1082,9 @@ public static void revokeFromTable(final HBaseTestingUtility util, final String SecureTestUtil.updateACLs(util, new Callable() { @Override public Void call() throws Exception { - Configuration conf = HBaseConfiguration.create(); - Connection connection = ConnectionFactory.createConnection(conf); - Table acl = connection.getTable(util.getConfiguration(), AccessControlLists.ACL_TABLE_NAME); - try { - BlockingRpcChannel service = acl.coprocessorService(HConstants.EMPTY_START_ROW); - AccessControlService.BlockingInterface protocol = - AccessControlService.newBlockingStub(service); - ProtobufUtil.revoke(protocol, user, table, family, qualifier, actions); - } finally { - acl.close(); + try (Connection connection = ConnectionFactory.createConnection(util.getConfiguration())) { + connection.getAdmin().revoke(new UserPermission(user, Permission.newBuilder(table) + .withFamily(family).withQualifier(qualifier).withActions(actions).build())); } return null; } -- 2.7.4