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.visibility;
19  
20  import static org.apache.hadoop.hbase.security.visibility.VisibilityConstants.LABELS_TABLE_NAME;
21  
22  import java.io.IOException;
23  import java.util.Map;
24  import java.util.regex.Pattern;
25  
26  import org.apache.hadoop.hbase.util.ByteStringer;
27  import org.apache.hadoop.hbase.classification.InterfaceAudience;
28  import org.apache.hadoop.hbase.classification.InterfaceStability;
29  import org.apache.hadoop.conf.Configuration;
30  import org.apache.hadoop.hbase.HConstants;
31  import org.apache.hadoop.hbase.client.HBaseAdmin;
32  import org.apache.hadoop.hbase.client.HTable;
33  import org.apache.hadoop.hbase.client.coprocessor.Batch;
34  import org.apache.hadoop.hbase.client.security.SecurityCapability;
35  import org.apache.hadoop.hbase.ipc.BlockingRpcCallback;
36  import org.apache.hadoop.hbase.ipc.ServerRpcController;
37  import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.GetAuthsRequest;
38  import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.GetAuthsResponse;
39  import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.ListLabelsRequest;
40  import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.ListLabelsResponse;
41  import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.SetAuthsRequest;
42  import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.VisibilityLabel;
43  import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.VisibilityLabelsRequest;
44  import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.VisibilityLabelsResponse;
45  import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.VisibilityLabelsService;
46  import org.apache.hadoop.hbase.util.Bytes;
47  
48  import com.google.protobuf.ServiceException;
49  
50  /**
51   * Utility client for doing visibility labels admin operations.
52   */
53  @InterfaceAudience.Public
54  @InterfaceStability.Unstable
55  public class VisibilityClient {
56  
57    /**
58     * Return true if cell visibility features are supported and enabled
59     * @param conf
60     * @return true if cell visibility features are supported and enabled, false otherwise
61     * @throws IOException
62     */
63    public static boolean isCellVisibilityEnabled(Configuration conf) throws IOException {
64      HBaseAdmin admin = new HBaseAdmin(conf);
65      try {
66        return admin.getSecurityCapabilities().contains(SecurityCapability.CELL_VISIBILITY);
67      } finally {
68        admin.close();
69      }
70    }
71  
72    /**
73     * Utility method for adding label to the system.
74     * 
75     * @param conf
76     * @param label
77     * @return VisibilityLabelsResponse
78     * @throws Throwable
79     */
80    public static VisibilityLabelsResponse addLabel(Configuration conf, final String label)
81        throws Throwable {
82      return addLabels(conf, new String[] { label });
83    }
84  
85    /**
86     * Utility method for adding labels to the system.
87     * 
88     * @param conf
89     * @param labels
90     * @return VisibilityLabelsResponse
91     * @throws Throwable
92     */
93    public static VisibilityLabelsResponse addLabels(Configuration conf, final String[] labels)
94        throws Throwable {
95      HTable ht = null;
96      try {
97        ht = new HTable(conf, LABELS_TABLE_NAME.getName());
98        Batch.Call<VisibilityLabelsService, VisibilityLabelsResponse> callable = 
99            new Batch.Call<VisibilityLabelsService, VisibilityLabelsResponse>() {
100         ServerRpcController controller = new ServerRpcController();
101         BlockingRpcCallback<VisibilityLabelsResponse> rpcCallback = 
102             new BlockingRpcCallback<VisibilityLabelsResponse>();
103 
104         public VisibilityLabelsResponse call(VisibilityLabelsService service) throws IOException {
105           VisibilityLabelsRequest.Builder builder = VisibilityLabelsRequest.newBuilder();
106           for (String label : labels) {
107             if (label.length() > 0) {
108               VisibilityLabel.Builder newBuilder = VisibilityLabel.newBuilder();
109               newBuilder.setLabel(ByteStringer.wrap(Bytes.toBytes(label)));
110               builder.addVisLabel(newBuilder.build());
111             }
112           }
113           service.addLabels(controller, builder.build(), rpcCallback);
114           VisibilityLabelsResponse response = rpcCallback.get();
115           if (controller.failedOnException()) {
116             throw controller.getFailedOn();
117           }
118           return response;
119         }
120       };
121       Map<byte[], VisibilityLabelsResponse> result = ht.coprocessorService(
122           VisibilityLabelsService.class, HConstants.EMPTY_BYTE_ARRAY, HConstants.EMPTY_BYTE_ARRAY,
123           callable);
124       return result.values().iterator().next(); // There will be exactly one region for labels
125                                                 // table and so one entry in result Map.
126     } finally {
127       if (ht != null) {
128         ht.close();
129       }
130     }
131   }
132 
133   /**
134    * Sets given labels globally authorized for the user.
135    * @param conf
136    * @param auths
137    * @param user
138    * @return VisibilityLabelsResponse
139    * @throws Throwable
140    */
141   public static VisibilityLabelsResponse setAuths(Configuration conf, final String[] auths,
142       final String user) throws Throwable {
143     return setOrClearAuths(conf, auths, user, true);
144   }
145 
146   /**
147    * @param conf
148    * @param user
149    * @return labels, the given user is globally authorized for.
150    * @throws Throwable
151    */
152   public static GetAuthsResponse getAuths(Configuration conf, final String user) throws Throwable {
153     HTable ht = null;
154     try {
155       ht = new HTable(conf, LABELS_TABLE_NAME.getName());
156       Batch.Call<VisibilityLabelsService, GetAuthsResponse> callable = 
157           new Batch.Call<VisibilityLabelsService, GetAuthsResponse>() {
158         ServerRpcController controller = new ServerRpcController();
159         BlockingRpcCallback<GetAuthsResponse> rpcCallback = 
160             new BlockingRpcCallback<GetAuthsResponse>();
161 
162         public GetAuthsResponse call(VisibilityLabelsService service) throws IOException {
163           GetAuthsRequest.Builder getAuthReqBuilder = GetAuthsRequest.newBuilder();
164           getAuthReqBuilder.setUser(ByteStringer.wrap(Bytes.toBytes(user)));
165           service.getAuths(controller, getAuthReqBuilder.build(), rpcCallback);
166           GetAuthsResponse response = rpcCallback.get();
167           if (controller.failedOnException()) {
168             throw controller.getFailedOn();
169           }
170           return response;
171         }
172       };
173       Map<byte[], GetAuthsResponse> result = ht.coprocessorService(VisibilityLabelsService.class,
174           HConstants.EMPTY_BYTE_ARRAY, HConstants.EMPTY_BYTE_ARRAY, callable);
175       return result.values().iterator().next(); // There will be exactly one region for labels
176                                                 // table and so one entry in result Map.
177     } finally {
178       if (ht != null) {
179         ht.close();
180       }
181     }
182   }
183 
184   /**
185    * Removes given labels from user's globally authorized list of labels.
186    * @param conf
187    * @param auths
188    * @param user
189    * @return VisibilityLabelsResponse
190    * @throws Throwable
191    */
192   public static VisibilityLabelsResponse clearAuths(Configuration conf, final String[] auths,
193       final String user) throws Throwable {
194     return setOrClearAuths(conf, auths, user, false);
195   }
196 
197   private static VisibilityLabelsResponse setOrClearAuths(Configuration conf, final String[] auths,
198       final String user, final boolean setOrClear) throws IOException, ServiceException, Throwable {
199     HTable ht = null;
200     try {
201       ht = new HTable(conf, LABELS_TABLE_NAME.getName());
202       Batch.Call<VisibilityLabelsService, VisibilityLabelsResponse> callable = 
203           new Batch.Call<VisibilityLabelsService, VisibilityLabelsResponse>() {
204         ServerRpcController controller = new ServerRpcController();
205         BlockingRpcCallback<VisibilityLabelsResponse> rpcCallback = 
206             new BlockingRpcCallback<VisibilityLabelsResponse>();
207 
208         public VisibilityLabelsResponse call(VisibilityLabelsService service) throws IOException {
209           SetAuthsRequest.Builder setAuthReqBuilder = SetAuthsRequest.newBuilder();
210           setAuthReqBuilder.setUser(ByteStringer.wrap(Bytes.toBytes(user)));
211           for (String auth : auths) {
212             if (auth.length() > 0) {
213               setAuthReqBuilder.addAuth(ByteStringer.wrap(Bytes.toBytes(auth)));
214             }
215           }
216           if (setOrClear) {
217             service.setAuths(controller, setAuthReqBuilder.build(), rpcCallback);
218           } else {
219             service.clearAuths(controller, setAuthReqBuilder.build(), rpcCallback);
220           }
221           VisibilityLabelsResponse response = rpcCallback.get();
222           if (controller.failedOnException()) {
223             throw controller.getFailedOn();
224           }
225           return response;
226         }
227       };
228       Map<byte[], VisibilityLabelsResponse> result = ht.coprocessorService(
229           VisibilityLabelsService.class, HConstants.EMPTY_BYTE_ARRAY, HConstants.EMPTY_BYTE_ARRAY,
230           callable);
231       return result.values().iterator().next(); // There will be exactly one region for labels
232                                                 // table and so one entry in result Map.
233     } finally {
234       if (ht != null) {
235         ht.close();
236       }
237     }
238   }
239 
240   /**
241    * Retrieve the list of visibility labels defined in the system.
242    * @param conf
243    * @param regex  The regular expression to filter which labels are returned.
244    * @return labels The list of visibility labels defined in the system.
245    * @throws Throwable
246    */
247   public static ListLabelsResponse listLabels(Configuration conf, final String regex)
248       throws Throwable {
249     HTable ht = null;
250     try {
251       ht = new HTable(conf, LABELS_TABLE_NAME.getName());
252       Batch.Call<VisibilityLabelsService, ListLabelsResponse> callable =
253           new Batch.Call<VisibilityLabelsService, ListLabelsResponse>() {
254         ServerRpcController controller = new ServerRpcController();
255         BlockingRpcCallback<ListLabelsResponse> rpcCallback =
256             new BlockingRpcCallback<ListLabelsResponse>();
257         public ListLabelsResponse call(VisibilityLabelsService service) throws IOException {
258          ListLabelsRequest.Builder listAuthLabelsReqBuilder = ListLabelsRequest.newBuilder();
259           if (regex != null) {
260             // Compile the regex here to catch any regex exception earlier.
261             Pattern pattern = Pattern.compile(regex);
262             listAuthLabelsReqBuilder.setRegex(pattern.toString());
263           }
264           service.listLabels(controller, listAuthLabelsReqBuilder.build(), rpcCallback);
265           ListLabelsResponse response = rpcCallback.get();
266           if (controller.failedOnException()) {
267             throw controller.getFailedOn();
268           }
269           return response;
270         }
271       };
272       Map<byte[], ListLabelsResponse> result =
273           ht.coprocessorService(VisibilityLabelsService.class, HConstants.EMPTY_BYTE_ARRAY,
274             HConstants.EMPTY_BYTE_ARRAY, callable);
275       return result.values().iterator().next(); // There will be exactly one region for labels
276       // table and so one entry in result Map.
277     }
278     finally {
279       if (ht != null) {
280         ht.close();
281       }
282     }
283   }
284 }