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.Map;
24  import java.util.regex.Pattern;
25  
26  import org.apache.hadoop.classification.InterfaceAudience;
27  import org.apache.hadoop.classification.InterfaceStability;
28  import org.apache.hadoop.conf.Configuration;
29  import org.apache.hadoop.hbase.HConstants;
30  import org.apache.hadoop.hbase.HTableDescriptor;
31  import org.apache.hadoop.hbase.MasterNotRunningException;
32  import org.apache.hadoop.hbase.NamespaceDescriptor;
33  import org.apache.hadoop.hbase.TableName;
34  import org.apache.hadoop.hbase.ZooKeeperConnectionException;
35  import org.apache.hadoop.hbase.client.Admin;
36  import org.apache.hadoop.hbase.client.HBaseAdmin;
37  import org.apache.hadoop.hbase.client.HTable;
38  import org.apache.hadoop.hbase.client.Table;
39  import org.apache.hadoop.hbase.client.coprocessor.Batch;
40  import org.apache.hadoop.hbase.ipc.BlockingRpcCallback;
41  import org.apache.hadoop.hbase.ipc.CoprocessorRpcChannel;
42  import org.apache.hadoop.hbase.ipc.ServerRpcController;
43  import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
44  import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos;
45  import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.AccessControlService;
46  import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.AccessControlService.BlockingInterface;
47  import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.GrantRequest;
48  import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.GrantResponse;
49  import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.RevokeRequest;
50  import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.RevokeResponse;
51  import org.apache.hadoop.hbase.util.ByteStringer;
52  
53  import com.google.protobuf.ByteString;
54  
55  /**
56   * Utility client for doing access control admin operations.
57   */
58  @InterfaceAudience.Public
59  @InterfaceStability.Evolving
60  public class AccessControlClient {
61    /**
62     * Grants permission on the specified table for the specified user
63     * @param conf
64     * @param tableName
65     * @param userName
66     * @param family
67     * @param qual
68     * @param actions
69     * @return GrantResponse
70     * @throws Throwable
71     */
72    public static GrantResponse grant(Configuration conf, final TableName tableName,
73        final String userName, final byte[] family, final byte[] qual,
74        final AccessControlProtos.Permission.Action... actions) throws Throwable {
75      Table ht = null;
76      try {
77        TableName aclTableName =
78            TableName.valueOf(NamespaceDescriptor.SYSTEM_NAMESPACE_NAME_STR, "acl");
79        ht = new HTable(conf, aclTableName.getName());
80        Batch.Call<AccessControlService, GrantResponse> callable =
81            new Batch.Call<AccessControlService, GrantResponse>() {
82          ServerRpcController controller = new ServerRpcController();
83          BlockingRpcCallback<GrantResponse> rpcCallback =
84              new BlockingRpcCallback<GrantResponse>();
85  
86          @Override
87          public GrantResponse call(AccessControlService service) throws IOException {
88            GrantRequest.Builder builder = GrantRequest.newBuilder();
89            AccessControlProtos.Permission.Builder ret =
90                AccessControlProtos.Permission.newBuilder();
91            AccessControlProtos.TablePermission.Builder permissionBuilder =
92                AccessControlProtos.TablePermission
93                .newBuilder();
94            for (AccessControlProtos.Permission.Action a : actions) {
95              permissionBuilder.addAction(a);
96            }
97            permissionBuilder.setTableName(ProtobufUtil.toProtoTableName(tableName));
98  
99            if (family != null) {
100             permissionBuilder.setFamily(ByteStringer.wrap(family));
101           }
102           if (qual != null) {
103             permissionBuilder.setQualifier(ByteStringer.wrap(qual));
104           }
105           ret.setType(AccessControlProtos.Permission.Type.Table).setTablePermission(
106               permissionBuilder);
107           builder.setUserPermission(AccessControlProtos.UserPermission.newBuilder()
108               .setUser(ByteString.copyFromUtf8(userName)).setPermission(ret));
109           service.grant(controller, builder.build(), rpcCallback);
110           return rpcCallback.get();
111         }
112       };
113       Map<byte[], GrantResponse> result = ht.coprocessorService(AccessControlService.class,
114           HConstants.EMPTY_BYTE_ARRAY, HConstants.EMPTY_BYTE_ARRAY, callable);
115       return result.values().iterator().next(); // There will be exactly one
116                                                 // region for labels
117                                                 // table and so one entry in
118                                                 // result Map.
119     } finally {
120       if (ht != null) {
121         ht.close();
122       }
123     }
124   }
125 
126   public static boolean isAccessControllerRunning(Configuration conf)
127       throws MasterNotRunningException, ZooKeeperConnectionException, IOException {
128     TableName aclTableName = TableName
129         .valueOf(NamespaceDescriptor.SYSTEM_NAMESPACE_NAME_STR, "acl");
130     HBaseAdmin ha = null;
131     try {
132       ha = new HBaseAdmin(conf);
133       return ha.isTableAvailable(aclTableName.getNameAsString());
134     } finally {
135       if (ha != null) {
136         ha.close();
137       }
138     }
139   }
140 
141   /**
142    * Revokes the permission on the table
143    * @param conf
144    * @param username
145    * @param tableName
146    * @param family
147    * @param qualifier
148    * @param actions
149    * @return RevokeResponse
150    * @throws Throwable
151    */
152   public static RevokeResponse revoke(Configuration conf, final String username,
153       final TableName tableName, final byte[] family, final byte[] qualifier,
154       final AccessControlProtos.Permission.Action... actions) throws Throwable {
155     Table ht = null;
156     try {
157       TableName aclTableName = TableName.valueOf(NamespaceDescriptor.SYSTEM_NAMESPACE_NAME_STR,
158           "acl");
159       ht = new HTable(conf, aclTableName.getName());
160       Batch.Call<AccessControlService, AccessControlProtos.RevokeResponse> callable =
161           new Batch.Call<AccessControlService, AccessControlProtos.RevokeResponse>() {
162         ServerRpcController controller = new ServerRpcController();
163         BlockingRpcCallback<AccessControlProtos.RevokeResponse> rpcCallback =
164             new BlockingRpcCallback<AccessControlProtos.RevokeResponse>();
165 
166         @Override
167         public RevokeResponse call(AccessControlService service) throws IOException {
168           AccessControlProtos.Permission.Builder ret =
169               AccessControlProtos.Permission.newBuilder();
170           AccessControlProtos.TablePermission.Builder permissionBuilder =
171               AccessControlProtos.TablePermission.newBuilder();
172           for (AccessControlProtos.Permission.Action a : actions) {
173             permissionBuilder.addAction(a);
174           }
175           if (tableName != null) {
176             permissionBuilder.setTableName(ProtobufUtil.toProtoTableName(tableName));
177           }
178           if (family != null) {
179             permissionBuilder.setFamily(ByteStringer.wrap(family));
180           }
181           if (qualifier != null) {
182             permissionBuilder.setQualifier(ByteStringer.wrap(qualifier));
183           }
184           ret.setType(AccessControlProtos.Permission.Type.Table).setTablePermission(
185               permissionBuilder);
186           RevokeRequest builder = AccessControlProtos.RevokeRequest
187               .newBuilder()
188               .setUserPermission(
189                   AccessControlProtos.UserPermission.newBuilder()
190                       .setUser(ByteString.copyFromUtf8(username)).setPermission(ret)).build();
191           service.revoke(controller, builder, rpcCallback);
192           return rpcCallback.get();
193         }
194       };
195       Map<byte[], RevokeResponse> result = ht.coprocessorService(AccessControlService.class,
196           HConstants.EMPTY_BYTE_ARRAY, HConstants.EMPTY_BYTE_ARRAY, callable);
197       return result.values().iterator().next();
198 
199     } finally {
200       if (ht != null) {
201         ht.close();
202       }
203     }
204   }
205 
206   /**
207    * List all the userPermissions matching the given pattern.
208    * @param conf
209    * @param tableRegex The regular expression string to match against
210    * @return - returns an array of UserPermissions
211    * @throws Throwable
212    */
213   public static List<UserPermission> getUserPermissions(Configuration conf, String tableRegex)
214       throws Throwable {
215     List<UserPermission> permList = new ArrayList<UserPermission>();
216     Table ht = null;
217     Admin ha = null;
218     try {
219       TableName aclTableName =
220           TableName.valueOf(NamespaceDescriptor.SYSTEM_NAMESPACE_NAME_STR, "acl");
221       ha = new HBaseAdmin(conf);
222       ht = new HTable(conf, aclTableName.getName());
223       CoprocessorRpcChannel service = ht.coprocessorService(HConstants.EMPTY_START_ROW);
224       BlockingInterface protocol =
225           AccessControlProtos.AccessControlService.newBlockingStub(service);
226       HTableDescriptor[] htds = null;
227       
228       if (tableRegex != null) {
229         htds = ha.listTables(Pattern.compile(tableRegex));
230         for (HTableDescriptor hd: htds) {
231           permList.addAll(ProtobufUtil.getUserPermissions(protocol, hd.getTableName()));
232         }
233       } else {
234         permList = ProtobufUtil.getUserPermissions(protocol);
235       }
236     } finally {
237       if (ht != null) {
238         ht.close();
239       }
240       if (ha != null) {
241         ha.close();
242       }
243     }
244     return permList;
245   }
246 
247 }