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