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