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<String, TablePermission> 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<String, TablePermission> 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}