HBASE-5342 Grant/Revoke global permissions (Matteo Bertozzi)

git-svn-id: https://svn.apache.org/repos/asf/hbase/trunk@1337499 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Zhihong Yu 2012-05-12 10:25:22 +00:00
parent 0498c89c72
commit 75bf5b04c4
15 changed files with 540 additions and 309 deletions

View File

@ -79,6 +79,7 @@ public class AccessControlLists {
/** Internal storage table for access control lists */
public static final String ACL_TABLE_NAME_STR = "_acl_";
public static final byte[] ACL_TABLE_NAME = Bytes.toBytes(ACL_TABLE_NAME_STR);
public static final byte[] ACL_GLOBAL_NAME = ACL_TABLE_NAME;
/** 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);
@ -117,31 +118,20 @@ public class AccessControlLists {
}
/**
* Stores a new table permission grant in the access control lists table.
* Stores a new user permission grant in the access control lists table.
* @param conf the configuration
* @param tableName the table to which access is being granted
* @param username the user or group being granted the permission
* @param perm the details of the permission being granted
* @param userPerm the details of the permission to be granted
* @throws IOException in the case of an error accessing the metadata table
*/
static void addTablePermission(Configuration conf,
byte[] tableName, String username, TablePermission perm)
throws IOException {
static void addUserPermission(Configuration conf, UserPermission userPerm)
throws IOException {
Permission.Action[] actions = userPerm.getActions();
Put p = new Put(tableName);
byte[] key = Bytes.toBytes(username);
if (perm.getFamily() != null && perm.getFamily().length > 0) {
key = Bytes.add(key,
Bytes.add(new byte[]{ACL_KEY_DELIMITER}, perm.getFamily()));
if (perm.getQualifier() != null && perm.getQualifier().length > 0) {
key = Bytes.add(key,
Bytes.add(new byte[]{ACL_KEY_DELIMITER}, perm.getQualifier()));
}
}
Put p = new Put(userPerm.isGlobal() ? ACL_GLOBAL_NAME : userPerm.getTable());
byte[] key = userPermissionKey(userPerm);
TablePermission.Action[] actions = perm.getActions();
if ((actions == null) || (actions.length == 0)) {
LOG.warn("No actions associated with user '"+username+"'");
LOG.warn("No actions associated with user '"+Bytes.toString(userPerm.getUser())+"'");
return;
}
@ -152,7 +142,7 @@ public class AccessControlLists {
p.add(ACL_LIST_FAMILY, key, value);
if (LOG.isDebugEnabled()) {
LOG.debug("Writing permission for table "+
Bytes.toString(tableName)+" "+
Bytes.toString(userPerm.getTable())+" "+
Bytes.toString(key)+": "+Bytes.toStringBinary(value)
);
}
@ -175,34 +165,17 @@ public class AccessControlLists {
* column qualifier "info:colA") will have no effect.
*
* @param conf the configuration
* @param tableName the table of the current permission grant
* @param userName the user or group currently granted the permission
* @param perm the details of the permission to be revoked
* @param userPerm the details of the permission to be revoked
* @throws IOException if there is an error accessing the metadata table
*/
static void removeTablePermission(Configuration conf,
byte[] tableName, String userName, TablePermission perm)
throws IOException {
static void removeUserPermission(Configuration conf, UserPermission userPerm)
throws IOException {
Delete d = new Delete(userPerm.isGlobal() ? ACL_GLOBAL_NAME : userPerm.getTable());
byte[] key = userPermissionKey(userPerm);
Delete d = new Delete(tableName);
byte[] key = null;
if (perm.getFamily() != null && perm.getFamily().length > 0) {
key = Bytes.toBytes(userName + ACL_KEY_DELIMITER +
Bytes.toString(perm.getFamily()));
if (perm.getQualifier() != null && perm.getQualifier().length > 0) {
key = Bytes.toBytes(userName + ACL_KEY_DELIMITER +
Bytes.toString(perm.getFamily()) + ACL_KEY_DELIMITER +
Bytes.toString(perm.getQualifier()));
} else {
key = Bytes.toBytes(userName + ACL_KEY_DELIMITER +
Bytes.toString(perm.getFamily()));
}
} else {
key = Bytes.toBytes(userName);
}
if (LOG.isDebugEnabled()) {
LOG.debug("Removing permission for user '" + userName+ "': "+
perm.toString());
LOG.debug("Removing permission "+ userPerm.toString());
}
d.deleteColumns(ACL_LIST_FAMILY, key);
HTable acls = null;
@ -214,6 +187,48 @@ public class AccessControlLists {
}
}
/**
* Remove specified table from the _acl_ table.
*/
static void removeTablePermissions(Configuration conf, byte[] tableName)
throws IOException{
Delete d = new Delete(tableName);
if (LOG.isDebugEnabled()) {
LOG.debug("Removing permissions of removed table "+ Bytes.toString(tableName));
}
HTable acls = null;
try {
acls = new HTable(conf, ACL_TABLE_NAME);
acls.delete(d);
} finally {
if (acls != null) acls.close();
}
}
/**
* Build qualifier key from user permission:
* username
* username,family
* username,family,qualifier
*/
static byte[] userPermissionKey(UserPermission userPerm) {
byte[] qualifier = userPerm.getQualifier();
byte[] family = userPerm.getFamily();
byte[] key = userPerm.getUser();
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.
@ -328,12 +343,13 @@ public class AccessControlLists {
static ListMultimap<String,TablePermission> getTablePermissions(
Configuration conf, byte[] tableName)
throws IOException {
if (tableName == null) tableName = ACL_TABLE_NAME;
/* TODO: -ROOT- and .META. cannot easily be handled because they must be
* online before _acl_ table. Can anything be done here?
*/
if (Bytes.equals(tableName, HConstants.ROOT_TABLE_NAME) ||
Bytes.equals(tableName, HConstants.META_TABLE_NAME) ||
Bytes.equals(tableName, AccessControlLists.ACL_TABLE_NAME)) {
Bytes.equals(tableName, HConstants.META_TABLE_NAME)) {
return ArrayListMultimap.create(0,0);
}

View File

@ -14,17 +14,19 @@
package org.apache.hadoop.hbase.security.access;
import java.io.*;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.TreeSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.CoprocessorEnvironment;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HRegionInfo;
@ -188,12 +190,10 @@ public class AccessController extends BaseRegionObserver
for (Map.Entry<byte[],ListMultimap<String,TablePermission>> t:
tables.entrySet()) {
byte[] table = t.getKey();
String tableName = Bytes.toString(table);
ListMultimap<String,TablePermission> perms = t.getValue();
byte[] serialized = AccessControlLists.writePermissionsAsBytes(perms,
regionEnv.getConfiguration());
this.authManager.getZKPermissionWatcher().writeToZookeeper(tableName,
serialized);
this.authManager.getZKPermissionWatcher().writeToZookeeper(table, serialized);
}
}
@ -204,31 +204,28 @@ public class AccessController extends BaseRegionObserver
*/
void updateACL(RegionCoprocessorEnvironment e,
final Map<byte[], List<KeyValue>> familyMap) {
Set<String> tableSet = new HashSet<String>();
Set<byte[]> tableSet = new TreeSet<byte[]>(Bytes.BYTES_COMPARATOR);
for (Map.Entry<byte[], List<KeyValue>> f : familyMap.entrySet()) {
List<KeyValue> kvs = f.getValue();
for (KeyValue kv: kvs) {
if (Bytes.compareTo(kv.getBuffer(), kv.getFamilyOffset(),
if (Bytes.equals(kv.getBuffer(), kv.getFamilyOffset(),
kv.getFamilyLength(), AccessControlLists.ACL_LIST_FAMILY, 0,
AccessControlLists.ACL_LIST_FAMILY.length) == 0) {
String tableName = Bytes.toString(kv.getRow());
tableSet.add(tableName);
AccessControlLists.ACL_LIST_FAMILY.length)) {
tableSet.add(kv.getRow());
}
}
}
for (String tableName: tableSet) {
ZKPermissionWatcher zkw = this.authManager.getZKPermissionWatcher();
Configuration conf = regionEnv.getConfiguration();
for (byte[] tableName: tableSet) {
try {
ListMultimap<String,TablePermission> perms =
AccessControlLists.getTablePermissions(regionEnv.getConfiguration(),
Bytes.toBytes(tableName));
byte[] serialized = AccessControlLists.writePermissionsAsBytes(
perms, regionEnv.getConfiguration());
this.authManager.getZKPermissionWatcher().writeToZookeeper(tableName,
serialized);
AccessControlLists.getTablePermissions(conf, tableName);
byte[] serialized = AccessControlLists.writePermissionsAsBytes(perms, conf);
zkw.writeToZookeeper(tableName, serialized);
} catch (IOException ex) {
LOG.error("Failed updating permissions mirror for '" + tableName +
"'", ex);
LOG.error("Failed updating permissions mirror for '" + tableName + "'", ex);
}
}
}
@ -256,29 +253,40 @@ public class AccessController extends BaseRegionObserver
// 1. All users need read access to .META. and -ROOT- tables.
// this is a very common operation, so deal with it quickly.
if ((hri.isRootRegion() || hri.isMetaRegion()) &&
(permRequest == TablePermission.Action.READ)) {
return AuthResult.allow("All users allowed", user, permRequest,
hri.getTableName());
if (hri.isRootRegion() || hri.isMetaRegion()) {
if (permRequest == TablePermission.Action.READ) {
return AuthResult.allow("All users allowed", user, permRequest, tableName);
}
}
if (user == null) {
return AuthResult.deny("No user associated with request!", null,
permRequest, hri.getTableName());
return AuthResult.deny("No user associated with request!", null, permRequest, tableName);
}
// Users with CREATE/ADMIN rights need to modify .META. and _acl_ table
// e.g. When a new table is created a new entry in .META. is added,
// so the user need to be allowed to write on it.
// e.g. When a table is removed an entry is removed from .META. and _acl_
// and the user need to be allowed to write on both tables.
if (permRequest == TablePermission.Action.WRITE &&
(hri.isRootRegion() || hri.isMetaRegion() ||
Bytes.equals(tableName, AccessControlLists.ACL_GLOBAL_NAME)) &&
(authManager.authorize(user, Permission.Action.CREATE) ||
authManager.authorize(user, Permission.Action.ADMIN)))
{
return AuthResult.allow("Table permission granted", user, permRequest, tableName);
}
// 2. The table owner has full privileges
String owner = htd.getOwnerString();
if (user.getShortName().equals(owner)) {
// owner of the table has full access
return AuthResult.allow("User is table owner", user, permRequest,
hri.getTableName());
return AuthResult.allow("User is table owner", user, permRequest, tableName);
}
// 3. check for the table-level, if successful we can short-circuit
if (authManager.authorize(user, tableName, (byte[])null, permRequest)) {
return AuthResult.allow("Table permission granted", user,
permRequest, tableName);
return AuthResult.allow("Table permission granted", user, permRequest, tableName);
}
// 4. check permissions against the requested families
@ -350,6 +358,7 @@ public class AccessController extends BaseRegionObserver
// for non-rpc handling, fallback to system user
user = User.getCurrent();
}
return user;
}
@ -497,10 +506,16 @@ public class AccessController extends BaseRegionObserver
desc.setOwner(owner);
}
}
@Override
public void preCreateTableHandler(ObserverContext<MasterCoprocessorEnvironment> c,
HTableDescriptor desc, HRegionInfo[] regions) throws IOException {}
@Override
public void postCreateTable(ObserverContext<MasterCoprocessorEnvironment> c,
HTableDescriptor desc, HRegionInfo[] regions) throws IOException {}
@Override
public void postCreateTableHandler(ObserverContext<MasterCoprocessorEnvironment> c,
HTableDescriptor desc, HRegionInfo[] regions) throws IOException {}
@Override
public void preDeleteTable(ObserverContext<MasterCoprocessorEnvironment> c,
@ -512,9 +527,16 @@ public class AccessController extends BaseRegionObserver
}
}
@Override
public void postDeleteTable(ObserverContext<MasterCoprocessorEnvironment> c,
public void preDeleteTableHandler(ObserverContext<MasterCoprocessorEnvironment> c,
byte[] tableName) throws IOException {}
@Override
public void postDeleteTable(ObserverContext<MasterCoprocessorEnvironment> c,
byte[] tableName) throws IOException {
AccessControlLists.removeTablePermissions(c.getEnvironment().getConfiguration(), tableName);
}
@Override
public void postDeleteTableHandler(ObserverContext<MasterCoprocessorEnvironment> c,
byte[] tableName) throws IOException {}
@Override
public void preModifyTable(ObserverContext<MasterCoprocessorEnvironment> c,
@ -522,8 +544,14 @@ public class AccessController extends BaseRegionObserver
requirePermission(Permission.Action.CREATE);
}
@Override
public void preModifyTableHandler(ObserverContext<MasterCoprocessorEnvironment> c,
byte[] tableName, HTableDescriptor htd) throws IOException {}
@Override
public void postModifyTable(ObserverContext<MasterCoprocessorEnvironment> c,
byte[] tableName, HTableDescriptor htd) throws IOException {}
@Override
public void postModifyTableHandler(ObserverContext<MasterCoprocessorEnvironment> c,
byte[] tableName, HTableDescriptor htd) throws IOException {}
@Override
@ -532,9 +560,14 @@ public class AccessController extends BaseRegionObserver
requirePermission(Permission.Action.CREATE);
}
@Override
public void preAddColumnHandler(ObserverContext<MasterCoprocessorEnvironment> c,
byte[] tableName, HColumnDescriptor column) throws IOException {}
@Override
public void postAddColumn(ObserverContext<MasterCoprocessorEnvironment> c,
byte[] tableName, HColumnDescriptor column) throws IOException {}
@Override
public void postAddColumnHandler(ObserverContext<MasterCoprocessorEnvironment> c,
byte[] tableName, HColumnDescriptor column) throws IOException {}
@Override
public void preModifyColumn(ObserverContext<MasterCoprocessorEnvironment> c,
@ -542,8 +575,14 @@ public class AccessController extends BaseRegionObserver
requirePermission(Permission.Action.CREATE);
}
@Override
public void preModifyColumnHandler(ObserverContext<MasterCoprocessorEnvironment> c,
byte[] tableName, HColumnDescriptor descriptor) throws IOException {}
@Override
public void postModifyColumn(ObserverContext<MasterCoprocessorEnvironment> c,
byte[] tableName, HColumnDescriptor descriptor) throws IOException {}
@Override
public void postModifyColumnHandler(ObserverContext<MasterCoprocessorEnvironment> c,
byte[] tableName, HColumnDescriptor descriptor) throws IOException {}
@Override
@ -552,9 +591,14 @@ public class AccessController extends BaseRegionObserver
requirePermission(Permission.Action.CREATE);
}
@Override
public void preDeleteColumnHandler(ObserverContext<MasterCoprocessorEnvironment> c,
byte[] tableName, byte[] col) throws IOException {}
@Override
public void postDeleteColumn(ObserverContext<MasterCoprocessorEnvironment> c,
byte[] tableName, byte[] col) throws IOException {}
@Override
public void postDeleteColumnHandler(ObserverContext<MasterCoprocessorEnvironment> c,
byte[] tableName, byte[] col) throws IOException {}
@Override
public void preEnableTable(ObserverContext<MasterCoprocessorEnvironment> c,
@ -566,8 +610,14 @@ public class AccessController extends BaseRegionObserver
}
}
@Override
public void preEnableTableHandler(ObserverContext<MasterCoprocessorEnvironment> c,
byte[] tableName) throws IOException {}
@Override
public void postEnableTable(ObserverContext<MasterCoprocessorEnvironment> c,
byte[] tableName) throws IOException {}
@Override
public void postEnableTableHandler(ObserverContext<MasterCoprocessorEnvironment> c,
byte[] tableName) throws IOException {}
@Override
public void preDisableTable(ObserverContext<MasterCoprocessorEnvironment> c,
@ -579,8 +629,14 @@ public class AccessController extends BaseRegionObserver
}
}
@Override
public void preDisableTableHandler(ObserverContext<MasterCoprocessorEnvironment> c,
byte[] tableName) throws IOException {}
@Override
public void postDisableTable(ObserverContext<MasterCoprocessorEnvironment> c,
byte[] tableName) throws IOException {}
@Override
public void postDisableTableHandler(ObserverContext<MasterCoprocessorEnvironment> c,
byte[] tableName) throws IOException {}
@Override
public void preMove(ObserverContext<MasterCoprocessorEnvironment> c,
@ -892,10 +948,10 @@ public class AccessController extends BaseRegionObserver
private void requireScannerOwner(InternalScanner s)
throws AccessDeniedException {
if (RequestContext.isInRequestContext()) {
String requestUserName = RequestContext.getRequestUserName();
String owner = scannerOwners.get(s);
if (owner != null && !owner.equals(RequestContext.getRequestUserName())) {
throw new AccessDeniedException("User '"+
RequestContext.getRequestUserName()+"' is not the scanner owner!");
if (owner != null && !owner.equals(requestUserName)) {
throw new AccessDeniedException("User '"+ requestUserName +"' is not the scanner owner!");
}
}
}
@ -906,24 +962,20 @@ public class AccessController extends BaseRegionObserver
* This will be restricted by both client side and endpoint implementations.
*/
@Override
public void grant(byte[] user, TablePermission permission)
public void grant(UserPermission userPermission)
throws IOException {
// verify it's only running at .acl.
if (aclRegion) {
if (LOG.isDebugEnabled()) {
LOG.debug("Received request to grant access permission to '"
+ Bytes.toString(user) + "'. "
+ permission.toString());
LOG.debug("Received request to grant access permission " + userPermission.toString());
}
requirePermission(Permission.Action.ADMIN);
AccessControlLists.addTablePermission(regionEnv.getConfiguration(),
permission.getTable(), Bytes.toString(user), permission);
AccessControlLists.addUserPermission(regionEnv.getConfiguration(), userPermission);
if (AUDITLOG.isTraceEnabled()) {
// audit log should store permission changes in addition to auth results
AUDITLOG.trace("Granted user '" + Bytes.toString(user) + "' permission "
+ permission.toString());
AUDITLOG.trace("Granted permission " + userPermission.toString());
}
} else {
throw new CoprocessorException(AccessController.class, "This method " +
@ -933,24 +985,29 @@ public class AccessController extends BaseRegionObserver
}
@Override
public void revoke(byte[] user, TablePermission permission)
@Deprecated
public void grant(byte[] user, TablePermission permission)
throws IOException {
grant(new UserPermission(user, permission.getTable(),
permission.getFamily(), permission.getQualifier(),
permission.getActions()));
}
@Override
public void revoke(UserPermission userPermission)
throws IOException{
// only allowed to be called on _acl_ region
if (aclRegion) {
if (LOG.isDebugEnabled()) {
LOG.debug("Received request to revoke access permission for '"
+ Bytes.toString(user) + "'. "
+ permission.toString());
LOG.debug("Received request to revoke access permission " + userPermission.toString());
}
requirePermission(Permission.Action.ADMIN);
AccessControlLists.removeTablePermission(regionEnv.getConfiguration(),
permission.getTable(), Bytes.toString(user), permission);
AccessControlLists.removeUserPermission(regionEnv.getConfiguration(), userPermission);
if (AUDITLOG.isTraceEnabled()) {
// audit log should record all permission changes
AUDITLOG.trace("Revoked user '" + Bytes.toString(user) + "' permission "
+ permission.toString());
AUDITLOG.trace("Revoked permission " + userPermission.toString());
}
} else {
throw new CoprocessorException(AccessController.class, "This method " +
@ -959,6 +1016,15 @@ public class AccessController extends BaseRegionObserver
}
}
@Override
@Deprecated
public void revoke(byte[] user, TablePermission permission)
throws IOException {
revoke(new UserPermission(user, permission.getTable(),
permission.getFamily(), permission.getQualifier(),
permission.getActions()));
}
@Override
public List<UserPermission> getUserPermissions(final byte[] tableName)
throws IOException {
@ -1038,7 +1104,7 @@ public class AccessController extends BaseRegionObserver
return tableName;
}
private String getTableOwner(MasterCoprocessorEnvironment e,
private String getTableOwner(MasterCoprocessorEnvironment e,
byte[] tableName) throws IOException {
HTableDescriptor htd = e.getTable(tableName).getTableDescriptor();
return htd.getOwnerString();
@ -1049,84 +1115,4 @@ public class AccessController extends BaseRegionObserver
String activeUser = getActiveUser().getShortName();
return activeUser.equals(getTableOwner(e, tableName));
}
@Override
public void preCreateTableHandler(ObserverContext<MasterCoprocessorEnvironment> ctx,
HTableDescriptor desc, HRegionInfo[] regions) throws IOException {
}
@Override
public void postCreateTableHandler(ObserverContext<MasterCoprocessorEnvironment> ctx,
HTableDescriptor desc, HRegionInfo[] regions) throws IOException {
}
@Override
public void preDeleteTableHandler(ObserverContext<MasterCoprocessorEnvironment> ctx,
byte[] tableName) throws IOException {
}
@Override
public void postDeleteTableHandler(ObserverContext<MasterCoprocessorEnvironment> ctx,
byte[] tableName) throws IOException {
}
@Override
public void preModifyTableHandler(ObserverContext<MasterCoprocessorEnvironment> ctx,
byte[] tableName, HTableDescriptor htd) throws IOException {
}
@Override
public void postModifyTableHandler(ObserverContext<MasterCoprocessorEnvironment> ctx,
byte[] tableName, HTableDescriptor htd) throws IOException {
}
@Override
public void preAddColumnHandler(ObserverContext<MasterCoprocessorEnvironment> ctx,
byte[] tableName, HColumnDescriptor column) throws IOException {
}
@Override
public void postAddColumnHandler(ObserverContext<MasterCoprocessorEnvironment> ctx,
byte[] tableName, HColumnDescriptor column) throws IOException {
}
@Override
public void preModifyColumnHandler(ObserverContext<MasterCoprocessorEnvironment> ctx,
byte[] tableName, HColumnDescriptor descriptor) throws IOException {
}
@Override
public void postModifyColumnHandler(ObserverContext<MasterCoprocessorEnvironment> ctx,
byte[] tableName, HColumnDescriptor descriptor) throws IOException {
}
@Override
public void preDeleteColumnHandler(ObserverContext<MasterCoprocessorEnvironment> ctx,
byte[] tableName, byte[] c) throws IOException {
}
@Override
public void postDeleteColumnHandler(ObserverContext<MasterCoprocessorEnvironment> ctx,
byte[] tableName, byte[] c) throws IOException {
}
@Override
public void preEnableTableHandler(ObserverContext<MasterCoprocessorEnvironment> ctx,
byte[] tableName) throws IOException {
}
@Override
public void postEnableTableHandler(ObserverContext<MasterCoprocessorEnvironment> ctx,
byte[] tableName) throws IOException {
}
@Override
public void preDisableTableHandler(ObserverContext<MasterCoprocessorEnvironment> ctx,
byte[] tableName) throws IOException {
}
@Override
public void postDisableTableHandler(ObserverContext<MasterCoprocessorEnvironment> ctx,
byte[] tableName) throws IOException {
}
}

View File

@ -30,6 +30,14 @@ public interface AccessControllerProtocol extends CoprocessorProtocol {
public static final long VERSION = 1L;
/**
* Grants the given user or group the privilege to perform the given actions
* @param userPermission the details of the provided user permissions
* @throws IOException if the grant could not be applied
*/
public void grant(UserPermission userPermission)
throws IOException;
/**
* Grants the given user or group the privilege to perform the given actions
* over the specified scope contained in {@link TablePermission}
@ -37,10 +45,26 @@ public interface AccessControllerProtocol extends CoprocessorProtocol {
* the grant
* @param permission the details of the provided permissions
* @throws IOException if the grant could not be applied
* @deprecated Use {@link #revoke(UserPermission userPermission)} instead
*/
@Deprecated
public void grant(byte[] user, TablePermission permission)
throws IOException;
/**
* Revokes a previously granted privilege from a user or group.
* Note that the provided {@link TablePermission} details must exactly match
* a stored grant. For example, if user "bob" has been granted "READ" access
* to table "data", over column family and qualifer "info:colA", then the
* table, column family and column qualifier must all be specified.
* Attempting to revoke permissions over just the "data" table will have
* no effect.
* @param permission the details of the previously granted permission to revoke
* @throws IOException if the revocation could not be performed
*/
public void revoke(UserPermission userPermission)
throws IOException;
/**
* Revokes a previously granted privilege from a user or group.
* Note that the provided {@link TablePermission} details must exactly match
@ -53,7 +77,9 @@ public interface AccessControllerProtocol extends CoprocessorProtocol {
* privileges are being revoked
* @param permission the details of the previously granted permission to revoke
* @throws IOException if the revocation could not be performed
* @deprecated Use {@link #revoke(UserPermission userPermission)} instead
*/
@Deprecated
public void revoke(byte[] user, TablePermission permission)
throws IOException;
@ -81,5 +107,4 @@ public interface AccessControllerProtocol extends CoprocessorProtocol {
*/
public void checkPermissions(Permission[] permissions)
throws IOException;
}

View File

@ -40,8 +40,6 @@ import java.util.concurrent.ConcurrentSkipListMap;
* Performs authorization checks for a given user's assigned permissions
*/
public class TableAuthManager {
/** Key for the user and group cache maps for globally assigned permissions */
private static final String GLOBAL_CACHE_KEY = ".access.";
private static Log LOG = LogFactory.getLog(TableAuthManager.class);
private static TableAuthManager instance;
@ -103,14 +101,36 @@ public class TableAuthManager {
public void refreshCacheFromWritable(byte[] table, byte[] data) throws IOException {
if (data != null && data.length > 0) {
DataInput in = new DataInputStream( new ByteArrayInputStream(data) );
DataInput in = new DataInputStream(new ByteArrayInputStream(data));
ListMultimap<String,TablePermission> perms = AccessControlLists.readPermissions(in, conf);
cache(table, perms);
if (perms != null) {
if (Bytes.equals(table, AccessControlLists.ACL_GLOBAL_NAME)) {
updateGlobalCache(perms);
} else {
updateTableCache(table, perms);
}
}
} else {
LOG.debug("Skipping permission cache refresh because writable data is empty");
}
}
/**
* Updates the internal global permissions cache
*
* @param userPerms
*/
private void updateGlobalCache(ListMultimap<String,TablePermission> userPerms) {
for (Map.Entry<String,TablePermission> entry : userPerms.entries()) {
if (AccessControlLists.isGroupPrincipal(entry.getKey())) {
GROUP_CACHE.put(AccessControlLists.getGroupName(entry.getKey()),
new Permission(entry.getValue().getActions()));
} else {
USER_CACHE.put(entry.getKey(), new Permission(entry.getValue().getActions()));
}
}
}
/**
* Updates the internal permissions cache for a single table, splitting
* the permissions listed into separate caches for users and groups to optimize
@ -119,26 +139,22 @@ public class TableAuthManager {
* @param table
* @param tablePerms
*/
private void cache(byte[] table,
ListMultimap<String,TablePermission> tablePerms) {
private void updateTableCache(byte[] table, ListMultimap<String,TablePermission> tablePerms) {
// split user from group assignments so we don't have to prepend the group
// prefix every time we query for groups
ListMultimap<String,TablePermission> userPerms = ArrayListMultimap.create();
ListMultimap<String,TablePermission> groupPerms = ArrayListMultimap.create();
if (tablePerms != null) {
for (Map.Entry<String,TablePermission> entry : tablePerms.entries()) {
if (AccessControlLists.isGroupPrincipal(entry.getKey())) {
groupPerms.put(
entry.getKey().substring(AccessControlLists.GROUP_PREFIX.length()),
entry.getValue());
} else {
userPerms.put(entry.getKey(), entry.getValue());
}
for (Map.Entry<String,TablePermission> entry : tablePerms.entries()) {
if (AccessControlLists.isGroupPrincipal(entry.getKey())) {
groupPerms.put(AccessControlLists.getGroupName(entry.getKey()), entry.getValue());
} else {
userPerms.put(entry.getKey(), entry.getValue());
}
TABLE_GROUP_CACHE.put(table, groupPerms);
TABLE_USER_CACHE.put(table, userPerms);
}
TABLE_GROUP_CACHE.put(table, groupPerms);
TABLE_USER_CACHE.put(table, userPerms);
}
private List<TablePermission> getUserPermissions(String username, byte[] table) {
@ -464,7 +480,7 @@ public class TableAuthManager {
}
}
byte[] serialized = AccessControlLists.writePermissionsAsBytes(tmp, conf);
zkperms.writeToZookeeper(Bytes.toString(table), serialized);
zkperms.writeToZookeeper(table, serialized);
}
static Map<ZooKeeperWatcher,TableAuthManager> managerMap =

View File

@ -40,6 +40,27 @@ public class UserPermission extends TablePermission {
super();
}
/**
* Creates a new instance for the given user.
* @param user the user
* @param assigned the list of allowed actions
*/
public UserPermission(byte[] user, Action... assigned) {
super(null, null, null, assigned);
this.user = user;
}
/**
* Creates a new instance for the given user,
* matching the actions with the given codes.
* @param user the user
* @param actionCodes the list of allowed action codes
*/
public UserPermission(byte[] user, byte[] actionCodes) {
super(null, null, null, actionCodes);
this.user = user;
}
/**
* Creates a new instance for the given user, table and column family.
* @param user the user
@ -92,6 +113,14 @@ public class UserPermission extends TablePermission {
return user;
}
/**
* Returns true if this permission describes a global user permission.
*/
public boolean isGlobal() {
byte[] tableName = getTable();
return(tableName == null || tableName.length == 0);
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof UserPermission)) {

View File

@ -146,18 +146,16 @@ public class ZKPermissionWatcher extends ZooKeeperListener {
* @param tableName
* @param permsData
*/
public void writeToZookeeper(String tableName,
byte[] permsData) {
String zkNode =
ZKUtil.joinZNode(ZKUtil.joinZNode(watcher.baseZNode, ACL_NODE),
tableName);
public void writeToZookeeper(byte[] tableName, byte[] parmsData) {
String zkNode = ZKUtil.joinZNode(watcher.baseZNode, ACL_NODE);
zkNode = ZKUtil.joinZNode(zkNode, Bytes.toString(tableName));
try {
ZKUtil.createWithParents(watcher, zkNode);
ZKUtil.updateExistingNodeData(watcher, zkNode,
permsData, -1);
ZKUtil.updateExistingNodeData(watcher, zkNode, parmsData, -1);
} catch (KeeperException e) {
LOG.error("Failed updating permissions for table '" + tableName +
"'", e);
LOG.error("Failed updating permissions for table '" +
Bytes.toString(tableName) + "'", e);
watcher.abort("Failed writing node "+zkNode+" to zookeeper", e);
}
}

View File

@ -31,62 +31,117 @@ module Hbase
end
#----------------------------------------------------------------------------------------------
def grant(user, permissions, table_name, family=nil, qualifier=nil)
def grant(user, permissions, table_name=nil, family=nil, qualifier=nil)
security_available?
# Table should exist
raise(ArgumentError, "Can't find a table: #{table_name}") unless exists?(table_name)
# TODO: need to validate user name
htd = @admin.getTableDescriptor(table_name.to_java_bytes)
if (table_name != nil)
# Table should exist
raise(ArgumentError, "Can't find a table: #{table_name}") unless exists?(table_name)
if (family != nil)
raise(ArgumentError, "Can't find a family: #{family}") unless htd.hasFamily(family.to_java_bytes)
htd = @admin.getTableDescriptor(table_name.to_java_bytes)
if (family != nil)
raise(ArgumentError, "Can't find a family: #{family}") unless htd.hasFamily(family.to_java_bytes)
end
# invoke cp endpoint to perform access controlse
fambytes = family.to_java_bytes if (family != nil)
qualbytes = qualifier.to_java_bytes if (qualifier != nil)
user_permission = org.apache.hadoop.hbase.security.access.UserPermission.new(
user.to_java_bytes, table_name.to_java_bytes,
fambytes, qualbytes, permissions.to_java_bytes)
else
user_permission = org.apache.hadoop.hbase.security.access.UserPermission.new(
user.to_java_bytes, permissions.to_java_bytes)
end
#TODO: need to validate user name
# invoke cp endpoint to perform access control
fambytes = family.to_java_bytes if (family != nil)
qualbytes = qualifier.to_java_bytes if (qualifier != nil)
tp = org.apache.hadoop.hbase.security.access.TablePermission.new(table_name.to_java_bytes, fambytes, qualbytes, permissions.to_java_bytes)
meta_table = org.apache.hadoop.hbase.client.HTable.new(@config, org.apache.hadoop.hbase.security.access.AccessControlLists::ACL_TABLE_NAME)
protocol = meta_table.coprocessorProxy(org.apache.hadoop.hbase.security.access.AccessControllerProtocol.java_class,
meta_table = org.apache.hadoop.hbase.client.HTable.new(@config,
org.apache.hadoop.hbase.security.access.AccessControlLists::ACL_TABLE_NAME)
protocol = meta_table.coprocessorProxy(
org.apache.hadoop.hbase.security.access.AccessControllerProtocol.java_class,
org.apache.hadoop.hbase.HConstants::EMPTY_START_ROW)
protocol.grant(user.to_java_bytes, tp)
begin
protocol.grant(user_permission)
rescue java.io.IOException => e
if !(e.message.include? "java.lang.NoSuchMethodException")
raise e
end
# Server has not the new API, try the old one
if (table_name == nil)
raise "Global permissions not supported by HBase Server"
end
tp = org.apache.hadoop.hbase.security.access.TablePermission.new(table_name.to_java_bytes, fambytes, qualbytes, permissions.to_java_bytes)
protocol.grant(user.to_java_bytes, tp)
end
end
#----------------------------------------------------------------------------------------------
def revoke(user, table_name, family=nil, qualifier=nil)
def revoke(user, table_name=nil, family=nil, qualifier=nil)
security_available?
# Table should exist
raise(ArgumentError, "Can't find table: #{table_name}") unless exists?(table_name)
# TODO: need to validate user name
htd = @admin.getTableDescriptor(table_name.to_java_bytes)
if (table_name != nil)
# Table should exist
raise(ArgumentError, "Can't find a table: #{table_name}") unless exists?(table_name)
if (family != nil)
raise(ArgumentError, "Can't find a family: #{family}") unless htd.hasFamily(family.to_java_bytes)
htd = @admin.getTableDescriptor(table_name.to_java_bytes)
if (family != nil)
raise(ArgumentError, "Can't find family: #{family}") unless htd.hasFamily(family.to_java_bytes)
end
# invoke cp endpoint to perform access control
fambytes = family.to_java_bytes if (family != nil)
qualbytes = qualifier.to_java_bytes if (qualifier != nil)
user_permission = org.apache.hadoop.hbase.security.access.UserPermission.new(
user.to_java_bytes, table_name.to_java_bytes,
fambytes, qualbytes, "".to_java_bytes)
else
user_permission = org.apache.hadoop.hbase.security.access.UserPermission.new(
user.to_java_bytes, "".to_java_bytes)
end
fambytes = family.to_java_bytes if (family != nil)
qualbytes = qualifier.to_java_bytes if (qualifier != nil)
tp = org.apache.hadoop.hbase.security.access.TablePermission.new(table_name.to_java_bytes, fambytes, qualbytes, "".to_java_bytes)
meta_table = org.apache.hadoop.hbase.client.HTable.new(@config, org.apache.hadoop.hbase.security.access.AccessControlLists::ACL_TABLE_NAME)
protocol = meta_table.coprocessorProxy(org.apache.hadoop.hbase.security.access.AccessControllerProtocol.java_class,
meta_table = org.apache.hadoop.hbase.client.HTable.new(@config,
org.apache.hadoop.hbase.security.access.AccessControlLists::ACL_TABLE_NAME)
protocol = meta_table.coprocessorProxy(
org.apache.hadoop.hbase.security.access.AccessControllerProtocol.java_class,
org.apache.hadoop.hbase.HConstants::EMPTY_START_ROW)
protocol.revoke(user.to_java_bytes, tp)
begin
protocol.revoke(user_permission)
rescue java.io.IOException => e
if !(e.message.include? "java.lang.NoSuchMethodException")
raise e
end
# Server has not the new API, try the old one
if (table_name == nil)
raise "Global permissions not supported by HBase Server"
end
tp = org.apache.hadoop.hbase.security.access.TablePermission.new(table_name.to_java_bytes, fambytes, qualbytes, "".to_java_bytes)
protocol.revoke(user.to_java_bytes, tp)
end
end
#----------------------------------------------------------------------------------------------
def user_permission(table_name)
def user_permission(table_name=nil)
security_available?
raise(ArgumentError, "Can't find table: #{table_name}") unless exists?(table_name)
if (table_name != nil)
raise(ArgumentError, "Can't find table: #{table_name}") unless exists?(table_name)
end
meta_table = org.apache.hadoop.hbase.client.HTable.new(@config, org.apache.hadoop.hbase.security.access.AccessControlLists::ACL_TABLE_NAME)
protocol = meta_table.coprocessorProxy(org.apache.hadoop.hbase.security.access.AccessControllerProtocol.java_class,
org.apache.hadoop.hbase.HConstants::EMPTY_START_ROW)
perms = protocol.getUserPermissions(table_name.to_java_bytes)
meta_table = org.apache.hadoop.hbase.client.HTable.new(@config,
org.apache.hadoop.hbase.security.access.AccessControlLists::ACL_TABLE_NAME)
protocol = meta_table.coprocessorProxy(
org.apache.hadoop.hbase.security.access.AccessControllerProtocol.java_class,
org.apache.hadoop.hbase.HConstants::EMPTY_START_ROW)
perms = protocol.getUserPermissions(table_name != nil ? table_name.to_java_bytes : nil)
res = {}
count = 0

View File

@ -226,6 +226,7 @@ Shell.load_command_group(
status
version
table_help
whoami
]
)

View File

@ -21,7 +21,7 @@ module Shell
class Grant < Command
def help
return <<-EOF
Grant users specific rights to tables.
Grant users specific rights.
Syntax : grant <user> <permissions> <table> <column family> <column qualifier>
permissions is either zero or more letters from the set "RWXCA".
@ -29,11 +29,12 @@ READ('R'), WRITE('W'), EXEC('X'), CREATE('C'), ADMIN('A')
For example:
hbase> grant 'bobsmith', 'RWXCA'
hbase> grant 'bobsmith', 'RW', 't1', 'f1', 'col1'
EOF
end
def command(user, rights, table_name, family=nil, qualifier=nil)
def command(user, rights, table_name=nil, family=nil, qualifier=nil)
format_simple_command do
security_admin.grant(user, rights, table_name, family, qualifier)
end

View File

@ -21,15 +21,15 @@ module Shell
class Revoke < Command
def help
return <<-EOF
Revoke a user's access rights to tables.
Syntax : revoke <user> <table> <column family>
Revoke a user's access rights.
Syntax : revoke <user> <table> <column family> <column qualifier>
For example:
hbase> revoke 'bobsmith', 't1', 'f1'
hbase> revoke 'bobsmith', 't1', 'f1', 'col1'
EOF
end
def command(user, table_name, family=nil, qualifier=nil)
def command(user, table_name=nil, family=nil, qualifier=nil)
format_simple_command do
security_admin.revoke(user, table_name, family, qualifier)
end

View File

@ -21,15 +21,16 @@ module Shell
class UserPermission < Command
def help
return <<-EOF
Show all table access permissions for the particular user.
Show all permissions for the particular user.
Syntax : user_permission <table>
For example:
hbase> user_permission
hbase> user_permission 'table1'
EOF
end
def command(table)
def command(table=nil)
#format_simple_command do
#admin.user_permission(table)
now = Time.now

View File

@ -0,0 +1,37 @@
#
# 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.
#
module Shell
module Commands
class Whoami < Command
def help
return <<-EOF
Show the current hbase user.
Syntax : whoami
For example:
hbase> whoami
EOF
end
def command()
puts "#{org.apache.hadoop.hbase.security.User.getCurrent().toString()}"
end
end
end
end

View File

@ -95,10 +95,12 @@ public class TestAccessControlFilter {
AccessControlLists.ACL_TABLE_NAME);
AccessControllerProtocol acls = aclmeta.coprocessorProxy(
AccessControllerProtocol.class, Bytes.toBytes("testtable"));
TablePermission perm = new TablePermission(TABLE, null, Permission.Action.READ);
acls.grant(Bytes.toBytes(READER.getShortName()), perm);
perm = new TablePermission(TABLE, FAMILY, PUBLIC_COL, Permission.Action.READ);
acls.grant(Bytes.toBytes(LIMITED.getShortName()), perm);
UserPermission perm = new UserPermission(Bytes.toBytes(READER.getShortName()),
TABLE, null, Permission.Action.READ);
acls.grant(perm);
perm = new UserPermission(Bytes.toBytes(LIMITED.getShortName()),
TABLE, FAMILY, PUBLIC_COL, Permission.Action.READ);
acls.grant(perm);
return null;
}
});

View File

@ -72,6 +72,8 @@ public class TestAccessController {
// user with all permissions
private static User SUPERUSER;
// user granted with all global permission
private static User USER_ADMIN;
// table owner user
private static User USER_OWNER;
// user with rw permissions
@ -104,6 +106,7 @@ public class TestAccessController {
// create a set of test users
SUPERUSER = User.createUserForTesting(conf, "admin", new String[]{"supergroup"});
USER_ADMIN = User.createUserForTesting(conf, "admin2", new String[0]);
USER_OWNER = User.createUserForTesting(conf, "owner", new String[0]);
USER_RW = User.createUserForTesting(conf, "rwuser", new String[0]);
USER_RO = User.createUserForTesting(conf, "rouser", new String[0]);
@ -119,12 +122,16 @@ public class TestAccessController {
HTable meta = new HTable(conf, AccessControlLists.ACL_TABLE_NAME);
AccessControllerProtocol protocol =
meta.coprocessorProxy(AccessControllerProtocol.class, TEST_TABLE);
protocol.grant(Bytes.toBytes(USER_RW.getShortName()),
new TablePermission(TEST_TABLE, TEST_FAMILY, Permission.Action.READ,
Permission.Action.WRITE));
protocol.grant(Bytes.toBytes(USER_RO.getShortName()),
new TablePermission(TEST_TABLE, TEST_FAMILY, Permission.Action.READ));
protocol.grant(new UserPermission(Bytes.toBytes(USER_ADMIN.getShortName()),
Permission.Action.ADMIN, Permission.Action.CREATE,
Permission.Action.READ, Permission.Action.WRITE));
protocol.grant(new UserPermission(Bytes.toBytes(USER_RW.getShortName()),
TEST_TABLE, TEST_FAMILY, Permission.Action.READ, Permission.Action.WRITE));
protocol.grant(new UserPermission(Bytes.toBytes(USER_RO.getShortName()),
TEST_TABLE, TEST_FAMILY, Permission.Action.READ));
}
@AfterClass
@ -195,6 +202,7 @@ public class TestAccessController {
// verify that superuser can create tables
verifyAllowed(SUPERUSER, createTable);
verifyAllowed(USER_ADMIN, createTable);
// all others should be denied
verifyDenied(USER_OWNER, createTable);
@ -223,6 +231,7 @@ public class TestAccessController {
// verify that superuser can create tables
verifyAllowed(SUPERUSER, modifyTable);
verifyAllowed(USER_ADMIN, modifyTable);
}
@Test
@ -242,6 +251,7 @@ public class TestAccessController {
// verify that superuser can create tables
verifyAllowed(SUPERUSER, deleteTable);
verifyAllowed(USER_ADMIN, deleteTable);
}
@Test
@ -262,6 +272,7 @@ public class TestAccessController {
// verify that superuser can create tables
verifyAllowed(SUPERUSER, action);
verifyAllowed(USER_ADMIN, action);
}
@Test
@ -283,6 +294,7 @@ public class TestAccessController {
// verify that superuser can create tables
verifyAllowed(SUPERUSER, action);
verifyAllowed(USER_ADMIN, action);
}
@Test
@ -302,6 +314,7 @@ public class TestAccessController {
// verify that superuser can create tables
verifyAllowed(SUPERUSER, action);
verifyAllowed(USER_ADMIN, action);
}
@Test
@ -321,6 +334,7 @@ public class TestAccessController {
// verify that superuser can create tables
verifyAllowed(SUPERUSER, disableTable);
verifyAllowed(USER_ADMIN, disableTable);
}
@Test
@ -340,6 +354,7 @@ public class TestAccessController {
// verify that superuser can create tables
verifyAllowed(SUPERUSER, enableTable);
verifyAllowed(USER_ADMIN, enableTable);
}
@Test
@ -365,6 +380,7 @@ public class TestAccessController {
// verify that superuser can create tables
verifyAllowed(SUPERUSER, action);
verifyAllowed(USER_ADMIN, action);
}
@Test
@ -390,6 +406,7 @@ public class TestAccessController {
// verify that superuser can create tables
verifyAllowed(SUPERUSER, action);
verifyAllowed(USER_ADMIN, action);
}
@Test
@ -415,6 +432,7 @@ public class TestAccessController {
// verify that superuser can create tables
verifyAllowed(SUPERUSER, action);
verifyAllowed(USER_ADMIN, action);
}
@Test
@ -434,6 +452,7 @@ public class TestAccessController {
// verify that superuser can create tables
verifyAllowed(SUPERUSER, action);
verifyAllowed(USER_ADMIN, action);
}
@Test
@ -453,6 +472,7 @@ public class TestAccessController {
// verify that superuser can create tables
verifyAllowed(SUPERUSER, action);
verifyAllowed(USER_ADMIN, action);
}
@Test
@ -472,6 +492,7 @@ public class TestAccessController {
// verify that superuser can create tables
verifyAllowed(SUPERUSER, action);
verifyAllowed(USER_ADMIN, action);
}
@Test
@ -491,6 +512,7 @@ public class TestAccessController {
// verify that superuser can create tables
verifyAllowed(SUPERUSER, action);
verifyAllowed(USER_ADMIN, action);
}
private void verifyWrite(PrivilegedExceptionAction action) throws Exception {
@ -500,6 +522,7 @@ public class TestAccessController {
// should be allowed
verifyAllowed(SUPERUSER, action);
verifyAllowed(USER_ADMIN, action);
verifyAllowed(USER_OWNER, action);
verifyAllowed(USER_RW, action);
}
@ -510,6 +533,7 @@ public class TestAccessController {
// should be allowed
verifyAllowed(SUPERUSER, action);
verifyAllowed(USER_ADMIN, action);
verifyAllowed(USER_OWNER, action);
verifyAllowed(USER_RW, action);
verifyAllowed(USER_RO, action);
@ -720,8 +744,8 @@ public class TestAccessController {
verifyDenied(user, deleteAction2);
// grant table read permission
protocol.grant(Bytes.toBytes(user.getShortName()),
new TablePermission(tableName, null, Permission.Action.READ));
protocol.grant(new UserPermission(Bytes.toBytes(user.getShortName()),
tableName, null, Permission.Action.READ));
Thread.sleep(100);
// check
verifyAllowed(user, getActionAll);
@ -737,8 +761,8 @@ public class TestAccessController {
verifyDenied(user, deleteAction2);
// grant table write permission
protocol.grant(Bytes.toBytes(user.getShortName()),
new TablePermission(tableName, null, Permission.Action.WRITE));
protocol.grant(new UserPermission(Bytes.toBytes(user.getShortName()),
tableName, null, Permission.Action.WRITE));
Thread.sleep(100);
verifyDenied(user, getActionAll);
verifyDenied(user, getAction1);
@ -753,12 +777,11 @@ public class TestAccessController {
verifyAllowed(user, deleteAction2);
// revoke table permission
protocol.grant(Bytes.toBytes(user.getShortName()),
new TablePermission(tableName, null, Permission.Action.READ,
Permission.Action.WRITE));
protocol.grant(new UserPermission(Bytes.toBytes(user.getShortName()),
tableName, null, Permission.Action.READ, Permission.Action.WRITE));
protocol.revoke(Bytes.toBytes(user.getShortName()),
new TablePermission(tableName, null));
protocol.revoke(new UserPermission(Bytes.toBytes(user.getShortName()),
tableName, null));
Thread.sleep(100);
verifyDenied(user, getActionAll);
verifyDenied(user, getAction1);
@ -773,8 +796,8 @@ public class TestAccessController {
verifyDenied(user, deleteAction2);
// grant column family read permission
protocol.grant(Bytes.toBytes(user.getShortName()),
new TablePermission(tableName, family1, Permission.Action.READ));
protocol.grant(new UserPermission(Bytes.toBytes(user.getShortName()),
tableName, family1, Permission.Action.READ));
Thread.sleep(100);
verifyAllowed(user, getActionAll);
@ -790,8 +813,8 @@ public class TestAccessController {
verifyDenied(user, deleteAction2);
// grant column family write permission
protocol.grant(Bytes.toBytes(user.getShortName()),
new TablePermission(tableName, family2, Permission.Action.WRITE));
protocol.grant(new UserPermission(Bytes.toBytes(user.getShortName()),
tableName, family2, Permission.Action.WRITE));
Thread.sleep(100);
verifyAllowed(user, getActionAll);
@ -807,8 +830,8 @@ public class TestAccessController {
verifyAllowed(user, deleteAction2);
// revoke column family permission
protocol.revoke(Bytes.toBytes(user.getShortName()),
new TablePermission(tableName, family2));
protocol.revoke(new UserPermission(Bytes.toBytes(user.getShortName()),
tableName, family2));
Thread.sleep(100);
verifyAllowed(user, getActionAll);
@ -890,15 +913,14 @@ public class TestAccessController {
}
};
protocol.revoke(Bytes.toBytes(user.getShortName()),
new TablePermission(tableName, family1));
protocol.revoke(new UserPermission(Bytes.toBytes(user.getShortName()),
tableName, family1));
verifyDenied(user, getQualifierAction);
verifyDenied(user, putQualifierAction);
verifyDenied(user, deleteQualifierAction);
protocol.grant(Bytes.toBytes(user.getShortName()),
new TablePermission(tableName, family1, qualifier,
Permission.Action.READ));
protocol.grant(new UserPermission(Bytes.toBytes(user.getShortName()),
tableName, family1, qualifier, Permission.Action.READ));
Thread.sleep(100);
verifyAllowed(user, getQualifierAction);
@ -907,9 +929,8 @@ public class TestAccessController {
// only grant write permission
// TODO: comment this portion after HBASE-3583
protocol.grant(Bytes.toBytes(user.getShortName()),
new TablePermission(tableName, family1, qualifier,
Permission.Action.WRITE));
protocol.grant(new UserPermission(Bytes.toBytes(user.getShortName()),
tableName, family1, qualifier, Permission.Action.WRITE));
Thread.sleep(100);
verifyDenied(user, getQualifierAction);
@ -917,9 +938,9 @@ public class TestAccessController {
verifyAllowed(user, deleteQualifierAction);
// grant both read and write permission.
protocol.grant(Bytes.toBytes(user.getShortName()),
new TablePermission(tableName, family1, qualifier,
Permission.Action.READ, Permission.Action.WRITE));
protocol.grant(new UserPermission(Bytes.toBytes(user.getShortName()),
tableName, family1, qualifier,
Permission.Action.READ, Permission.Action.WRITE));
Thread.sleep(100);
verifyAllowed(user, getQualifierAction);
@ -927,8 +948,8 @@ public class TestAccessController {
verifyAllowed(user, deleteQualifierAction);
// revoke family level permission won't impact column level.
protocol.revoke(Bytes.toBytes(user.getShortName()),
new TablePermission(tableName, family1, qualifier));
protocol.revoke(new UserPermission(Bytes.toBytes(user.getShortName()),
tableName, family1, qualifier));
Thread.sleep(100);
verifyDenied(user, getQualifierAction);
@ -974,7 +995,7 @@ public class TestAccessController {
// grant read permission
UserPermission upToSet = new UserPermission(user,
tableName, family1, qualifier, Permission.Action.READ);
protocol.grant(user, upToSet);
protocol.grant(upToSet);
perms = protocol.getUserPermissions(tableName);
UserPermission upToVerify = new UserPermission(user,
@ -990,7 +1011,7 @@ public class TestAccessController {
// grant read+write
upToSet = new UserPermission(user, tableName, family1, qualifier,
Permission.Action.WRITE, Permission.Action.READ);
protocol.grant(user, upToSet);
protocol.grant(upToSet);
perms = protocol.getUserPermissions(tableName);
upToVerify = new UserPermission(user, tableName, family1, qualifier,
@ -998,7 +1019,7 @@ public class TestAccessController {
assertTrue("User should be granted permission: " + upToVerify.toString(),
hasFoundUserPermission(upToVerify, perms));
protocol.revoke(user, upToSet);
protocol.revoke(upToSet);
perms = protocol.getUserPermissions(tableName);
assertFalse("User should not be granted permission: " + upToVerify.toString(),
hasFoundUserPermission(upToVerify, perms));
@ -1053,7 +1074,7 @@ public class TestAccessController {
public void grant(AccessControllerProtocol protocol, User user, byte[] t, byte[] f,
byte[] q, Permission.Action... actions) throws IOException {
protocol.grant(Bytes.toBytes(user.getShortName()), new TablePermission(t, f, q, actions));
protocol.grant(new UserPermission(Bytes.toBytes(user.getShortName()), t, f, q, actions));
}
@Test

View File

@ -103,15 +103,16 @@ public class TestTablePermissions {
public void testBasicWrite() throws Exception {
Configuration conf = UTIL.getConfiguration();
// add some permissions
AccessControlLists.addTablePermission(conf, TEST_TABLE,
"george", new TablePermission(TEST_TABLE, null,
TablePermission.Action.READ, TablePermission.Action.WRITE));
AccessControlLists.addTablePermission(conf, TEST_TABLE,
"hubert", new TablePermission(TEST_TABLE, null,
TablePermission.Action.READ));
AccessControlLists.addTablePermission(conf, TEST_TABLE,
"humphrey", new TablePermission(TEST_TABLE, TEST_FAMILY, TEST_QUALIFIER,
TablePermission.Action.READ));
AccessControlLists.addUserPermission(conf,
new UserPermission(Bytes.toBytes("george"), TEST_TABLE, null, (byte[])null,
UserPermission.Action.READ, UserPermission.Action.WRITE));
AccessControlLists.addUserPermission(conf,
new UserPermission(Bytes.toBytes("hubert"), TEST_TABLE, null, (byte[])null,
UserPermission.Action.READ));
AccessControlLists.addUserPermission(conf,
new UserPermission(Bytes.toBytes("humphrey"),
TEST_TABLE, TEST_FAMILY, TEST_QUALIFIER,
UserPermission.Action.READ));
// retrieve the same
ListMultimap<String,TablePermission> perms =
@ -165,8 +166,8 @@ public class TestTablePermissions {
assertFalse(actions.contains(TablePermission.Action.WRITE));
// table 2 permissions
AccessControlLists.addTablePermission(conf, TEST_TABLE2, "hubert",
new TablePermission(TEST_TABLE2, null,
AccessControlLists.addUserPermission(conf,
new UserPermission(Bytes.toBytes("hubert"), TEST_TABLE2, null, (byte[])null,
TablePermission.Action.READ, TablePermission.Action.WRITE));
// check full load
@ -197,16 +198,21 @@ public class TestTablePermissions {
@Test
public void testPersistence() throws Exception {
Configuration conf = UTIL.getConfiguration();
AccessControlLists.addTablePermission(conf, TEST_TABLE, "albert",
new TablePermission(TEST_TABLE, null, TablePermission.Action.READ));
AccessControlLists.addTablePermission(conf, TEST_TABLE, "betty",
new TablePermission(TEST_TABLE, null, TablePermission.Action.READ,
TablePermission.Action.WRITE));
AccessControlLists.addTablePermission(conf, TEST_TABLE, "clark",
new TablePermission(TEST_TABLE, TEST_FAMILY, TablePermission.Action.READ));
AccessControlLists.addTablePermission(conf, TEST_TABLE, "dwight",
new TablePermission(TEST_TABLE, TEST_FAMILY, TEST_QUALIFIER,
TablePermission.Action.WRITE));
AccessControlLists.addUserPermission(conf,
new UserPermission(Bytes.toBytes("albert"), TEST_TABLE, null,
(byte[])null, TablePermission.Action.READ));
AccessControlLists.addUserPermission(conf,
new UserPermission(Bytes.toBytes("betty"), TEST_TABLE, null,
(byte[])null, TablePermission.Action.READ,
TablePermission.Action.WRITE));
AccessControlLists.addUserPermission(conf,
new UserPermission(Bytes.toBytes("clark"),
TEST_TABLE, TEST_FAMILY,
TablePermission.Action.READ));
AccessControlLists.addUserPermission(conf,
new UserPermission(Bytes.toBytes("dwight"),
TEST_TABLE, TEST_FAMILY, TEST_QUALIFIER,
TablePermission.Action.WRITE));
// verify permissions survive changes in table metadata
ListMultimap<String,TablePermission> preperms =
@ -313,4 +319,41 @@ public class TestTablePermissions {
assertFalse(p1.equals(p2));
assertFalse(p2.equals(p1));
}
@Test
public void testGlobalPermission() throws Exception {
Configuration conf = UTIL.getConfiguration();
// add some permissions
AccessControlLists.addUserPermission(conf,
new UserPermission(Bytes.toBytes("user1"),
Permission.Action.READ, Permission.Action.WRITE));
AccessControlLists.addUserPermission(conf,
new UserPermission(Bytes.toBytes("user2"),
Permission.Action.CREATE));
AccessControlLists.addUserPermission(conf,
new UserPermission(Bytes.toBytes("user3"),
Permission.Action.ADMIN, Permission.Action.READ, Permission.Action.CREATE));
ListMultimap<String,TablePermission> perms = AccessControlLists.getTablePermissions(conf, null);
List<TablePermission> user1Perms = perms.get("user1");
assertEquals("Should have 1 permission for user1", 1, user1Perms.size());
assertEquals("user1 should have WRITE permission",
new Permission.Action[] { Permission.Action.READ, Permission.Action.WRITE },
user1Perms.get(0).getActions());
List<TablePermission> user2Perms = perms.get("user2");
assertEquals("Should have 1 permission for user2", 1, user2Perms.size());
assertEquals("user2 should have CREATE permission",
new Permission.Action[] { Permission.Action.CREATE },
user2Perms.get(0).getActions());
List<TablePermission> user3Perms = perms.get("user3");
assertEquals("Should have 1 permission for user3", 1, user3Perms.size());
assertEquals("user3 should have ADMIN, READ, CREATE permission",
new Permission.Action[] {
Permission.Action.ADMIN, Permission.Action.READ, Permission.Action.CREATE
},
user3Perms.get(0).getActions());
}
}