Repository: hbase
Updated Branches:
  refs/heads/branch-1 a731ea630 -> 09617cc2a
  refs/heads/master b4371252f -> 8a2c84156


http://git-wip-us.apache.org/repos/asf/hbase/blob/8a2c8415/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/TableAuthManager.java
----------------------------------------------------------------------
diff --git 
a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/TableAuthManager.java
 
b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/TableAuthManager.java
index ae4af26..4ed81dc 100644
--- 
a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/TableAuthManager.java
+++ 
b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/TableAuthManager.java
@@ -223,7 +223,7 @@ public class TableAuthManager {
    * Updates the internal permissions cache for a single table, splitting
    * the permissions listed into separate caches for users and groups to 
optimize
    * group lookups.
-   * 
+   *
    * @param table
    * @param tablePerms
    */
@@ -349,6 +349,20 @@ public class TableAuthManager {
     return false;
   }
 
+  private boolean hasAccess(List<TablePermission> perms,
+                            TableName table, Permission.Action action) {
+    if (perms != null) {
+      for (TablePermission p : perms) {
+        if (p.implies(action)) {
+          return true;
+        }
+      }
+    } else if (LOG.isDebugEnabled()) {
+      LOG.debug("No permissions found for table="+table);
+    }
+    return false;
+  }
+
   /**
    * Authorize a user for a given KV. This is called from AccessControlFilter.
    */
@@ -442,7 +456,7 @@ public class TableAuthManager {
       byte[] qualifier, Permission.Action action) {
     if (table == null) table = AccessControlLists.ACL_TABLE_NAME;
     // Global and namespace authorizations supercede table level
-    if (authorize(user, table.getNamespaceAsString(), action)) {    
+    if (authorize(user, table.getNamespaceAsString(), action)) {
       return true;
     }
     // Check table permissions
@@ -451,6 +465,25 @@ public class TableAuthManager {
   }
 
   /**
+   * Checks if the user has access to the full table or at least a 
family/qualifier
+   * for the specified action.
+   *
+   * @param user
+   * @param table
+   * @param action
+   * @return true if the user has access to the table, false otherwise
+   */
+  public boolean userHasAccess(User user, TableName table, Permission.Action 
action) {
+    if (table == null) table = AccessControlLists.ACL_TABLE_NAME;
+    // Global and namespace authorizations supercede table level
+    if (authorize(user, table.getNamespaceAsString(), action)) {
+      return true;
+    }
+    // Check table permissions
+    return hasAccess(getTablePermissions(table).getUser(user.getShortName()), 
table, action);
+  }
+
+  /**
    * Checks global authorization for a given action for a group, based on the 
stored
    * permissions.
    */
@@ -460,7 +493,7 @@ public class TableAuthManager {
 
   /**
    * Checks authorization to a given table and column family for a group, based
-   * on the stored permissions. 
+   * on the stored permissions.
    * @param groupName
    * @param table
    * @param family
@@ -483,6 +516,29 @@ public class TableAuthManager {
     return authorize(getTablePermissions(table).getGroup(groupName), table, 
family, action);
   }
 
+  /**
+   * Checks if the user has access to the full table or at least a 
family/qualifier
+   * for the specified action.
+   * @param groupName
+   * @param table
+   * @param action
+   * @return true if the group has access to the table, false otherwise
+   */
+  public boolean groupHasAccess(String groupName, TableName table, 
Permission.Action action) {
+    // Global authorization supercedes table level
+    if (authorizeGroup(groupName, action)) {
+      return true;
+    }
+    if (table == null) table = AccessControlLists.ACL_TABLE_NAME;
+    // Namespace authorization supercedes table level
+    if 
(hasAccess(getNamespacePermissions(table.getNamespaceAsString()).getGroup(groupName),
+        table, action)) {
+      return true;
+    }
+    // Check table level
+    return hasAccess(getTablePermissions(table).getGroup(groupName), table, 
action);
+  }
+
   public boolean authorize(User user, TableName table, byte[] family,
       byte[] qualifier, Permission.Action action) {
     if (authorizeUser(user, table, family, qualifier, action)) {
@@ -500,6 +556,22 @@ public class TableAuthManager {
     return false;
   }
 
+  public boolean hasAccess(User user, TableName table, Permission.Action 
action) {
+    if (userHasAccess(user, table, action)) {
+      return true;
+    }
+
+    String[] groups = user.getGroupNames();
+    if (groups != null) {
+      for (String group : groups) {
+        if (groupHasAccess(group, table, action)) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
   public boolean authorize(User user, TableName table, byte[] family,
       Permission.Action action) {
     return authorize(user, table, family, null, action);

http://git-wip-us.apache.org/repos/asf/hbase/blob/8a2c8415/hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java
----------------------------------------------------------------------
diff --git 
a/hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java
 
b/hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java
index 8fc4471..d3593cd 100644
--- 
a/hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java
+++ 
b/hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java
@@ -54,6 +54,7 @@ import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
 import org.apache.hadoop.hbase.protobuf.RequestConverter;
 import 
org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
 import 
org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableDescriptorsRequest;
+import 
org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableNamesRequest;
 import org.apache.hadoop.hbase.protobuf.generated.QuotaProtos.Quotas;
 import org.apache.hadoop.hbase.regionserver.HRegionServer;
 import org.apache.hadoop.hbase.testclassification.CoprocessorTests;
@@ -150,6 +151,8 @@ public class TestMasterObserver {
     private boolean postModifyTableHandlerCalled;
     private boolean preGetTableDescriptorsCalled;
     private boolean postGetTableDescriptorsCalled;
+    private boolean postGetTableNamesCalled;
+    private boolean preGetTableNamesCalled;
 
     public void enableBypass(boolean bypass) {
       this.bypass = bypass;
@@ -224,6 +227,8 @@ public class TestMasterObserver {
       postModifyTableHandlerCalled = false;
       preGetTableDescriptorsCalled = false;
       postGetTableDescriptorsCalled = false;
+      postGetTableNamesCalled = false;
+      preGetTableNamesCalled = false;
     }
 
     @Override
@@ -773,11 +778,6 @@ public class TestMasterObserver {
       postDeleteSnapshotCalled = true;
     }
 
-    @Override
-    public void 
preGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
-        List<TableName> tableNamesList, List<HTableDescriptor> descriptors) 
throws IOException {
-    }
-
     public boolean wasDeleteSnapshotCalled() {
       return preDeleteSnapshotCalled && postDeleteSnapshotCalled;
     }
@@ -1018,17 +1018,29 @@ public class TestMasterObserver {
 
     @Override
     public void 
postGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
-        List<HTableDescriptor> descriptors) throws IOException {
+        List<TableName> tableNamesList, List<HTableDescriptor> descriptors,
+        String regex) throws IOException {
+      postGetTableDescriptorsCalled = true;
+    }
+
+    public boolean wasGetTableDescriptorsCalled() {
+      return preGetTableDescriptorsCalled && postGetTableDescriptorsCalled;
     }
 
     @Override
-    public void 
postGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
+    public void preGetTableNames(ObserverContext<MasterCoprocessorEnvironment> 
ctx,
         List<HTableDescriptor> descriptors, String regex) throws IOException {
-      postGetTableDescriptorsCalled = true;
+      preGetTableNamesCalled = true;
     }
 
-    public boolean wasGetTableDescriptorsCalled() {
-      return preGetTableDescriptorsCalled && postGetTableDescriptorsCalled;
+    @Override
+    public void 
postGetTableNames(ObserverContext<MasterCoprocessorEnvironment> ctx,
+        List<HTableDescriptor> descriptors, String regex) throws IOException {
+      postGetTableNamesCalled = true;
+    }
+
+    public boolean wasGetTableNamesCalled() {
+      return preGetTableNamesCalled && postGetTableNamesCalled;
     }
 
     @Override
@@ -1552,4 +1564,19 @@ public class TestMasterObserver {
       cp.wasGetTableDescriptorsCalled());
   }
 
+  @Test
+  public void testTableNamesEnumeration() throws Exception {
+    MiniHBaseCluster cluster = UTIL.getHBaseCluster();
+
+    HMaster master = cluster.getMaster();
+    MasterCoprocessorHost host = master.getMasterCoprocessorHost();
+    CPMasterObserver cp = (CPMasterObserver)host.findCoprocessor(
+        CPMasterObserver.class.getName());
+    cp.resetStates();
+
+    master.getMasterRpcServices().getTableNames(null,
+        GetTableNamesRequest.newBuilder().build());
+    assertTrue("Coprocessor should be called on table names request",
+      cp.wasGetTableNamesCalled());
+  }
 }

http://git-wip-us.apache.org/repos/asf/hbase/blob/8a2c8415/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 9f268c9..fb7af84 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
@@ -26,6 +26,7 @@ import static org.junit.Assert.fail;
 
 import java.io.IOException;
 import java.security.PrivilegedAction;
+import java.util.Arrays;
 import java.util.List;
 
 import org.apache.commons.logging.Log;
@@ -264,7 +265,7 @@ public class TestAccessController extends SecureTestUtil {
     try {
       assertEquals(4, AccessControlClient.getUserPermissions(conf, 
TEST_TABLE.toString()).size());
     } catch (Throwable e) {
-      LOG.error("error during call of AccessControlClient.getUserPermissions. 
" + e.getStackTrace());
+      LOG.error("error during call of AccessControlClient.getUserPermissions. 
", e);
     }
   }
 
@@ -2059,11 +2060,14 @@ public class TestAccessController extends 
SecureTestUtil {
     AccessTestAction listTablesAction = new AccessTestAction() {
       @Override
       public Object run() throws Exception {
-        Admin admin = TEST_UTIL.getHBaseAdmin();
+        Connection unmanagedConnection =
+          ConnectionFactory.createConnection(TEST_UTIL.getConfiguration());
+        Admin admin = unmanagedConnection.getAdmin();
         try {
           admin.listTables();
         } finally {
           admin.close();
+          unmanagedConnection.close();
         }
         return null;
       }
@@ -2072,24 +2076,48 @@ public class TestAccessController extends 
SecureTestUtil {
     AccessTestAction getTableDescAction = new AccessTestAction() {
       @Override
       public Object run() throws Exception {
-        Admin admin = TEST_UTIL.getHBaseAdmin();
+        Connection unmanagedConnection =
+          ConnectionFactory.createConnection(TEST_UTIL.getConfiguration());
+        Admin admin = unmanagedConnection.getAdmin();
         try {
           admin.getTableDescriptor(TEST_TABLE.getTableName());
         } finally {
           admin.close();
+          unmanagedConnection.close();
         }
         return null;
       }
     };
 
-    verifyAllowed(listTablesAction, SUPERUSER, USER_ADMIN);
-    verifyDenied(listTablesAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, 
TABLE_ADMIN);
+    verifyAllowed(listTablesAction, SUPERUSER, USER_ADMIN, USER_CREATE, 
TABLE_ADMIN);
+    verifyDenied(listTablesAction, USER_RW, USER_RO, USER_NONE);
 
     verifyAllowed(getTableDescAction, SUPERUSER, USER_ADMIN, USER_CREATE, 
TABLE_ADMIN);
     verifyDenied(getTableDescAction, USER_RW, USER_RO, USER_NONE);
   }
 
   @Test
+  public void testTableNameEnumeration() throws Exception {
+    AccessTestAction listTablesAction = new AccessTestAction() {
+      @Override
+      public Object run() throws Exception {
+        Connection unmanagedConnection =
+            ConnectionFactory.createConnection(TEST_UTIL.getConfiguration());
+        Admin admin = unmanagedConnection.getAdmin();
+        try {
+          return Arrays.asList(admin.listTableNames());
+        } finally {
+          admin.close();
+          unmanagedConnection.close();
+        }
+      }
+    };
+
+    verifyAllowed(listTablesAction, SUPERUSER, USER_ADMIN, USER_CREATE, 
USER_RW, USER_RO);
+    verifyDenied(listTablesAction, USER_NONE);
+  }
+
+  @Test
   public void testTableDeletion() throws Exception {
     User TABLE_ADMIN = User.createUserForTesting(conf, "TestUser", new 
String[0]);
 
@@ -2166,7 +2194,7 @@ public class TestAccessController extends SecureTestUtil {
       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());
+      LOG.error("error during call of AccessControlClient.grant. ", e);
     }
 
     // Now testGrantRevoke should be able to read also
@@ -2177,7 +2205,7 @@ public class TestAccessController extends SecureTestUtil {
       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());
+      LOG.error("error during call of AccessControlClient.revoke ", e);
     }
 
     // Now testGrantRevoke shouldn't be able read
@@ -2207,7 +2235,7 @@ public class TestAccessController extends SecureTestUtil {
       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());
+      LOG.error("error during call of AccessControlClient.grant. ", e);
     }
 
     // Now testNS should be able to read also
@@ -2218,7 +2246,7 @@ public class TestAccessController extends SecureTestUtil {
       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());
+      LOG.error("error during call of AccessControlClient.revoke ", e);
     }
 
     // Now testNS shouldn't be able read
@@ -2451,8 +2479,7 @@ public class TestAccessController extends SecureTestUtil {
         try {
           return AccessControlClient.getUserPermissions(conf, regex);
         } catch (Throwable e) {
-          LOG.error("error during call of 
AccessControlClient.getUserPermissions. "
-              + e.getStackTrace());
+          LOG.error("error during call of 
AccessControlClient.getUserPermissions.", e);
           return null;
         }
       }
@@ -2462,10 +2489,12 @@ public class TestAccessController extends 
SecureTestUtil {
   @Test
   public void testAccessControlClientUserPerms() throws Exception {
     // adding default prefix explicitly as it is not included in the table 
name.
-    final String regex = TEST_TABLE.getTableName().getNamespaceAsString() + ":"
-        + TEST_TABLE.getTableName().getNameAsString();
+    assertEquals(NamespaceDescriptor.DEFAULT_NAMESPACE_NAME_STR,
+                 TEST_TABLE.getTableName().getNamespaceAsString());
+    final String regex = NamespaceDescriptor.DEFAULT_NAMESPACE_NAME_STR +
+      TableName.NAMESPACE_DELIM + TEST_TABLE.getTableName().getNameAsString();
     User testUserPerms = User.createUserForTesting(conf, "testUserPerms", new 
String[0]);
-    assertNull(testUserPerms.runAs(getPrivilegedAction(regex)));
+    assertEquals(0, testUserPerms.runAs(getPrivilegedAction(regex)).size());
     // Grant TABLE ADMIN privs to testUserPerms
     grantOnTable(TEST_UTIL, testUserPerms.getShortName(), 
TEST_TABLE.getTableName(), null,
       null, Action.ADMIN);
@@ -2475,12 +2504,12 @@ public class TestAccessController extends 
SecureTestUtil {
     assertEquals(5, perms.size());
   }
 
-
-
   @Test
-  public void testAccessControllerRegexHandling() throws Exception {
+  public void testAccessControllerUserPermsRegexHandling() throws Exception {
     User testRegexHandler = User.createUserForTesting(conf, 
"testRegexHandling", new String[0]);
-    String tableName = "testRegex";
+
+    final String REGEX_ALL_TABLES = ".*";
+    final String tableName = "testRegex";
     final TableName table1 = TableName.valueOf(tableName);
     final byte[] family = Bytes.toBytes("f1");
 
@@ -2494,20 +2523,32 @@ public class TestAccessController extends 
SecureTestUtil {
     // creating the ns and table in it
     String ns = "testNamespace";
     NamespaceDescriptor desc = NamespaceDescriptor.create(ns).build();
-    final TableName table2 = TableName.valueOf(ns + ":" + tableName);
+    final TableName table2 = TableName.valueOf(ns, tableName);
     TEST_UTIL.getMiniHBaseCluster().getMaster().createNamespace(desc);
     htd = new HTableDescriptor(table2);
     htd.addFamily(new HColumnDescriptor(family));
     admin.createTable(htd);
+    TEST_UTIL.waitUntilAllRegionsAssigned(table2);
+
+    // Verify that we can read sys-tables
+    String aclTableName = AccessControlLists.ACL_TABLE_NAME.getNameAsString();
+    assertEquals(1, SUPERUSER.runAs(getPrivilegedAction(aclTableName)).size());
+    assertEquals(0, 
testRegexHandler.runAs(getPrivilegedAction(aclTableName)).size());
 
     // Grant TABLE ADMIN privs to testUserPerms
+    assertEquals(0, 
testRegexHandler.runAs(getPrivilegedAction(REGEX_ALL_TABLES)).size());
     grantOnTable(TEST_UTIL, testRegexHandler.getShortName(), table1, null, 
null, Action.ADMIN);
+    assertEquals(2, 
testRegexHandler.runAs(getPrivilegedAction(REGEX_ALL_TABLES)).size());
     grantOnTable(TEST_UTIL, testRegexHandler.getShortName(), table2, null, 
null, Action.ADMIN);
+    assertEquals(4, 
testRegexHandler.runAs(getPrivilegedAction(REGEX_ALL_TABLES)).size());
 
     // USER_ADMIN, testUserPerms must have a row each.
     assertEquals(2, 
testRegexHandler.runAs(getPrivilegedAction(tableName)).size());
-    assertEquals(2, testRegexHandler.runAs(getPrivilegedAction("default:" + 
tableName)).size());
-    assertEquals(2, testRegexHandler.runAs(getPrivilegedAction(ns + ":" + 
tableName)).size());
+    assertEquals(2, testRegexHandler.runAs(getPrivilegedAction(
+          NamespaceDescriptor.DEFAULT_NAMESPACE_NAME_STR + 
TableName.NAMESPACE_DELIM + tableName)
+        ).size());
+    assertEquals(2, testRegexHandler.runAs(getPrivilegedAction(
+        ns + TableName.NAMESPACE_DELIM + tableName)).size());
     assertEquals(0, 
testRegexHandler.runAs(getPrivilegedAction("notMatchingAny")).size());
 
     TEST_UTIL.deleteTable(table1);

http://git-wip-us.apache.org/repos/asf/hbase/blob/8a2c8415/hbase-shell/src/main/ruby/hbase/admin.rb
----------------------------------------------------------------------
diff --git a/hbase-shell/src/main/ruby/hbase/admin.rb 
b/hbase-shell/src/main/ruby/hbase/admin.rb
index 2c8828e..748a41c 100644
--- a/hbase-shell/src/main/ruby/hbase/admin.rb
+++ b/hbase-shell/src/main/ruby/hbase/admin.rb
@@ -43,7 +43,7 @@ module Hbase
     
#----------------------------------------------------------------------------------------------
     # Returns a list of tables in hbase
     def list(regex = ".*")
-      @admin.getTableNames(regex).to_a
+      @admin.listTableNames(regex).map { |t| t.getNameAsString }
     end
 
     
#----------------------------------------------------------------------------------------------

Reply via email to