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.hbase.HConstants;
26  import org.apache.hadoop.hbase.HTableDescriptor;
27  import org.apache.hadoop.hbase.MasterNotRunningException;
28  import org.apache.hadoop.hbase.NamespaceDescriptor;
29  import org.apache.hadoop.hbase.TableName;
30  import org.apache.hadoop.hbase.ZooKeeperConnectionException;
31  import org.apache.hadoop.hbase.classification.InterfaceAudience;
32  import org.apache.hadoop.hbase.classification.InterfaceStability;
33  import org.apache.hadoop.hbase.client.Admin;
34  import org.apache.hadoop.hbase.client.Connection;
35  import org.apache.hadoop.hbase.client.Table;
36  import org.apache.hadoop.hbase.client.security.SecurityCapability;
37  import org.apache.hadoop.hbase.ipc.CoprocessorRpcChannel;
38  import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
39  import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos;
40  import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.AccessControlService.BlockingInterface;
41  import org.apache.hadoop.hbase.util.Bytes;
42  
43  /**
44   * Utility client for doing access control admin operations.
45   */
46  @InterfaceAudience.Public
47  @InterfaceStability.Evolving
48  public class AccessControlClient {
49    public static final TableName ACL_TABLE_NAME =
50        TableName.valueOf(NamespaceDescriptor.SYSTEM_NAMESPACE_NAME_STR, "acl");
51  
52    /**
53     * Return true if authorization is supported and enabled
54     * @param connection The connection to use
55     * @return true if authorization is supported and enabled, false otherwise
56     * @throws IOException
57     */
58    public static boolean isAuthorizationEnabled(Connection connection) throws IOException {
59      return connection.getAdmin().getSecurityCapabilities()
60          .contains(SecurityCapability.AUTHORIZATION);
61    }
62  
63    /**
64     * Return true if cell authorization is supported and enabled
65     * @param connection The connection to use
66     * @return true if cell authorization is supported and enabled, false otherwise
67     * @throws IOException
68     */
69    public static boolean isCellAuthorizationEnabled(Connection connection) throws IOException {
70      return connection.getAdmin().getSecurityCapabilities()
71          .contains(SecurityCapability.CELL_AUTHORIZATION);
72    }
73  
74    private static BlockingInterface getAccessControlServiceStub(Table ht)
75        throws IOException {
76      CoprocessorRpcChannel service = ht.coprocessorService(HConstants.EMPTY_START_ROW);
77      BlockingInterface protocol =
78          AccessControlProtos.AccessControlService.newBlockingStub(service);
79      return protocol;
80    }
81  
82    /**
83     * Grants permission on the specified table for the specified user
84     * @param connection The Connection instance to use
85     * @param tableName
86     * @param userName
87     * @param family
88     * @param qual
89     * @param actions
90     * @throws Throwable
91     */
92    public static void grant(Connection connection, final TableName tableName,
93        final String userName, final byte[] family, final byte[] qual,
94        final Permission.Action... actions) throws Throwable {
95      try (Table table = connection.getTable(ACL_TABLE_NAME)) {
96        ProtobufUtil.grant(getAccessControlServiceStub(table), userName, tableName, family, qual,
97            actions);
98      }
99    }
100 
101   /**
102    * Grants permission on the specified namespace for the specified user.
103    * @param connection The Connection instance to use
104    * @param namespace
105    * @param userName
106    * @param actions
107    * @throws Throwable
108    */
109   public static void grant(Connection connection, final String namespace,
110       final String userName, final Permission.Action... actions) throws Throwable {
111     try (Table table = connection.getTable(ACL_TABLE_NAME)) {
112       ProtobufUtil.grant(getAccessControlServiceStub(table), userName, namespace, actions);
113     }
114   }
115 
116   /**
117    * @param connection The Connection instance to use
118    * Grant global permissions for the specified user.
119    */
120   public static void grant(Connection connection, final String userName,
121        final Permission.Action... actions) throws Throwable {
122     try (Table table = connection.getTable(ACL_TABLE_NAME)) {
123       ProtobufUtil.grant(getAccessControlServiceStub(table), userName, actions);
124     }
125   }
126 
127   public static boolean isAccessControllerRunning(Connection connection)
128       throws MasterNotRunningException, ZooKeeperConnectionException, IOException {
129     try (Admin admin = connection.getAdmin()) {
130       return admin.isTableAvailable(ACL_TABLE_NAME);
131     }
132   }
133 
134   /**
135    * Revokes the permission on the table
136    * @param connection The Connection instance to use
137    * @param tableName
138    * @param username
139    * @param family
140    * @param qualifier
141    * @param actions
142    * @throws Throwable
143    */
144   public static void revoke(Connection connection, final TableName tableName,
145       final String username, final byte[] family, final byte[] qualifier,
146       final Permission.Action... actions) throws Throwable {
147     try (Table table = connection.getTable(ACL_TABLE_NAME)) {
148       ProtobufUtil.revoke(getAccessControlServiceStub(table), username, tableName, family,
149           qualifier, actions);
150     }
151   }
152 
153   /**
154    * Revokes the permission on the table for the specified user.
155    * @param connection The Connection instance to use
156    * @param namespace
157    * @param userName
158    * @param actions
159    * @throws Throwable
160    */
161   public static void revoke(Connection connection, final String namespace,
162       final String userName, final Permission.Action... actions) throws Throwable {
163     try (Table table = connection.getTable(ACL_TABLE_NAME)) {
164       ProtobufUtil.revoke(getAccessControlServiceStub(table), userName, namespace, actions);
165     }
166   }
167 
168   /**
169    * Revoke global permissions for the specified user.
170    * @param connection The Connection instance to use
171    */
172   public static void revoke(Connection connection, final String userName,
173       final Permission.Action... actions) throws Throwable {
174     try (Table table = connection.getTable(ACL_TABLE_NAME)) {
175       ProtobufUtil.revoke(getAccessControlServiceStub(table), userName, actions);
176     }
177 
178   }
179 
180   /**
181    * List all the userPermissions matching the given pattern. If pattern is null, the behavior is
182    * dependent on whether user has global admin privileges or not. If yes, the global permissions
183    * along with the list of superusers would be returned. Else, no rows get returned.
184    * @param connection The Connection instance to use
185    * @param tableRegex The regular expression string to match against
186    * @return - returns an array of UserPermissions
187    * @throws Throwable
188    */
189   public static List<UserPermission> getUserPermissions(Connection connection, String tableRegex)
190       throws Throwable {
191     List<UserPermission> permList = new ArrayList<UserPermission>();
192     try (Table table = connection.getTable(ACL_TABLE_NAME)) {
193       try (Admin admin = connection.getAdmin()) {
194         CoprocessorRpcChannel service = table.coprocessorService(HConstants.EMPTY_START_ROW);
195         BlockingInterface protocol =
196             AccessControlProtos.AccessControlService.newBlockingStub(service);
197         HTableDescriptor[] htds = null;
198         if (tableRegex == null || tableRegex.isEmpty()) {
199           permList = ProtobufUtil.getUserPermissions(protocol);
200         } else if (tableRegex.charAt(0) == '@') {
201           String namespace = tableRegex.substring(1);
202           permList = ProtobufUtil.getUserPermissions(protocol, Bytes.toBytes(namespace));
203         } else {
204           htds = admin.listTables(Pattern.compile(tableRegex), true);
205           for (HTableDescriptor hd : htds) {
206             permList.addAll(ProtobufUtil.getUserPermissions(protocol, hd.getTableName()));
207           }
208         }
209       }
210     }
211     return permList;
212   }
213 }