You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by mb...@apache.org on 2014/10/19 10:31:13 UTC
git commit: HBASE-12161 Add support for grant/revoke on namespaces in
AccessControlClient (Srikanth Srungarapu)
Repository: hbase
Updated Branches:
refs/heads/0.98 d9a730e66 -> 2383c293b
HBASE-12161 Add support for grant/revoke on namespaces in AccessControlClient (Srikanth Srungarapu)
Project: http://git-wip-us.apache.org/repos/asf/hbase/repo
Commit: http://git-wip-us.apache.org/repos/asf/hbase/commit/2383c293
Tree: http://git-wip-us.apache.org/repos/asf/hbase/tree/2383c293
Diff: http://git-wip-us.apache.org/repos/asf/hbase/diff/2383c293
Branch: refs/heads/0.98
Commit: 2383c293b0fff1b881f99b107fc48a1cd387fdf9
Parents: d9a730e
Author: Matteo Bertozzi <ma...@cloudera.com>
Authored: Sun Oct 19 09:30:25 2014 +0100
Committer: Matteo Bertozzi <ma...@cloudera.com>
Committed: Sun Oct 19 09:30:25 2014 +0100
----------------------------------------------------------------------
.../security/access/AccessControlClient.java | 175 ++++++++-----------
...egrationTestBigLinkedListWithVisibility.java | 4 +-
.../hbase/security/access/SecureTestUtil.java | 84 +++++++++
.../security/access/TestAccessController.java | 83 +++++++++
.../apache/hadoop/hbase/util/LoadTestTool.java | 8 +-
5 files changed, 242 insertions(+), 112 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/hbase/blob/2383c293/hbase-client/src/main/java/org/apache/hadoop/hbase/security/access/AccessControlClient.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/security/access/AccessControlClient.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/security/access/AccessControlClient.java
index b1de763..861befd 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/security/access/AccessControlClient.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/security/access/AccessControlClient.java
@@ -20,7 +20,6 @@ package org.apache.hadoop.hbase.security.access;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
-import java.util.Map;
import java.util.regex.Pattern;
import org.apache.hadoop.conf.Configuration;
@@ -34,29 +33,35 @@ import org.apache.hadoop.hbase.classification.InterfaceAudience;
import org.apache.hadoop.hbase.classification.InterfaceStability;
import org.apache.hadoop.hbase.client.HBaseAdmin;
import org.apache.hadoop.hbase.client.HTable;
-import org.apache.hadoop.hbase.client.coprocessor.Batch;
-import org.apache.hadoop.hbase.ipc.BlockingRpcCallback;
import org.apache.hadoop.hbase.ipc.CoprocessorRpcChannel;
-import org.apache.hadoop.hbase.ipc.ServerRpcController;
import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos;
-import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.AccessControlService;
import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.AccessControlService.BlockingInterface;
-import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.GrantRequest;
-import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.GrantResponse;
-import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.RevokeRequest;
-import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.RevokeResponse;
-import org.apache.hadoop.hbase.util.ByteStringer;
import org.apache.hadoop.hbase.util.Bytes;
-import com.google.protobuf.ByteString;
-
/**
* Utility client for doing access control admin operations.
*/
@InterfaceAudience.Public
@InterfaceStability.Evolving
public class AccessControlClient {
+
+ private static HTable getAclTable(Configuration conf) throws IOException {
+ TableName aclTableName =
+ TableName.valueOf(NamespaceDescriptor.SYSTEM_NAMESPACE_NAME_STR,
+ AccessControlConstants.OP_ATTRIBUTE_ACL);
+ return new HTable(conf, aclTableName.getName());
+ }
+
+ private static BlockingInterface getAccessControlServiceStub(HTable ht)
+ throws IOException {
+ CoprocessorRpcChannel service = ht.coprocessorService(HConstants.EMPTY_START_ROW);
+ BlockingInterface protocol =
+ AccessControlProtos.AccessControlService.newBlockingStub(service);
+ return protocol;
+ }
+
+
/**
* Grants permission on the specified table for the specified user
* @param conf
@@ -65,63 +70,42 @@ public class AccessControlClient {
* @param family
* @param qual
* @param actions
- * @return GrantResponse
* @throws Throwable
*/
- public static GrantResponse grant(Configuration conf, final TableName tableName,
+ public static void grant(Configuration conf, final TableName tableName,
final String userName, final byte[] family, final byte[] qual,
- final AccessControlProtos.Permission.Action... actions) throws Throwable {
+ final Permission.Action... actions) throws Throwable {
HTable ht = null;
try {
- TableName aclTableName =
- TableName.valueOf(NamespaceDescriptor.SYSTEM_NAMESPACE_NAME_STR, "acl");
- ht = new HTable(conf, aclTableName.getName());
- Batch.Call<AccessControlService, GrantResponse> callable =
- new Batch.Call<AccessControlService, GrantResponse>() {
- ServerRpcController controller = new ServerRpcController();
- BlockingRpcCallback<GrantResponse> rpcCallback =
- new BlockingRpcCallback<GrantResponse>();
-
- @Override
- public GrantResponse call(AccessControlService service) throws IOException {
- GrantRequest.Builder builder = GrantRequest.newBuilder();
- AccessControlProtos.Permission.Builder ret =
- AccessControlProtos.Permission.newBuilder();
- AccessControlProtos.TablePermission.Builder permissionBuilder =
- AccessControlProtos.TablePermission
- .newBuilder();
- for (AccessControlProtos.Permission.Action a : actions) {
- permissionBuilder.addAction(a);
- }
- permissionBuilder.setTableName(ProtobufUtil.toProtoTableName(tableName));
-
- if (family != null) {
- permissionBuilder.setFamily(ByteStringer.wrap(family));
- }
- if (qual != null) {
- permissionBuilder.setQualifier(ByteStringer.wrap(qual));
- }
- ret.setType(AccessControlProtos.Permission.Type.Table).setTablePermission(
- permissionBuilder);
- builder.setUserPermission(AccessControlProtos.UserPermission.newBuilder()
- .setUser(ByteString.copyFromUtf8(userName)).setPermission(ret));
- service.grant(controller, builder.build(), rpcCallback);
- return rpcCallback.get();
- }
- };
- Map<byte[], GrantResponse> result = ht.coprocessorService(AccessControlService.class,
- HConstants.EMPTY_BYTE_ARRAY, HConstants.EMPTY_BYTE_ARRAY, callable);
- return result.values().iterator().next(); // There will be exactly one
- // region for labels
- // table and so one entry in
- // result Map.
+ ht = getAclTable(conf);
+ ProtobufUtil.grant(getAccessControlServiceStub(ht), userName, tableName, family, qual,
+ actions);
+ } finally {
+ if (ht != null) {
+ ht.close();
+ }
+ }
+ }
+ /**
+ * Grants permission on the specified namespace for the specified user.
+ * @param conf
+ * @param namespace
+ * @param userName
+ * @param actions
+ * @throws Throwable
+ */
+ public static void grant(Configuration conf, final String namespace,
+ final String userName, final Permission.Action... actions) throws Throwable {
+ HTable ht = null;
+ try {
+ ht = getAclTable(conf);
+ ProtobufUtil.grant(getAccessControlServiceStub(ht), userName, namespace, actions);
} finally {
if (ht != null) {
ht.close();
}
}
}
-
public static boolean isAccessControllerRunning(Configuration conf)
throws MasterNotRunningException, ZooKeeperConnectionException, IOException {
TableName aclTableName = TableName
@@ -136,65 +120,44 @@ public class AccessControlClient {
}
}
}
-
/**
* Revokes the permission on the table
* @param conf
- * @param username
* @param tableName
+ * @param username
* @param family
* @param qualifier
* @param actions
- * @return RevokeResponse
* @throws Throwable
*/
- public static RevokeResponse revoke(Configuration conf, final String username,
- final TableName tableName, final byte[] family, final byte[] qualifier,
- final AccessControlProtos.Permission.Action... actions) throws Throwable {
+ public static void revoke(Configuration conf, final TableName tableName,
+ final String username, final byte[] family, final byte[] qualifier,
+ final Permission.Action... actions) throws Throwable {
HTable ht = null;
try {
- TableName aclTableName = TableName.valueOf(NamespaceDescriptor.SYSTEM_NAMESPACE_NAME_STR,
- "acl");
- ht = new HTable(conf, aclTableName.getName());
- Batch.Call<AccessControlService, AccessControlProtos.RevokeResponse> callable =
- new Batch.Call<AccessControlService, AccessControlProtos.RevokeResponse>() {
- ServerRpcController controller = new ServerRpcController();
- BlockingRpcCallback<AccessControlProtos.RevokeResponse> rpcCallback =
- new BlockingRpcCallback<AccessControlProtos.RevokeResponse>();
-
- @Override
- public RevokeResponse call(AccessControlService service) throws IOException {
- AccessControlProtos.Permission.Builder ret =
- AccessControlProtos.Permission.newBuilder();
- AccessControlProtos.TablePermission.Builder permissionBuilder =
- AccessControlProtos.TablePermission.newBuilder();
- for (AccessControlProtos.Permission.Action a : actions) {
- permissionBuilder.addAction(a);
- }
- if (tableName != null) {
- permissionBuilder.setTableName(ProtobufUtil.toProtoTableName(tableName));
- }
- if (family != null) {
- permissionBuilder.setFamily(ByteStringer.wrap(family));
- }
- if (qualifier != null) {
- permissionBuilder.setQualifier(ByteStringer.wrap(qualifier));
- }
- ret.setType(AccessControlProtos.Permission.Type.Table).setTablePermission(
- permissionBuilder);
- RevokeRequest builder = AccessControlProtos.RevokeRequest
- .newBuilder()
- .setUserPermission(
- AccessControlProtos.UserPermission.newBuilder()
- .setUser(ByteString.copyFromUtf8(username)).setPermission(ret)).build();
- service.revoke(controller, builder, rpcCallback);
- return rpcCallback.get();
- }
- };
- Map<byte[], RevokeResponse> result = ht.coprocessorService(AccessControlService.class,
- HConstants.EMPTY_BYTE_ARRAY, HConstants.EMPTY_BYTE_ARRAY, callable);
- return result.values().iterator().next();
-
+ ht = getAclTable(conf);
+ ProtobufUtil.revoke(getAccessControlServiceStub(ht), username, tableName, family, qualifier,
+ actions);
+ } finally {
+ if (ht != null) {
+ ht.close();
+ }
+ }
+ }
+ /**
+ * Revokes the permission on the table for the specified user.
+ * @param conf
+ * @param namespace
+ * @param userName
+ * @param actions
+ * @throws Throwable
+ */
+ public static void revoke(Configuration conf, final String namespace,
+ final String userName, final Permission.Action... actions) throws Throwable {
+ HTable ht = null;
+ try {
+ ht = getAclTable(conf);
+ ProtobufUtil.revoke(getAccessControlServiceStub(ht), userName, namespace, actions);
} finally {
if (ht != null) {
ht.close();
http://git-wip-us.apache.org/repos/asf/hbase/blob/2383c293/hbase-it/src/test/java/org/apache/hadoop/hbase/test/IntegrationTestBigLinkedListWithVisibility.java
----------------------------------------------------------------------
diff --git a/hbase-it/src/test/java/org/apache/hadoop/hbase/test/IntegrationTestBigLinkedListWithVisibility.java b/hbase-it/src/test/java/org/apache/hadoop/hbase/test/IntegrationTestBigLinkedListWithVisibility.java
index 9748b31..3122dbe 100644
--- a/hbase-it/src/test/java/org/apache/hadoop/hbase/test/IntegrationTestBigLinkedListWithVisibility.java
+++ b/hbase-it/src/test/java/org/apache/hadoop/hbase/test/IntegrationTestBigLinkedListWithVisibility.java
@@ -50,9 +50,9 @@ import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.io.hfile.HFile;
import org.apache.hadoop.hbase.mapreduce.Import;
import org.apache.hadoop.hbase.mapreduce.TableMapReduceUtil;
-import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos;
import org.apache.hadoop.hbase.security.User;
import org.apache.hadoop.hbase.security.access.AccessControlClient;
+import org.apache.hadoop.hbase.security.access.Permission;
import org.apache.hadoop.hbase.security.visibility.Authorizations;
import org.apache.hadoop.hbase.security.visibility.CellVisibility;
import org.apache.hadoop.hbase.security.visibility.VisibilityClient;
@@ -152,7 +152,7 @@ public class IntegrationTestBigLinkedListWithVisibility extends IntegrationTestB
admin.createTable(htd);
if (acl) {
LOG.info("Granting permissions for user " + USER.getShortName());
- AccessControlProtos.Permission.Action[] actions = { AccessControlProtos.Permission.Action.READ };
+ Permission.Action[] actions = { Permission.Action.READ };
try {
AccessControlClient.grant(getConf(), tableName, USER.getShortName(), null, null,
actions);
http://git-wip-us.apache.org/repos/asf/hbase/blob/2383c293/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/SecureTestUtil.java
----------------------------------------------------------------------
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 ca27807..af24961 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
@@ -390,6 +390,48 @@ public class SecureTestUtil {
}
/**
+ * Grant permissions on a namespace to the given user using AccessControl Client.
+ * Will wait until all active AccessController instances have updated their permissions caches
+ * or will throw an exception upon timeout (10 seconds).
+ */
+ public static void grantOnNamespaceUsingAccessControlClient(final HBaseTestingUtility util,
+ final Configuration conf, final String user, final String namespace,
+ final Permission.Action... actions) throws Exception {
+ SecureTestUtil.updateACLs(util, new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ try {
+ AccessControlClient.grant(conf, namespace, user, actions);
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ return null;
+ }
+ });
+ }
+
+ /**
+ * Revoke permissions on a namespace from the given user using AccessControl Client.
+ * Will wait until all active AccessController instances have updated their permissions caches
+ * or will throw an exception upon timeout (10 seconds).
+ */
+ public static void revokeFromNamespaceUsingAccessControlClient(final HBaseTestingUtility util,
+ final Configuration conf, final String user, final String namespace,
+ final Permission.Action... actions) throws Exception {
+ SecureTestUtil.updateACLs(util, new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ try {
+ AccessControlClient.revoke(conf, namespace, user, actions);
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ return null;
+ }
+ });
+ }
+
+ /**
* Revoke permissions on a namespace from the given user. Will wait until all active
* AccessController instances have updated their permissions caches or will
* throw an exception upon timeout (10 seconds).
@@ -439,6 +481,27 @@ public class SecureTestUtil {
}
/**
+ * Grant permissions on a table to the given user using AccessControlClient. Will wait until all
+ * active AccessController instances have updated their permissions caches or will
+ * throw an exception upon timeout (10 seconds).
+ */
+ public static void grantOnTableUsingAccessControlClient(final HBaseTestingUtility util,
+ final Configuration conf, final String user, final TableName table, final byte[] family,
+ final byte[] qualifier, final Permission.Action... actions) throws Exception {
+ SecureTestUtil.updateACLs(util, new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ try {
+ AccessControlClient.grant(conf, table, user, family, qualifier, actions);
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ return null;
+ }
+ });
+ }
+
+ /**
* Revoke permissions on a table from the given user. Will wait until all active
* AccessController instances have updated their permissions caches or will
* throw an exception upon timeout (10 seconds).
@@ -462,4 +525,25 @@ public class SecureTestUtil {
}
});
}
+
+ /**
+ * Revoke permissions on a table from the given user using AccessControlClient. Will wait until
+ * all active AccessController instances have updated their permissions caches or will
+ * throw an exception upon timeout (10 seconds).
+ */
+ public static void revokeFromTableUsingAccessControlClient(final HBaseTestingUtility util,
+ final Configuration conf, final String user, final TableName table, final byte[] family,
+ final byte[] qualifier, final Permission.Action... actions) throws Exception {
+ SecureTestUtil.updateACLs(util, new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ try {
+ AccessControlClient.revoke(conf, table, user, family, qualifier, actions);
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ return null;
+ }
+ });
+ }
}
http://git-wip-us.apache.org/repos/asf/hbase/blob/2383c293/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessController.java
----------------------------------------------------------------------
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 edf591c..613d1d7 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
@@ -2039,6 +2039,89 @@ public class TestAccessController extends SecureTestUtil {
verifyAllowed(getAction, USER_NONE);
}
+ @Test
+ public void testAccessControlClientGrantRevoke() throws Exception {
+ // Create user for testing, who has no READ privileges by default.
+ User testGrantRevoke = User.createUserForTesting(conf, "testGrantRevoke", new String[0]);
+ AccessTestAction getAction = new AccessTestAction() {
+ @Override
+ public Object run() throws Exception {
+ HTable t = new HTable(conf, TEST_TABLE.getTableName());
+ try {
+ return t.get(new Get(TEST_ROW));
+ } finally {
+ t.close();
+ }
+ }
+ };
+
+ verifyDenied(getAction, testGrantRevoke);
+
+ // Grant table READ permissions to testGrantRevoke.
+ try {
+ grantOnTableUsingAccessControlClient(TEST_UTIL, conf, testGrantRevoke.getShortName(),
+ TEST_TABLE.getTableName(), null, null, Permission.Action.READ);
+ } catch (Throwable e) {
+ LOG.error("error during call of AccessControlClient.grant. " + e.getStackTrace());
+ }
+
+ // Now testGrantRevoke should be able to read also
+ verifyAllowed(getAction, testGrantRevoke);
+
+ // Revoke table READ permission to testGrantRevoke.
+ try {
+ revokeFromTableUsingAccessControlClient(TEST_UTIL, conf, testGrantRevoke.getShortName(),
+ TEST_TABLE.getTableName(), null, null, Permission.Action.READ);
+ } catch (Throwable e) {
+ LOG.error("error during call of AccessControlClient.revoke " + e.getStackTrace());
+ }
+
+ // Now testGrantRevoke shouldn't be able read
+ verifyDenied(getAction, testGrantRevoke);
+ }
+
+ @Test
+ public void testAccessControlClientGrantRevokeOnNamespace() throws Exception {
+ // Create user for testing, who has no READ privileges by default.
+ User testNS = User.createUserForTesting(conf, "testNS", new String[0]);
+ AccessTestAction getAction = new AccessTestAction() {
+ @Override
+ public Object run() throws Exception {
+ HTable t = new HTable(conf, TEST_TABLE.getTableName());
+ try {
+ return t.get(new Get(TEST_ROW));
+ } finally {
+ t.close();
+ }
+ }
+ };
+
+ verifyDenied(getAction, testNS);
+
+ // Grant namespace READ to testNS, this should supersede any table permissions
+ try {
+ grantOnNamespaceUsingAccessControlClient(TEST_UTIL, conf, testNS.getShortName(),
+ TEST_TABLE.getTableName().getNamespaceAsString(), Permission.Action.READ);
+ } catch (Throwable e) {
+ LOG.error("error during call of AccessControlClient.grant. " + e.getStackTrace());
+ }
+
+ // Now testNS should be able to read also
+ verifyAllowed(getAction, testNS);
+
+ // Revoke namespace READ to testNS, this should supersede any table permissions
+ try {
+ revokeFromNamespaceUsingAccessControlClient(TEST_UTIL, conf, testNS.getShortName(),
+ TEST_TABLE.getTableName().getNamespaceAsString(), Permission.Action.READ);
+ } catch (Throwable e) {
+ LOG.error("error during call of AccessControlClient.revoke " + e.getStackTrace());
+ }
+
+ // Now testNS shouldn't be able read
+ verifyDenied(getAction, testNS);
+ }
+
+
public static class PingCoprocessor extends PingService implements Coprocessor,
CoprocessorService {
http://git-wip-us.apache.org/repos/asf/hbase/blob/2383c293/hbase-server/src/test/java/org/apache/hadoop/hbase/util/LoadTestTool.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/util/LoadTestTool.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/util/LoadTestTool.java
index b207202..0efc7d3 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/util/LoadTestTool.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/util/LoadTestTool.java
@@ -46,11 +46,11 @@ import org.apache.hadoop.hbase.io.compress.Compression;
import org.apache.hadoop.hbase.io.crypto.Cipher;
import org.apache.hadoop.hbase.io.crypto.Encryption;
import org.apache.hadoop.hbase.io.encoding.DataBlockEncoding;
-import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos;
import org.apache.hadoop.hbase.regionserver.BloomType;
import org.apache.hadoop.hbase.security.EncryptionUtil;
import org.apache.hadoop.hbase.security.User;
import org.apache.hadoop.hbase.security.access.AccessControlClient;
+import org.apache.hadoop.hbase.security.access.Permission;
import org.apache.hadoop.hbase.util.test.LoadTestDataGenerator;
import org.apache.hadoop.hbase.util.test.LoadTestDataGeneratorWithACL;
import org.apache.hadoop.security.SecurityUtil;
@@ -529,9 +529,9 @@ public class LoadTestTool extends AbstractHBaseTool {
if (userOwner != null) {
LOG.info("Granting permissions for user " + userOwner.getShortName());
- AccessControlProtos.Permission.Action[] actions = {
- AccessControlProtos.Permission.Action.ADMIN, AccessControlProtos.Permission.Action.CREATE,
- AccessControlProtos.Permission.Action.READ, AccessControlProtos.Permission.Action.WRITE };
+ Permission.Action[] actions = {
+ Permission.Action.ADMIN, Permission.Action.CREATE,
+ Permission.Action.READ, Permission.Action.WRITE };
try {
AccessControlClient.grant(conf, tableName, userOwner.getShortName(), null, null, actions);
} catch (Throwable e) {