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.io.DataInput; 021import java.io.DataOutput; 022import java.io.IOException; 023import org.apache.hadoop.hbase.CellUtil; 024import org.apache.hadoop.hbase.KeyValue; 025import org.apache.hadoop.hbase.TableName; 026import org.apache.hadoop.hbase.util.Bytes; 027import org.apache.yetus.audience.InterfaceAudience; 028 029/** 030 * Represents an authorization for access for the given actions, optionally restricted to the given 031 * column family or column qualifier, over the given table. If the family property is 032 * <code>null</code>, it implies full table access. 033 */ 034@InterfaceAudience.Public 035public class TablePermission extends Permission { 036 037 private TableName table; 038 private byte[] family; 039 private byte[] qualifier; 040 041 /** 042 * Construct a table:family:qualifier permission. 043 * @param table table name 044 * @param family family name 045 * @param qualifier qualifier name 046 * @param assigned assigned actions 047 */ 048 TablePermission(TableName table, byte[] family, byte[] qualifier, Action... assigned) { 049 super(assigned); 050 this.table = table; 051 this.family = family; 052 this.qualifier = qualifier; 053 this.scope = Scope.TABLE; 054 } 055 056 public TableName getTableName() { 057 return table; 058 } 059 060 public boolean hasFamily() { 061 return family != null; 062 } 063 064 public byte[] getFamily() { 065 return family; 066 } 067 068 public boolean hasQualifier() { 069 return qualifier != null; 070 } 071 072 public byte[] getQualifier() { 073 return qualifier; 074 } 075 076 public String getNamespace() { 077 return table.getNamespaceAsString(); 078 } 079 080 /** 081 * Check if given action can performs on given table:family:qualifier. 082 * @param table table name 083 * @param family family name 084 * @param qualifier qualifier name 085 * @param action one of [Read, Write, Create, Exec, Admin] 086 * @return true if can, false otherwise 087 */ 088 public boolean implies(TableName table, byte[] family, byte[] qualifier, Action action) { 089 if (failCheckTable(table)) { 090 return false; 091 } 092 if (failCheckFamily(family)) { 093 return false; 094 } 095 if (failCheckQualifier(qualifier)) { 096 return false; 097 } 098 return implies(action); 099 } 100 101 /** 102 * Check if given action can performs on given table:family. 103 * @param table table name 104 * @param family family name 105 * @param action one of [Read, Write, Create, Exec, Admin] 106 * @return true if can, false otherwise 107 */ 108 public boolean implies(TableName table, byte[] family, Action action) { 109 if (failCheckTable(table)) { 110 return false; 111 } 112 if (failCheckFamily(family)) { 113 return false; 114 } 115 return implies(action); 116 } 117 118 private boolean failCheckTable(TableName table) { 119 return this.table == null || !this.table.equals(table); 120 } 121 122 private boolean failCheckFamily(byte[] family) { 123 return this.family != null && (family == null || !Bytes.equals(this.family, family)); 124 } 125 126 private boolean failCheckQualifier(byte[] qual) { 127 return this.qualifier != null && (qual == null || !Bytes.equals(this.qualifier, qual)); 128 } 129 130 /** 131 * Checks if this permission grants access to perform the given action on the given table and key 132 * value. 133 * @param table the table on which the operation is being performed 134 * @param kv the KeyValue on which the operation is being requested 135 * @param action the action requested 136 * @return <code>true</code> if the action is allowed over the given scope by this permission, 137 * otherwise <code>false</code> 138 */ 139 public boolean implies(TableName table, KeyValue kv, Action action) { 140 if (failCheckTable(table)) { 141 return false; 142 } 143 144 if (family != null && !CellUtil.matchingFamily(kv, family)) { 145 return false; 146 } 147 148 if (qualifier != null && !CellUtil.matchingQualifier(kv, qualifier)) { 149 return false; 150 } 151 152 // check actions 153 return super.implies(action); 154 } 155 156 /** 157 * Check if fields of table in table permission equals. 158 * @param tp to be checked table permission 159 * @return true if equals, false otherwise 160 */ 161 public boolean tableFieldsEqual(TablePermission tp) { 162 if (tp == null) { 163 return false; 164 } 165 166 boolean tEq = (table == null && tp.table == null) || (table != null && table.equals(tp.table)); 167 boolean fEq = (family == null && tp.family == null) || Bytes.equals(family, tp.family); 168 boolean qEq = 169 (qualifier == null && tp.qualifier == null) || Bytes.equals(qualifier, tp.qualifier); 170 return tEq && fEq && qEq; 171 } 172 173 @Override 174 public boolean equalsExceptActions(Object obj) { 175 if (!(obj instanceof TablePermission)) { 176 return false; 177 } 178 TablePermission other = (TablePermission) obj; 179 return tableFieldsEqual(other); 180 } 181 182 @Override 183 public boolean equals(Object obj) { 184 return equalsExceptActions(obj) && super.equals(obj); 185 } 186 187 @Override 188 public int hashCode() { 189 final int prime = 37; 190 int result = super.hashCode(); 191 if (table != null) { 192 result = prime * result + table.hashCode(); 193 } 194 if (family != null) { 195 result = prime * result + Bytes.hashCode(family); 196 } 197 if (qualifier != null) { 198 result = prime * result + Bytes.hashCode(qualifier); 199 } 200 return result; 201 } 202 203 @Override 204 public String toString() { 205 return "[TablePermission: " + rawExpression() + "]"; 206 } 207 208 @Override 209 protected String rawExpression() { 210 StringBuilder raw = new StringBuilder(); 211 if (table != null) { 212 raw.append("table=").append(table).append(", family=") 213 .append(family == null ? null : Bytes.toString(family)).append(", qualifier=") 214 .append(qualifier == null ? null : Bytes.toString(qualifier)).append(", "); 215 } 216 return raw.toString() + super.rawExpression(); 217 } 218 219 @Override 220 public void readFields(DataInput in) throws IOException { 221 super.readFields(in); 222 byte[] tableBytes = Bytes.readByteArray(in); 223 if (tableBytes.length > 0) { 224 table = TableName.valueOf(tableBytes); 225 } 226 if (in.readBoolean()) { 227 family = Bytes.readByteArray(in); 228 } 229 if (in.readBoolean()) { 230 qualifier = Bytes.readByteArray(in); 231 } 232 } 233 234 @Override 235 public void write(DataOutput out) throws IOException { 236 super.write(out); 237 // Explicitly writing null to maintain se/deserialize backward compatibility. 238 Bytes.writeByteArray(out, table == null ? null : table.getName()); 239 out.writeBoolean(family != null); 240 if (family != null) { 241 Bytes.writeByteArray(out, family); 242 } 243 out.writeBoolean(qualifier != null); 244 if (qualifier != null) { 245 Bytes.writeByteArray(out, qualifier); 246 } 247 } 248}