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