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