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