You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by zh...@apache.org on 2017/02/20 12:35:30 UTC
hbase git commit: HBASE-17472: Correct the semantic of permission
grant
Repository: hbase
Updated Branches:
refs/heads/master d08bafad1 -> 22fa1cd3d
HBASE-17472: Correct the semantic of permission grant
Signed-off-by: zhangduo <zh...@apache.org>
Project: http://git-wip-us.apache.org/repos/asf/hbase/repo
Commit: http://git-wip-us.apache.org/repos/asf/hbase/commit/22fa1cd3
Tree: http://git-wip-us.apache.org/repos/asf/hbase/tree/22fa1cd3
Diff: http://git-wip-us.apache.org/repos/asf/hbase/diff/22fa1cd3
Branch: refs/heads/master
Commit: 22fa1cd3df3ed16ddbc0336ac2e52964c1e22665
Parents: d08bafa
Author: huzheng <op...@gmail.com>
Authored: Wed Jan 25 15:20:42 2017 +0800
Committer: zhangduo <zh...@apache.org>
Committed: Mon Feb 20 20:13:43 2017 +0800
----------------------------------------------------------------------
.../security/access/AccessControlClient.java | 96 +++++++++----
.../security/access/AccessControlUtil.java | 30 ++--
.../hbase/security/access/TablePermission.java | 25 ++--
.../protobuf/generated/AccessControlProtos.java | 139 +++++++++++++++----
.../src/main/protobuf/AccessControl.proto | 1 +
.../security/access/AccessControlLists.java | 39 +++++-
.../hbase/security/access/AccessController.java | 2 +-
.../hbase/security/access/SecureTestUtil.java | 18 +--
.../security/access/TestAccessController.java | 125 ++++++++++++++++-
.../security/access/TestNamespaceCommands.java | 4 +-
.../security/access/TestTablePermissions.java | 2 +-
11 files changed, 391 insertions(+), 90 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/hbase/blob/22fa1cd3/hbase-client/src/main/java/org/apache/hadoop/hbase/security/access/AccessControlClient.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/security/access/AccessControlClient.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/security/access/AccessControlClient.java
index 96db2d1..eeac9c7 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/security/access/AccessControlClient.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/security/access/AccessControlClient.java
@@ -85,58 +85,106 @@ public class AccessControlClient {
* @param userName
* @param family
* @param qual
+ * @param mergeExistingPermissions If set to false, later granted permissions will override
+ * previous granted permissions. otherwise, it'll merge with previous granted
+ * permissions.
* @param actions
* @throws Throwable
*/
- public static void grant(Connection connection, final TableName tableName,
- final String userName, final byte[] family, final byte[] qual,
+ private static void grant(Connection connection, final TableName tableName,
+ final String userName, final byte[] family, final byte[] qual, boolean mergeExistingPermissions,
final Permission.Action... actions) throws Throwable {
- /* TODO: Priority is not used.
- HBaseRpcController controller
- = ((ClusterConnection) connection).getRpcControllerFactory().newController();
- controller.setPriority(tableName);
- */
+ // TODO: Priority is not used.
try (Table table = connection.getTable(ACL_TABLE_NAME)) {
AccessControlUtil.grant(null, getAccessControlServiceStub(table), userName, tableName,
- family, qual, actions);
+ family, qual, mergeExistingPermissions, actions);
}
}
/**
- * Grants permission on the specified namespace for the specified user.
+ * Grants permission on the specified table for the specified user.
+ * If permissions for a specified user exists, later granted permissions will override previous granted permissions.
* @param connection The Connection instance to use
+ * @param tableName
+ * @param userName
+ * @param family
+ * @param qual
+ * @param actions
+ * @throws Throwable
+ */
+ public static void grant(Connection connection, final TableName tableName, final String userName,
+ final byte[] family, final byte[] qual, final Permission.Action... actions) throws Throwable {
+ grant(connection, tableName, userName, family, qual, true, actions);
+ }
+
+ /**
+ * Grants permission on the specified namespace for the specified user.
+ * @param connection
* @param namespace
* @param userName
+ * @param mergeExistingPermissions If set to false, later granted permissions will override
+ * previous granted permissions. otherwise, it'll merge with previous granted
+ * permissions.
* @param actions
* @throws Throwable
*/
- public static void grant(Connection connection, final String namespace,
- final String userName, final Permission.Action... actions) throws Throwable {
- /* TODO: Pass an rpcController.
- HBaseRpcController controller
- = ((ClusterConnection) connection).getRpcControllerFactory().newController();
- */
+ private static void grant(Connection connection, final String namespace, final String userName,
+ boolean mergeExistingPermissions, final Permission.Action... actions) throws Throwable {
+ // TODO: Pass an rpcController.
try (Table table = connection.getTable(ACL_TABLE_NAME)) {
AccessControlUtil.grant(null, getAccessControlServiceStub(table), userName, namespace,
- actions);
+ mergeExistingPermissions, actions);
}
}
/**
+ * Grants permission on the specified namespace for the specified user.
+ * If permissions on the specified namespace exists, later granted permissions will override previous granted
+ * permissions.
* @param connection The Connection instance to use
- * Grant global permissions for the specified user.
+ * @param namespace
+ * @param userName
+ * @param actions
+ * @throws Throwable
*/
- public static void grant(Connection connection, final String userName,
- final Permission.Action... actions) throws Throwable {
- /* TODO: Pass an rpcController
- HBaseRpcController controller
- = ((ClusterConnection) connection).getRpcControllerFactory().newController();
- */
+ public static void grant(Connection connection, final String namespace, final String userName,
+ final Permission.Action... actions) throws Throwable {
+ grant(connection, namespace, userName, true, actions);
+ }
+
+ /**
+ * Grants permission on the specified namespace for the specified user.
+ * @param connection
+ * @param userName
+ * @param mergeExistingPermissions If set to false, later granted permissions will override
+ * previous granted permissions. otherwise, it'll merge with previous granted
+ * permissions.
+ * @param actions
+ * @throws Throwable
+ */
+ private static void grant(Connection connection, final String userName,
+ boolean mergeExistingPermissions, final Permission.Action... actions) throws Throwable {
+ // TODO: Pass an rpcController
try (Table table = connection.getTable(ACL_TABLE_NAME)) {
- AccessControlUtil.grant(null, getAccessControlServiceStub(table), userName, actions);
+ AccessControlUtil.grant(null, getAccessControlServiceStub(table), userName,
+ mergeExistingPermissions, actions);
}
}
+ /**
+ * Grant global permissions for the specified user.
+ * If permissions for the specified user exists, later granted permissions will override previous granted
+ * permissions.
+ * @param connection
+ * @param userName
+ * @param actions
+ * @throws Throwable
+ */
+ public static void grant(Connection connection, final String userName,
+ final Permission.Action... actions) throws Throwable {
+ grant(connection, userName, true, actions);
+ }
+
public static boolean isAccessControllerRunning(Connection connection)
throws MasterNotRunningException, ZooKeeperConnectionException, IOException {
try (Admin admin = connection.getAdmin()) {
http://git-wip-us.apache.org/repos/asf/hbase/blob/22fa1cd3/hbase-client/src/main/java/org/apache/hadoop/hbase/security/access/AccessControlUtil.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/security/access/AccessControlUtil.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/security/access/AccessControlUtil.java
index 11c68b3..1d26366 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/security/access/AccessControlUtil.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/security/access/AccessControlUtil.java
@@ -53,7 +53,7 @@ public class AccessControlUtil {
*/
public static AccessControlProtos.GrantRequest buildGrantRequest(
String username, TableName tableName, byte[] family, byte[] qualifier,
- AccessControlProtos.Permission.Action... actions) {
+ boolean mergeExistingPermissions, AccessControlProtos.Permission.Action... actions) {
AccessControlProtos.Permission.Builder ret =
AccessControlProtos.Permission.newBuilder();
AccessControlProtos.TablePermission.Builder permissionBuilder =
@@ -79,7 +79,7 @@ public class AccessControlUtil {
AccessControlProtos.UserPermission.newBuilder()
.setUser(ByteString.copyFromUtf8(username))
.setPermission(ret)
- ).build();
+ ).setMergeExistingPermissions(mergeExistingPermissions).build();
}
/**
@@ -91,7 +91,7 @@ public class AccessControlUtil {
* @return A {@link AccessControlProtos} GrantRequest
*/
public static AccessControlProtos.GrantRequest buildGrantRequest(
- String username, String namespace,
+ String username, String namespace, boolean mergeExistingPermissions,
AccessControlProtos.Permission.Action... actions) {
AccessControlProtos.Permission.Builder ret =
AccessControlProtos.Permission.newBuilder();
@@ -110,7 +110,7 @@ public class AccessControlUtil {
AccessControlProtos.UserPermission.newBuilder()
.setUser(ByteString.copyFromUtf8(username))
.setPermission(ret)
- ).build();
+ ).setMergeExistingPermissions(mergeExistingPermissions).build();
}
/**
@@ -177,8 +177,8 @@ public class AccessControlUtil {
* @param actions the permissions to be granted
* @return A {@link AccessControlProtos} GrantRequest
*/
- public static AccessControlProtos.GrantRequest buildGrantRequest(
- String username, AccessControlProtos.Permission.Action... actions) {
+ public static AccessControlProtos.GrantRequest buildGrantRequest(String username,
+ boolean mergeExistingPermissions, AccessControlProtos.Permission.Action... actions) {
AccessControlProtos.Permission.Builder ret =
AccessControlProtos.Permission.newBuilder();
AccessControlProtos.GlobalPermission.Builder permissionBuilder =
@@ -193,7 +193,7 @@ public class AccessControlUtil {
AccessControlProtos.UserPermission.newBuilder()
.setUser(ByteString.copyFromUtf8(username))
.setPermission(ret)
- ).build();
+ ).setMergeExistingPermissions(mergeExistingPermissions).build();
}
public static AccessControlProtos.UsersAndPermissions toUsersAndPermissions(String user,
@@ -490,14 +490,14 @@ public class AccessControlUtil {
* @throws ServiceException
*/
public static void grant(RpcController controller,
- AccessControlService.BlockingInterface protocol, String userShortName,
+ AccessControlService.BlockingInterface protocol, String userShortName, boolean mergeExistingPermissions,
Permission.Action... actions) throws ServiceException {
List<AccessControlProtos.Permission.Action> permActions =
Lists.newArrayListWithCapacity(actions.length);
for (Permission.Action a : actions) {
permActions.add(toPermissionAction(a));
}
- AccessControlProtos.GrantRequest request = buildGrantRequest(userShortName,
+ AccessControlProtos.GrantRequest request = buildGrantRequest(userShortName, mergeExistingPermissions,
permActions.toArray(new AccessControlProtos.Permission.Action[actions.length]));
protocol.grant(controller, request);
}
@@ -518,14 +518,16 @@ public class AccessControlUtil {
*/
public static void grant(RpcController controller,
AccessControlService.BlockingInterface protocol, String userShortName, TableName tableName,
- byte[] f, byte[] q, Permission.Action... actions) throws ServiceException {
+ byte[] f, byte[] q, boolean mergeExistingPermissions, Permission.Action... actions)
+ throws ServiceException {
List<AccessControlProtos.Permission.Action> permActions =
Lists.newArrayListWithCapacity(actions.length);
for (Permission.Action a : actions) {
permActions.add(toPermissionAction(a));
}
- AccessControlProtos.GrantRequest request = buildGrantRequest(userShortName, tableName, f, q,
- permActions.toArray(new AccessControlProtos.Permission.Action[actions.length]));
+ AccessControlProtos.GrantRequest request =
+ buildGrantRequest(userShortName, tableName, f, q, mergeExistingPermissions,
+ permActions.toArray(new AccessControlProtos.Permission.Action[actions.length]));
protocol.grant(controller, request);
}
@@ -541,13 +543,13 @@ public class AccessControlUtil {
*/
public static void grant(RpcController controller,
AccessControlService.BlockingInterface protocol, String userShortName, String namespace,
- Permission.Action... actions) throws ServiceException {
+ boolean mergeExistingPermissions, Permission.Action... actions) throws ServiceException {
List<AccessControlProtos.Permission.Action> permActions =
Lists.newArrayListWithCapacity(actions.length);
for (Permission.Action a : actions) {
permActions.add(toPermissionAction(a));
}
- AccessControlProtos.GrantRequest request = buildGrantRequest(userShortName, namespace,
+ AccessControlProtos.GrantRequest request = buildGrantRequest(userShortName, namespace, mergeExistingPermissions,
permActions.toArray(new AccessControlProtos.Permission.Action[actions.length]));
protocol.grant(controller, request);
}
http://git-wip-us.apache.org/repos/asf/hbase/blob/22fa1cd3/hbase-client/src/main/java/org/apache/hadoop/hbase/security/access/TablePermission.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/security/access/TablePermission.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/security/access/TablePermission.java
index e9ecea4..4804b30 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/security/access/TablePermission.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/security/access/TablePermission.java
@@ -305,6 +305,21 @@ public class TablePermission extends Permission {
return super.implies(action);
}
+ public boolean tableFieldsEqual(TablePermission other){
+ if (!(((table == null && other.getTableName() == null) ||
+ (table != null && table.equals(other.getTableName()))) &&
+ ((family == null && other.getFamily() == null) ||
+ Bytes.equals(family, other.getFamily())) &&
+ ((qualifier == null && other.getQualifier() == null) ||
+ Bytes.equals(qualifier, other.getQualifier())) &&
+ ((namespace == null && other.getNamespace() == null) ||
+ (namespace != null && namespace.equals(other.getNamespace())))
+ )) {
+ return false;
+ }
+ return true;
+ }
+
@Override
@edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NP_NULL_ON_SOME_PATH",
justification="Passed on construction except on constructor not to be used")
@@ -314,15 +329,7 @@ public class TablePermission extends Permission {
}
TablePermission other = (TablePermission)obj;
- if (!(((table == null && other.getTableName() == null) ||
- (table != null && table.equals(other.getTableName()))) &&
- ((family == null && other.getFamily() == null) ||
- Bytes.equals(family, other.getFamily())) &&
- ((qualifier == null && other.getQualifier() == null) ||
- Bytes.equals(qualifier, other.getQualifier())) &&
- ((namespace == null && other.getNamespace() == null) ||
- (namespace != null && namespace.equals(other.getNamespace())))
- )) {
+ if(!this.tableFieldsEqual(other)){
return false;
}
http://git-wip-us.apache.org/repos/asf/hbase/blob/22fa1cd3/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/AccessControlProtos.java
----------------------------------------------------------------------
diff --git a/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/AccessControlProtos.java b/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/AccessControlProtos.java
index cd1dda1..b72e6e5 100644
--- a/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/AccessControlProtos.java
+++ b/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/AccessControlProtos.java
@@ -5569,6 +5569,16 @@ public final class AccessControlProtos {
* <code>required .hbase.pb.UserPermission user_permission = 1;</code>
*/
org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.UserPermissionOrBuilder getUserPermissionOrBuilder();
+
+ // optional bool merge_existing_permissions = 2 [default = false];
+ /**
+ * <code>optional bool merge_existing_permissions = 2 [default = false];</code>
+ */
+ boolean hasMergeExistingPermissions();
+ /**
+ * <code>optional bool merge_existing_permissions = 2 [default = false];</code>
+ */
+ boolean getMergeExistingPermissions();
}
/**
* Protobuf type {@code hbase.pb.GrantRequest}
@@ -5634,6 +5644,11 @@ public final class AccessControlProtos {
bitField0_ |= 0x00000001;
break;
}
+ case 16: {
+ bitField0_ |= 0x00000002;
+ mergeExistingPermissions_ = input.readBool();
+ break;
+ }
}
}
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
@@ -5696,8 +5711,25 @@ public final class AccessControlProtos {
return userPermission_;
}
+ // optional bool merge_existing_permissions = 2 [default = false];
+ public static final int MERGE_EXISTING_PERMISSIONS_FIELD_NUMBER = 2;
+ private boolean mergeExistingPermissions_;
+ /**
+ * <code>optional bool merge_existing_permissions = 2 [default = false];</code>
+ */
+ public boolean hasMergeExistingPermissions() {
+ return ((bitField0_ & 0x00000002) == 0x00000002);
+ }
+ /**
+ * <code>optional bool merge_existing_permissions = 2 [default = false];</code>
+ */
+ public boolean getMergeExistingPermissions() {
+ return mergeExistingPermissions_;
+ }
+
private void initFields() {
userPermission_ = org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.UserPermission.getDefaultInstance();
+ mergeExistingPermissions_ = false;
}
private byte memoizedIsInitialized = -1;
public final boolean isInitialized() {
@@ -5722,6 +5754,9 @@ public final class AccessControlProtos {
if (((bitField0_ & 0x00000001) == 0x00000001)) {
output.writeMessage(1, userPermission_);
}
+ if (((bitField0_ & 0x00000002) == 0x00000002)) {
+ output.writeBool(2, mergeExistingPermissions_);
+ }
getUnknownFields().writeTo(output);
}
@@ -5735,6 +5770,10 @@ public final class AccessControlProtos {
size += com.google.protobuf.CodedOutputStream
.computeMessageSize(1, userPermission_);
}
+ if (((bitField0_ & 0x00000002) == 0x00000002)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBoolSize(2, mergeExistingPermissions_);
+ }
size += getUnknownFields().getSerializedSize();
memoizedSerializedSize = size;
return size;
@@ -5763,6 +5802,11 @@ public final class AccessControlProtos {
result = result && getUserPermission()
.equals(other.getUserPermission());
}
+ result = result && (hasMergeExistingPermissions() == other.hasMergeExistingPermissions());
+ if (hasMergeExistingPermissions()) {
+ result = result && (getMergeExistingPermissions()
+ == other.getMergeExistingPermissions());
+ }
result = result &&
getUnknownFields().equals(other.getUnknownFields());
return result;
@@ -5780,6 +5824,10 @@ public final class AccessControlProtos {
hash = (37 * hash) + USER_PERMISSION_FIELD_NUMBER;
hash = (53 * hash) + getUserPermission().hashCode();
}
+ if (hasMergeExistingPermissions()) {
+ hash = (37 * hash) + MERGE_EXISTING_PERMISSIONS_FIELD_NUMBER;
+ hash = (53 * hash) + hashBoolean(getMergeExistingPermissions());
+ }
hash = (29 * hash) + getUnknownFields().hashCode();
memoizedHashCode = hash;
return hash;
@@ -5896,6 +5944,8 @@ public final class AccessControlProtos {
userPermissionBuilder_.clear();
}
bitField0_ = (bitField0_ & ~0x00000001);
+ mergeExistingPermissions_ = false;
+ bitField0_ = (bitField0_ & ~0x00000002);
return this;
}
@@ -5932,6 +5982,10 @@ public final class AccessControlProtos {
} else {
result.userPermission_ = userPermissionBuilder_.build();
}
+ if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
+ to_bitField0_ |= 0x00000002;
+ }
+ result.mergeExistingPermissions_ = mergeExistingPermissions_;
result.bitField0_ = to_bitField0_;
onBuilt();
return result;
@@ -5951,6 +6005,9 @@ public final class AccessControlProtos {
if (other.hasUserPermission()) {
mergeUserPermission(other.getUserPermission());
}
+ if (other.hasMergeExistingPermissions()) {
+ setMergeExistingPermissions(other.getMergeExistingPermissions());
+ }
this.mergeUnknownFields(other.getUnknownFields());
return this;
}
@@ -6103,6 +6160,39 @@ public final class AccessControlProtos {
return userPermissionBuilder_;
}
+ // optional bool merge_existing_permissions = 2 [default = false];
+ private boolean mergeExistingPermissions_ ;
+ /**
+ * <code>optional bool merge_existing_permissions = 2 [default = false];</code>
+ */
+ public boolean hasMergeExistingPermissions() {
+ return ((bitField0_ & 0x00000002) == 0x00000002);
+ }
+ /**
+ * <code>optional bool merge_existing_permissions = 2 [default = false];</code>
+ */
+ public boolean getMergeExistingPermissions() {
+ return mergeExistingPermissions_;
+ }
+ /**
+ * <code>optional bool merge_existing_permissions = 2 [default = false];</code>
+ */
+ public Builder setMergeExistingPermissions(boolean value) {
+ bitField0_ |= 0x00000002;
+ mergeExistingPermissions_ = value;
+ onChanged();
+ return this;
+ }
+ /**
+ * <code>optional bool merge_existing_permissions = 2 [default = false];</code>
+ */
+ public Builder clearMergeExistingPermissions() {
+ bitField0_ = (bitField0_ & ~0x00000002);
+ mergeExistingPermissions_ = false;
+ onChanged();
+ return this;
+ }
+
// @@protoc_insertion_point(builder_scope:hbase.pb.GrantRequest)
}
@@ -10432,29 +10522,30 @@ public final class AccessControlProtos {
"\0132-.hbase.pb.UsersAndPermissions.UserPer" +
"missions\032J\n\017UserPermissions\022\014\n\004user\030\001 \002(" +
"\014\022)\n\013permissions\030\002 \003(\0132\024.hbase.pb.Permis" +
- "sion\"A\n\014GrantRequest\0221\n\017user_permission\030" +
- "\001 \002(\0132\030.hbase.pb.UserPermission\"\017\n\rGrant" +
- "Response\"B\n\rRevokeRequest\0221\n\017user_permis" +
- "sion\030\001 \002(\0132\030.hbase.pb.UserPermission\"\020\n\016" +
- "RevokeResponse\"\205\001\n\031GetUserPermissionsReq" +
- "uest\022\'\n\004type\030\001 \001(\0162\031.hbase.pb.Permission" +
- ".Type\022\'\n\ntable_name\030\002 \001(\0132\023.hbase.pb.Tab",
- "leName\022\026\n\016namespace_name\030\003 \001(\014\"O\n\032GetUse" +
- "rPermissionsResponse\0221\n\017user_permission\030" +
- "\001 \003(\0132\030.hbase.pb.UserPermission\"C\n\027Check" +
- "PermissionsRequest\022(\n\npermission\030\001 \003(\0132\024" +
- ".hbase.pb.Permission\"\032\n\030CheckPermissions" +
- "Response2\311\002\n\024AccessControlService\0228\n\005Gra" +
- "nt\022\026.hbase.pb.GrantRequest\032\027.hbase.pb.Gr" +
- "antResponse\022;\n\006Revoke\022\027.hbase.pb.RevokeR" +
- "equest\032\030.hbase.pb.RevokeResponse\022_\n\022GetU" +
- "serPermissions\022#.hbase.pb.GetUserPermiss",
- "ionsRequest\032$.hbase.pb.GetUserPermission" +
- "sResponse\022Y\n\020CheckPermissions\022!.hbase.pb" +
- ".CheckPermissionsRequest\032\".hbase.pb.Chec" +
- "kPermissionsResponseBI\n*org.apache.hadoo" +
- "p.hbase.protobuf.generatedB\023AccessContro" +
- "lProtosH\001\210\001\001\240\001\001"
+ "sion\"l\n\014GrantRequest\0221\n\017user_permission\030" +
+ "\001 \002(\0132\030.hbase.pb.UserPermission\022)\n\032merge" +
+ "_existing_permissions\030\002 \001(\010:\005false\"\017\n\rGr" +
+ "antResponse\"B\n\rRevokeRequest\0221\n\017user_per" +
+ "mission\030\001 \002(\0132\030.hbase.pb.UserPermission\"" +
+ "\020\n\016RevokeResponse\"\205\001\n\031GetUserPermissions" +
+ "Request\022\'\n\004type\030\001 \001(\0162\031.hbase.pb.Permiss",
+ "ion.Type\022\'\n\ntable_name\030\002 \001(\0132\023.hbase.pb." +
+ "TableName\022\026\n\016namespace_name\030\003 \001(\014\"O\n\032Get" +
+ "UserPermissionsResponse\0221\n\017user_permissi" +
+ "on\030\001 \003(\0132\030.hbase.pb.UserPermission\"C\n\027Ch" +
+ "eckPermissionsRequest\022(\n\npermission\030\001 \003(" +
+ "\0132\024.hbase.pb.Permission\"\032\n\030CheckPermissi" +
+ "onsResponse2\311\002\n\024AccessControlService\0228\n\005" +
+ "Grant\022\026.hbase.pb.GrantRequest\032\027.hbase.pb" +
+ ".GrantResponse\022;\n\006Revoke\022\027.hbase.pb.Revo" +
+ "keRequest\032\030.hbase.pb.RevokeResponse\022_\n\022G",
+ "etUserPermissions\022#.hbase.pb.GetUserPerm" +
+ "issionsRequest\032$.hbase.pb.GetUserPermiss" +
+ "ionsResponse\022Y\n\020CheckPermissions\022!.hbase" +
+ ".pb.CheckPermissionsRequest\032\".hbase.pb.C" +
+ "heckPermissionsResponseBI\n*org.apache.ha" +
+ "doop.hbase.protobuf.generatedB\023AccessCon" +
+ "trolProtosH\001\210\001\001\240\001\001"
};
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
@@ -10508,7 +10599,7 @@ public final class AccessControlProtos {
internal_static_hbase_pb_GrantRequest_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_hbase_pb_GrantRequest_descriptor,
- new java.lang.String[] { "UserPermission", });
+ new java.lang.String[] { "UserPermission", "MergeExistingPermissions", });
internal_static_hbase_pb_GrantResponse_descriptor =
getDescriptor().getMessageTypes().get(7);
internal_static_hbase_pb_GrantResponse_fieldAccessorTable = new
http://git-wip-us.apache.org/repos/asf/hbase/blob/22fa1cd3/hbase-protocol/src/main/protobuf/AccessControl.proto
----------------------------------------------------------------------
diff --git a/hbase-protocol/src/main/protobuf/AccessControl.proto b/hbase-protocol/src/main/protobuf/AccessControl.proto
index e67540b..cc0d4a5 100644
--- a/hbase-protocol/src/main/protobuf/AccessControl.proto
+++ b/hbase-protocol/src/main/protobuf/AccessControl.proto
@@ -79,6 +79,7 @@ message UsersAndPermissions {
message GrantRequest {
required UserPermission user_permission = 1;
+ optional bool merge_existing_permissions = 2 [default = false];
}
message GrantResponse {
http://git-wip-us.apache.org/repos/asf/hbase/blob/22fa1cd3/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessControlLists.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessControlLists.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessControlLists.java
index cbdcea9..f06330c 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessControlLists.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessControlLists.java
@@ -150,8 +150,8 @@ public class AccessControlLists {
* @param t acl table instance. It is closed upon method return.
* @throws IOException in the case of an error accessing the metadata table
*/
- static void addUserPermission(Configuration conf, UserPermission userPerm, Table t)
- throws IOException {
+ static void addUserPermission(Configuration conf, UserPermission userPerm, Table t,
+ boolean mergeExistingPermissions) throws IOException {
Permission.Action[] actions = userPerm.getActions();
byte[] rowKey = userPermissionRowKey(userPerm);
Put p = new Put(rowKey);
@@ -163,10 +163,34 @@ public class AccessControlLists {
throw new IOException(msg);
}
- byte[] value = new byte[actions.length];
- for (int i = 0; i < actions.length; i++) {
- value[i] = actions[i].code();
+ Set<Permission.Action> actionSet = new TreeSet<Permission.Action>();
+ if(mergeExistingPermissions){
+ List<UserPermission> perms = getUserPermissions(conf, rowKey);
+ UserPermission currentPerm = null;
+ for (UserPermission perm : perms) {
+ if (Bytes.equals(perm.getUser(), userPerm.getUser())
+ && ((userPerm.isGlobal() && ACL_TABLE_NAME.equals(perm.getTableName()))
+ || perm.tableFieldsEqual(userPerm))) {
+ currentPerm = perm;
+ break;
+ }
+ }
+
+ if(currentPerm != null && currentPerm.getActions() != null){
+ actionSet.addAll(Arrays.asList(currentPerm.getActions()));
+ }
+ }
+
+ // merge current action with new action.
+ actionSet.addAll(Arrays.asList(actions));
+
+ // serialize to byte array.
+ byte[] value = new byte[actionSet.size()];
+ int index = 0;
+ for (Permission.Action action : actionSet) {
+ value[index++] = action.code();
}
+
p.addImmutable(ACL_LIST_FAMILY, key, value);
if (LOG.isDebugEnabled()) {
LOG.debug("Writing permission with rowKey "+
@@ -181,6 +205,11 @@ public class AccessControlLists {
}
}
+ static void addUserPermission(Configuration conf, UserPermission userPerm, Table t)
+ throws IOException{
+ addUserPermission(conf, userPerm, t, false);
+ }
+
/**
* Removes a previously granted permission from the stored access control
* lists. The {@link TablePermission} being removed must exactly match what
http://git-wip-us.apache.org/repos/asf/hbase/blob/22fa1cd3/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 d89e053..ec41490 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
@@ -2246,7 +2246,7 @@ public class AccessController extends BaseMasterAndRegionObserver
@Override
public Void run() throws Exception {
AccessControlLists.addUserPermission(regionEnv.getConfiguration(), perm,
- regionEnv.getTable(AccessControlLists.ACL_TABLE_NAME));
+ regionEnv.getTable(AccessControlLists.ACL_TABLE_NAME), request.getMergeExistingPermissions());
return null;
}
});
http://git-wip-us.apache.org/repos/asf/hbase/blob/22fa1cd3/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/SecureTestUtil.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/SecureTestUtil.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/SecureTestUtil.java
index 067e1f5..b0c68ba 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/SecureTestUtil.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/SecureTestUtil.java
@@ -371,7 +371,7 @@ public class SecureTestUtil {
BlockingRpcChannel service = acl.coprocessorService(HConstants.EMPTY_START_ROW);
AccessControlService.BlockingInterface protocol =
AccessControlService.newBlockingStub(service);
- AccessControlUtil.grant(null, protocol, user, actions);
+ AccessControlUtil.grant(null, protocol, user, false, actions);
}
}
return null;
@@ -417,7 +417,7 @@ public class SecureTestUtil {
BlockingRpcChannel service = acl.coprocessorService(HConstants.EMPTY_START_ROW);
AccessControlService.BlockingInterface protocol =
AccessControlService.newBlockingStub(service);
- AccessControlUtil.grant(null, protocol, user, namespace, actions);
+ AccessControlUtil.grant(null, protocol, user, namespace, false, actions);
}
}
return null;
@@ -439,7 +439,7 @@ public class SecureTestUtil {
try {
AccessControlClient.grant(connection, namespace, user, actions);
} catch (Throwable t) {
- t.printStackTrace();
+ LOG.error("grant failed: ", t);
}
return null;
}
@@ -460,7 +460,7 @@ public class SecureTestUtil {
try {
AccessControlClient.revoke(connection, namespace, user, actions);
} catch (Throwable t) {
- t.printStackTrace();
+ LOG.error("revoke failed: ", t);
}
return null;
}
@@ -506,7 +506,7 @@ public class SecureTestUtil {
BlockingRpcChannel service = acl.coprocessorService(HConstants.EMPTY_START_ROW);
AccessControlService.BlockingInterface protocol =
AccessControlService.newBlockingStub(service);
- AccessControlUtil.grant(null, protocol, user, table, family, qualifier, actions);
+ AccessControlUtil.grant(null, protocol, user, table, family, qualifier, false, actions);
}
}
return null;
@@ -528,7 +528,7 @@ public class SecureTestUtil {
try {
AccessControlClient.grant(connection, table, user, family, qualifier, actions);
} catch (Throwable t) {
- t.printStackTrace();
+ LOG.error("grant failed: ", t);
}
return null;
}
@@ -549,7 +549,7 @@ public class SecureTestUtil {
try {
AccessControlClient.grant(connection, user, actions);
} catch (Throwable t) {
- t.printStackTrace();
+ LOG.error("grant failed: ", t);
}
return null;
}
@@ -594,7 +594,7 @@ public class SecureTestUtil {
try {
AccessControlClient.revoke(connection, table, user, family, qualifier, actions);
} catch (Throwable t) {
- t.printStackTrace();
+ LOG.error("revoke failed: ", t);
}
return null;
}
@@ -615,7 +615,7 @@ public class SecureTestUtil {
try {
AccessControlClient.revoke(connection, user, actions);
} catch (Throwable t) {
- t.printStackTrace();
+ LOG.error("revoke failed: ", t);
}
return null;
}
http://git-wip-us.apache.org/repos/asf/hbase/blob/22fa1cd3/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 29fe573..0377190 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
@@ -1191,7 +1191,7 @@ public class TestAccessController extends SecureTestUtil {
AccessControlService.BlockingInterface protocol =
AccessControlService.newBlockingStub(service);
AccessControlUtil.grant(null, protocol, USER_RO.getShortName(), TEST_TABLE, TEST_FAMILY,
- null, Action.READ);
+ null, false, Action.READ);
}
return null;
}
@@ -2404,6 +2404,129 @@ public class TestAccessController extends SecureTestUtil {
}
}
+ @Test(timeout = 180000)
+ public void testAccessControlClientMultiGrantRevoke() throws Exception {
+ User testGrantRevoke =
+ User.createUserForTesting(conf, "testGrantRevoke", new String[0]);
+ AccessTestAction getAction = new AccessTestAction() {
+ @Override
+ public Object run() throws Exception {
+ try(Connection conn = ConnectionFactory.createConnection(conf);
+ Table t = conn.getTable(TEST_TABLE)) {
+ return t.get(new Get(TEST_ROW));
+ }
+ }
+ };
+
+ AccessTestAction putAction = new AccessTestAction() {
+ @Override
+ public Object run() throws Exception {
+ Put p = new Put(TEST_ROW);
+ p.addColumn(TEST_FAMILY, TEST_QUALIFIER, Bytes.toBytes(1));
+ try(Connection conn = ConnectionFactory.createConnection(conf);
+ Table t = conn.getTable(TEST_TABLE)) {
+ t.put(p);
+ return null;
+ }
+ }
+ };
+
+ verifyDenied(getAction, testGrantRevoke);
+ verifyDenied(putAction, testGrantRevoke);
+
+ // Grant global READ permissions to testGrantRevoke.
+ String userName = testGrantRevoke.getShortName();
+ try {
+ grantGlobalUsingAccessControlClient(TEST_UTIL, systemUserConnection, userName,
+ Permission.Action.READ);
+ } catch (Throwable e) {
+ LOG.error("error during call of AccessControlClient.grant. ", e);
+ }
+ verifyAllowed(getAction, testGrantRevoke);
+ verifyDenied(putAction, testGrantRevoke);
+
+ // Grant global READ permissions to testGrantRevoke.
+ try {
+ grantGlobalUsingAccessControlClient(TEST_UTIL, systemUserConnection, userName,
+ Permission.Action.WRITE);
+ } catch (Throwable e) {
+ LOG.error("error during call of AccessControlClient.grant. ", e);
+ }
+ verifyAllowed(getAction, testGrantRevoke);
+ verifyAllowed(putAction, testGrantRevoke);
+
+ // Revoke global READ permission to testGrantRevoke.
+ try {
+ revokeGlobalUsingAccessControlClient(TEST_UTIL, systemUserConnection, userName,
+ Permission.Action.READ, Permission.Action.WRITE);
+ } catch (Throwable e) {
+ LOG.error("error during call of AccessControlClient.revoke ", e);
+ }
+ verifyDenied(getAction, testGrantRevoke);
+ verifyDenied(putAction, testGrantRevoke);
+
+ // Grant table READ & WRITE permissions to testGrantRevoke
+ try {
+ grantOnTableUsingAccessControlClient(TEST_UTIL, systemUserConnection, userName, TEST_TABLE,
+ null, null, Permission.Action.READ);
+ } catch (Throwable e) {
+ LOG.error("error during call of AccessControlClient.grant. ", e);
+ }
+ verifyAllowed(getAction, testGrantRevoke);
+ verifyDenied(putAction, testGrantRevoke);
+
+ // Grant table WRITE permissions to testGrantRevoke
+ try {
+ grantOnTableUsingAccessControlClient(TEST_UTIL, systemUserConnection, userName, TEST_TABLE,
+ null, null, Action.WRITE);
+ } catch (Throwable e) {
+ LOG.error("error during call of AccessControlClient.grant. ", e);
+ }
+ verifyAllowed(getAction, testGrantRevoke);
+ verifyAllowed(putAction, testGrantRevoke);
+
+ // Revoke table READ & WRITE permission to testGrantRevoke.
+ try {
+ revokeFromTableUsingAccessControlClient(TEST_UTIL, systemUserConnection, userName, TEST_TABLE, null, null,
+ Permission.Action.READ, Permission.Action.WRITE);
+ } catch (Throwable e) {
+ LOG.error("error during call of AccessControlClient.revoke ", e);
+ }
+ verifyDenied(getAction, testGrantRevoke);
+ verifyDenied(putAction, testGrantRevoke);
+
+ // Grant Namespace READ permissions to testGrantRevoke
+ String namespace = TEST_TABLE.getNamespaceAsString();
+ try {
+ grantOnNamespaceUsingAccessControlClient(TEST_UTIL, systemUserConnection, userName,
+ namespace, Permission.Action.READ);
+ } catch (Throwable e) {
+ LOG.error("error during call of AccessControlClient.grant. ", e);
+ }
+ verifyAllowed(getAction, testGrantRevoke);
+ verifyDenied(putAction, testGrantRevoke);
+
+ // Grant Namespace WRITE permissions to testGrantRevoke
+ try {
+ grantOnNamespaceUsingAccessControlClient(TEST_UTIL, systemUserConnection, userName,
+ namespace, Permission.Action.WRITE);
+ } catch (Throwable e) {
+ LOG.error("error during call of AccessControlClient.grant. ", e);
+ }
+ verifyAllowed(getAction, testGrantRevoke);
+ verifyAllowed(putAction, testGrantRevoke);
+
+ // Revoke table READ & WRITE permission to testGrantRevoke.
+ try {
+ revokeFromNamespaceUsingAccessControlClient(TEST_UTIL, systemUserConnection, userName,
+ TEST_TABLE.getNamespaceAsString(), Permission.Action.READ, Permission.Action.WRITE);
+ } catch (Throwable e) {
+ LOG.error("error during call of AccessControlClient.revoke ", e);
+ }
+ verifyDenied(getAction, testGrantRevoke);
+ verifyDenied(putAction, testGrantRevoke);
+ }
+
@Test (timeout=180000)
public void testAccessControlClientGrantRevokeOnNamespace() throws Exception {
// Create user for testing, who has no READ privileges by default.
http://git-wip-us.apache.org/repos/asf/hbase/blob/22fa1cd3/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestNamespaceCommands.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestNamespaceCommands.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestNamespaceCommands.java
index de98092..3c37d4b 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestNamespaceCommands.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestNamespaceCommands.java
@@ -359,7 +359,7 @@ public class TestNamespaceCommands extends SecureTestUtil {
acl.coprocessorService(HConstants.EMPTY_START_ROW);
AccessControlService.BlockingInterface protocol =
AccessControlService.newBlockingStub(service);
- AccessControlUtil.grant(null, protocol, testUser, TEST_NAMESPACE, Action.WRITE);
+ AccessControlUtil.grant(null, protocol, testUser, TEST_NAMESPACE, false, Action.WRITE);
} finally {
acl.close();
connection.close();
@@ -377,7 +377,7 @@ public class TestNamespaceCommands extends SecureTestUtil {
AccessControlService.BlockingInterface protocol =
AccessControlService.newBlockingStub(service);
AccessControlUtil.grant(null, protocol, USER_GROUP_NS_ADMIN.getShortName(),
- TEST_NAMESPACE, Action.READ);
+ TEST_NAMESPACE, false, Action.READ);
}
return null;
}
http://git-wip-us.apache.org/repos/asf/hbase/blob/22fa1cd3/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestTablePermissions.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestTablePermissions.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestTablePermissions.java
index 602d18f..4d2cb0b 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestTablePermissions.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestTablePermissions.java
@@ -458,7 +458,7 @@ public class TestTablePermissions {
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
+ Permission.Action.READ, Permission.Action.CREATE, Permission.Action.ADMIN
},
user3Perms.get(0).getActions());
}