hbase-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mberto...@apache.org
Subject hbase git commit: HBASE-12925 Use acl cache for doing access control checks in prepare and clean phases of Bulkloading (Srikanth Srungarapu)
Date Tue, 27 Jan 2015 13:34:54 GMT
Repository: hbase
Updated Branches:
  refs/heads/0.98 a837d0a04 -> 9115f303c


HBASE-12925 Use acl cache for doing access control checks in prepare and clean phases of Bulkloading
(Srikanth Srungarapu)


Project: http://git-wip-us.apache.org/repos/asf/hbase/repo
Commit: http://git-wip-us.apache.org/repos/asf/hbase/commit/9115f303
Tree: http://git-wip-us.apache.org/repos/asf/hbase/tree/9115f303
Diff: http://git-wip-us.apache.org/repos/asf/hbase/diff/9115f303

Branch: refs/heads/0.98
Commit: 9115f303c19f01264272b4472108ff3e4b44907f
Parents: a837d0a
Author: Matteo Bertozzi <matteo.bertozzi@cloudera.com>
Authored: Tue Jan 27 13:33:56 2015 +0000
Committer: Matteo Bertozzi <matteo.bertozzi@cloudera.com>
Committed: Tue Jan 27 13:33:56 2015 +0000

----------------------------------------------------------------------
 .../hbase/security/access/AccessController.java | 83 +++++++++-----------
 .../hbase/security/access/TableAuthManager.java | 78 +++++++++++++++++-
 .../security/access/TestAccessController.java   | 27 ++++++-
 3 files changed, 137 insertions(+), 51 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/hbase/blob/9115f303/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java
----------------------------------------------------------------------
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 b564f64..cffcf10 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
@@ -18,7 +18,6 @@ import java.io.IOException;
 import java.net.InetAddress;
 import java.security.PrivilegedExceptionAction;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -30,7 +29,6 @@ import java.util.TreeSet;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.apache.hadoop.hbase.classification.InterfaceAudience;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.hbase.Cell;
 import org.apache.hadoop.hbase.CellScanner;
@@ -51,6 +49,7 @@ import org.apache.hadoop.hbase.ServerName;
 import org.apache.hadoop.hbase.TableName;
 import org.apache.hadoop.hbase.Tag;
 import org.apache.hadoop.hbase.catalog.MetaReader;
+import org.apache.hadoop.hbase.classification.InterfaceAudience;
 import org.apache.hadoop.hbase.client.Append;
 import org.apache.hadoop.hbase.client.Delete;
 import org.apache.hadoop.hbase.client.Durability;
@@ -431,6 +430,36 @@ public class AccessController extends BaseMasterAndRegionObserver
   }
 
   /**
+   * Authorizes that the current user has any of the given permissions to access the table.
+   *
+   * @param tableName Table requested
+   * @param permissions Actions being requested
+   * @throws IOException if obtaining the current user fails
+   * @throws AccessDeniedException if user has no authorization
+   */
+  private void requireAccess(String request, TableName tableName,
+      Action... permissions) throws IOException {
+    User user = getActiveUser();
+    AuthResult result = null;
+
+    for (Action permission : permissions) {
+      if (authManager.hasAccess(user, tableName, permission)) {
+        result = AuthResult.allow(request, "Table permission granted", user,
+                                  permission, tableName, null, null);
+        break;
+      } else {
+        // rest of the world
+        result = AuthResult.deny(request, "Insufficient permissions", user,
+                                 permission, tableName, null, null);
+      }
+    }
+    logResult(result);
+    if (!result.isAllowed()) {
+      throw new AccessDeniedException("Insufficient permissions " + result.toContextString());
+    }
+  }
+
+  /**
    * Authorizes that the current user has global privileges for the given action.
    * @param perm The action being requested
    * @throws IOException if obtaining the current user fails
@@ -1000,7 +1029,7 @@ public class AccessController extends BaseMasterAndRegionObserver
       TableName tableName, final HTableDescriptor htd) throws IOException {
     final Configuration conf = c.getEnvironment().getConfiguration();
     // default the table owner to current user, if not specified.
-    final String owner = (htd.getOwnerString() != null) ? htd.getOwnerString() : 
+    final String owner = (htd.getOwnerString() != null) ? htd.getOwnerString() :
       getActiveUser().getShortName();
     User.runAsLoginUser(new PrivilegedExceptionAction<Void>() {
       @Override
@@ -1903,34 +1932,6 @@ public class AccessController extends BaseMasterAndRegionObserver
     }
   }
 
-  private AuthResult hasSomeAccess(RegionCoprocessorEnvironment e, String method, Action
action)
-      throws IOException {
-    User requestUser = getActiveUser();
-    final TableName tableName = e.getRegion().getTableDesc().getTableName();
-    AuthResult authResult = permissionGranted(method, requestUser, action, e,
-      Collections.EMPTY_MAP);
-    if (!authResult.isAllowed()) {
-      final Configuration conf = e.getConfiguration();
-      // hasSomeAccess is called from bulkload pre hooks
-      List<UserPermission> perms =
-        User.runAsLoginUser(new PrivilegedExceptionAction<List<UserPermission>>()
{
-          @Override
-          public List<UserPermission> run() throws Exception {
-            return AccessControlLists.getUserTablePermissions(conf, tableName);
-          }
-        });
-      for (UserPermission userPerm: perms) {
-        for (Action userAction: userPerm.getActions()) {
-          if (userAction.equals(action)) {
-            return AuthResult.allow(method, "Access allowed", requestUser,
-              action, tableName, null, null);
-          }
-        }
-      }
-    }
-    return authResult;
-  }
-
   /**
    * Authorization check for
    * SecureBulkLoadProtocol.prepareBulkLoad()
@@ -1941,14 +1942,8 @@ public class AccessController extends BaseMasterAndRegionObserver
   @Override
   public void prePrepareBulkLoad(ObserverContext<RegionCoprocessorEnvironment> ctx,
                                  PrepareBulkLoadRequest request) throws IOException {
-    RegionCoprocessorEnvironment e = ctx.getEnvironment();
-
-    AuthResult authResult = hasSomeAccess(e, "prePrepareBulkLoad", Action.CREATE);
-    logResult(authResult);
-    if (!authResult.isAllowed()) {
-      throw new AccessDeniedException("Insufficient permissions (table=" +
-        e.getRegion().getTableDesc().getTableName() + ", action=CREATE)");
-    }
+    requireAccess("prePareBulkLoad",
+        ctx.getEnvironment().getRegion().getTableDesc().getTableName(), Action.CREATE);
   }
 
   /**
@@ -1961,14 +1956,8 @@ public class AccessController extends BaseMasterAndRegionObserver
   @Override
   public void preCleanupBulkLoad(ObserverContext<RegionCoprocessorEnvironment> ctx,
                                  CleanupBulkLoadRequest request) throws IOException {
-    RegionCoprocessorEnvironment e = ctx.getEnvironment();
-
-    AuthResult authResult = hasSomeAccess(e, "preCleanupBulkLoad", Action.CREATE);
-    logResult(authResult);
-    if (!authResult.isAllowed()) {
-      throw new AccessDeniedException("Insufficient permissions (table=" +
-        e.getRegion().getTableDesc().getTableName() + ", action=CREATE)");
-    }
+    requireAccess("preCleanupBulkLoad",
+        ctx.getEnvironment().getRegion().getTableDesc().getTableName(), Action.CREATE);
   }
 
   /* ---- EndpointObserver implementation ---- */

http://git-wip-us.apache.org/repos/asf/hbase/blob/9115f303/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 f2983ad..6ca40e6 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/9115f303/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 e10e0f1..ed885e2 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
@@ -257,7 +257,7 @@ public class TestAccessController extends SecureTestUtil {
 
     grantOnTable(TEST_UTIL, USER_ADMIN_CF.getShortName(),
       TEST_TABLE.getTableName(), TEST_FAMILY,
-      null, Permission.Action.ADMIN);
+      null, Permission.Action.ADMIN, Permission.Action.CREATE);
 
     assertEquals(5, AccessControlLists.getTablePermissions(conf, TEST_TABLE.getTableName()).size());
     try {
@@ -2370,4 +2370,29 @@ public class TestAccessController extends SecureTestUtil {
       throw new HBaseIOException(e);
     }
   }
+
+  private void verifyAnyCreate(AccessTestAction action) throws Exception {
+    verifyAllowed(action, SUPERUSER, USER_ADMIN, USER_OWNER, USER_CREATE, USER_ADMIN_CF);
+    verifyDenied(action, USER_NONE, USER_RO, USER_RW);
+  }
+
+  @Test
+  public void testPrepareAndCleanBulkLoad() throws Exception {
+    AccessTestAction prepareBulkLoadAction = new AccessTestAction() {
+      @Override
+      public Object run() throws Exception {
+        ACCESS_CONTROLLER.prePrepareBulkLoad(ObserverContext.createAndPrepare(RCP_ENV, null),
null);
+        return null;
+      }
+    };
+    AccessTestAction cleanupBulkLoadAction = new AccessTestAction() {
+      @Override
+      public Object run() throws Exception {
+        ACCESS_CONTROLLER.preCleanupBulkLoad(ObserverContext.createAndPrepare(RCP_ENV, null),
null);
+        return null;
+      }
+    };
+    verifyAnyCreate(prepareBulkLoadAction);
+    verifyAnyCreate(cleanupBulkLoadAction);
+  }
 }


Mime
View raw message