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 */
018
019package org.apache.hadoop.hbase.security.access;
020
021
022import org.apache.hbase.thirdparty.com.google.common.collect.ArrayListMultimap;
023import org.apache.hbase.thirdparty.com.google.common.collect.ListMultimap;
024import org.apache.hadoop.hbase.TableName;
025import org.apache.yetus.audience.InterfaceAudience;
026import org.apache.hadoop.hbase.security.access.Permission.Action;
027import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos;
028import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos;
029import org.apache.hbase.thirdparty.com.google.protobuf.ByteString;
030
031import java.util.ArrayList;
032import java.util.Collection;
033import java.util.List;
034import java.util.Map;
035
036/**
037 * Convert protobuf objects in AccessControl.proto under hbase-protocol-shaded to user-oriented
038 * objects and vice versa. <br>
039 *
040 * In HBASE-15638, we create a hbase-protocol-shaded module for upgrading protobuf version to 3.x,
041 * but there are still some coprocessor endpoints(such as AccessControl, Authentication,
042 * MulitRowMutation) which depend on hbase-protocol module for CPEP compatibility. In fact, we use
043 * PB objects in AccessControl.proto under hbase-protocol for access control logic and use shaded
044 * AccessControl.proto only for serializing/deserializing permissions of .snapshotinfo.
045 */
046@InterfaceAudience.Private
047public class ShadedAccessControlUtil {
048
049  /**
050   * Convert a client user permission to a user permission shaded proto.
051   */
052  public static
053      org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.Permission.Action
054      toPermissionAction(Permission.Action action) {
055    switch (action) {
056    case READ:
057      return org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.Permission.Action.READ;
058    case WRITE:
059      return org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.Permission.Action.WRITE;
060    case EXEC:
061      return org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.Permission.Action.EXEC;
062    case CREATE:
063      return org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.Permission.Action.CREATE;
064    case ADMIN:
065      return org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.Permission.Action.ADMIN;
066    }
067    throw new IllegalArgumentException("Unknown action value " + action.name());
068  }
069
070  /**
071   * Convert a Permission.Action shaded proto to a client Permission.Action object.
072   */
073  public static Permission.Action toPermissionAction(
074      org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.Permission.Action action) {
075    switch (action) {
076    case READ:
077      return Permission.Action.READ;
078    case WRITE:
079      return Permission.Action.WRITE;
080    case EXEC:
081      return Permission.Action.EXEC;
082    case CREATE:
083      return Permission.Action.CREATE;
084    case ADMIN:
085      return Permission.Action.ADMIN;
086    }
087    throw new IllegalArgumentException("Unknown action value " + action.name());
088  }
089
090  /**
091   * Converts a list of Permission.Action shaded proto to a list of client Permission.Action
092   * objects.
093   * @param protoActions the list of shaded protobuf Actions
094   * @return the converted list of Actions
095   */
096  public static List<Permission.Action> toPermissionActions(
097      List<org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.Permission.Action> protoActions) {
098    List<Permission.Action> actions = new ArrayList<>(protoActions.size());
099    for (org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.Permission.Action a : protoActions) {
100      actions.add(toPermissionAction(a));
101    }
102    return actions;
103  }
104
105  public static org.apache.hadoop.hbase.TableName toTableName(HBaseProtos.TableName tableNamePB) {
106    return org.apache.hadoop.hbase.TableName.valueOf(
107      tableNamePB.getNamespace().asReadOnlyByteBuffer(),
108      tableNamePB.getQualifier().asReadOnlyByteBuffer());
109  }
110
111  public static HBaseProtos.TableName toProtoTableName(TableName tableName) {
112    return HBaseProtos.TableName.newBuilder()
113        .setNamespace(ByteString.copyFrom(tableName.getNamespace()))
114        .setQualifier(ByteString.copyFrom(tableName.getQualifier())).build();
115  }
116
117  /**
118   * Converts a Permission shaded proto to a client TablePermission object.
119   * @param proto the protobuf Permission
120   * @return the converted TablePermission
121   */
122  public static TablePermission toTablePermission(AccessControlProtos.Permission proto) {
123
124    if (proto.getType() == AccessControlProtos.Permission.Type.Global) {
125      AccessControlProtos.GlobalPermission perm = proto.getGlobalPermission();
126      List<Action> actions = toPermissionActions(perm.getActionList());
127
128      return new TablePermission(null, null, null,
129          actions.toArray(new Permission.Action[actions.size()]));
130    }
131    if (proto.getType() == AccessControlProtos.Permission.Type.Namespace) {
132      AccessControlProtos.NamespacePermission perm = proto.getNamespacePermission();
133      List<Permission.Action> actions = toPermissionActions(perm.getActionList());
134
135      if (!proto.hasNamespacePermission()) {
136        throw new IllegalStateException("Namespace must not be empty in NamespacePermission");
137      }
138      String namespace = perm.getNamespaceName().toStringUtf8();
139      return new TablePermission(namespace, actions.toArray(new Permission.Action[actions.size()]));
140    }
141    if (proto.getType() == AccessControlProtos.Permission.Type.Table) {
142      AccessControlProtos.TablePermission perm = proto.getTablePermission();
143      List<Permission.Action> actions = toPermissionActions(perm.getActionList());
144
145      byte[] qualifier = null;
146      byte[] family = null;
147      TableName table = null;
148
149      if (!perm.hasTableName()) {
150        throw new IllegalStateException("TableName cannot be empty");
151      }
152      table = toTableName(perm.getTableName());
153
154      if (perm.hasFamily()) family = perm.getFamily().toByteArray();
155      if (perm.hasQualifier()) qualifier = perm.getQualifier().toByteArray();
156
157      return new TablePermission(table, family, qualifier,
158          actions.toArray(new Permission.Action[actions.size()]));
159    }
160    throw new IllegalStateException("Unrecognize Perm Type: " + proto.getType());
161  }
162
163  /**
164   * Convert a client Permission to a Permission shaded proto
165   * @param perm the client Permission
166   * @return the protobuf Permission
167   */
168  public static org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.Permission
169      toPermission(Permission perm) {
170    org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.Permission.Builder ret =
171        org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.Permission
172            .newBuilder();
173    if (perm instanceof TablePermission) {
174      TablePermission tablePerm = (TablePermission) perm;
175      if (tablePerm.hasNamespace()) {
176        ret.setType(
177          org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.Permission.Type.Namespace);
178
179        org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.NamespacePermission.Builder builder =
180            org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.NamespacePermission
181                .newBuilder();
182        builder.setNamespaceName(org.apache.hbase.thirdparty.com.google.protobuf.ByteString
183            .copyFromUtf8(tablePerm.getNamespace()));
184        Permission.Action[] actions = perm.getActions();
185        if (actions != null) {
186          for (Permission.Action a : actions) {
187            builder.addAction(toPermissionAction(a));
188          }
189        }
190        ret.setNamespacePermission(builder);
191        return ret.build();
192      } else if (tablePerm.hasTable()) {
193        ret.setType(
194          org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.Permission.Type.Table);
195
196        org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.TablePermission.Builder builder =
197            org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.TablePermission
198                .newBuilder();
199        builder.setTableName(toProtoTableName(tablePerm.getTableName()));
200        if (tablePerm.hasFamily()) {
201          builder.setFamily(ByteString.copyFrom(tablePerm.getFamily()));
202        }
203        if (tablePerm.hasQualifier()) {
204          builder.setQualifier(ByteString.copyFrom(tablePerm.getQualifier()));
205        }
206        Permission.Action actions[] = perm.getActions();
207        if (actions != null) {
208          for (Permission.Action a : actions) {
209            builder.addAction(toPermissionAction(a));
210          }
211        }
212        ret.setTablePermission(builder);
213        return ret.build();
214      }
215    }
216
217    ret.setType(
218      org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.Permission.Type.Global);
219
220    org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.GlobalPermission.Builder builder =
221        org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.GlobalPermission
222            .newBuilder();
223    Permission.Action actions[] = perm.getActions();
224    if (actions != null) {
225      for (Permission.Action a : actions) {
226        builder.addAction(toPermissionAction(a));
227      }
228    }
229    ret.setGlobalPermission(builder);
230    return ret.build();
231  }
232
233  /**
234   * Convert a shaded protobuf UserTablePermissions to a ListMultimap&lt;String, TablePermission&gt;
235   * where key is username.
236   * @param proto the protobuf UserPermission
237   * @return the converted UserPermission
238   */
239  public static ListMultimap<String, TablePermission> toUserTablePermissions(
240      org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.UsersAndPermissions proto) {
241    ListMultimap<String, TablePermission> perms = ArrayListMultimap.create();
242    org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.UsersAndPermissions.UserPermissions userPerm;
243    for (int i = 0; i < proto.getUserPermissionsCount(); i++) {
244      userPerm = proto.getUserPermissions(i);
245      for (int j = 0; j < userPerm.getPermissionsCount(); j++) {
246        TablePermission tablePerm = toTablePermission(userPerm.getPermissions(j));
247        perms.put(userPerm.getUser().toStringUtf8(), tablePerm);
248      }
249    }
250    return perms;
251  }
252
253  /**
254   * Convert a ListMultimap&lt;String, TablePermission&gt; where key is username to a shaded
255   * protobuf UserPermission
256   * @param perm the list of user and table permissions
257   * @return the protobuf UserTablePermissions
258   */
259  public static
260      org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.UsersAndPermissions
261      toUserTablePermissions(ListMultimap<String, TablePermission> perm) {
262    org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.UsersAndPermissions.Builder builder =
263        org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.UsersAndPermissions
264            .newBuilder();
265    for (Map.Entry<String, Collection<TablePermission>> entry : perm.asMap().entrySet()) {
266      org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.UsersAndPermissions.UserPermissions.Builder userPermBuilder =
267          org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.UsersAndPermissions.UserPermissions
268              .newBuilder();
269      userPermBuilder.setUser(ByteString.copyFromUtf8(entry.getKey()));
270      for (TablePermission tablePerm : entry.getValue()) {
271        userPermBuilder.addPermissions(toPermission(tablePerm));
272      }
273      builder.addUserPermissions(userPermBuilder.build());
274    }
275    return builder.build();
276  }
277
278  /**
279   * Converts a user permission proto to a client user permission object.
280   *
281   * @param proto the protobuf UserPermission
282   * @return the converted UserPermission
283   */
284  public static UserPermission toUserPermission(org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.UserPermission proto) {
285    return new UserPermission(proto.getUser().toByteArray(),
286        toTablePermission(proto.getPermission()));
287  }
288}