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