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 021import java.util.Collection; 022import java.util.List; 023import java.util.Map; 024import org.apache.hadoop.hbase.TableName; 025import org.apache.hadoop.hbase.security.access.Permission.Action; 026import org.apache.yetus.audience.InterfaceAudience; 027 028import org.apache.hbase.thirdparty.com.google.common.collect.ArrayListMultimap; 029import org.apache.hbase.thirdparty.com.google.common.collect.ListMultimap; 030import org.apache.hbase.thirdparty.com.google.protobuf.ByteString; 031import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos; 032import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.GetUserPermissionsResponse; 033import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.GrantRequest; 034import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.HasUserPermissionsRequest; 035import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.Permission.Type; 036import org.apache.hadoop.hbase.shaded.protobuf.generated.AccessControlProtos.RevokeRequest; 037import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos; 038 039/** 040 * Convert protobuf objects in AccessControl.proto under hbase-protocol-shaded to user-oriented 041 * objects and vice versa. <br> 042 * 043 * In HBASE-15638, we create a hbase-protocol-shaded module for upgrading protobuf version to 3.x, 044 * but there are still some coprocessor endpoints(such as AccessControl, Authentication, 045 * MulitRowMutation) which depend on hbase-protocol module for CPEP compatibility. In fact, we use 046 * PB objects in AccessControl.proto under hbase-protocol for access control logic and use shaded 047 * AccessControl.proto only for serializing/deserializing permissions of .snapshotinfo. 048 */ 049@InterfaceAudience.Private 050public class ShadedAccessControlUtil { 051 052 /** 053 * Convert a client user permission to a user permission shaded proto. 054 */ 055 public static AccessControlProtos.Permission.Action toPermissionAction(Permission.Action action) { 056 switch (action) { 057 case READ: 058 return AccessControlProtos.Permission.Action.READ; 059 case WRITE: 060 return AccessControlProtos.Permission.Action.WRITE; 061 case EXEC: 062 return AccessControlProtos.Permission.Action.EXEC; 063 case CREATE: 064 return AccessControlProtos.Permission.Action.CREATE; 065 case ADMIN: 066 return AccessControlProtos.Permission.Action.ADMIN; 067 } 068 throw new IllegalArgumentException("Unknown action value " + action.name()); 069 } 070 071 /** 072 * Convert a Permission.Action shaded proto to a client Permission.Action object. 073 */ 074 public static Permission.Action toPermissionAction(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 an array of client Permission.Action 092 * objects. 093 * @param protoActions the list of shaded protobuf Actions 094 * @return the converted array of Actions 095 */ 096 public static Permission.Action[] 097 toPermissionActions(List<AccessControlProtos.Permission.Action> protoActions) { 098 Permission.Action[] actions = new Permission.Action[protoActions.size()]; 099 for (int i = 0; i < protoActions.size(); i++) { 100 actions[i] = toPermissionAction(protoActions.get(i)); 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 Permission toPermission(AccessControlProtos.Permission proto) { 123 124 if (proto.getType() == AccessControlProtos.Permission.Type.Global) { 125 AccessControlProtos.GlobalPermission perm = proto.getGlobalPermission(); 126 Action[] actions = toPermissionActions(perm.getActionList()); 127 return Permission.newBuilder().withActions(actions).build(); 128 } 129 if (proto.getType() == AccessControlProtos.Permission.Type.Namespace) { 130 AccessControlProtos.NamespacePermission perm = proto.getNamespacePermission(); 131 Action[] actions = toPermissionActions(perm.getActionList()); 132 133 if (!proto.hasNamespacePermission()) { 134 throw new IllegalStateException("Namespace must not be empty in NamespacePermission"); 135 } 136 String ns = perm.getNamespaceName().toStringUtf8(); 137 return Permission.newBuilder(ns).withActions(actions).build(); 138 } 139 if (proto.getType() == AccessControlProtos.Permission.Type.Table) { 140 AccessControlProtos.TablePermission perm = proto.getTablePermission(); 141 Action[] actions = toPermissionActions(perm.getActionList()); 142 143 byte[] qualifier = null; 144 byte[] family = null; 145 146 if (!perm.hasTableName()) { 147 throw new IllegalStateException("TableName cannot be empty"); 148 } 149 TableName table = toTableName(perm.getTableName()); 150 151 if (perm.hasFamily()) family = perm.getFamily().toByteArray(); 152 if (perm.hasQualifier()) qualifier = perm.getQualifier().toByteArray(); 153 return Permission.newBuilder(table).withFamily(family).withQualifier(qualifier) 154 .withActions(actions).build(); 155 } 156 throw new IllegalStateException("Unrecognize Perm Type: " + proto.getType()); 157 } 158 159 /** 160 * Convert a client Permission to a Permission shaded proto 161 * @param perm the client Permission 162 * @return the protobuf Permission 163 */ 164 public static AccessControlProtos.Permission toPermission(Permission perm) { 165 AccessControlProtos.Permission.Builder ret = AccessControlProtos.Permission.newBuilder(); 166 if (perm instanceof NamespacePermission) { 167 NamespacePermission nsPerm = (NamespacePermission) perm; 168 ret.setType(AccessControlProtos.Permission.Type.Namespace); 169 AccessControlProtos.NamespacePermission.Builder builder = 170 AccessControlProtos.NamespacePermission.newBuilder(); 171 builder.setNamespaceName(org.apache.hbase.thirdparty.com.google.protobuf.ByteString 172 .copyFromUtf8(nsPerm.getNamespace())); 173 Permission.Action[] actions = perm.getActions(); 174 if (actions != null) { 175 for (Permission.Action a : actions) { 176 builder.addAction(toPermissionAction(a)); 177 } 178 } 179 ret.setNamespacePermission(builder); 180 } else if (perm instanceof TablePermission) { 181 TablePermission tablePerm = (TablePermission) perm; 182 ret.setType(AccessControlProtos.Permission.Type.Table); 183 AccessControlProtos.TablePermission.Builder builder = 184 AccessControlProtos.TablePermission.newBuilder(); 185 builder.setTableName(toProtoTableName(tablePerm.getTableName())); 186 if (tablePerm.hasFamily()) { 187 builder.setFamily(ByteString.copyFrom(tablePerm.getFamily())); 188 } 189 if (tablePerm.hasQualifier()) { 190 builder.setQualifier(ByteString.copyFrom(tablePerm.getQualifier())); 191 } 192 Permission.Action[] actions = perm.getActions(); 193 if (actions != null) { 194 for (Permission.Action a : actions) { 195 builder.addAction(toPermissionAction(a)); 196 } 197 } 198 ret.setTablePermission(builder); 199 } else { 200 // perm.getAccessScope() == Permission.Scope.GLOBAL 201 ret.setType(AccessControlProtos.Permission.Type.Global); 202 AccessControlProtos.GlobalPermission.Builder builder = 203 AccessControlProtos.GlobalPermission.newBuilder(); 204 Permission.Action[] actions = perm.getActions(); 205 if (actions != null) { 206 for (Permission.Action a : actions) { 207 builder.addAction(toPermissionAction(a)); 208 } 209 } 210 ret.setGlobalPermission(builder); 211 } 212 return ret.build(); 213 } 214 215 /** 216 * Convert a shaded protobuf UserTablePermissions to a ListMultimap<String, TablePermission> 217 * where key is username. 218 * @param proto the protobuf UserPermission 219 * @return the converted UserPermission 220 */ 221 public static ListMultimap<String, Permission> toUserTablePermissions( 222 AccessControlProtos.UsersAndPermissions proto) { 223 ListMultimap<String, Permission> perms = ArrayListMultimap.create(); 224 AccessControlProtos.UsersAndPermissions.UserPermissions userPerm; 225 for (int i = 0; i < proto.getUserPermissionsCount(); i++) { 226 userPerm = proto.getUserPermissions(i); 227 for (int j = 0; j < userPerm.getPermissionsCount(); j++) { 228 Permission perm = toPermission(userPerm.getPermissions(j)); 229 perms.put(userPerm.getUser().toStringUtf8(), perm); 230 } 231 } 232 return perms; 233 } 234 235 /** 236 * Convert a ListMultimap<String, TablePermission> where key is username to a shaded 237 * protobuf UserPermission 238 * @param perm the list of user and table permissions 239 * @return the protobuf UserTablePermissions 240 */ 241 public static AccessControlProtos.UsersAndPermissions 242 toUserTablePermissions(ListMultimap<String, UserPermission> perm) { 243 AccessControlProtos.UsersAndPermissions.Builder builder = 244 AccessControlProtos.UsersAndPermissions.newBuilder(); 245 for (Map.Entry<String, Collection<UserPermission>> entry : perm.asMap().entrySet()) { 246 AccessControlProtos.UsersAndPermissions.UserPermissions.Builder userPermBuilder = 247 AccessControlProtos.UsersAndPermissions.UserPermissions.newBuilder(); 248 userPermBuilder.setUser(ByteString.copyFromUtf8(entry.getKey())); 249 for (UserPermission userPerm : entry.getValue()) { 250 userPermBuilder.addPermissions(toPermission(userPerm.getPermission())); 251 } 252 builder.addUserPermissions(userPermBuilder.build()); 253 } 254 return builder.build(); 255 } 256 257 /** 258 * Converts a user permission proto to a client user permission object. 259 * @param proto the protobuf UserPermission 260 * @return the converted UserPermission 261 */ 262 public static UserPermission toUserPermission(AccessControlProtos.UserPermission proto) { 263 return new UserPermission(proto.getUser().toStringUtf8(), toPermission(proto.getPermission())); 264 } 265 266 /** 267 * Convert a client user permission to a user permission proto 268 * @param perm the client UserPermission 269 * @return the protobuf UserPermission 270 */ 271 public static AccessControlProtos.UserPermission toUserPermission(UserPermission perm) { 272 return AccessControlProtos.UserPermission.newBuilder() 273 .setUser(ByteString.copyFromUtf8(perm.getUser())) 274 .setPermission(toPermission(perm.getPermission())).build(); 275 } 276 277 public static GrantRequest buildGrantRequest(UserPermission userPermission, 278 boolean mergeExistingPermissions) { 279 return GrantRequest.newBuilder().setUserPermission(toUserPermission(userPermission)) 280 .setMergeExistingPermissions(mergeExistingPermissions).build(); 281 } 282 283 public static RevokeRequest buildRevokeRequest(UserPermission userPermission) { 284 return RevokeRequest.newBuilder().setUserPermission(toUserPermission(userPermission)).build(); 285 } 286 287 public static AccessControlProtos.GetUserPermissionsRequest 288 buildGetUserPermissionsRequest(GetUserPermissionsRequest request) { 289 AccessControlProtos.GetUserPermissionsRequest.Builder builder = 290 AccessControlProtos.GetUserPermissionsRequest.newBuilder(); 291 if (request.getUserName() != null && !request.getUserName().isEmpty()) { 292 builder.setUserName(ByteString.copyFromUtf8(request.getUserName())); 293 } 294 if (request.getNamespace() != null && !request.getNamespace().isEmpty()) { 295 builder.setNamespaceName(ByteString.copyFromUtf8(request.getNamespace())); 296 builder.setType(Type.Namespace); 297 } 298 if (request.getTableName() != null) { 299 builder.setTableName(toProtoTableName(request.getTableName())); 300 builder.setType(Type.Table); 301 } 302 if (!builder.hasType()) { 303 builder.setType(Type.Global); 304 } 305 if (request.getFamily() != null && request.getFamily().length > 0) { 306 builder.setColumnFamily(ByteString.copyFrom(request.getFamily())); 307 } 308 if (request.getQualifier() != null && request.getQualifier().length > 0) { 309 builder.setColumnQualifier(ByteString.copyFrom(request.getQualifier())); 310 } 311 return builder.build(); 312 } 313 314 public static GetUserPermissionsResponse 315 buildGetUserPermissionsResponse(final List<UserPermission> permissions) { 316 GetUserPermissionsResponse.Builder builder = GetUserPermissionsResponse.newBuilder(); 317 for (UserPermission perm : permissions) { 318 builder.addUserPermission(toUserPermission(perm)); 319 } 320 return builder.build(); 321 } 322 323 public static HasUserPermissionsRequest buildHasUserPermissionsRequest(String userName, 324 List<Permission> permissions) { 325 HasUserPermissionsRequest.Builder builder = HasUserPermissionsRequest.newBuilder(); 326 if (userName != null && !userName.isEmpty()) { 327 builder.setUserName(ByteString.copyFromUtf8(userName)); 328 } 329 for (Permission permission : permissions) { 330 builder.addPermission(toPermission(permission)); 331 } 332 return builder.build(); 333 } 334}