View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  package org.apache.hadoop.hbase.security.access;
20  
21  import org.apache.commons.logging.Log;
22  import org.apache.commons.logging.LogFactory;
23  import org.apache.hadoop.hbase.KeyValue;
24  import org.apache.hadoop.hbase.util.Bytes;
25  
26  import java.io.DataInput;
27  import java.io.DataOutput;
28  import java.io.IOException;
29  
30  /**
31   * Represents an authorization for access for the given actions, optionally
32   * restricted to the given column family or column qualifier, over the
33   * given table.  If the family property is <code>null</code>, it implies
34   * full table access.
35   */
36  public class TablePermission extends Permission {
37    private static Log LOG = LogFactory.getLog(TablePermission.class);
38  
39    private byte[] table;
40    private byte[] family;
41    private byte[] qualifier;
42  
43    /** Nullary constructor for Writable, do not use */
44    public TablePermission() {
45      super();
46    }
47  
48    /**
49     * Create a new permission for the given table and (optionally) column family,
50     * allowing the given actions.
51     * @param table the table
52     * @param family the family, can be null if a global permission on the table
53     * @param assigned the list of allowed actions
54     */
55    public TablePermission(byte[] table, byte[] family, Action... assigned) {
56      this(table, family, null, assigned);
57    }
58  
59    /**
60     * Creates a new permission for the given table, restricted to the given
61     * column family and qualifer, allowing the assigned actions to be performed.
62     * @param table the table
63     * @param family the family, can be null if a global permission on the table
64     * @param assigned the list of allowed actions
65     */
66    public TablePermission(byte[] table, byte[] family, byte[] qualifier,
67        Action... assigned) {
68      super(assigned);
69      this.table = table;
70      this.family = family;
71      this.qualifier = qualifier;
72    }
73  
74    /**
75     * Creates a new permission for the given table, family and column qualifier,
76     * allowing the actions matching the provided byte codes to be performed.
77     * @param table the table
78     * @param family the family, can be null if a global permission on the table
79     * @param actionCodes the list of allowed action codes
80     */
81    public TablePermission(byte[] table, byte[] family, byte[] qualifier,
82        byte[] actionCodes) {
83      super(actionCodes);
84      this.table = table;
85      this.family = family;
86      this.qualifier = qualifier;
87    }
88  
89    public boolean hasTable() {
90      return table != null;
91    }
92  
93    public byte[] getTable() {
94      return table;
95    }
96  
97    public boolean hasFamily() {
98      return family != null;
99    }
100 
101   public byte[] getFamily() {
102     return family;
103   }
104 
105   public boolean hasQualifier() {
106     return qualifier != null;
107   }
108 
109   public byte[] getQualifier() {
110     return qualifier;
111   }
112 
113   /**
114    * Checks that a given table operation is authorized by this permission
115    * instance.
116    *
117    * @param table the table where the operation is being performed
118    * @param family the column family to which the operation is restricted,
119    *   if <code>null</code> implies "all"
120    * @param qualifier the column qualifier to which the action is restricted,
121    *   if <code>null</code> implies "all"
122    * @param action the action being requested
123    * @return <code>true</code> if the action within the given scope is allowed
124    *   by this permission, <code>false</code>
125    */
126   public boolean implies(byte[] table, byte[] family, byte[] qualifier,
127       Action action) {
128     if (!Bytes.equals(this.table, table)) {
129       return false;
130     }
131 
132     if (this.family != null &&
133         (family == null ||
134          !Bytes.equals(this.family, family))) {
135       return false;
136     }
137 
138     if (this.qualifier != null &&
139         (qualifier == null ||
140          !Bytes.equals(this.qualifier, qualifier))) {
141       return false;
142     }
143 
144     // check actions
145     return super.implies(action);
146   }
147 
148   /**
149    * Checks if this permission grants access to perform the given action on
150    * the given table and key value.
151    * @param table the table on which the operation is being performed
152    * @param kv the KeyValue on which the operation is being requested
153    * @param action the action requested
154    * @return <code>true</code> if the action is allowed over the given scope
155    *   by this permission, otherwise <code>false</code>
156    */
157   public boolean implies(byte[] table, KeyValue kv, Action action) {
158     if (!Bytes.equals(this.table, table)) {
159       return false;
160     }
161 
162     if (family != null &&
163         (Bytes.compareTo(family, 0, family.length,
164             kv.getBuffer(), kv.getFamilyOffset(), kv.getFamilyLength()) != 0)) {
165       return false;
166     }
167 
168     if (qualifier != null &&
169         (Bytes.compareTo(qualifier, 0, qualifier.length,
170             kv.getBuffer(), kv.getQualifierOffset(), kv.getQualifierLength()) != 0)) {
171       return false;
172     }
173 
174     // check actions
175     return super.implies(action);
176   }
177 
178   /**
179    * Returns <code>true</code> if this permission matches the given column
180    * family at least.  This only indicates a partial match against the table
181    * and column family, however, and does not guarantee that implies() for the
182    * column same family would return <code>true</code>.  In the case of a
183    * column-qualifier specific permission, for example, implies() would still
184    * return false.
185    */
186   public boolean matchesFamily(byte[] table, byte[] family, Action action) {
187     if (!Bytes.equals(this.table, table)) {
188       return false;
189     }
190 
191     if (this.family != null &&
192         (family == null ||
193          !Bytes.equals(this.family, family))) {
194       return false;
195     }
196 
197     // ignore qualifier
198     // check actions
199     return super.implies(action);
200   }
201 
202   /**
203    * Returns if the given permission matches the given qualifier.
204    * @param table the table name to match
205    * @param family the column family to match
206    * @param qualifier the qualifier name to match
207    * @param action the action requested
208    * @return <code>true</code> if the table, family and qualifier match,
209    *   otherwise <code>false</code>
210    */
211   public boolean matchesFamilyQualifier(byte[] table, byte[] family, byte[] qualifier,
212                                 Action action) {
213     if (!matchesFamily(table, family, action)) {
214       return false;
215     } else {
216       if (this.qualifier != null &&
217           (qualifier == null ||
218            !Bytes.equals(this.qualifier, qualifier))) {
219         return false;
220       }
221     }
222     return super.implies(action);
223   }
224 
225   @Override
226   public boolean equals(Object obj) {
227     if (!(obj instanceof TablePermission)) {
228       return false;
229     }
230     TablePermission other = (TablePermission)obj;
231 
232     if (!(Bytes.equals(table, other.getTable()) &&
233         ((family == null && other.getFamily() == null) ||
234          Bytes.equals(family, other.getFamily())) &&
235         ((qualifier == null && other.getQualifier() == null) ||
236          Bytes.equals(qualifier, other.getQualifier()))
237        )) {
238       return false;
239     }
240 
241     // check actions
242     return super.equals(other);
243   }
244 
245   @Override
246   public int hashCode() {
247     final int prime = 37;
248     int result = super.hashCode();
249     if (table != null) {
250       result = prime * result + Bytes.hashCode(table);
251     }
252     if (family != null) {
253       result = prime * result + Bytes.hashCode(family);
254     }
255     if (qualifier != null) {
256       result = prime * result + Bytes.hashCode(qualifier);
257     }
258     return result;
259   }
260 
261   public String toString() {
262     StringBuilder str = new StringBuilder("[TablePermission: ")
263         .append("table=").append(Bytes.toString(table))
264         .append(", family=").append(Bytes.toString(family))
265         .append(", qualifier=").append(Bytes.toString(qualifier))
266         .append(", actions=");
267     if (actions != null) {
268       for (int i=0; i<actions.length; i++) {
269         if (i > 0)
270           str.append(",");
271         if (actions[i] != null)
272           str.append(actions[i].toString());
273         else
274           str.append("NULL");
275       }
276     }
277     str.append("]");
278 
279     return str.toString();
280   }
281 
282   @Override
283   public void readFields(DataInput in) throws IOException {
284     super.readFields(in);
285     table = Bytes.readByteArray(in);
286     if (in.readBoolean()) {
287       family = Bytes.readByteArray(in);
288     }
289     if (in.readBoolean()) {
290       qualifier = Bytes.readByteArray(in);
291     }
292   }
293 
294   @Override
295   public void write(DataOutput out) throws IOException {
296     super.write(out);
297     Bytes.writeByteArray(out, table);
298     out.writeBoolean(family != null);
299     if (family != null) {
300       Bytes.writeByteArray(out, family);
301     }
302     out.writeBoolean(qualifier != null);
303     if (qualifier != null) {
304       Bytes.writeByteArray(out, qualifier);
305     }
306   }
307 }