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