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  package org.apache.hadoop.hbase.security.access;
19  
20  import java.io.IOException;
21  import java.util.ArrayList;
22  import java.util.List;
23  import java.util.regex.Pattern;
24  
25  import org.apache.hadoop.conf.Configuration;
26  import org.apache.hadoop.hbase.HConstants;
27  import org.apache.hadoop.hbase.HTableDescriptor;
28  import org.apache.hadoop.hbase.MasterNotRunningException;
29  import org.apache.hadoop.hbase.NamespaceDescriptor;
30  import org.apache.hadoop.hbase.TableName;
31  import org.apache.hadoop.hbase.ZooKeeperConnectionException;
32  import org.apache.hadoop.hbase.classification.InterfaceAudience;
33  import org.apache.hadoop.hbase.classification.InterfaceStability;
34  import org.apache.hadoop.hbase.client.Admin;
35  import org.apache.hadoop.hbase.client.ClusterConnection;
36  import org.apache.hadoop.hbase.client.Connection;
37  import org.apache.hadoop.hbase.client.ConnectionFactory;
38  import org.apache.hadoop.hbase.client.Table;
39  import org.apache.hadoop.hbase.ipc.CoprocessorRpcChannel;
40  import org.apache.hadoop.hbase.ipc.PayloadCarryingRpcController;
41  import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
42  import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos;
43  import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.AccessControlService.BlockingInterface;
44  import org.apache.hadoop.hbase.util.Bytes;
45  
46  /**
47   * Utility client for doing access control admin operations.
48   */
49  @InterfaceAudience.Public
50  @InterfaceStability.Evolving
51  public class AccessControlClient {
52    public static final TableName ACL_TABLE_NAME =
53        TableName.valueOf(NamespaceDescriptor.SYSTEM_NAMESPACE_NAME_STR, "acl");
54  
55    private static BlockingInterface getAccessControlServiceStub(Table ht)
56        throws IOException {
57      CoprocessorRpcChannel service = ht.coprocessorService(HConstants.EMPTY_START_ROW);
58      BlockingInterface protocol =
59          AccessControlProtos.AccessControlService.newBlockingStub(service);
60      return protocol;
61    }
62  
63    /**
64     * Grants permission on the specified table for the specified user
65     * @param connection The Connection instance to use
66     * @param tableName
67     * @param userName
68     * @param family
69     * @param qual
70     * @param actions
71     * @throws Throwable
72     */
73    public static void grant(final Connection connection, final TableName tableName,
74        final String userName, final byte[] family, final byte[] qual,
75        final Permission.Action... actions) throws Throwable {
76      PayloadCarryingRpcController controller
77        = ((ClusterConnection) connection).getRpcControllerFactory().newController();
78      controller.setPriority(tableName);
79      try (Table table = connection.getTable(ACL_TABLE_NAME)) {
80        ProtobufUtil.grant(controller, getAccessControlServiceStub(table), userName, tableName,
81          family, qual, actions);
82      }
83    }
84  
85    /**
86     * Grants permission on the specified namespace for the specified user.
87     * @param connection The Connection instance to use
88     * @param namespace
89     * @param userName
90     * @param actions
91     * @throws Throwable
92     */
93    public static void grant(final Connection connection, final String namespace,
94        final String userName, final Permission.Action... actions) throws Throwable {
95      PayloadCarryingRpcController controller
96        = ((ClusterConnection) connection).getRpcControllerFactory().newController();
97  
98      try (Table table = connection.getTable(ACL_TABLE_NAME)) {
99        ProtobufUtil.grant(controller, getAccessControlServiceStub(table), userName, namespace,
100         actions);
101     }
102   }
103 
104   /**
105    * @param connection The Connection instance to use
106    * Grant global permissions for the specified user.
107    */
108   public static void grant(final Connection connection, final String userName,
109        final Permission.Action... actions) throws Throwable {
110     PayloadCarryingRpcController controller
111       = ((ClusterConnection) connection).getRpcControllerFactory().newController();
112     try (Table table = connection.getTable(ACL_TABLE_NAME)) {
113       ProtobufUtil.grant(controller, getAccessControlServiceStub(table), userName, actions);
114     }
115   }
116 
117   public static boolean isAccessControllerRunning(final Connection connection)
118       throws MasterNotRunningException, ZooKeeperConnectionException, IOException {
119     try (Admin admin = connection.getAdmin()) {
120       return admin.isTableAvailable(ACL_TABLE_NAME);
121     }
122   }
123 
124   /**
125    * Revokes the permission on the table
126    * @param connection The Connection instance to use
127    * @param tableName
128    * @param username
129    * @param family
130    * @param qualifier
131    * @param actions
132    * @throws Throwable
133    */
134   public static void revoke(final Connection connection, final TableName tableName,
135       final String username, final byte[] family, final byte[] qualifier,
136       final Permission.Action... actions) throws Throwable {
137     PayloadCarryingRpcController controller
138       = ((ClusterConnection) connection).getRpcControllerFactory().newController();
139     controller.setPriority(tableName);
140     try (Table table = connection.getTable(ACL_TABLE_NAME)) {
141       ProtobufUtil.revoke(controller, getAccessControlServiceStub(table), username, tableName,
142         family, qualifier, actions);
143     }
144   }
145 
146   /**
147    * Revokes the permission on the table for the specified user.
148    * @param connection The Connection instance to use
149    * @param namespace
150    * @param userName
151    * @param actions
152    * @throws Throwable
153    */
154   public static void revoke(final Connection connection, final String namespace,
155       final String userName, final Permission.Action... actions) throws Throwable {
156     PayloadCarryingRpcController controller
157       = ((ClusterConnection) connection).getRpcControllerFactory().newController();
158     try (Table table = connection.getTable(ACL_TABLE_NAME)) {
159       ProtobufUtil.revoke(controller, getAccessControlServiceStub(table), userName, namespace,
160         actions);
161     }
162   }
163 
164   /**
165    * Revoke global permissions for the specified user.
166    * @param connection The Connection instance to use
167    */
168   public static void revoke(final Connection connection, final String userName,
169       final Permission.Action... actions) throws Throwable {
170     PayloadCarryingRpcController controller
171       = ((ClusterConnection) connection).getRpcControllerFactory().newController();
172     try (Table table = connection.getTable(ACL_TABLE_NAME)) {
173       ProtobufUtil.revoke(controller, getAccessControlServiceStub(table), userName, actions);
174     }
175   }
176 
177   /**
178    * List all the userPermissions matching the given pattern.
179    * @param connection The Connection instance to use
180    * @param tableRegex The regular expression string to match against
181    * @return - returns an array of UserPermissions
182    * @throws Throwable
183    */
184   public static List<UserPermission> getUserPermissions(Connection connection, String tableRegex)
185       throws Throwable {
186     PayloadCarryingRpcController controller
187       = ((ClusterConnection) connection).getRpcControllerFactory().newController();
188     List<UserPermission> permList = new ArrayList<UserPermission>();
189     try (Table table = connection.getTable(ACL_TABLE_NAME)) {
190       try (Admin admin = connection.getAdmin()) {
191         CoprocessorRpcChannel service = table.coprocessorService(HConstants.EMPTY_START_ROW);
192         BlockingInterface protocol =
193             AccessControlProtos.AccessControlService.newBlockingStub(service);
194         HTableDescriptor[] htds = null;
195         if (tableRegex == null || tableRegex.isEmpty()) {
196           permList = ProtobufUtil.getUserPermissions(controller, protocol);
197         } else if (tableRegex.charAt(0) == '@') {
198           String namespace = tableRegex.substring(1);
199           permList = ProtobufUtil.getUserPermissions(controller, protocol,
200             Bytes.toBytes(namespace));
201         } else {
202           htds = admin.listTables(Pattern.compile(tableRegex), true);
203           for (HTableDescriptor hd : htds) {
204             permList.addAll(ProtobufUtil.getUserPermissions(controller, protocol,
205               hd.getTableName()));
206           }
207         }
208       }
209     }
210     return permList;
211   }
212 
213   /**
214    * Grants permission on the specified table for the specified user
215    * @param conf
216    * @param tableName
217    * @param userName
218    * @param family
219    * @param qual
220    * @param actions
221    * @throws Throwable
222    * @deprecated Use {@link #grant(Connection, TableName, String, byte[], byte[],
223    * Permission.Action...)} instead.
224    */
225   @Deprecated
226   public static void grant(Configuration conf, final TableName tableName,
227       final String userName, final byte[] family, final byte[] qual,
228       final Permission.Action... actions) throws Throwable {
229     try (Connection connection = ConnectionFactory.createConnection(conf)) {
230       grant(connection, tableName, userName, family, qual, actions);
231     }
232   }
233 
234   /**
235    * Grants permission on the specified namespace for the specified user.
236    * @param conf
237    * @param namespace
238    * @param userName
239    * @param actions
240    * @throws Throwable
241    * @deprecated Use {@link #grant(Connection, String, String, Permission.Action...)}
242    * instead.
243    */
244   @Deprecated
245   public static void grant(Configuration conf, final String namespace,
246       final String userName, final Permission.Action... actions) throws Throwable {
247     try (Connection connection = ConnectionFactory.createConnection(conf)) {
248       grant(connection, namespace, userName, actions);
249     }
250   }
251 
252   /**
253    * Grant global permissions for the specified user.
254    * @deprecated Use {@link #grant(Connection, String, Permission.Action...)} instead.
255    */
256   @Deprecated
257   public static void grant(Configuration conf, final String userName,
258       final Permission.Action... actions) throws Throwable {
259     try (Connection connection = ConnectionFactory.createConnection(conf)) {
260       grant(connection, userName, actions);
261     }
262   }
263 
264   /**
265    * @deprecated Use {@link #isAccessControllerRunning(Connection)} instead.
266    */
267   @Deprecated
268   public static boolean isAccessControllerRunning(Configuration conf)
269       throws MasterNotRunningException, ZooKeeperConnectionException, IOException {
270     try (Connection connection = ConnectionFactory.createConnection(conf)) {
271       return isAccessControllerRunning(connection);
272     }
273   }
274 
275   /**
276    * Revokes the permission on the table
277    * @param conf
278    * @param tableName
279    * @param username
280    * @param family
281    * @param qualifier
282    * @param actions
283    * @throws Throwable
284    * @deprecated Use {@link #revoke(Connection, TableName, String, byte[], byte[],
285    * Permission.Action...)} instead.
286    */
287   @Deprecated
288   public static void revoke(Configuration conf, final TableName tableName,
289       final String username, final byte[] family, final byte[] qualifier,
290       final Permission.Action... actions) throws Throwable {
291     try (Connection connection = ConnectionFactory.createConnection(conf)) {
292       revoke(connection, tableName, username, family, qualifier, actions);
293     }
294   }
295 
296   /**
297    * Revokes the permission on the table for the specified user.
298    * @param conf
299    * @param namespace
300    * @param userName
301    * @param actions
302    * @throws Throwable
303    * @deprecated Use {@link #revoke(Connection, String, String, Permission.Action...)} instead.
304    */
305   @Deprecated
306   public static void revoke(Configuration conf, final String namespace,
307       final String userName, final Permission.Action... actions) throws Throwable {
308     try (Connection connection = ConnectionFactory.createConnection(conf)) {
309       revoke(connection, namespace, userName, actions);
310     }
311   }
312 
313   /**
314    * Revoke global permissions for the specified user.
315    * @deprecated Use {@link #revoke(Connection, String, Permission.Action...)} instead.
316    */
317   @Deprecated
318   public static void revoke(Configuration conf, final String userName,
319       final Permission.Action... actions) throws Throwable {
320     try (Connection connection = ConnectionFactory.createConnection(conf)) {
321       revoke(connection, userName, actions);
322     }
323   }
324 
325   /**
326    * List all the userPermissions matching the given pattern.
327    * @param conf
328    * @param tableRegex The regular expression string to match against
329    * @return - returns an array of UserPermissions
330    * @throws Throwable
331    * @deprecated Use {@link #getUserPermissions(Connection, String)} instead.
332    */
333   @Deprecated
334   public static List<UserPermission> getUserPermissions(Configuration conf, String tableRegex)
335   throws Throwable {
336     try (Connection connection = ConnectionFactory.createConnection(conf)) {
337       return getUserPermissions(connection, tableRegex);
338     }
339   }
340 }