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