From b7bb9d95051dcb691faf77ee85cc6641117bb594 Mon Sep 17 00:00:00 2001 From: tedyu Date: Sat, 13 Dec 2014 10:19:18 -0800 Subject: [PATCH] HBASE-12659 Replace the method calls to grant and revoke in shell scripts with AccessControlClient (Srikanth Srungarapu) --- .../security/access/AccessControlClient.java | 28 +++++++++ .../hbase/security/access/SecureTestUtil.java | 42 ++++++++++++++ .../security/access/TestAccessController.java | 42 ++++++++++++++ hbase-shell/src/main/ruby/hbase/security.rb | 57 ++++++------------- 4 files changed, 128 insertions(+), 41 deletions(-) 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 72861a4d8ed..4500573aea5 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 @@ -100,6 +100,20 @@ public class AccessControlClient { } } + /** + * Grant global permissions for the specified user. + */ + public static void grant(Configuration conf, final String userName, + final Permission.Action... actions) throws Throwable { + // TODO: Make it so caller passes in a Connection rather than have us do this expensive + // setup each time. This class only used in test and shell at moment though. + try (Connection connection = ConnectionFactory.createConnection(conf)) { + try (Table table = connection.getTable(ACL_TABLE_NAME)) { + ProtobufUtil.grant(getAccessControlServiceStub(table), userName, actions); + } + } + } + public static boolean isAccessControllerRunning(Configuration conf) throws MasterNotRunningException, ZooKeeperConnectionException, IOException { // TODO: Make it so caller passes in a Connection rather than have us do this expensive @@ -153,6 +167,20 @@ public class AccessControlClient { } } + /** + * Revoke global permissions for the specified user. + */ + public static void revoke(Configuration conf, final String userName, + final Permission.Action... actions) throws Throwable { + // TODO: Make it so caller passes in a Connection rather than have us do this expensive + // setup each time. This class only used in test and shell at moment though. + try (Connection connection = ConnectionFactory.createConnection(conf)) { + try (Table table = connection.getTable(ACL_TABLE_NAME)) { + ProtobufUtil.revoke(getAccessControlServiceStub(table), userName, actions); + } + } + } + /** * List all the userPermissions matching the given pattern. * @param conf 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 a66a8e82497..ea1baeb2564 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 @@ -498,6 +498,27 @@ public class SecureTestUtil { }); } + /** + * Grant global permissions 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 grantGlobalUsingAccessControlClient(final HBaseTestingUtility util, + final Configuration conf, final String user, final Permission.Action... actions) + throws Exception { + SecureTestUtil.updateACLs(util, new Callable() { + @Override + public Void call() throws Exception { + try { + AccessControlClient.grant(conf, user, 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 @@ -542,4 +563,25 @@ public class SecureTestUtil { } }); } + + /** + * Revoke global permissions 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 revokeGlobalUsingAccessControlClient(final HBaseTestingUtility util, + final Configuration conf, final String user,final Permission.Action... actions) + throws Exception { + SecureTestUtil.updateACLs(util, new Callable() { + @Override + public Void call() throws Exception { + try { + AccessControlClient.revoke(conf, user, actions); + } catch (Throwable t) { + t.printStackTrace(); + } + return null; + } + }); + } } 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 b5d7e3dade6..e164a6f2582 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 @@ -2147,6 +2147,48 @@ public class TestAccessController extends SecureTestUtil { verifyDenied(getAction, testGrantRevoke); } + @Test + public void testAccessControlClientGlobalGrantRevoke() throws Exception { + // Create user for testing, who has no READ privileges by default. + User testGlobalGrantRevoke = User.createUserForTesting(conf, + "testGlobalGrantRevoke", 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, testGlobalGrantRevoke); + + // Grant table READ permissions to testGlobalGrantRevoke. + try { + grantGlobalUsingAccessControlClient(TEST_UTIL, conf, testGlobalGrantRevoke.getShortName(), + Permission.Action.READ); + } catch (Throwable e) { + LOG.error("error during call of AccessControlClient.grant. ", e); + } + + // Now testGlobalGrantRevoke should be able to read also + verifyAllowed(getAction, testGlobalGrantRevoke); + + // Revoke table READ permission to testGlobalGrantRevoke. + try { + revokeGlobalUsingAccessControlClient(TEST_UTIL, conf, testGlobalGrantRevoke.getShortName(), + Permission.Action.READ); + } catch (Throwable e) { + LOG.error("error during call of AccessControlClient.revoke ", e); + } + + // Now testGlobalGrantRevoke shouldn't be able read + verifyDenied(getAction, testGlobalGrantRevoke); + } + @Test public void testAccessControlClientGrantRevokeOnNamespace() throws Exception { // Create user for testing, who has no READ privileges by default. diff --git a/hbase-shell/src/main/ruby/hbase/security.rb b/hbase-shell/src/main/ruby/hbase/security.rb index 1bd025cfd93..a0d6e919cc8 100644 --- a/hbase-shell/src/main/ruby/hbase/security.rb +++ b/hbase-shell/src/main/ruby/hbase/security.rb @@ -38,21 +38,14 @@ module Hbase # TODO: need to validate user name begin - meta_table = @connection.getTable( - org.apache.hadoop.hbase.security.access.AccessControlLists::ACL_TABLE_NAME) - service = meta_table.coprocessorService( - org.apache.hadoop.hbase.HConstants::EMPTY_START_ROW) - - protocol = org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos:: - AccessControlService.newBlockingStub(service) - perm = org.apache.hadoop.hbase.security.access.Permission.new( - permissions.to_java_bytes) - # Verify that the specified permission is valid if (permissions == nil || permissions.length == 0) raise(ArgumentError, "Invalid permission: no actions associated with user") end + perm = org.apache.hadoop.hbase.security.access.Permission.new( + permissions.to_java_bytes) + if (table_name != nil) tablebytes=table_name.to_java_bytes #check if the tablename passed is actually a namespace @@ -62,9 +55,8 @@ module Hbase raise(ArgumentError, "Can't find a namespace: #{namespace_name}") unless namespace_exists?(namespace_name) - # invoke cp endpoint to perform access controlse - org.apache.hadoop.hbase.protobuf.ProtobufUtil.grant( - protocol, user, namespace_name, perm.getActions()) + org.apache.hadoop.hbase.security.access.AccessControlClient.grant( + @config, namespace_name, user, perm.getActions()) else # Table should exist raise(ArgumentError, "Can't find a table: #{table_name}") unless exists?(table_name) @@ -79,19 +71,14 @@ module Hbase fambytes = family.to_java_bytes if (family != nil) qualbytes = qualifier.to_java_bytes if (qualifier != nil) - # invoke cp endpoint to perform access controlse - org.apache.hadoop.hbase.protobuf.ProtobufUtil.grant( - protocol, user, tableName, fambytes, - qualbytes, perm.getActions()) + org.apache.hadoop.hbase.security.access.AccessControlClient.grant( + @config, tableName, user, fambytes, qualbytes, perm.getActions()) end else - # invoke cp endpoint to perform access controlse - org.apache.hadoop.hbase.protobuf.ProtobufUtil.grant( - protocol, user, perm.getActions()) + # invoke cp endpoint to perform access controls + org.apache.hadoop.hbase.security.access.AccessControlClient.grant( + @config, user, perm.getActions()) end - - ensure - meta_table.close() end end @@ -102,14 +89,6 @@ module Hbase # TODO: need to validate user name begin - meta_table = @connection.getTable( - org.apache.hadoop.hbase.security.access.AccessControlLists::ACL_TABLE_NAME) - service = meta_table.coprocessorService( - org.apache.hadoop.hbase.HConstants::EMPTY_START_ROW) - - protocol = org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos:: - AccessControlService.newBlockingStub(service) - if (table_name != nil) #check if the tablename passed is actually a namespace if (isNamespace?(table_name)) @@ -118,9 +97,8 @@ module Hbase raise(ArgumentError, "Can't find a namespace: #{namespace_name}") unless namespace_exists?(namespace_name) tablebytes=table_name.to_java_bytes - # invoke cp endpoint to perform access controlse - org.apache.hadoop.hbase.protobuf.ProtobufUtil.revoke( - protocol, user, namespace_name) + org.apache.hadoop.hbase.security.access.AccessControlClient.revoke( + @config, namespace_name, user) else # Table should exist raise(ArgumentError, "Can't find a table: #{table_name}") unless exists?(table_name) @@ -135,17 +113,14 @@ module Hbase fambytes = family.to_java_bytes if (family != nil) qualbytes = qualifier.to_java_bytes if (qualifier != nil) - # invoke cp endpoint to perform access controlse - org.apache.hadoop.hbase.protobuf.ProtobufUtil.revoke( - protocol, user, tableName, fambytes, qualbytes) + org.apache.hadoop.hbase.security.access.AccessControlClient.revoke( + @config, tableName, user, fambytes, qualbytes) end else - # invoke cp endpoint to perform access controlse perm = org.apache.hadoop.hbase.security.access.Permission.new(''.to_java_bytes) - org.apache.hadoop.hbase.protobuf.ProtobufUtil.revoke(protocol, user, perm.getActions()) + org.apache.hadoop.hbase.security.access.AccessControlClient.revoke( + @config, user, perm.getActions()) end - ensure - meta_table.close() end end