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