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 byte[] getTable() {
90      return table;
91    }
92  
93    public byte[] getFamily() {
94      return family;
95    }
96  
97    public byte[] getQualifier() {
98      return qualifier;
99    }
100 
101   /**
102    * Checks that a given table operation is authorized by this permission
103    * instance.
104    *
105    * @param table the table where the operation is being performed
106    * @param family the column family to which the operation is restricted,
107    *   if <code>null</code> implies "all"
108    * @param qualifier the column qualifier to which the action is restricted,
109    *   if <code>null</code> implies "all"
110    * @param action the action being requested
111    * @return <code>true</code> if the action within the given scope is allowed
112    *   by this permission, <code>false</code>
113    */
114   public boolean implies(byte[] table, byte[] family, byte[] qualifier,
115       Action action) {
116     if (!Bytes.equals(this.table, table)) {
117       return false;
118     }
119 
120     if (this.family != null &&
121         (family == null ||
122          !Bytes.equals(this.family, family))) {
123       return false;
124     }
125 
126     if (this.qualifier != null &&
127         (qualifier == null ||
128          !Bytes.equals(this.qualifier, qualifier))) {
129       return false;
130     }
131 
132     // check actions
133     return super.implies(action);
134   }
135 
136   /**
137    * Checks if this permission grants access to perform the given action on
138    * the given table and key value.
139    * @param table the table on which the operation is being performed
140    * @param kv the KeyValue on which the operation is being requested
141    * @param action the action requested
142    * @return <code>true</code> if the action is allowed over the given scope
143    *   by this permission, otherwise <code>false</code>
144    */
145   public boolean implies(byte[] table, KeyValue kv, Action action) {
146     if (!Bytes.equals(this.table, table)) {
147       return false;
148     }
149 
150     if (family != null &&
151         (Bytes.compareTo(family, 0, family.length,
152             kv.getBuffer(), kv.getFamilyOffset(), kv.getFamilyLength()) != 0)) {
153       return false;
154     }
155 
156     if (qualifier != null &&
157         (Bytes.compareTo(qualifier, 0, qualifier.length,
158             kv.getBuffer(), kv.getQualifierOffset(), kv.getQualifierLength()) != 0)) {
159       return false;
160     }
161 
162     // check actions
163     return super.implies(action);
164   }
165 
166   /**
167    * Returns <code>true</code> if this permission matches the given column
168    * family at least.  This only indicates a partial match against the table
169    * and column family, however, and does not guarantee that implies() for the
170    * column same family would return <code>true</code>.  In the case of a
171    * column-qualifier specific permission, for example, implies() would still
172    * return false.
173    */
174   public boolean matchesFamily(byte[] table, byte[] family, Action action) {
175     if (!Bytes.equals(this.table, table)) {
176       return false;
177     }
178 
179     if (this.family != null &&
180         (family == null ||
181          !Bytes.equals(this.family, family))) {
182       return false;
183     }
184 
185     // ignore qualifier
186     // check actions
187     return super.implies(action);
188   }
189 
190   /**
191    * Returns if the given permission matches the given qualifier.
192    * @param table the table name to match
193    * @param family the column family to match
194    * @param qualifier the qualifier name to match
195    * @param action the action requested
196    * @return <code>true</code> if the table, family and qualifier match,
197    *   otherwise <code>false</code>
198    */
199   public boolean matchesFamilyQualifier(byte[] table, byte[] family, byte[] qualifier,
200                                 Action action) {
201     if (!matchesFamily(table, family, action)) {
202       return false;
203     } else {
204       if (this.qualifier != null &&
205           (qualifier == null ||
206            !Bytes.equals(this.qualifier, qualifier))) {
207         return false;
208       }
209     }
210     return super.implies(action);
211   }
212 
213   @Override
214   public boolean equals(Object obj) {
215     if (!(obj instanceof TablePermission)) {
216       return false;
217     }
218     TablePermission other = (TablePermission)obj;
219 
220     if (!(Bytes.equals(table, other.getTable()) &&
221         ((family == null && other.getFamily() == null) ||
222          Bytes.equals(family, other.getFamily())) &&
223         ((qualifier == null && other.getQualifier() == null) ||
224          Bytes.equals(qualifier, other.getQualifier()))
225        )) {
226       return false;
227     }
228 
229     // check actions
230     return super.equals(other);
231   }
232 
233   @Override
234   public int hashCode() {
235     final int prime = 37;
236     int result = super.hashCode();
237     if (table != null) {
238       result = prime * result + Bytes.hashCode(table);
239     }
240     if (family != null) {
241       result = prime * result + Bytes.hashCode(family);
242     }
243     if (qualifier != null) {
244       result = prime * result + Bytes.hashCode(qualifier);
245     }
246     return result;
247   }
248 
249   public String toString() {
250     StringBuilder str = new StringBuilder("[TablePermission: ")
251         .append("table=").append(Bytes.toString(table))
252         .append(", family=").append(Bytes.toString(family))
253         .append(", qualifier=").append(Bytes.toString(qualifier))
254         .append(", actions=");
255     if (actions != null) {
256       for (int i=0; i<actions.length; i++) {
257         if (i > 0)
258           str.append(",");
259         if (actions[i] != null)
260           str.append(actions[i].toString());
261         else
262           str.append("NULL");
263       }
264     }
265     str.append("]");
266 
267     return str.toString();
268   }
269 
270   @Override
271   public void readFields(DataInput in) throws IOException {
272     super.readFields(in);
273     table = Bytes.readByteArray(in);
274     if (in.readBoolean()) {
275       family = Bytes.readByteArray(in);
276     }
277     if (in.readBoolean()) {
278       qualifier = Bytes.readByteArray(in);
279     }
280   }
281 
282   @Override
283   public void write(DataOutput out) throws IOException {
284     super.write(out);
285     Bytes.writeByteArray(out, table);
286     out.writeBoolean(family != null);
287     if (family != null) {
288       Bytes.writeByteArray(out, family);
289     }
290     out.writeBoolean(qualifier != null);
291     if (qualifier != null) {
292       Bytes.writeByteArray(out, qualifier);
293     }
294   }
295 }