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