001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.security.access;
019
020import java.util.ArrayList;
021import java.util.Collection;
022import java.util.List;
023import java.util.Map;
024import java.util.Objects;
025import org.apache.commons.lang3.StringUtils;
026import org.apache.hadoop.hbase.HConstants;
027import org.apache.hadoop.hbase.TableName;
028import org.apache.hadoop.hbase.client.Admin;
029import org.apache.hadoop.hbase.util.Bytes;
030import org.apache.yetus.audience.InterfaceAudience;
031
032import org.apache.hbase.thirdparty.com.google.common.collect.ArrayListMultimap;
033import org.apache.hbase.thirdparty.com.google.common.collect.ListMultimap;
034import org.apache.hbase.thirdparty.com.google.common.collect.Lists;
035import org.apache.hbase.thirdparty.com.google.protobuf.ByteString;
036import org.apache.hbase.thirdparty.com.google.protobuf.RpcController;
037import org.apache.hbase.thirdparty.com.google.protobuf.ServiceException;
038import org.apache.hbase.thirdparty.com.google.protobuf.UnsafeByteOperations;
039
040import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
041import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos;
042import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.AccessControlService;
043import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.GetUserPermissionsResponse;
044
045@InterfaceAudience.Private
046public class AccessControlUtil {
047  private AccessControlUtil() {
048  }
049
050  /**
051   * Create a request to grant user table permissions.
052   * @param username  the short user name who to grant permissions
053   * @param tableName optional table name the permissions apply
054   * @param family    optional column family
055   * @param qualifier optional qualifier
056   * @param actions   the permissions to be granted
057   * @return A {@link AccessControlProtos} GrantRequest
058   * @throws NullPointerException if {@code tableName} is {@code null}
059   */
060  public static AccessControlProtos.GrantRequest buildGrantRequest(String username,
061    TableName tableName, byte[] family, byte[] qualifier, boolean mergeExistingPermissions,
062    AccessControlProtos.Permission.Action... actions) {
063    AccessControlProtos.Permission.Builder ret = AccessControlProtos.Permission.newBuilder();
064    AccessControlProtos.TablePermission.Builder permissionBuilder =
065      AccessControlProtos.TablePermission.newBuilder();
066    for (AccessControlProtos.Permission.Action a : actions) {
067      permissionBuilder.addAction(a);
068    }
069
070    Objects.requireNonNull(tableName, "TableName cannot be null");
071
072    permissionBuilder.setTableName(ProtobufUtil.toProtoTableName(tableName));
073
074    if (family != null) {
075      permissionBuilder.setFamily(UnsafeByteOperations.unsafeWrap(family));
076    }
077    if (qualifier != null) {
078      permissionBuilder.setQualifier(UnsafeByteOperations.unsafeWrap(qualifier));
079    }
080    ret.setType(AccessControlProtos.Permission.Type.Table).setTablePermission(permissionBuilder);
081    return AccessControlProtos.GrantRequest.newBuilder()
082      .setUserPermission(AccessControlProtos.UserPermission.newBuilder()
083        .setUser(ByteString.copyFromUtf8(username)).setPermission(ret))
084      .setMergeExistingPermissions(mergeExistingPermissions).build();
085  }
086
087  /**
088   * Create a request to grant user namespace permissions.
089   * @param username  the short user name who to grant permissions
090   * @param namespace optional table name the permissions apply
091   * @param actions   the permissions to be granted
092   * @return A {@link AccessControlProtos} GrantRequest
093   */
094  public static AccessControlProtos.GrantRequest buildGrantRequest(String username,
095    String namespace, boolean mergeExistingPermissions,
096    AccessControlProtos.Permission.Action... actions) {
097    AccessControlProtos.Permission.Builder ret = AccessControlProtos.Permission.newBuilder();
098    AccessControlProtos.NamespacePermission.Builder permissionBuilder =
099      AccessControlProtos.NamespacePermission.newBuilder();
100    for (AccessControlProtos.Permission.Action a : actions) {
101      permissionBuilder.addAction(a);
102    }
103    if (namespace != null) {
104      permissionBuilder.setNamespaceName(ByteString.copyFromUtf8(namespace));
105    }
106    ret.setType(AccessControlProtos.Permission.Type.Namespace)
107      .setNamespacePermission(permissionBuilder);
108    return AccessControlProtos.GrantRequest.newBuilder()
109      .setUserPermission(AccessControlProtos.UserPermission.newBuilder()
110        .setUser(ByteString.copyFromUtf8(username)).setPermission(ret))
111      .setMergeExistingPermissions(mergeExistingPermissions).build();
112  }
113
114  /**
115   * Create a request to revoke user global permissions.
116   * @param username the short user name whose permissions to be revoked
117   * @param actions  the permissions to be revoked
118   * @return A {@link AccessControlProtos} RevokeRequest
119   */
120  public static AccessControlProtos.RevokeRequest buildRevokeRequest(String username,
121    AccessControlProtos.Permission.Action... actions) {
122    AccessControlProtos.Permission.Builder ret = AccessControlProtos.Permission.newBuilder();
123    AccessControlProtos.GlobalPermission.Builder permissionBuilder =
124      AccessControlProtos.GlobalPermission.newBuilder();
125    for (AccessControlProtos.Permission.Action a : actions) {
126      permissionBuilder.addAction(a);
127    }
128    ret.setType(AccessControlProtos.Permission.Type.Global).setGlobalPermission(permissionBuilder);
129    return AccessControlProtos.RevokeRequest.newBuilder()
130      .setUserPermission(AccessControlProtos.UserPermission.newBuilder()
131        .setUser(ByteString.copyFromUtf8(username)).setPermission(ret))
132      .build();
133  }
134
135  /**
136   * Create a request to revoke user namespace permissions.
137   * @param username  the short user name whose permissions to be revoked
138   * @param namespace optional table name the permissions apply
139   * @param actions   the permissions to be revoked
140   * @return A {@link AccessControlProtos} RevokeRequest
141   */
142  public static AccessControlProtos.RevokeRequest buildRevokeRequest(String username,
143    String namespace, AccessControlProtos.Permission.Action... actions) {
144    AccessControlProtos.Permission.Builder ret = AccessControlProtos.Permission.newBuilder();
145    AccessControlProtos.NamespacePermission.Builder permissionBuilder =
146      AccessControlProtos.NamespacePermission.newBuilder();
147    for (AccessControlProtos.Permission.Action a : actions) {
148      permissionBuilder.addAction(a);
149    }
150    if (namespace != null) {
151      permissionBuilder.setNamespaceName(ByteString.copyFromUtf8(namespace));
152    }
153    ret.setType(AccessControlProtos.Permission.Type.Namespace)
154      .setNamespacePermission(permissionBuilder);
155    return AccessControlProtos.RevokeRequest.newBuilder()
156      .setUserPermission(AccessControlProtos.UserPermission.newBuilder()
157        .setUser(ByteString.copyFromUtf8(username)).setPermission(ret))
158      .build();
159  }
160
161  /**
162   * Create a request to grant user global permissions.
163   * @param username the short user name who to grant permissions
164   * @param actions  the permissions to be granted
165   * @return A {@link AccessControlProtos} GrantRequest
166   */
167  public static AccessControlProtos.GrantRequest buildGrantRequest(String username,
168    boolean mergeExistingPermissions, AccessControlProtos.Permission.Action... actions) {
169    AccessControlProtos.Permission.Builder ret = AccessControlProtos.Permission.newBuilder();
170    AccessControlProtos.GlobalPermission.Builder permissionBuilder =
171      AccessControlProtos.GlobalPermission.newBuilder();
172    for (AccessControlProtos.Permission.Action a : actions) {
173      permissionBuilder.addAction(a);
174    }
175    ret.setType(AccessControlProtos.Permission.Type.Global).setGlobalPermission(permissionBuilder);
176    return AccessControlProtos.GrantRequest.newBuilder()
177      .setUserPermission(AccessControlProtos.UserPermission.newBuilder()
178        .setUser(ByteString.copyFromUtf8(username)).setPermission(ret))
179      .setMergeExistingPermissions(mergeExistingPermissions).build();
180  }
181
182  public static AccessControlProtos.UsersAndPermissions toUsersAndPermissions(String user,
183    Permission perms) {
184    return AccessControlProtos.UsersAndPermissions.newBuilder()
185      .addUserPermissions(AccessControlProtos.UsersAndPermissions.UserPermissions.newBuilder()
186        .setUser(ByteString.copyFromUtf8(user)).addPermissions(toPermission(perms)).build())
187      .build();
188  }
189
190  public static AccessControlProtos.UsersAndPermissions
191    toUsersAndPermissions(ListMultimap<String, Permission> perms) {
192    AccessControlProtos.UsersAndPermissions.Builder builder =
193      AccessControlProtos.UsersAndPermissions.newBuilder();
194    for (Map.Entry<String, Collection<Permission>> entry : perms.asMap().entrySet()) {
195      AccessControlProtos.UsersAndPermissions.UserPermissions.Builder userPermBuilder =
196        AccessControlProtos.UsersAndPermissions.UserPermissions.newBuilder();
197      userPermBuilder.setUser(ByteString.copyFromUtf8(entry.getKey()));
198      for (Permission perm : entry.getValue()) {
199        userPermBuilder.addPermissions(toPermission(perm));
200      }
201      builder.addUserPermissions(userPermBuilder.build());
202    }
203    return builder.build();
204  }
205
206  public static ListMultimap<String, Permission>
207    toUsersAndPermissions(AccessControlProtos.UsersAndPermissions proto) {
208    ListMultimap<String, Permission> result = ArrayListMultimap.create();
209    for (AccessControlProtos.UsersAndPermissions.UserPermissions userPerms : proto
210      .getUserPermissionsList()) {
211      String user = userPerms.getUser().toStringUtf8();
212      for (AccessControlProtos.Permission perm : userPerms.getPermissionsList()) {
213        result.put(user, toPermission(perm));
214      }
215    }
216    return result;
217  }
218
219  /**
220   * Converts a TablePermission proto to a client TablePermission object.
221   * @param proto the protobuf TablePermission
222   * @return the converted TablePermission
223   */
224  public static TablePermission toTablePermission(AccessControlProtos.TablePermission proto) {
225    Permission.Action[] actions = toPermissionActions(proto.getActionList());
226    if (!proto.hasTableName()) {
227      throw new IllegalStateException("TableName cannot be empty");
228    }
229    TableName table = ProtobufUtil.toTableName(proto.getTableName());
230    byte[] family = null;
231    byte[] qualifier = null;
232    if (proto.hasFamily()) {
233      family = proto.getFamily().toByteArray();
234    }
235    if (proto.hasQualifier()) {
236      qualifier = proto.getQualifier().toByteArray();
237    }
238    return new TablePermission(table, family, qualifier, actions);
239  }
240
241  /**
242   * Converts a Permission proto to a client Permission object.
243   * @param proto the protobuf Permission
244   * @return the converted Permission
245   */
246  public static Permission toPermission(AccessControlProtos.Permission proto) {
247    if (proto.getType() == AccessControlProtos.Permission.Type.Global) {
248      AccessControlProtos.GlobalPermission perm = proto.getGlobalPermission();
249      Permission.Action[] actions = toPermissionActions(perm.getActionList());
250      return Permission.newBuilder().withActions(actions).build();
251    }
252    if (proto.getType() == AccessControlProtos.Permission.Type.Namespace) {
253      AccessControlProtos.NamespacePermission perm = proto.getNamespacePermission();
254      Permission.Action[] actions = toPermissionActions(perm.getActionList());
255      if (!proto.hasNamespacePermission()) {
256        throw new IllegalStateException("Namespace must not be empty in NamespacePermission");
257      }
258      return Permission.newBuilder(perm.getNamespaceName().toStringUtf8()).withActions(actions)
259        .build();
260    }
261    if (proto.getType() == AccessControlProtos.Permission.Type.Table) {
262      AccessControlProtos.TablePermission perm = proto.getTablePermission();
263      Permission.Action[] actions = toPermissionActions(perm.getActionList());
264      if (!perm.hasTableName()) {
265        throw new IllegalStateException("TableName cannot be empty");
266      }
267      TableName table = ProtobufUtil.toTableName(perm.getTableName());
268      byte[] family = null;
269      byte[] qualifier = null;
270      if (perm.hasFamily()) {
271        family = perm.getFamily().toByteArray();
272      }
273      if (perm.hasQualifier()) {
274        qualifier = perm.getQualifier().toByteArray();
275      }
276      return Permission.newBuilder(table).withFamily(family).withQualifier(qualifier)
277        .withActions(actions).build();
278    }
279    throw new IllegalStateException("Unrecognize Perm Type: " + proto.getType());
280  }
281
282  /**
283   * Convert a client Permission to a Permission proto
284   * @param perm the client Permission
285   * @return the protobuf Permission
286   */
287  public static AccessControlProtos.Permission toPermission(Permission perm) {
288    AccessControlProtos.Permission.Builder ret = AccessControlProtos.Permission.newBuilder();
289    if (perm instanceof NamespacePermission) {
290      NamespacePermission namespace = (NamespacePermission) perm;
291      ret.setType(AccessControlProtos.Permission.Type.Namespace);
292      AccessControlProtos.NamespacePermission.Builder builder =
293        AccessControlProtos.NamespacePermission.newBuilder();
294      builder.setNamespaceName(ByteString.copyFromUtf8(namespace.getNamespace()));
295      Permission.Action[] actions = perm.getActions();
296      if (actions != null) {
297        for (Permission.Action a : actions) {
298          builder.addAction(toPermissionAction(a));
299        }
300      }
301      ret.setNamespacePermission(builder);
302    } else if (perm instanceof TablePermission) {
303      TablePermission table = (TablePermission) perm;
304      ret.setType(AccessControlProtos.Permission.Type.Table);
305      AccessControlProtos.TablePermission.Builder builder =
306        AccessControlProtos.TablePermission.newBuilder();
307      builder.setTableName(ProtobufUtil.toProtoTableName(table.getTableName()));
308      if (table.hasFamily()) {
309        builder.setFamily(UnsafeByteOperations.unsafeWrap(table.getFamily()));
310      }
311      if (table.hasQualifier()) {
312        builder.setQualifier(UnsafeByteOperations.unsafeWrap(table.getQualifier()));
313      }
314      Permission.Action[] actions = perm.getActions();
315      if (actions != null) {
316        for (Permission.Action a : actions) {
317          builder.addAction(toPermissionAction(a));
318        }
319      }
320      ret.setTablePermission(builder);
321    } else {
322      // perm instanceof GlobalPermission
323      ret.setType(AccessControlProtos.Permission.Type.Global);
324      AccessControlProtos.GlobalPermission.Builder builder =
325        AccessControlProtos.GlobalPermission.newBuilder();
326      Permission.Action[] actions = perm.getActions();
327      if (actions != null) {
328        for (Permission.Action a : actions) {
329          builder.addAction(toPermissionAction(a));
330        }
331      }
332      ret.setGlobalPermission(builder);
333    }
334    return ret.build();
335  }
336
337  /**
338   * Converts a list of Permission.Action proto to an array of client Permission.Action objects.
339   * @param protoActions the list of protobuf Actions
340   * @return the converted array of Actions
341   */
342  public static Permission.Action[]
343    toPermissionActions(List<AccessControlProtos.Permission.Action> protoActions) {
344    Permission.Action[] actions = new Permission.Action[protoActions.size()];
345    for (int i = 0; i < protoActions.size(); i++) {
346      actions[i] = toPermissionAction(protoActions.get(i));
347    }
348    return actions;
349  }
350
351  /**
352   * Converts a Permission.Action proto to a client Permission.Action object.
353   * @param action the protobuf Action
354   * @return the converted Action
355   */
356  public static Permission.Action toPermissionAction(AccessControlProtos.Permission.Action action) {
357    switch (action) {
358      case READ:
359        return Permission.Action.READ;
360      case WRITE:
361        return Permission.Action.WRITE;
362      case EXEC:
363        return Permission.Action.EXEC;
364      case CREATE:
365        return Permission.Action.CREATE;
366      case ADMIN:
367        return Permission.Action.ADMIN;
368    }
369    throw new IllegalArgumentException("Unknown action value " + action.name());
370  }
371
372  /**
373   * Convert a client Permission.Action to a Permission.Action proto
374   * @param action the client Action
375   * @return the protobuf Action
376   */
377  public static AccessControlProtos.Permission.Action toPermissionAction(Permission.Action action) {
378    switch (action) {
379      case READ:
380        return AccessControlProtos.Permission.Action.READ;
381      case WRITE:
382        return AccessControlProtos.Permission.Action.WRITE;
383      case EXEC:
384        return AccessControlProtos.Permission.Action.EXEC;
385      case CREATE:
386        return AccessControlProtos.Permission.Action.CREATE;
387      case ADMIN:
388        return AccessControlProtos.Permission.Action.ADMIN;
389    }
390    throw new IllegalArgumentException("Unknown action value " + action.name());
391  }
392
393  /**
394   * Convert a client user permission to a user permission proto
395   * @param perm the client UserPermission
396   * @return the protobuf UserPermission
397   */
398  public static AccessControlProtos.UserPermission toUserPermission(UserPermission perm) {
399    return AccessControlProtos.UserPermission.newBuilder()
400      .setUser(ByteString.copyFromUtf8(perm.getUser()))
401      .setPermission(toPermission(perm.getPermission())).build();
402  }
403
404  /**
405   * Converts the permissions list into a protocol buffer GetUserPermissionsResponse
406   */
407  public static GetUserPermissionsResponse
408    buildGetUserPermissionsResponse(final List<UserPermission> permissions) {
409    GetUserPermissionsResponse.Builder builder = GetUserPermissionsResponse.newBuilder();
410    for (UserPermission perm : permissions) {
411      builder.addUserPermission(toUserPermission(perm));
412    }
413    return builder.build();
414  }
415
416  /**
417   * Converts a user permission proto to a client user permission object.
418   * @param proto the protobuf UserPermission
419   * @return the converted UserPermission
420   */
421  public static UserPermission toUserPermission(AccessControlProtos.UserPermission proto) {
422    return new UserPermission(proto.getUser().toStringUtf8(), toPermission(proto.getPermission()));
423  }
424
425  /**
426   * Convert a ListMultimap&lt;String, TablePermission&gt; where key is username to a protobuf
427   * UserPermission
428   * @param perm the list of user and table permissions
429   * @return the protobuf UserTablePermissions
430   */
431  public static AccessControlProtos.UsersAndPermissions
432    toUserTablePermissions(ListMultimap<String, UserPermission> perm) {
433    AccessControlProtos.UsersAndPermissions.Builder builder =
434      AccessControlProtos.UsersAndPermissions.newBuilder();
435    for (Map.Entry<String, Collection<UserPermission>> entry : perm.asMap().entrySet()) {
436      AccessControlProtos.UsersAndPermissions.UserPermissions.Builder userPermBuilder =
437        AccessControlProtos.UsersAndPermissions.UserPermissions.newBuilder();
438      userPermBuilder.setUser(ByteString.copyFromUtf8(entry.getKey()));
439      for (UserPermission userPerm : entry.getValue()) {
440        userPermBuilder.addPermissions(toPermission(userPerm.getPermission()));
441      }
442      builder.addUserPermissions(userPermBuilder.build());
443    }
444    return builder.build();
445  }
446
447  /**
448   * A utility used to grant a user global permissions.
449   * <p>
450   * It's also called by the shell, in case you want to find references.
451   * @param protocol      the AccessControlService protocol proxy
452   * @param userShortName the short name of the user to grant permissions
453   * @param actions       the permissions to be granted
454   * @deprecated Use {@link Admin#grant(UserPermission, boolean)} instead.
455   */
456  @Deprecated
457  public static void grant(RpcController controller,
458    AccessControlService.BlockingInterface protocol, String userShortName,
459    boolean mergeExistingPermissions, Permission.Action... actions) throws ServiceException {
460    List<AccessControlProtos.Permission.Action> permActions =
461      Lists.newArrayListWithCapacity(actions.length);
462    for (Permission.Action a : actions) {
463      permActions.add(toPermissionAction(a));
464    }
465    AccessControlProtos.GrantRequest request =
466      buildGrantRequest(userShortName, mergeExistingPermissions,
467        permActions.toArray(new AccessControlProtos.Permission.Action[actions.length]));
468    protocol.grant(controller, request);
469  }
470
471  /**
472   * A utility used to grant a user table permissions. The permissions will be for a table
473   * table/column family/qualifier.
474   * <p>
475   * It's also called by the shell, in case you want to find references.
476   * @param protocol      the AccessControlService protocol proxy
477   * @param userShortName the short name of the user to grant permissions
478   * @param tableName     optional table name
479   * @param f             optional column family
480   * @param q             optional qualifier
481   * @param actions       the permissions to be granted
482   * @deprecated Use {@link Admin#grant(UserPermission, boolean)} instead.
483   */
484  @Deprecated
485  public static void grant(RpcController controller,
486    AccessControlService.BlockingInterface protocol, String userShortName, TableName tableName,
487    byte[] f, byte[] q, boolean mergeExistingPermissions, Permission.Action... actions)
488    throws ServiceException {
489    List<AccessControlProtos.Permission.Action> permActions =
490      Lists.newArrayListWithCapacity(actions.length);
491    for (Permission.Action a : actions) {
492      permActions.add(toPermissionAction(a));
493    }
494    AccessControlProtos.GrantRequest request =
495      buildGrantRequest(userShortName, tableName, f, q, mergeExistingPermissions,
496        permActions.toArray(new AccessControlProtos.Permission.Action[actions.length]));
497    protocol.grant(controller, request);
498  }
499
500  /**
501   * A utility used to grant a user namespace permissions.
502   * <p>
503   * It's also called by the shell, in case you want to find references.
504   * @param controller RpcController
505   * @param protocol   the AccessControlService protocol proxy
506   * @param namespace  the short name of the user to grant permissions
507   * @param actions    the permissions to be granted
508   * @deprecated Use {@link Admin#grant(UserPermission, boolean)} instead.
509   */
510  @Deprecated
511  public static void grant(RpcController controller,
512    AccessControlService.BlockingInterface protocol, String userShortName, String namespace,
513    boolean mergeExistingPermissions, Permission.Action... actions) throws ServiceException {
514    List<AccessControlProtos.Permission.Action> permActions =
515      Lists.newArrayListWithCapacity(actions.length);
516    for (Permission.Action a : actions) {
517      permActions.add(toPermissionAction(a));
518    }
519    AccessControlProtos.GrantRequest request =
520      buildGrantRequest(userShortName, namespace, mergeExistingPermissions,
521        permActions.toArray(new AccessControlProtos.Permission.Action[actions.length]));
522    protocol.grant(controller, request);
523  }
524
525  /**
526   * A utility used to revoke a user's global permissions.
527   * <p>
528   * It's also called by the shell, in case you want to find references.
529   * @param controller    RpcController
530   * @param protocol      the AccessControlService protocol proxy
531   * @param userShortName the short name of the user to revoke permissions
532   * @param actions       the permissions to be revoked
533   * @throws ServiceException on failure
534   * @deprecated Use {@link Admin#revoke(UserPermission)} instead.
535   */
536  @Deprecated
537  public static void revoke(RpcController controller,
538    AccessControlService.BlockingInterface protocol, String userShortName,
539    Permission.Action... actions) throws ServiceException {
540    List<AccessControlProtos.Permission.Action> permActions =
541      Lists.newArrayListWithCapacity(actions.length);
542    for (Permission.Action a : actions) {
543      permActions.add(toPermissionAction(a));
544    }
545    AccessControlProtos.RevokeRequest request = buildRevokeRequest(userShortName,
546      permActions.toArray(new AccessControlProtos.Permission.Action[actions.length]));
547    protocol.revoke(controller, request);
548  }
549
550  /**
551   * A utility used to revoke a user's table permissions. The permissions will be for a table/column
552   * family/qualifier.
553   * <p>
554   * It's also called by the shell, in case you want to find references.
555   * @param controller    RpcController
556   * @param protocol      the AccessControlService protocol proxy
557   * @param userShortName the short name of the user to revoke permissions
558   * @param tableName     optional table name
559   * @param f             optional column family
560   * @param q             optional qualifier
561   * @param actions       the permissions to be revoked
562   * @throws ServiceException on failure
563   * @deprecated Use {@link Admin#revoke(UserPermission)} instead.
564   */
565  @Deprecated
566  public static void revoke(RpcController controller,
567    AccessControlService.BlockingInterface protocol, String userShortName, TableName tableName,
568    byte[] f, byte[] q, Permission.Action... actions) throws ServiceException {
569    List<AccessControlProtos.Permission.Action> permActions =
570      Lists.newArrayListWithCapacity(actions.length);
571    for (Permission.Action a : actions) {
572      permActions.add(toPermissionAction(a));
573    }
574    AccessControlProtos.RevokeRequest request = buildRevokeRequest(userShortName, tableName, f, q,
575      permActions.toArray(new AccessControlProtos.Permission.Action[actions.length]));
576    protocol.revoke(controller, request);
577  }
578
579  /**
580   * A utility used to revoke a user's namespace permissions.
581   * <p>
582   * It's also called by the shell, in case you want to find references.
583   * @param controller    RpcController
584   * @param protocol      the AccessControlService protocol proxy
585   * @param userShortName the short name of the user to revoke permissions
586   * @param namespace     optional table name
587   * @param actions       the permissions to be revoked
588   * @throws ServiceException on failure
589   * @deprecated Use {@link Admin#revoke(UserPermission)} instead.
590   */
591  @Deprecated
592  public static void revoke(RpcController controller,
593    AccessControlService.BlockingInterface protocol, String userShortName, String namespace,
594    Permission.Action... actions) throws ServiceException {
595    List<AccessControlProtos.Permission.Action> permActions =
596      Lists.newArrayListWithCapacity(actions.length);
597    for (Permission.Action a : actions) {
598      permActions.add(toPermissionAction(a));
599    }
600    AccessControlProtos.RevokeRequest request = buildRevokeRequest(userShortName, namespace,
601      permActions.toArray(new AccessControlProtos.Permission.Action[actions.length]));
602    protocol.revoke(controller, request);
603  }
604
605  /**
606   * A utility used to get user's global permissions.
607   * <p>
608   * It's also called by the shell, in case you want to find references.
609   * @param controller RpcController
610   * @param protocol   the AccessControlService protocol proxy
611   * @throws ServiceException on failure
612   * @deprecated Use {@link Admin#getUserPermissions(GetUserPermissionsRequest)} instead.
613   */
614  @Deprecated
615  public static List<UserPermission> getUserPermissions(RpcController controller,
616    AccessControlService.BlockingInterface protocol) throws ServiceException {
617    return getUserPermissions(controller, protocol, HConstants.EMPTY_STRING);
618  }
619
620  /**
621   * A utility used to get user's global permissions based on the specified user name.
622   * @param controller RpcController
623   * @param protocol   the AccessControlService protocol proxy
624   * @param userName   User name, if empty then all user permissions will be retrieved.
625   * @deprecated Use {@link Admin#getUserPermissions(GetUserPermissionsRequest)} instead.
626   */
627  @Deprecated
628  public static List<UserPermission> getUserPermissions(RpcController controller,
629    AccessControlService.BlockingInterface protocol, String userName) throws ServiceException {
630    AccessControlProtos.GetUserPermissionsRequest.Builder builder =
631      AccessControlProtos.GetUserPermissionsRequest.newBuilder();
632    builder.setType(AccessControlProtos.Permission.Type.Global);
633    if (!StringUtils.isEmpty(userName)) {
634      builder.setUserName(ByteString.copyFromUtf8(userName));
635    }
636
637    AccessControlProtos.GetUserPermissionsRequest request = builder.build();
638    AccessControlProtos.GetUserPermissionsResponse response =
639      protocol.getUserPermissions(controller, request);
640    List<UserPermission> perms = new ArrayList<>(response.getUserPermissionCount());
641    for (AccessControlProtos.UserPermission perm : response.getUserPermissionList()) {
642      perms.add(toUserPermission(perm));
643    }
644    return perms;
645  }
646
647  /**
648   * A utility used to get user table permissions.
649   * <p>
650   * It's also called by the shell, in case you want to find references.
651   * @param controller RpcController
652   * @param protocol   the AccessControlService protocol proxy
653   * @param t          optional table name
654   * @deprecated Use {@link Admin#getUserPermissions(GetUserPermissionsRequest)} instead.
655   */
656  @Deprecated
657  public static List<UserPermission> getUserPermissions(RpcController controller,
658    AccessControlService.BlockingInterface protocol, TableName t) throws ServiceException {
659    return getUserPermissions(controller, protocol, t, null, null, HConstants.EMPTY_STRING);
660  }
661
662  /**
663   * A utility used to get user table permissions based on the column family, column qualifier and
664   * user name.
665   * @param controller      RpcController
666   * @param protocol        the AccessControlService protocol proxy
667   * @param t               optional table name
668   * @param columnFamily    Column family
669   * @param columnQualifier Column qualifier
670   * @param userName        User name, if empty then all user permissions will be retrieved.
671   * @deprecated Use {@link Admin#getUserPermissions(GetUserPermissionsRequest)} instead.
672   */
673  @Deprecated
674  public static List<UserPermission> getUserPermissions(RpcController controller,
675    AccessControlService.BlockingInterface protocol, TableName t, byte[] columnFamily,
676    byte[] columnQualifier, String userName) throws ServiceException {
677    AccessControlProtos.GetUserPermissionsRequest.Builder builder =
678      AccessControlProtos.GetUserPermissionsRequest.newBuilder();
679    if (t != null) {
680      builder.setTableName(ProtobufUtil.toProtoTableName(t));
681    }
682    if (Bytes.len(columnFamily) > 0) {
683      builder.setColumnFamily(ByteString.copyFrom(columnFamily));
684    }
685    if (Bytes.len(columnQualifier) > 0) {
686      builder.setColumnQualifier(ByteString.copyFrom(columnQualifier));
687    }
688    if (!StringUtils.isEmpty(userName)) {
689      builder.setUserName(ByteString.copyFromUtf8(userName));
690    }
691
692    builder.setType(AccessControlProtos.Permission.Type.Table);
693    AccessControlProtos.GetUserPermissionsRequest request = builder.build();
694    AccessControlProtos.GetUserPermissionsResponse response =
695      protocol.getUserPermissions(controller, request);
696    List<UserPermission> perms = new ArrayList<>(response.getUserPermissionCount());
697    for (AccessControlProtos.UserPermission perm : response.getUserPermissionList()) {
698      perms.add(toUserPermission(perm));
699    }
700    return perms;
701  }
702
703  /**
704   * A utility used to get permissions for selected namespace.
705   * <p>
706   * It's also called by the shell, in case you want to find references.
707   * @param controller RpcController
708   * @param protocol   the AccessControlService protocol proxy
709   * @param namespace  name of the namespace
710   * @deprecated Use {@link Admin#getUserPermissions(GetUserPermissionsRequest)} instead.
711   */
712  @Deprecated
713  public static List<UserPermission> getUserPermissions(RpcController controller,
714    AccessControlService.BlockingInterface protocol, byte[] namespace) throws ServiceException {
715    return getUserPermissions(controller, protocol, namespace, HConstants.EMPTY_STRING);
716  }
717
718  /**
719   * A utility used to get permissions for selected namespace based on the specified user name.
720   * @param controller RpcController
721   * @param protocol   the AccessControlService protocol proxy
722   * @param namespace  name of the namespace
723   * @param userName   User name, if empty then all user permissions will be retrieved.
724   * @deprecated Use {@link Admin#getUserPermissions(GetUserPermissionsRequest)} instead.
725   */
726  @Deprecated
727  public static List<UserPermission> getUserPermissions(RpcController controller,
728    AccessControlService.BlockingInterface protocol, byte[] namespace, String userName)
729    throws ServiceException {
730    AccessControlProtos.GetUserPermissionsRequest.Builder builder =
731      AccessControlProtos.GetUserPermissionsRequest.newBuilder();
732    if (namespace != null) {
733      builder.setNamespaceName(UnsafeByteOperations.unsafeWrap(namespace));
734    }
735    if (!StringUtils.isEmpty(userName)) {
736      builder.setUserName(ByteString.copyFromUtf8(userName));
737    }
738    builder.setType(AccessControlProtos.Permission.Type.Namespace);
739    AccessControlProtos.GetUserPermissionsRequest request = builder.build();
740    AccessControlProtos.GetUserPermissionsResponse response =
741      protocol.getUserPermissions(controller, request);
742    List<UserPermission> perms = new ArrayList<>(response.getUserPermissionCount());
743    for (AccessControlProtos.UserPermission perm : response.getUserPermissionList()) {
744      perms.add(toUserPermission(perm));
745    }
746    return perms;
747  }
748
749  /**
750   * Validates whether specified user has permission to perform actions on the mentioned table,
751   * column family or column qualifier.
752   * @param controller      RpcController
753   * @param protocol        the AccessControlService protocol proxy
754   * @param tableName       Table name, it shouldn't be null or empty.
755   * @param columnFamily    The column family. Optional argument, can be empty. If empty then
756   *                        validation will happen at table level.
757   * @param columnQualifier The column qualifier. Optional argument, can be empty. If empty then
758   *                        validation will happen at table and column family level. columnQualifier
759   *                        will not be considered if columnFamily is passed as null or empty.
760   * @param userName        User name, it shouldn't be null or empty.
761   * @param actions         Actions
762   * @return true if access allowed, otherwise false
763   * @deprecated Use {@link Admin#hasUserPermissions(String, List)} instead.
764   */
765  @Deprecated
766  public static boolean hasPermission(RpcController controller,
767    AccessControlService.BlockingInterface protocol, TableName tableName, byte[] columnFamily,
768    byte[] columnQualifier, String userName, Permission.Action[] actions) throws ServiceException {
769    AccessControlProtos.TablePermission.Builder tablePermissionBuilder =
770      AccessControlProtos.TablePermission.newBuilder();
771    tablePermissionBuilder.setTableName(ProtobufUtil.toProtoTableName(tableName));
772    if (Bytes.len(columnFamily) > 0) {
773      tablePermissionBuilder.setFamily(UnsafeByteOperations.unsafeWrap(columnFamily));
774    }
775    if (Bytes.len(columnQualifier) > 0) {
776      tablePermissionBuilder.setQualifier(UnsafeByteOperations.unsafeWrap(columnQualifier));
777    }
778    for (Permission.Action a : actions) {
779      tablePermissionBuilder.addAction(toPermissionAction(a));
780    }
781    AccessControlProtos.HasPermissionRequest request = AccessControlProtos.HasPermissionRequest
782      .newBuilder().setTablePermission(tablePermissionBuilder)
783      .setUserName(ByteString.copyFromUtf8(userName)).build();
784    AccessControlProtos.HasPermissionResponse response =
785      protocol.hasPermission(controller, request);
786    return response.getHasPermission();
787  }
788
789  /**
790   * Convert a protobuf UserTablePermissions to a ListMultimap&lt;Username, UserPermission&gt
791   * @param proto the proto UsersAndPermissions
792   * @return a ListMultimap with user and its permissions
793   */
794  public static ListMultimap<String, UserPermission>
795    toUserPermission(AccessControlProtos.UsersAndPermissions proto) {
796    ListMultimap<String, UserPermission> userPermission = ArrayListMultimap.create();
797    AccessControlProtos.UsersAndPermissions.UserPermissions userPerm;
798    for (int i = 0; i < proto.getUserPermissionsCount(); i++) {
799      userPerm = proto.getUserPermissions(i);
800      String username = userPerm.getUser().toStringUtf8();
801      for (int j = 0; j < userPerm.getPermissionsCount(); j++) {
802        userPermission.put(username,
803          new UserPermission(username, toPermission(userPerm.getPermissions(j))));
804      }
805    }
806    return userPermission;
807  }
808
809  /**
810   * Convert a protobuf UserTablePermissions to a ListMultimap&lt;Username, Permission&gt
811   * @param proto the proto UsersAndPermissions
812   * @return a ListMultimap with user and its permissions
813   */
814  public static ListMultimap<String, Permission>
815    toPermission(AccessControlProtos.UsersAndPermissions proto) {
816    ListMultimap<String, Permission> perms = ArrayListMultimap.create();
817    AccessControlProtos.UsersAndPermissions.UserPermissions userPerm;
818    for (int i = 0; i < proto.getUserPermissionsCount(); i++) {
819      userPerm = proto.getUserPermissions(i);
820      String username = userPerm.getUser().toStringUtf8();
821      for (int j = 0; j < userPerm.getPermissionsCount(); j++) {
822        perms.put(username, toPermission(userPerm.getPermissions(j)));
823      }
824    }
825    return perms;
826  }
827
828  /**
829   * Create a request to revoke user table permissions.
830   * @param username  the short user name whose permissions to be revoked
831   * @param tableName optional table name the permissions apply
832   * @param family    optional column family
833   * @param qualifier optional qualifier
834   * @param actions   the permissions to be revoked
835   * @return A {@link AccessControlProtos} RevokeRequest
836   */
837  public static AccessControlProtos.RevokeRequest buildRevokeRequest(String username,
838    TableName tableName, byte[] family, byte[] qualifier,
839    AccessControlProtos.Permission.Action... actions) {
840    AccessControlProtos.Permission.Builder ret = AccessControlProtos.Permission.newBuilder();
841    AccessControlProtos.TablePermission.Builder permissionBuilder =
842      AccessControlProtos.TablePermission.newBuilder();
843    for (AccessControlProtos.Permission.Action a : actions) {
844      permissionBuilder.addAction(a);
845    }
846    if (tableName != null) {
847      permissionBuilder.setTableName(ProtobufUtil.toProtoTableName(tableName));
848    }
849    if (family != null) {
850      permissionBuilder.setFamily(UnsafeByteOperations.unsafeWrap(family));
851    }
852    if (qualifier != null) {
853      permissionBuilder.setQualifier(UnsafeByteOperations.unsafeWrap(qualifier));
854    }
855    ret.setType(AccessControlProtos.Permission.Type.Table).setTablePermission(permissionBuilder);
856    return AccessControlProtos.RevokeRequest.newBuilder()
857      .setUserPermission(AccessControlProtos.UserPermission.newBuilder()
858        .setUser(ByteString.copyFromUtf8(username)).setPermission(ret))
859      .build();
860  }
861}