diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Admin.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Admin.java index 6f8ee7a4d06..0605a03bcc9 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Admin.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Admin.java @@ -56,6 +56,7 @@ import org.apache.hadoop.hbase.regionserver.wal.FailedLogCloseException; import org.apache.hadoop.hbase.replication.ReplicationException; import org.apache.hadoop.hbase.replication.ReplicationPeerConfig; import org.apache.hadoop.hbase.replication.ReplicationPeerDescription; +import org.apache.hadoop.hbase.security.access.GetUserPermissionsRequest; import org.apache.hadoop.hbase.security.access.UserPermission; import org.apache.hadoop.hbase.snapshot.HBaseSnapshotException; import org.apache.hadoop.hbase.snapshot.RestoreSnapshotException; @@ -2921,4 +2922,14 @@ public interface Admin extends Abortable, Closeable { * @throws IOException if a remote or network exception occurs */ void revoke(UserPermission userPermission) throws IOException; + + /** + * Get the global/namespace/table permissions for user + * @param getUserPermissionsRequest A request contains which user, global, namespace or table + * permissions needed + * @return The user and permission list + * @throws IOException if a remote or network exception occurs + */ + List getUserPermissions(GetUserPermissionsRequest getUserPermissionsRequest) + throws IOException; } diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncAdmin.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncAdmin.java index 682ae62c82a..bce0327f2d0 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncAdmin.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncAdmin.java @@ -42,6 +42,7 @@ import org.apache.hadoop.hbase.quotas.QuotaSettings; import org.apache.hadoop.hbase.quotas.SpaceQuotaSnapshotView; import org.apache.hadoop.hbase.replication.ReplicationPeerConfig; import org.apache.hadoop.hbase.replication.ReplicationPeerDescription; +import org.apache.hadoop.hbase.security.access.GetUserPermissionsRequest; import org.apache.hadoop.hbase.security.access.UserPermission; import org.apache.yetus.audience.InterfaceAudience; @@ -1414,4 +1415,13 @@ public interface AsyncAdmin { * @param userPermission user name and the specific permission */ CompletableFuture revoke(UserPermission userPermission); + + /** + * Get the global/namespace/table permissions for user + * @param getUserPermissionsRequest A request contains which user, global, namespace or table + * permissions needed + * @return The user and permission list + */ + CompletableFuture> + getUserPermissions(GetUserPermissionsRequest getUserPermissionsRequest); } diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncHBaseAdmin.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncHBaseAdmin.java index f037b4e1b0c..3c696059c1c 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncHBaseAdmin.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/AsyncHBaseAdmin.java @@ -41,6 +41,7 @@ import org.apache.hadoop.hbase.quotas.QuotaSettings; import org.apache.hadoop.hbase.quotas.SpaceQuotaSnapshot; import org.apache.hadoop.hbase.replication.ReplicationPeerConfig; import org.apache.hadoop.hbase.replication.ReplicationPeerDescription; +import org.apache.hadoop.hbase.security.access.GetUserPermissionsRequest; import org.apache.hadoop.hbase.security.access.UserPermission; import org.apache.hadoop.hbase.util.FutureUtils; import org.apache.yetus.audience.InterfaceAudience; @@ -805,4 +806,10 @@ class AsyncHBaseAdmin implements AsyncAdmin { public CompletableFuture revoke(UserPermission userPermission) { return wrap(rawAdmin.revoke(userPermission)); } + + @Override + public CompletableFuture> + getUserPermissions(GetUserPermissionsRequest getUserPermissionsRequest) { + return wrap(rawAdmin.getUserPermissions(getUserPermissionsRequest)); + } } diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionImplementation.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionImplementation.java index d0b29d13bf2..6eb0ca11035 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionImplementation.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionImplementation.java @@ -93,6 +93,8 @@ import org.apache.hbase.thirdparty.com.google.protobuf.ServiceException; import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; import org.apache.hadoop.hbase.shaded.protobuf.RequestConverter; import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos; +import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.GetUserPermissionsRequest; +import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.GetUserPermissionsResponse; import org.apache.hadoop.hbase.shaded.protobuf.generated.AdminProtos; import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos; import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.ClientService.BlockingInterface; @@ -1786,6 +1788,12 @@ class ConnectionImplementation implements ClusterConnection, Closeable { AccessControlProtos.RevokeRequest request) throws ServiceException { return stub.revoke(controller, request); } + + @Override + public GetUserPermissionsResponse getUserPermissions(RpcController controller, + GetUserPermissionsRequest request) throws ServiceException { + return stub.getUserPermissions(controller, request); + } }; } diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java index e75b86938dc..cc8590fd244 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java @@ -87,6 +87,7 @@ import org.apache.hadoop.hbase.quotas.SpaceQuotaSnapshot; import org.apache.hadoop.hbase.regionserver.wal.FailedLogCloseException; import org.apache.hadoop.hbase.replication.ReplicationPeerConfig; import org.apache.hadoop.hbase.replication.ReplicationPeerDescription; +import org.apache.hadoop.hbase.security.access.GetUserPermissionsRequest; import org.apache.hadoop.hbase.security.access.ShadedAccessControlUtil; import org.apache.hadoop.hbase.security.access.UserPermission; import org.apache.hadoop.hbase.snapshot.ClientSnapshotDescriptionUtils; @@ -112,6 +113,7 @@ import org.apache.hbase.thirdparty.com.google.protobuf.ServiceException; import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; import org.apache.hadoop.hbase.shaded.protobuf.RequestConverter; +import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos; import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.GrantRequest; import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.RevokeRequest; import org.apache.hadoop.hbase.shaded.protobuf.generated.AdminProtos; @@ -4256,4 +4258,22 @@ public class HBaseAdmin implements Admin { } }); } + + @Override + public List + getUserPermissions(GetUserPermissionsRequest getUserPermissionsRequest) throws IOException { + return executeCallable( + new MasterCallable>(getConnection(), getRpcControllerFactory()) { + @Override + protected List rpcCall() throws Exception { + AccessControlProtos.GetUserPermissionsRequest req = + ShadedAccessControlUtil.buildGetUserPermissionsRequest(getUserPermissionsRequest); + AccessControlProtos.GetUserPermissionsResponse response = + this.master.getUserPermissions(getRpcController(), req); + return response.getUserPermissionList().stream() + .map(userPermission -> ShadedAccessControlUtil.toUserPermission(userPermission)) + .collect(Collectors.toList()); + } + }); + } } diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RawAsyncHBaseAdmin.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RawAsyncHBaseAdmin.java index f00a38da9bd..42152ce94ed 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RawAsyncHBaseAdmin.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/RawAsyncHBaseAdmin.java @@ -84,6 +84,7 @@ import org.apache.hadoop.hbase.quotas.SpaceQuotaSnapshot; import org.apache.hadoop.hbase.replication.ReplicationException; import org.apache.hadoop.hbase.replication.ReplicationPeerConfig; import org.apache.hadoop.hbase.replication.ReplicationPeerDescription; +import org.apache.hadoop.hbase.security.access.GetUserPermissionsRequest; import org.apache.hadoop.hbase.security.access.ShadedAccessControlUtil; import org.apache.hadoop.hbase.security.access.UserPermission; import org.apache.hadoop.hbase.snapshot.ClientSnapshotDescriptionUtils; @@ -105,6 +106,8 @@ import org.apache.hbase.thirdparty.io.netty.util.TimerTask; import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; import org.apache.hadoop.hbase.shaded.protobuf.RequestConverter; +import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos; +import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.GetUserPermissionsResponse; import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.GrantRequest; import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.GrantResponse; import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.RevokeRequest; @@ -3769,4 +3772,18 @@ class RawAsyncHBaseAdmin implements AsyncAdmin { (s, c, req, done) -> s.revoke(c, req, done), resp -> null)) .call(); } + + @Override + public CompletableFuture> + getUserPermissions(GetUserPermissionsRequest getUserPermissionsRequest) { + return this.> newMasterCaller().action((controller, + stub) -> this.> call(controller, stub, + ShadedAccessControlUtil.buildGetUserPermissionsRequest(getUserPermissionsRequest), + (s, c, req, done) -> s.getUserPermissions(c, req, done), + resp -> resp.getUserPermissionList().stream() + .map(uPerm -> ShadedAccessControlUtil.toUserPermission(uPerm)) + .collect(Collectors.toList()))) + .call(); + } } diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ShortCircuitMasterConnection.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ShortCircuitMasterConnection.java index 1bd349a7db5..89624669096 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ShortCircuitMasterConnection.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ShortCircuitMasterConnection.java @@ -21,6 +21,8 @@ import org.apache.yetus.audience.InterfaceAudience; import org.apache.hbase.thirdparty.com.google.protobuf.RpcController; import org.apache.hbase.thirdparty.com.google.protobuf.ServiceException; +import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.GetUserPermissionsRequest; +import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.GetUserPermissionsResponse; import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.GrantRequest; import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.GrantResponse; import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.RevokeRequest; @@ -679,4 +681,10 @@ public class ShortCircuitMasterConnection implements MasterKeepAliveConnection { throws ServiceException { return stub.revoke(controller, request); } + + @Override + public GetUserPermissionsResponse getUserPermissions(RpcController controller, + GetUserPermissionsRequest request) throws ServiceException { + return stub.getUserPermissions(controller, request); + } } 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 91e438284ca..8457290fd15 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 @@ -24,11 +24,11 @@ import java.util.regex.Pattern; import org.apache.commons.lang3.StringUtils; import org.apache.hadoop.hbase.HConstants; -import org.apache.hadoop.hbase.HTableDescriptor; import org.apache.hadoop.hbase.MasterNotRunningException; import org.apache.hadoop.hbase.NamespaceDescriptor; import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.ZooKeeperConnectionException; +import org.apache.hadoop.hbase.client.TableDescriptor; import org.apache.yetus.audience.InterfaceAudience; import org.apache.hadoop.hbase.client.Admin; import org.apache.hadoop.hbase.client.Connection; @@ -250,36 +250,27 @@ public class AccessControlClient { */ public static List getUserPermissions(Connection connection, String tableRegex, String userName) throws Throwable { - /** - * TODO: Pass an rpcController HBaseRpcController controller = ((ClusterConnection) - * connection).getRpcControllerFactory().newController(); - */ List permList = new ArrayList<>(); - try (Table table = connection.getTable(ACL_TABLE_NAME)) { - try (Admin admin = connection.getAdmin()) { - CoprocessorRpcChannel service = table.coprocessorService(HConstants.EMPTY_START_ROW); - BlockingInterface protocol = - AccessControlProtos.AccessControlService.newBlockingStub(service); - HTableDescriptor[] htds = null; - if (tableRegex == null || tableRegex.isEmpty()) { - permList = AccessControlUtil.getUserPermissions(null, protocol, userName); - } else if (tableRegex.charAt(0) == '@') { // Namespaces - String namespaceRegex = tableRegex.substring(1); - for (NamespaceDescriptor nsds : admin.listNamespaceDescriptors()) { // Read out all - // namespaces - String namespace = nsds.getName(); - if (namespace.matches(namespaceRegex)) { // Match the given namespace regex? - permList.addAll(AccessControlUtil.getUserPermissions(null, protocol, - Bytes.toBytes(namespace), userName)); - } - } - } else { // Tables - htds = admin.listTables(Pattern.compile(tableRegex), true); - for (HTableDescriptor htd : htds) { - permList.addAll(AccessControlUtil.getUserPermissions(null, protocol, htd.getTableName(), - null, null, userName)); + try (Admin admin = connection.getAdmin()) { + if (tableRegex == null || tableRegex.isEmpty()) { + permList = admin.getUserPermissions( + GetUserPermissionsRequest.newBuilder().withUserName(userName).build()); + } else if (tableRegex.charAt(0) == '@') { // Namespaces + String namespaceRegex = tableRegex.substring(1); + for (NamespaceDescriptor nsds : admin.listNamespaceDescriptors()) { // Read out all + // namespaces + String namespace = nsds.getName(); + if (namespace.matches(namespaceRegex)) { // Match the given namespace regex? + permList.addAll(admin.getUserPermissions( + GetUserPermissionsRequest.newBuilder(namespace).withUserName(userName).build())); } } + } else { // Tables + List htds = admin.listTableDescriptors(Pattern.compile(tableRegex), true); + for (TableDescriptor htd : htds) { + permList.addAll(admin.getUserPermissions(GetUserPermissionsRequest + .newBuilder(htd.getTableName()).withUserName(userName).build())); + } } } return permList; @@ -348,22 +339,14 @@ public class AccessControlClient { if (tableRegex == null || tableRegex.isEmpty() || tableRegex.charAt(0) == '@') { throw new IllegalArgumentException("Table name can't be null or empty or a namespace."); } - /** - * TODO: Pass an rpcController HBaseRpcController controller = ((ClusterConnection) - * connection).getRpcControllerFactory().newController(); - */ List permList = new ArrayList(); - try (Table table = connection.getTable(ACL_TABLE_NAME)) { - try (Admin admin = connection.getAdmin()) { - CoprocessorRpcChannel service = table.coprocessorService(HConstants.EMPTY_START_ROW); - BlockingInterface protocol = - AccessControlProtos.AccessControlService.newBlockingStub(service); - HTableDescriptor[] htds = admin.listTables(Pattern.compile(tableRegex), true); - // Retrieve table permissions - for (HTableDescriptor htd : htds) { - permList.addAll(AccessControlUtil.getUserPermissions(null, protocol, htd.getTableName(), - columnFamily, columnQualifier, userName)); - } + try (Admin admin = connection.getAdmin()) { + List htds = admin.listTableDescriptors(Pattern.compile(tableRegex), true); + // Retrieve table permissions + for (TableDescriptor htd : htds) { + permList.addAll(admin.getUserPermissions( + GetUserPermissionsRequest.newBuilder(htd.getTableName()).withFamily(columnFamily) + .withQualifier(columnQualifier).withUserName(userName).build())); } } return permList; 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 05f173e4b26..0220d89eeae 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 @@ -654,7 +654,9 @@ public class AccessControlUtil { * @param controller RpcController * @param protocol the AccessControlService protocol proxy * @throws ServiceException on failure + * @deprecated Use {@link Admin#getUserPermissions(GetUserPermissionsRequest)} instead. */ + @Deprecated public static List getUserPermissions(RpcController controller, AccessControlService.BlockingInterface protocol) throws ServiceException { return getUserPermissions(controller, protocol, HConstants.EMPTY_STRING); @@ -666,7 +668,9 @@ public class AccessControlUtil { * @param protocol the AccessControlService protocol proxy * @param userName User name, if empty then all user permissions will be retrieved. * @throws ServiceException + * @deprecated Use {@link Admin#getUserPermissions(GetUserPermissionsRequest)} instead. */ + @Deprecated public static List getUserPermissions(RpcController controller, AccessControlService.BlockingInterface protocol, String userName) throws ServiceException { AccessControlProtos.GetUserPermissionsRequest.Builder builder = @@ -695,7 +699,9 @@ public class AccessControlUtil { * @param protocol the AccessControlService protocol proxy * @param t optional table name * @throws ServiceException + * @deprecated Use {@link Admin#getUserPermissions(GetUserPermissionsRequest)} instead. */ + @Deprecated public static List getUserPermissions(RpcController controller, AccessControlService.BlockingInterface protocol, TableName t) throws ServiceException { @@ -712,7 +718,9 @@ public class AccessControlUtil { * @param columnQualifier Column qualifier * @param userName User name, if empty then all user permissions will be retrieved. * @throws ServiceException + * @deprecated Use {@link Admin#getUserPermissions(GetUserPermissionsRequest)} instead. */ + @Deprecated public static List getUserPermissions(RpcController controller, AccessControlService.BlockingInterface protocol, TableName t, byte[] columnFamily, byte[] columnQualifier, String userName) throws ServiceException { @@ -751,7 +759,9 @@ public class AccessControlUtil { * @param protocol the AccessControlService protocol proxy * @param namespace name of the namespace * @throws ServiceException + * @deprecated Use {@link Admin#getUserPermissions(GetUserPermissionsRequest)} instead. */ + @Deprecated public static List getUserPermissions(RpcController controller, AccessControlService.BlockingInterface protocol, byte[] namespace) throws ServiceException { @@ -765,7 +775,9 @@ public class AccessControlUtil { * @param namespace name of the namespace * @param userName User name, if empty then all user permissions will be retrieved. * @throws ServiceException + * @deprecated Use {@link Admin#getUserPermissions(GetUserPermissionsRequest)} instead. */ + @Deprecated public static List getUserPermissions(RpcController controller, AccessControlService.BlockingInterface protocol, byte[] namespace, String userName) throws ServiceException { diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/security/access/GetUserPermissionsRequest.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/security/access/GetUserPermissionsRequest.java new file mode 100644 index 00000000000..8e1767cce94 --- /dev/null +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/security/access/GetUserPermissionsRequest.java @@ -0,0 +1,136 @@ +/* + * 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. + */ + +package org.apache.hadoop.hbase.security.access; + +import java.util.Objects; +import org.apache.hadoop.hbase.TableName; +import org.apache.yetus.audience.InterfaceAudience; + +/** + * Used by + * {@link org.apache.hadoop.hbase.client.Admin#getUserPermissions(GetUserPermissionsRequest)}. + * Represents the params of user permissions needed to get from HBase. + */ +@InterfaceAudience.Public +public final class GetUserPermissionsRequest { + private String userName; + private String namespace; + private TableName tableName; + private byte[] family; + private byte[] qualifier; + + private GetUserPermissionsRequest(String userName, String namespace, TableName tableName, + byte[] family, byte[] qualifier) { + this.userName = userName; + this.namespace = namespace; + this.tableName = tableName; + this.family = family; + this.qualifier = qualifier; + } + + /** + * Build a get global permission request + * @return a get global permission request builder + */ + public static Builder newBuilder() { + return new Builder(); + } + + /** + * Build a get namespace permission request + * @param namespace the specific namespace + * @return a get namespace permission request builder + */ + public static Builder newBuilder(String namespace) { + return new Builder(namespace); + } + + /** + * Build a get table permission request + * @param tableName the specific table name + * @return a get table permission request builder + */ + public static Builder newBuilder(TableName tableName) { + return new Builder(tableName); + } + + public String getUserName() { + return userName; + } + + public String getNamespace() { + return namespace; + } + + public TableName getTableName() { + return tableName; + } + + public byte[] getFamily() { + return family; + } + + public byte[] getQualifier() { + return qualifier; + } + + public static final class Builder { + private String userName; + private String namespace; + private TableName tableName; + private byte[] family; + private byte[] qualifier; + + private Builder() { + } + + private Builder(String namespace) { + this.namespace = namespace; + } + + private Builder(TableName tableName) { + this.tableName = tableName; + } + + /** + * user name could be null if need all global/namespace/table permissions + */ + public Builder withUserName(String userName) { + this.userName = userName; + return this; + } + + public Builder withFamily(byte[] family) { + Objects.requireNonNull(tableName, "The tableName can't be NULL"); + this.family = family; + return this; + } + + public Builder withQualifier(byte[] qualifier) { + Objects.requireNonNull(tableName, "The tableName can't be NULL"); + // Objects.requireNonNull(family, "The family can't be NULL"); + this.qualifier = qualifier; + return this; + } + + public GetUserPermissionsRequest build() { + return new GetUserPermissionsRequest(userName, namespace, tableName, family, qualifier); + } + } +} diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/security/access/ShadedAccessControlUtil.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/security/access/ShadedAccessControlUtil.java index b354d879c07..be3b75e97c2 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/security/access/ShadedAccessControlUtil.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/security/access/ShadedAccessControlUtil.java @@ -29,7 +29,9 @@ import org.apache.hbase.thirdparty.com.google.common.collect.ArrayListMultimap; import org.apache.hbase.thirdparty.com.google.common.collect.ListMultimap; import org.apache.hbase.thirdparty.com.google.protobuf.ByteString; import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos; +import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.GetUserPermissionsResponse; import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.GrantRequest; +import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.Permission.Type; import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.RevokeRequest; import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos; @@ -280,4 +282,40 @@ public class ShadedAccessControlUtil { public static RevokeRequest buildRevokeRequest(UserPermission userPermission) { return RevokeRequest.newBuilder().setUserPermission(toUserPermission(userPermission)).build(); } + + public static AccessControlProtos.GetUserPermissionsRequest + buildGetUserPermissionsRequest(GetUserPermissionsRequest request) { + AccessControlProtos.GetUserPermissionsRequest.Builder builder = + AccessControlProtos.GetUserPermissionsRequest.newBuilder(); + if (request.getUserName() != null && !request.getUserName().isEmpty()) { + builder.setUserName(ByteString.copyFromUtf8(request.getUserName())); + } + if (request.getNamespace() != null && !request.getNamespace().isEmpty()) { + builder.setNamespaceName(ByteString.copyFromUtf8(request.getNamespace())); + builder.setType(Type.Namespace); + } + if (request.getTableName() != null) { + builder.setTableName(toProtoTableName(request.getTableName())); + builder.setType(Type.Table); + } + if (!builder.hasType()) { + builder.setType(Type.Global); + } + if (request.getFamily() != null && request.getFamily().length > 0) { + builder.setColumnFamily(ByteString.copyFrom(request.getFamily())); + } + if (request.getQualifier() != null && request.getQualifier().length > 0) { + builder.setColumnQualifier(ByteString.copyFrom(request.getQualifier())); + } + return builder.build(); + } + + public static GetUserPermissionsResponse + buildGetUserPermissionsResponse(final List permissions) { + GetUserPermissionsResponse.Builder builder = GetUserPermissionsResponse.newBuilder(); + for (UserPermission perm : permissions) { + builder.addUserPermission(toUserPermission(perm)); + } + return builder.build(); + } } diff --git a/hbase-protocol-shaded/src/main/protobuf/AccessControl.proto b/hbase-protocol-shaded/src/main/protobuf/AccessControl.proto index 3b0e9bbffd7..af60fe21cf5 100644 --- a/hbase-protocol-shaded/src/main/protobuf/AccessControl.proto +++ b/hbase-protocol-shaded/src/main/protobuf/AccessControl.proto @@ -103,6 +103,9 @@ message GetUserPermissionsRequest { optional Permission.Type type = 1; optional TableName table_name = 2; optional bytes namespace_name = 3; + optional bytes column_family = 4; + optional bytes column_qualifier = 5; + optional bytes user_name = 6; } message GetUserPermissionsResponse { diff --git a/hbase-protocol-shaded/src/main/protobuf/Master.proto b/hbase-protocol-shaded/src/main/protobuf/Master.proto index 55d499880c1..a57695160fd 100644 --- a/hbase-protocol-shaded/src/main/protobuf/Master.proto +++ b/hbase-protocol-shaded/src/main/protobuf/Master.proto @@ -1027,6 +1027,8 @@ service MasterService { rpc Grant(GrantRequest) returns (GrantResponse); rpc Revoke(RevokeRequest) returns (RevokeResponse); + + rpc GetUserPermissions (GetUserPermissionsRequest) returns (GetUserPermissionsResponse); } // HBCK Service definitions. diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java index eae64f73c2b..20e845ed787 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java @@ -1545,4 +1545,34 @@ public interface MasterObserver { default void postRevoke(ObserverContext ctx, UserPermission userPermission) throws IOException { } + + /** + * Called before getting user permissions. + * @param ctx the coprocessor instance's environment + * @param userName the user name, null if get all user permissions + * @param namespace the namespace, null if don't get namespace permission + * @param tableName the table name, null if don't get table permission + * @param family the table column family, null if don't get table family permission + * @param qualifier the table column qualifier, null if don't get table qualifier permission + * @throws IOException if something went wrong + */ + default void preGetUserPermissions(ObserverContext ctx, + String userName, String namespace, TableName tableName, byte[] family, byte[] qualifier) + throws IOException { + } + + /** + * Called after getting user permissions. + * @param ctx the coprocessor instance's environment + * @param userName the user name, null if get all user permissions + * @param namespace the namespace, null if don't get namespace permission + * @param tableName the table name, null if don't get table permission + * @param family the table column family, null if don't get table family permission + * @param qualifier the table column qualifier, null if don't get table qualifier permission + * @throws IOException if something went wrong + */ + default void postGetUserPermissions(ObserverContext ctx, + String userName, String namespace, TableName tableName, byte[] family, byte[] qualifier) + throws IOException { + } } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java index ec03058f09f..6f91b57d00c 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java @@ -1798,4 +1798,24 @@ public class MasterCoprocessorHost } }); } + + public void preGetUserPermissions(String userName, String namespace, TableName tableName, + byte[] family, byte[] qualifier) throws IOException { + execOperation(coprocEnvironments.isEmpty() ? null : new MasterObserverOperation() { + @Override + public void call(MasterObserver observer) throws IOException { + observer.preGetUserPermissions(this, userName, namespace, tableName, family, qualifier); + } + }); + } + + public void postGetUserPermissions(String userName, String namespace, TableName tableName, + byte[] family, byte[] qualifier) throws IOException { + execOperation(coprocEnvironments.isEmpty() ? null : new MasterObserverOperation() { + @Override + public void call(MasterObserver observer) throws IOException { + observer.postGetUserPermissions(this, userName, namespace, tableName, family, qualifier); + } + }); + } } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java index c0d42bbd2bc..b93bbede5cb 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java @@ -91,11 +91,13 @@ import org.apache.hadoop.hbase.regionserver.RpcSchedulerFactory; import org.apache.hadoop.hbase.replication.ReplicationException; import org.apache.hadoop.hbase.replication.ReplicationPeerConfig; import org.apache.hadoop.hbase.replication.ReplicationPeerDescription; +import org.apache.hadoop.hbase.security.Superusers; import org.apache.hadoop.hbase.security.User; import org.apache.hadoop.hbase.security.access.AccessChecker; import org.apache.hadoop.hbase.security.access.AccessControlLists; import org.apache.hadoop.hbase.security.access.AccessController; import org.apache.hadoop.hbase.security.access.Permission; +import org.apache.hadoop.hbase.security.access.Permission.Action; import org.apache.hadoop.hbase.security.access.ShadedAccessControlUtil; import org.apache.hadoop.hbase.security.access.UserPermission; import org.apache.hadoop.hbase.security.visibility.VisibilityController; @@ -118,8 +120,12 @@ import org.apache.hbase.thirdparty.com.google.protobuf.UnsafeByteOperations; import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; import org.apache.hadoop.hbase.shaded.protobuf.ResponseConverter; +import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos; +import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.GetUserPermissionsRequest; +import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.GetUserPermissionsResponse; import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.GrantRequest; import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.GrantResponse; +import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.Permission.Type; import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.RevokeRequest; import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.RevokeResponse; import org.apache.hadoop.hbase.shaded.protobuf.generated.AdminProtos.CompactRegionRequest; @@ -2537,6 +2543,57 @@ public class MasterRpcServices extends RSRpcServices } } + @Override + public GetUserPermissionsResponse getUserPermissions(RpcController controller, + GetUserPermissionsRequest request) throws ServiceException { + try { + final String userName = request.hasUserName() ? request.getUserName().toStringUtf8() : null; + String namespace = + request.hasNamespaceName() ? request.getNamespaceName().toStringUtf8() : null; + TableName table = + request.hasTableName() ? ProtobufUtil.toTableName(request.getTableName()) : null; + byte[] cf = request.hasColumnFamily() ? request.getColumnFamily().toByteArray() : null; + byte[] cq = request.hasColumnQualifier() ? request.getColumnQualifier().toByteArray() : null; + Type permissionType = request.hasType() ? request.getType() : null; + if (master.cpHost != null) { + master.getMasterCoprocessorHost().preGetUserPermissions(userName, namespace, table, cf, cq); + } + + List perms = null; + if (permissionType == Type.Table) { + boolean filter = (cf != null || userName != null) ? true : false; + perms = AccessControlLists.getUserTablePermissions(master.getConfiguration(), table, cf, cq, + userName, filter); + } else if (permissionType == Type.Namespace) { + perms = AccessControlLists.getUserNamespacePermissions(master.getConfiguration(), namespace, + userName, userName != null ? true : false); + } else { + perms = AccessControlLists.getUserPermissions(master.getConfiguration(), null, null, null, + userName, userName != null ? true : false); + // Skip super users when filter user is specified + if (userName == null) { + // Adding superusers explicitly to the result set as AccessControlLists do not store + // them. Also using acl as table name to be inline with the results of global admin and + // will help in avoiding any leakage of information about being superusers. + for (String user : Superusers.getSuperUsers()) { + perms.add(new UserPermission(user, + Permission.newBuilder().withActions(Action.values()).build())); + } + } + } + + if (master.cpHost != null) { + master.getMasterCoprocessorHost().postGetUserPermissions(userName, namespace, table, cf, + cq); + } + AccessControlProtos.GetUserPermissionsResponse response = + ShadedAccessControlUtil.buildGetUserPermissionsResponse(perms); + return response; + } catch (IOException ioe) { + throw new ServiceException(ioe); + } + } + private boolean containMetaWals(ServerName serverName) throws IOException { Path logDir = new Path(master.getWALRootDir(), AbstractFSWALProvider.getWALDirectoryName(serverName.toString())); 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 74c848d1462..1182baafce5 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 @@ -538,8 +538,9 @@ public class AccessControlLists { * Returns the currently granted permissions for a given table as the specified user plus * associated permissions. */ - static List getUserTablePermissions(Configuration conf, TableName tableName, - byte[] cf, byte[] cq, String userName, boolean hasFilterUser) throws IOException { + public static List getUserTablePermissions(Configuration conf, + TableName tableName, byte[] cf, byte[] cq, String userName, boolean hasFilterUser) + throws IOException { return getUserPermissions(conf, tableName == null ? null : tableName.getName(), cf, cq, userName, hasFilterUser); } @@ -548,8 +549,8 @@ public class AccessControlLists { * Returns the currently granted permissions for a given namespace as the specified user plus * associated permissions. */ - static List getUserNamespacePermissions(Configuration conf, String namespace, - String user, boolean hasFilterUser) throws IOException { + public static List getUserNamespacePermissions(Configuration conf, + String namespace, String user, boolean hasFilterUser) throws IOException { return getUserPermissions(conf, Bytes.toBytes(toNamespaceEntry(namespace)), null, null, user, hasFilterUser); } @@ -566,8 +567,8 @@ public class AccessControlLists { * @return List of UserPermissions * @throws IOException on failure */ - static List getUserPermissions(Configuration conf, byte[] entryName, byte[] cf, - byte[] cq, String user, boolean hasFilterUser) throws IOException { + public static List getUserPermissions(Configuration conf, byte[] entryName, + byte[] cf, byte[] cq, String user, boolean hasFilterUser) throws IOException { ListMultimap allPerms = getPermissions(conf, entryName, null, cf, cq, user, hasFilterUser); List perms = new ArrayList<>(); 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 6d5707611c0..2ae61bc2e44 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 @@ -2136,6 +2136,10 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, done.run(response); } + /** + * @deprecated Use {@link Admin#getUserPermissions(GetUserPermissionsRequest)} instead. + */ + @Deprecated @Override public void getUserPermissions(RpcController controller, AccessControlProtos.GetUserPermissionsRequest request, @@ -2148,77 +2152,29 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, throw new CoprocessorException("AccessController not yet initialized"); } User caller = RpcServer.getRequestUser().orElse(null); - - List perms = null; - // Initialize username, cf and cq. Set to null if request doesn't have. final String userName = request.hasUserName() ? request.getUserName().toStringUtf8() : null; + final String namespace = + request.hasNamespaceName() ? request.getNamespaceName().toStringUtf8() : null; + final TableName table = + request.hasTableName() ? ProtobufUtil.toTableName(request.getTableName()) : null; final byte[] cf = request.hasColumnFamily() ? request.getColumnFamily().toByteArray() : null; final byte[] cq = request.hasColumnQualifier() ? request.getColumnQualifier().toByteArray() : null; - + preGetUserPermissions(caller, userName, namespace, table, cf, cq); + GetUserPermissionsRequest getUserPermissionsRequest = null; if (request.getType() == AccessControlProtos.Permission.Type.Table) { - final TableName table = request.hasTableName() ? - ProtobufUtil.toTableName(request.getTableName()) : null; - accessChecker.requirePermission(caller, "userPermissions", table, cf, cq, userName, - Action.ADMIN); - perms = User.runAsLoginUser(new PrivilegedExceptionAction>() { - @Override - public List run() throws Exception { - if (cf != null || userName != null) { - // retrieve permission based on the requested parameters - return AccessControlLists.getUserTablePermissions(regionEnv.getConfiguration(), - table, cf, cq, userName, true); - } else { - return AccessControlLists.getUserTablePermissions(regionEnv.getConfiguration(), - table, null, null, null, false); - } - } - }); + getUserPermissionsRequest = GetUserPermissionsRequest.newBuilder(table).withFamily(cf) + .withQualifier(cq).withUserName(userName).build(); } else if (request.getType() == AccessControlProtos.Permission.Type.Namespace) { - final String namespace = request.getNamespaceName().toStringUtf8(); - accessChecker.requireNamespacePermission(caller, "userPermissions", - namespace, userName, Action.ADMIN); - perms = User.runAsLoginUser(new PrivilegedExceptionAction>() { - @Override - public List run() throws Exception { - if (userName != null) { - // retrieve permission based on the requested parameters - return AccessControlLists.getUserNamespacePermissions(regionEnv.getConfiguration(), - namespace, userName, true); - } else { - return AccessControlLists.getUserNamespacePermissions(regionEnv.getConfiguration(), - namespace, null, false); - } - } - }); + getUserPermissionsRequest = + GetUserPermissionsRequest.newBuilder(namespace).withUserName(userName).build(); } else { - accessChecker.requirePermission(caller, "userPermissions", userName, Action.ADMIN); - perms = User.runAsLoginUser(new PrivilegedExceptionAction>() { - @Override - public List run() throws Exception { - if (userName != null) { - // retrieve permission based on the requested parameters - return AccessControlLists.getUserPermissions(regionEnv.getConfiguration(), null, - null, null, userName, true); - } else { - return AccessControlLists.getUserPermissions(regionEnv.getConfiguration(), null, - null, null, null, false); - } - } - }); - - // Skip super users when filter user is specified - if (userName == null) { - // Adding superusers explicitly to the result set as AccessControlLists do not store - // them. Also using acl as table name to be inline with the results of global admin and - // will help in avoiding any leakage of information about being superusers. - for (String user : Superusers.getSuperUsers()) { - perms.add(new UserPermission(user, - Permission.newBuilder().withActions(Action.values()).build())); - } - } + getUserPermissionsRequest = + GetUserPermissionsRequest.newBuilder().withUserName(userName).build(); } + List perms = + regionEnv.getConnection().getAdmin().getUserPermissions(getUserPermissionsRequest); response = AccessControlUtil.buildGetUserPermissionsResponse(perms); } else { throw new CoprocessorException(AccessController.class, "This method " @@ -2674,4 +2630,24 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor, accessChecker.performOnSuperuser(request, caller, userPermission.getUser()); } } + + @Override + public void preGetUserPermissions(ObserverContext ctx, + String userName, String namespace, TableName tableName, byte[] family, byte[] qualifier) + throws IOException { + preGetUserPermissions(getActiveUser(ctx), userName, namespace, tableName, family, qualifier); + } + + private void preGetUserPermissions(User caller, String userName, String namespace, + TableName tableName, byte[] family, byte[] qualifier) throws IOException { + if (tableName != null) { + accessChecker.requirePermission(caller, "getUserPermissions", tableName, family, qualifier, + userName, Action.ADMIN); + } else if (namespace != null) { + accessChecker.requireNamespacePermission(caller, "getUserPermissions", namespace, userName, + Action.ADMIN); + } else { + accessChecker.requirePermission(caller, "getUserPermissions", userName, Action.ADMIN); + } + } } diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAsyncAccessControlAdminApi.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAsyncAccessControlAdminApi.java new file mode 100644 index 00000000000..8075ae043fc --- /dev/null +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAsyncAccessControlAdminApi.java @@ -0,0 +1,74 @@ +/** + * 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. + */ + +package org.apache.hadoop.hbase.client; + +import static org.junit.Assert.assertEquals; + +import java.util.List; +import org.apache.hadoop.hbase.HBaseClassTestRule; +import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.security.access.AccessControlLists; +import org.apache.hadoop.hbase.security.access.GetUserPermissionsRequest; +import org.apache.hadoop.hbase.security.access.Permission; +import org.apache.hadoop.hbase.security.access.SecureTestUtil; +import org.apache.hadoop.hbase.security.access.UserPermission; +import org.apache.hadoop.hbase.testclassification.ClientTests; +import org.apache.hadoop.hbase.testclassification.SmallTests; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +@Category({ ClientTests.class, SmallTests.class }) +public class TestAsyncAccessControlAdminApi extends TestAsyncAdminBase { + + @ClassRule + public static final HBaseClassTestRule CLASS_RULE = + HBaseClassTestRule.forClass(TestAsyncAccessControlAdminApi.class); + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + SecureTestUtil.enableSecurity(TEST_UTIL.getConfiguration()); + TEST_UTIL.startMiniCluster(1); + TEST_UTIL.waitTableAvailable(AccessControlLists.ACL_TABLE_NAME); + ASYNC_CONN = ConnectionFactory.createAsyncConnection(TEST_UTIL.getConfiguration()).get(); + } + + @Test + public void testGrant() throws Exception { + TableName tableName = TableName.valueOf("test-table"); + String user = "test-user"; + UserPermission userPermission = new UserPermission(user, + Permission.newBuilder(tableName).withActions(Permission.Action.READ).build()); + // grant user table permission + admin.grant(userPermission, false).get(); + + // get table permissions + List userPermissions = + admin.getUserPermissions(GetUserPermissionsRequest.newBuilder(tableName).build()).get(); + assertEquals(1, userPermissions.size()); + assertEquals(userPermission, userPermissions.get(0)); + + // get user table permissions + userPermissions = admin.getUserPermissions( + GetUserPermissionsRequest.newBuilder(tableName).withUserName(user).build()).get(); + assertEquals(1, userPermissions.size()); + assertEquals(userPermission, userPermissions.get(0)); + + userPermissions = admin.getUserPermissions( + GetUserPermissionsRequest.newBuilder(tableName).withUserName("u").build()).get(); + assertEquals(0, userPermissions.size()); + } +} 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 129f2b67947..eecd7737c08 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 @@ -144,7 +144,8 @@ public class SecureTestUtil { Permission.Action... actions) throws IOException { Permission[] perms = new Permission[actions.length]; for (int i = 0; i < actions.length; i++) { - perms[i] = new TablePermission(table, family, column, actions[i]); + perms[i] = Permission.newBuilder(table).withFamily(family).withQualifier(column) + .withActions(actions[i]).build(); } checkTablePerms(conf, table, perms); @@ -878,7 +879,8 @@ public class SecureTestUtil { byte[] column, Permission.Action... actions) throws IOException { Permission[] perms = new Permission[actions.length]; for (int i = 0; i < actions.length; i++) { - perms[i] = new TablePermission(table, family, column, actions[i]); + perms[i] = Permission.newBuilder(table).withFamily(family).withQualifier(column) + .withActions(actions[i]).build(); } checkTablePerms(testUtil, table, perms); } 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 9e66daeba2d..7cbe0e6284b 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 @@ -1190,12 +1190,9 @@ public class TestAccessController extends SecureTestUtil { AccessTestAction getTablePermissionsAction = new AccessTestAction() { @Override public Object run() throws Exception { - try(Connection conn = ConnectionFactory.createConnection(conf); - Table acl = conn.getTable(AccessControlLists.ACL_TABLE_NAME)){ - BlockingRpcChannel service = acl.coprocessorService(TEST_TABLE.getName()); - AccessControlService.BlockingInterface protocol = - AccessControlService.newBlockingStub(service); - AccessControlUtil.getUserPermissions(null, protocol, TEST_TABLE); + try (Connection conn = ConnectionFactory.createConnection(conf)) { + conn.getAdmin() + .getUserPermissions(GetUserPermissionsRequest.newBuilder(TEST_TABLE).build()); } return null; } @@ -1204,12 +1201,9 @@ public class TestAccessController extends SecureTestUtil { AccessTestAction getGlobalPermissionsAction = new AccessTestAction() { @Override public Object run() throws Exception { - try(Connection conn = ConnectionFactory.createConnection(conf); - Table acl = conn.getTable(AccessControlLists.ACL_TABLE_NAME);) { - BlockingRpcChannel service = acl.coprocessorService(HConstants.EMPTY_START_ROW); - AccessControlService.BlockingInterface protocol = - AccessControlService.newBlockingStub(service); - AccessControlUtil.getUserPermissions(null, protocol); + try (Connection conn = ConnectionFactory.createConnection(conf); + Table acl = conn.getTable(AccessControlLists.ACL_TABLE_NAME)) { + conn.getAdmin().getUserPermissions(GetUserPermissionsRequest.newBuilder().build()); } return null; } @@ -1679,17 +1673,8 @@ public class TestAccessController extends SecureTestUtil { htd.setOwner(USER_OWNER); createTable(TEST_UTIL, htd); try { - List perms; - Table acl = systemUserConnection.getTable(AccessControlLists.ACL_TABLE_NAME); - try { - BlockingRpcChannel service = acl.coprocessorService(tableName.getName()); - AccessControlService.BlockingInterface protocol = - AccessControlService.newBlockingStub(service); - perms = AccessControlUtil.getUserPermissions(null, protocol, tableName); - } finally { - acl.close(); - } - + List perms = + admin.getUserPermissions(GetUserPermissionsRequest.newBuilder(tableName).build()); UserPermission ownerperm = new UserPermission(USER_OWNER.getName(), Permission.newBuilder(tableName).withActions(Action.values()).build()); assertTrue("Owner should have all permissions on table", @@ -1708,16 +1693,7 @@ public class TestAccessController extends SecureTestUtil { grantOnTable(TEST_UTIL, user.getShortName(), tableName, family1, qualifier, Permission.Action.READ); - acl = systemUserConnection.getTable(AccessControlLists.ACL_TABLE_NAME); - try { - BlockingRpcChannel service = acl.coprocessorService(tableName.getName()); - AccessControlService.BlockingInterface protocol = - AccessControlService.newBlockingStub(service); - perms = AccessControlUtil.getUserPermissions(null, protocol, tableName); - } finally { - acl.close(); - } - + perms = admin.getUserPermissions(GetUserPermissionsRequest.newBuilder(tableName).build()); UserPermission upToVerify = new UserPermission(userName, Permission.newBuilder(tableName).withFamily(family1) .withQualifier(qualifier).withActions(Permission.Action.READ).build()); @@ -1733,16 +1709,7 @@ public class TestAccessController extends SecureTestUtil { grantOnTable(TEST_UTIL, user.getShortName(), tableName, family1, qualifier, Permission.Action.WRITE, Permission.Action.READ); - acl = systemUserConnection.getTable(AccessControlLists.ACL_TABLE_NAME); - try { - BlockingRpcChannel service = acl.coprocessorService(tableName.getName()); - AccessControlService.BlockingInterface protocol = - AccessControlService.newBlockingStub(service); - perms = AccessControlUtil.getUserPermissions(null, protocol, tableName); - } finally { - acl.close(); - } - + perms = admin.getUserPermissions(GetUserPermissionsRequest.newBuilder(tableName).build()); upToVerify = new UserPermission(userName, Permission.newBuilder(tableName).withFamily(family1).withQualifier(qualifier) .withActions(Permission.Action.WRITE, Permission.Action.READ).build()); @@ -1753,16 +1720,7 @@ public class TestAccessController extends SecureTestUtil { revokeFromTable(TEST_UTIL, user.getShortName(), tableName, family1, qualifier, Permission.Action.WRITE, Permission.Action.READ); - acl = systemUserConnection.getTable(AccessControlLists.ACL_TABLE_NAME); - try { - BlockingRpcChannel service = acl.coprocessorService(tableName.getName()); - AccessControlService.BlockingInterface protocol = - AccessControlService.newBlockingStub(service); - perms = AccessControlUtil.getUserPermissions(null, protocol, tableName); - } finally { - acl.close(); - } - + perms = admin.getUserPermissions(GetUserPermissionsRequest.newBuilder(tableName).build()); assertFalse("User should not be granted permission: " + upToVerify.toString(), hasFoundUserPermission(upToVerify, perms)); @@ -1773,16 +1731,7 @@ public class TestAccessController extends SecureTestUtil { htd.setOwner(newOwner); admin.modifyTable(tableName, htd); - acl = systemUserConnection.getTable(AccessControlLists.ACL_TABLE_NAME); - try { - BlockingRpcChannel service = acl.coprocessorService(tableName.getName()); - AccessControlService.BlockingInterface protocol = - AccessControlService.newBlockingStub(service); - perms = AccessControlUtil.getUserPermissions(null, protocol, tableName); - } finally { - acl.close(); - } - + perms = admin.getUserPermissions(GetUserPermissionsRequest.newBuilder(tableName).build()); UserPermission newOwnerperm = new UserPermission(newOwner.getName(), Permission.newBuilder(tableName).withActions(Action.values()).build()); assertTrue("New owner should have all permissions on table", @@ -1795,16 +1744,8 @@ public class TestAccessController extends SecureTestUtil { @Test public void testGlobalPermissionList() throws Exception { - List perms; - Table acl = systemUserConnection.getTable(AccessControlLists.ACL_TABLE_NAME); - try { - BlockingRpcChannel service = acl.coprocessorService(HConstants.EMPTY_START_ROW); - AccessControlService.BlockingInterface protocol = - AccessControlService.newBlockingStub(service); - perms = AccessControlUtil.getUserPermissions(null, protocol); - } finally { - acl.close(); - } + List perms = systemUserConnection.getAdmin() + .getUserPermissions(GetUserPermissionsRequest.newBuilder().build()); Collection superUsers = Superusers.getSuperUsers(); List adminPerms = new ArrayList<>(superUsers.size() + 1); @@ -1900,9 +1841,12 @@ public class TestAccessController extends SecureTestUtil { AccessTestAction multiQualifierRead = new AccessTestAction() { @Override public Void run() throws Exception { - checkTablePerms(TEST_UTIL, TEST_TABLE, new Permission[] { - new TablePermission(TEST_TABLE, TEST_FAMILY, TEST_Q1, Permission.Action.READ), - new TablePermission(TEST_TABLE, TEST_FAMILY, TEST_Q2, Permission.Action.READ), }); + checkTablePerms(TEST_UTIL, TEST_TABLE, + new Permission[] { + Permission.newBuilder(TEST_TABLE).withFamily(TEST_FAMILY).withQualifier(TEST_Q1) + .withActions(Permission.Action.READ).build(), + Permission.newBuilder(TEST_TABLE).withFamily(TEST_FAMILY).withQualifier(TEST_Q2) + .withActions(Permission.Action.READ).build(), }); return null; } }; @@ -1912,7 +1856,7 @@ public class TestAccessController extends SecureTestUtil { public Void run() throws Exception { checkTablePerms(TEST_UTIL, TEST_TABLE, new Permission[] { new Permission(Permission.Action.READ), - new TablePermission(TEST_TABLE, null, (byte[]) null, Permission.Action.READ), }); + Permission.newBuilder(TEST_TABLE).withActions(Permission.Action.READ).build() }); return null; } }; @@ -3527,12 +3471,9 @@ public class TestAccessController extends SecureTestUtil { AccessTestAction globalUserPermissionAction = new AccessTestAction() { @Override public Object run() throws Exception { - try (Connection conn = ConnectionFactory.createConnection(conf); - Table acl = conn.getTable(AccessControlLists.ACL_TABLE_NAME)) { - BlockingRpcChannel service = acl.coprocessorService(TEST_TABLE.getName()); - AccessControlService.BlockingInterface protocol = - AccessControlService.newBlockingStub(service); - AccessControlUtil.getUserPermissions(null, protocol, "dummy"); + try (Connection conn = ConnectionFactory.createConnection(conf)) { + conn.getAdmin().getUserPermissions( + GetUserPermissionsRequest.newBuilder().withUserName("dummy").build()); } return null; } @@ -3566,12 +3507,9 @@ public class TestAccessController extends SecureTestUtil { AccessTestAction namespaceUserPermissionAction = new AccessTestAction() { @Override public Object run() throws Exception { - try (Connection conn = ConnectionFactory.createConnection(conf); - Table acl = conn.getTable(AccessControlLists.ACL_TABLE_NAME)) { - BlockingRpcChannel service = acl.coprocessorService(TEST_TABLE.getName()); - AccessControlService.BlockingInterface protocol = - AccessControlService.newBlockingStub(service); - AccessControlUtil.getUserPermissions(null, protocol, Bytes.toBytes(namespace1), "dummy"); + try (Connection conn = ConnectionFactory.createConnection(conf)) { + conn.getAdmin().getUserPermissions( + GetUserPermissionsRequest.newBuilder(namespace1).withUserName("dummy").build()); } return null; } @@ -3610,13 +3548,9 @@ public class TestAccessController extends SecureTestUtil { AccessTestAction tableUserPermissionAction = new AccessTestAction() { @Override public Object run() throws Exception { - try (Connection conn = ConnectionFactory.createConnection(conf); - Table acl = conn.getTable(AccessControlLists.ACL_TABLE_NAME)) { - BlockingRpcChannel service = acl.coprocessorService(TEST_TABLE.getName()); - AccessControlService.BlockingInterface protocol = - AccessControlService.newBlockingStub(service); - AccessControlUtil.getUserPermissions(null, protocol, TEST_TABLE, TEST_FAMILY, - TEST_QUALIFIER, "dummy"); + try (Connection conn = ConnectionFactory.createConnection(conf)) { + conn.getAdmin().getUserPermissions(GetUserPermissionsRequest.newBuilder(TEST_TABLE) + .withFamily(TEST_FAMILY).withQualifier(TEST_QUALIFIER).withUserName("dummy").build()); } return null; } 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 4e35dc1d20a..15577aa827e 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 @@ -405,12 +405,9 @@ public class TestNamespaceCommands extends SecureTestUtil { AccessTestAction getPermissionsAction = new AccessTestAction() { @Override public Object run() throws Exception { - try (Connection connection = ConnectionFactory.createConnection(conf); - Table acl = connection.getTable(AccessControlLists.ACL_TABLE_NAME)) { - BlockingRpcChannel service = acl.coprocessorService(HConstants.EMPTY_START_ROW); - AccessControlService.BlockingInterface protocol = - AccessControlService.newBlockingStub(service); - AccessControlUtil.getUserPermissions(null, protocol, Bytes.toBytes(TEST_NAMESPACE)); + try (Connection connection = ConnectionFactory.createConnection(conf)) { + connection.getAdmin() + .getUserPermissions(GetUserPermissionsRequest.newBuilder(TEST_NAMESPACE).build()); } return null; } @@ -420,7 +417,8 @@ public class TestNamespaceCommands extends SecureTestUtil { @Override public Object run() throws Exception { ACCESS_CONTROLLER.preGrant(ObserverContextImpl.createAndPrepare(CP_ENV), - new UserPermission(testUser, new NamespacePermission(TEST_NAMESPACE, Action.WRITE)), + new UserPermission(testUser, + Permission.newBuilder(TEST_NAMESPACE).withActions(Action.WRITE).build()), false); return null; } @@ -429,7 +427,8 @@ public class TestNamespaceCommands extends SecureTestUtil { @Override public Object run() throws Exception { ACCESS_CONTROLLER.preRevoke(ObserverContextImpl.createAndPrepare(CP_ENV), - new UserPermission(testUser, new NamespacePermission(TEST_NAMESPACE, Action.WRITE))); + new UserPermission(testUser, + Permission.newBuilder(TEST_NAMESPACE).withActions(Action.WRITE).build())); return null; } }; diff --git a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift2/client/ThriftAdmin.java b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift2/client/ThriftAdmin.java index d70115261c3..355468e7e29 100644 --- a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift2/client/ThriftAdmin.java +++ b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift2/client/ThriftAdmin.java @@ -58,6 +58,7 @@ import org.apache.hadoop.hbase.quotas.QuotaSettings; import org.apache.hadoop.hbase.quotas.SpaceQuotaSnapshot; import org.apache.hadoop.hbase.replication.ReplicationPeerConfig; import org.apache.hadoop.hbase.replication.ReplicationPeerDescription; +import org.apache.hadoop.hbase.security.access.GetUserPermissionsRequest; import org.apache.hadoop.hbase.security.access.UserPermission; import org.apache.hadoop.hbase.snapshot.RestoreSnapshotException; import org.apache.hadoop.hbase.thrift2.ThriftUtilities; @@ -1349,4 +1350,10 @@ public class ThriftAdmin implements Admin { public void revoke(UserPermission userPermission) { throw new NotImplementedException("revoke not supported in ThriftAdmin"); } + + @Override + public List + getUserPermissions(GetUserPermissionsRequest getUserPermissionsRequest) { + throw new NotImplementedException("getUserPermissions not supported in ThriftAdmin"); + } }