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.io.DataInput; 022import java.io.DataOutput; 023import java.io.IOException; 024 025import org.apache.hadoop.hbase.CellUtil; 026import org.apache.hadoop.hbase.KeyValue; 027import org.apache.hadoop.hbase.TableName; 028import org.apache.yetus.audience.InterfaceAudience; 029import org.apache.hadoop.hbase.util.Bytes; 030 031/** 032 * Represents an authorization for access for the given actions, optionally 033 * restricted to the given column family or column qualifier, over the 034 * given table. If the family property is <code>null</code>, it implies 035 * full table access. 036 */ 037@InterfaceAudience.Private 038public class TablePermission extends Permission { 039 040 private TableName table; 041 private byte[] family; 042 private byte[] qualifier; 043 044 //TODO refactor this class 045 //we need to refacting this into three classes (Global, Table, Namespace) 046 private String namespace; 047 048 /** Nullary constructor for Writable, do not use */ 049 public TablePermission() { 050 super(); 051 } 052 053 /** 054 * Create a new permission for the given table and (optionally) column family, 055 * allowing the given actions. 056 * @param table the table 057 * @param family the family, can be null if a global permission on the table 058 * @param assigned the list of allowed actions 059 */ 060 public TablePermission(TableName table, byte[] family, Action... assigned) { 061 this(table, family, null, assigned); 062 } 063 064 /** 065 * Creates a new permission for the given table, restricted to the given 066 * column family and qualifier, allowing the assigned actions to be performed. 067 * @param table the table 068 * @param family the family, can be null if a global permission on the table 069 * @param assigned the list of allowed actions 070 */ 071 public TablePermission(TableName table, byte[] family, byte[] qualifier, 072 Action... assigned) { 073 super(assigned); 074 this.table = table; 075 this.family = family; 076 this.qualifier = qualifier; 077 } 078 079 /** 080 * Creates a new permission for the given table, family and column qualifier, 081 * allowing the actions matching the provided byte codes to be performed. 082 * @param table the table 083 * @param family the family, can be null if a global permission on the table 084 * @param actionCodes the list of allowed action codes 085 */ 086 public TablePermission(TableName table, byte[] family, byte[] qualifier, 087 byte[] actionCodes) { 088 super(actionCodes); 089 this.table = table; 090 this.family = family; 091 this.qualifier = qualifier; 092 } 093 094 /** 095 * Creates a new permission for the given namespace or table, restricted to the given 096 * column family and qualifier, allowing the assigned actions to be performed. 097 * @param namespace 098 * @param table the table 099 * @param family the family, can be null if a global permission on the table 100 * @param assigned the list of allowed actions 101 */ 102 public TablePermission(String namespace, TableName table, byte[] family, byte[] qualifier, 103 Action... assigned) { 104 super(assigned); 105 this.namespace = namespace; 106 this.table = table; 107 this.family = family; 108 this.qualifier = qualifier; 109 } 110 111 /** 112 * Creates a new permission for the given namespace or table, family and column qualifier, 113 * allowing the actions matching the provided byte codes to be performed. 114 * @param namespace 115 * @param table the table 116 * @param family the family, can be null if a global permission on the table 117 * @param actionCodes the list of allowed action codes 118 */ 119 public TablePermission(String namespace, TableName table, byte[] family, byte[] qualifier, 120 byte[] actionCodes) { 121 super(actionCodes); 122 this.namespace = namespace; 123 this.table = table; 124 this.family = family; 125 this.qualifier = qualifier; 126 } 127 128 /** 129 * Creates a new permission for the given namespace, 130 * allowing the actions matching the provided byte codes to be performed. 131 * @param namespace 132 * @param actionCodes the list of allowed action codes 133 */ 134 public TablePermission(String namespace, byte[] actionCodes) { 135 super(actionCodes); 136 this.namespace = namespace; 137 } 138 139 /** 140 * Create a new permission for the given namespace, 141 * allowing the given actions. 142 * @param namespace 143 * @param assigned the list of allowed actions 144 */ 145 public TablePermission(String namespace, Action... assigned) { 146 super(assigned); 147 this.namespace = namespace; 148 } 149 150 public boolean hasTable() { 151 return table != null; 152 } 153 154 public TableName getTableName() { 155 return table; 156 } 157 158 public void setTableName(TableName table) { 159 this.table = table; 160 } 161 162 public boolean hasFamily() { 163 return family != null; 164 } 165 166 public byte[] getFamily() { 167 return family; 168 } 169 170 public boolean hasQualifier() { 171 return qualifier != null; 172 } 173 174 public byte[] getQualifier() { 175 return qualifier; 176 } 177 178 public boolean hasNamespace() { 179 return namespace != null; 180 } 181 182 public String getNamespace() { 183 return namespace; 184 } 185 186 /** 187 * Checks that a given table operation is authorized by this permission 188 * instance. 189 * 190 * @param namespace the namespace where the operation is being performed 191 * @param action the action being requested 192 * @return <code>true</code> if the action within the given scope is allowed 193 * by this permission, <code>false</code> 194 */ 195 public boolean implies(String namespace, Action action) { 196 if (this.namespace == null || !this.namespace.equals(namespace)) { 197 return false; 198 } 199 200 // check actions 201 return super.implies(action); 202 } 203 204 /** 205 * Checks that a given table operation is authorized by this permission 206 * instance. 207 * 208 * @param table the table where the operation is being performed 209 * @param family the column family to which the operation is restricted, 210 * if <code>null</code> implies "all" 211 * @param qualifier the column qualifier to which the action is restricted, 212 * if <code>null</code> implies "all" 213 * @param action the action being requested 214 * @return <code>true</code> if the action within the given scope is allowed 215 * by this permission, <code>false</code> 216 */ 217 public boolean implies(TableName table, byte[] family, byte[] qualifier, 218 Action action) { 219 if (this.table == null || !this.table.equals(table)) { 220 return false; 221 } 222 223 if (this.family != null && 224 (family == null || 225 !Bytes.equals(this.family, family))) { 226 return false; 227 } 228 229 if (this.qualifier != null && 230 (qualifier == null || 231 !Bytes.equals(this.qualifier, qualifier))) { 232 return false; 233 } 234 235 // check actions 236 return super.implies(action); 237 } 238 239 /** 240 * Checks if this permission grants access to perform the given action on 241 * the given table and key value. 242 * @param table the table on which the operation is being performed 243 * @param kv the KeyValue on which the operation is being requested 244 * @param action the action requested 245 * @return <code>true</code> if the action is allowed over the given scope 246 * by this permission, otherwise <code>false</code> 247 */ 248 public boolean implies(TableName table, KeyValue kv, Action action) { 249 if (this.table == null || !this.table.equals(table)) { 250 return false; 251 } 252 253 if (family != null && !(CellUtil.matchingFamily(kv, family))) { 254 return false; 255 } 256 257 if (qualifier != null && !(CellUtil.matchingQualifier(kv, qualifier))) { 258 return false; 259 } 260 261 // check actions 262 return super.implies(action); 263 } 264 265 /** 266 * Returns <code>true</code> if this permission matches the given column 267 * family at least. This only indicates a partial match against the table 268 * and column family, however, and does not guarantee that implies() for the 269 * column same family would return <code>true</code>. In the case of a 270 * column-qualifier specific permission, for example, implies() would still 271 * return false. 272 */ 273 public boolean matchesFamily(TableName table, byte[] family, Action action) { 274 if (this.table == null || !this.table.equals(table)) { 275 return false; 276 } 277 278 if (this.family != null && 279 (family == null || 280 !Bytes.equals(this.family, family))) { 281 return false; 282 } 283 284 // ignore qualifier 285 // check actions 286 return super.implies(action); 287 } 288 289 /** 290 * Returns if the given permission matches the given qualifier. 291 * @param table the table name to match 292 * @param family the column family to match 293 * @param qualifier the qualifier name to match 294 * @param action the action requested 295 * @return <code>true</code> if the table, family and qualifier match, 296 * otherwise <code>false</code> 297 */ 298 public boolean matchesFamilyQualifier(TableName table, byte[] family, byte[] qualifier, 299 Action action) { 300 if (!matchesFamily(table, family, action)) { 301 return false; 302 } else { 303 if (this.qualifier != null && 304 (qualifier == null || 305 !Bytes.equals(this.qualifier, qualifier))) { 306 return false; 307 } 308 } 309 return super.implies(action); 310 } 311 312 public boolean tableFieldsEqual(TablePermission other){ 313 if (!(((table == null && other.getTableName() == null) || 314 (table != null && table.equals(other.getTableName()))) && 315 ((family == null && other.getFamily() == null) || 316 Bytes.equals(family, other.getFamily())) && 317 ((qualifier == null && other.getQualifier() == null) || 318 Bytes.equals(qualifier, other.getQualifier())) && 319 ((namespace == null && other.getNamespace() == null) || 320 (namespace != null && namespace.equals(other.getNamespace()))) 321 )) { 322 return false; 323 } 324 return true; 325 } 326 327 @Override 328 @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NP_NULL_ON_SOME_PATH", 329 justification="Passed on construction except on constructor not to be used") 330 public boolean equals(Object obj) { 331 if (!(obj instanceof TablePermission)) { 332 return false; 333 } 334 TablePermission other = (TablePermission)obj; 335 336 if(!this.tableFieldsEqual(other)){ 337 return false; 338 } 339 340 // check actions 341 return super.equals(other); 342 } 343 344 @Override 345 public int hashCode() { 346 final int prime = 37; 347 int result = super.hashCode(); 348 if (table != null) { 349 result = prime * result + table.hashCode(); 350 } 351 if (family != null) { 352 result = prime * result + Bytes.hashCode(family); 353 } 354 if (qualifier != null) { 355 result = prime * result + Bytes.hashCode(qualifier); 356 } 357 if (namespace != null) { 358 result = prime * result + namespace.hashCode(); 359 } 360 return result; 361 } 362 363 @Override 364 public String toString() { 365 StringBuilder str = new StringBuilder("[TablePermission: "); 366 if(namespace != null) { 367 str.append("namespace=").append(namespace) 368 .append(", "); 369 } 370 if(table != null) { 371 str.append("table=").append(table) 372 .append(", family=") 373 .append(family == null ? null : Bytes.toString(family)) 374 .append(", qualifier=") 375 .append(qualifier == null ? null : Bytes.toString(qualifier)) 376 .append(", "); 377 } 378 if (actions != null) { 379 str.append("actions="); 380 for (int i=0; i<actions.length; i++) { 381 if (i > 0) 382 str.append(","); 383 if (actions[i] != null) 384 str.append(actions[i].toString()); 385 else 386 str.append("NULL"); 387 } 388 } 389 str.append("]"); 390 391 return str.toString(); 392 } 393 394 @Override 395 public void readFields(DataInput in) throws IOException { 396 super.readFields(in); 397 byte[] tableBytes = Bytes.readByteArray(in); 398 if(tableBytes.length > 0) { 399 table = TableName.valueOf(tableBytes); 400 } 401 if (in.readBoolean()) { 402 family = Bytes.readByteArray(in); 403 } 404 if (in.readBoolean()) { 405 qualifier = Bytes.readByteArray(in); 406 } 407 if(in.readBoolean()) { 408 namespace = Bytes.toString(Bytes.readByteArray(in)); 409 } 410 } 411 412 @Override 413 public void write(DataOutput out) throws IOException { 414 super.write(out); 415 // Explicitly writing null to maintain se/deserialize backward compatibility. 416 Bytes.writeByteArray(out, (table == null) ? null : table.getName()); 417 out.writeBoolean(family != null); 418 if (family != null) { 419 Bytes.writeByteArray(out, family); 420 } 421 out.writeBoolean(qualifier != null); 422 if (qualifier != null) { 423 Bytes.writeByteArray(out, qualifier); 424 } 425 out.writeBoolean(namespace != null); 426 if(namespace != null) { 427 Bytes.writeByteArray(out, Bytes.toBytes(namespace)); 428 } 429 } 430}