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  import static org.junit.Assert.assertEquals;
22  import static org.junit.Assert.assertFalse;
23  import static org.junit.Assert.assertTrue;
24  import static org.junit.Assert.fail;
25  
26  import java.io.IOException;
27  import java.security.PrivilegedExceptionAction;
28  import java.util.ArrayList;
29  import java.util.List;
30  
31  import org.apache.hadoop.conf.Configuration;
32  import org.apache.hadoop.hbase.Cell;
33  import org.apache.hadoop.hbase.CellScanner;
34  import org.apache.hadoop.hbase.HBaseTestingUtility;
35  import org.apache.hadoop.hbase.HConstants;
36  import org.apache.hadoop.hbase.TableName;
37  import org.apache.hadoop.hbase.client.HTable;
38  import org.apache.hadoop.hbase.client.Put;
39  import org.apache.hadoop.hbase.client.Result;
40  import org.apache.hadoop.hbase.client.ResultScanner;
41  import org.apache.hadoop.hbase.client.Scan;
42  import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.GetAuthsResponse;
43  import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.VisibilityLabelsResponse;
44  import org.apache.hadoop.hbase.security.User;
45  import org.apache.hadoop.hbase.testclassification.MediumTests;
46  import org.apache.hadoop.hbase.util.Bytes;
47  import org.junit.AfterClass;
48  import org.junit.BeforeClass;
49  import org.junit.Rule;
50  import org.junit.Test;
51  import org.junit.experimental.categories.Category;
52  import org.junit.rules.TestName;
53  
54  import com.google.protobuf.ByteString;
55  
56  @Category(MediumTests.class)
57  public class TestVisibilityLablesWithGroups {
58  
59    public static final String CONFIDENTIAL = "confidential";
60    private static final String SECRET = "secret";
61    public static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
62    private static final byte[] ROW_1 = Bytes.toBytes("row1");
63    private final static byte[] CF = Bytes.toBytes("f");
64    private final static byte[] Q1 = Bytes.toBytes("q1");
65    private final static byte[] Q2 = Bytes.toBytes("q2");
66    private final static byte[] Q3 = Bytes.toBytes("q3");
67    private final static byte[] value1 = Bytes.toBytes("value1");
68    private final static byte[] value2 = Bytes.toBytes("value2");
69    private final static byte[] value3 = Bytes.toBytes("value3");
70    public static Configuration conf;
71  
72    @Rule
73    public final TestName TEST_NAME = new TestName();
74    public static User SUPERUSER;
75    public static User TESTUSER;
76  
77    @BeforeClass
78    public static void setupBeforeClass() throws Exception {
79      // setup configuration
80      conf = TEST_UTIL.getConfiguration();
81      VisibilityTestUtil.enableVisiblityLabels(conf);
82      // Not setting any SLG class. This means to use the default behavior.
83      // Use a group as the super user.
84      conf.set("hbase.superuser", "@supergroup");
85      TEST_UTIL.startMiniCluster(1);
86      // 'admin' has super user permission because it is part of the 'supergroup'
87      SUPERUSER = User.createUserForTesting(conf, "admin", new String[] { "supergroup" });
88      // 'test' user will inherit 'testgroup' visibility labels
89      TESTUSER = User.createUserForTesting(conf, "test", new String[] {"testgroup" });
90  
91      // Wait for the labels table to become available
92      TEST_UTIL.waitTableEnabled(LABELS_TABLE_NAME.getName(), 50000);
93  
94      // Set up for the test
95      SUPERUSER.runAs(new PrivilegedExceptionAction<Void>() {
96        public Void run() throws Exception {
97          try {
98            VisibilityClient.addLabels(conf, new String[] { SECRET, CONFIDENTIAL });
99            // set auth for @testgroup
100           VisibilityClient.setAuths(conf, new String[] { CONFIDENTIAL }, "@testgroup");
101         } catch (Throwable t) {
102           throw new IOException(t);
103         }
104         return null;
105       }
106     });
107   }
108 
109   @Test
110   public void testGroupAuths() throws Exception {
111     final TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
112 
113     // create the table and put data.
114     SUPERUSER.runAs(new PrivilegedExceptionAction<Void>() {
115       public Void run() throws Exception {
116         HTable table = TEST_UTIL.createTable(tableName, CF);
117         try {
118           Put put = new Put(ROW_1);
119           put.add(CF, Q1, HConstants.LATEST_TIMESTAMP, value1);
120           put.setCellVisibility(new CellVisibility(SECRET));
121           table.put(put);
122           put = new Put(ROW_1);
123           put.add(CF, Q2, HConstants.LATEST_TIMESTAMP, value2);
124           put.setCellVisibility(new CellVisibility(CONFIDENTIAL));
125           table.put(put);
126           put = new Put(ROW_1);
127           put.add(CF, Q3, HConstants.LATEST_TIMESTAMP, value3);
128           table.put(put);
129         } finally {
130           table.close();
131         }
132         return null;
133       }
134     });
135 
136     // 'admin' user is part of 'supergroup', thus can see all the cells.
137     SUPERUSER.runAs(new PrivilegedExceptionAction<Void>() {
138       public Void run() throws Exception {
139         HTable table = new HTable(conf, tableName);
140         try {
141           Scan s = new Scan();
142           ResultScanner scanner = table.getScanner(s);
143           Result[] next = scanner.next(1);
144 
145           // Test that super user can see all the cells.
146           assertTrue(next.length == 1);
147           CellScanner cellScanner = next[0].cellScanner();
148           cellScanner.advance();
149           Cell current = cellScanner.current();
150           assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(),
151               current.getRowLength(), ROW_1, 0, ROW_1.length));
152           assertTrue(Bytes.equals(current.getQualifier(), Q1));
153           assertTrue(Bytes.equals(current.getValue(), value1));
154           cellScanner.advance();
155           current = cellScanner.current();
156           assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(),
157               current.getRowLength(), ROW_1, 0, ROW_1.length));
158           assertTrue(Bytes.equals(current.getQualifier(), Q2));
159           assertTrue(Bytes.equals(current.getValue(), value2));
160           cellScanner.advance();
161           current = cellScanner.current();
162           assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(),
163               current.getRowLength(), ROW_1, 0, ROW_1.length));
164           assertTrue(Bytes.equals(current.getQualifier(), Q3));
165           assertTrue(Bytes.equals(current.getValue(), value3));
166 
167         } finally {
168           table.close();
169         }
170         return null;
171       }
172     });
173 
174     // Get testgroup's labels.
175     SUPERUSER.runAs(new PrivilegedExceptionAction<Void>() {
176       public Void run() throws Exception {
177         GetAuthsResponse authsResponse = null;
178         try {
179           authsResponse = VisibilityClient.getAuths(conf, "@testgroup");
180         } catch (Throwable e) {
181           fail("Should not have failed");
182         }
183         List<String> authsList = new ArrayList<String>();
184         for (ByteString authBS : authsResponse.getAuthList()) {
185           authsList.add(Bytes.toString(authBS.toByteArray()));
186         }
187         assertEquals(1, authsList.size());
188         assertTrue(authsList.contains(CONFIDENTIAL));
189         return null;
190       }
191     });
192 
193     // Test that test user can see what 'testgroup' has been authorized to.
194     TESTUSER.runAs(new PrivilegedExceptionAction<Void>() {
195       public Void run() throws Exception {
196         HTable table = new HTable(conf, tableName);
197         try {
198           // Test scan with no auth attribute
199           Scan s = new Scan();
200           ResultScanner scanner = table.getScanner(s);
201           Result[] next = scanner.next(1);
202 
203           assertTrue(next.length == 1);
204           CellScanner cellScanner = next[0].cellScanner();
205           cellScanner.advance();
206           Cell current = cellScanner.current();
207           // test user can see value2 (CONFIDENTIAL) and value3 (no label)
208           assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(),
209               current.getRowLength(), ROW_1, 0, ROW_1.length));
210           assertTrue(Bytes.equals(current.getQualifier(), Q2));
211           assertTrue(Bytes.equals(current.getValue(), value2));
212           cellScanner.advance();
213           current = cellScanner.current();
214           // test user can see value2 (CONFIDENTIAL) and value3 (no label)
215           assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(),
216               current.getRowLength(), ROW_1, 0, ROW_1.length));
217           assertTrue(Bytes.equals(current.getQualifier(), Q3));
218           assertTrue(Bytes.equals(current.getValue(), value3));
219 
220           // Test scan with correct auth attribute for test user
221           Scan s1 = new Scan();
222           // test user is entitled to 'CONFIDENTIAL'.
223           // If we set both labels in the scan, 'SECRET' will be dropped by the SLGs.
224           s1.setAuthorizations(new Authorizations(new String[] { SECRET, CONFIDENTIAL }));
225           ResultScanner scanner1 = table.getScanner(s1);
226           Result[] next1 = scanner1.next(1);
227 
228           assertTrue(next1.length == 1);
229           CellScanner cellScanner1 = next1[0].cellScanner();
230           cellScanner1.advance();
231           Cell current1 = cellScanner1.current();
232           // test user can see value2 (CONFIDENTIAL) and value3 (no label)
233           assertTrue(Bytes.equals(current1.getRowArray(), current1.getRowOffset(),
234             current1.getRowLength(), ROW_1, 0, ROW_1.length));
235           assertTrue(Bytes.equals(current1.getQualifier(), Q2));
236           assertTrue(Bytes.equals(current1.getValue(), value2));
237           cellScanner1.advance();
238           current1 = cellScanner1.current();
239           // test user can see value2 (CONFIDENTIAL) and value3 (no label)
240           assertTrue(Bytes.equals(current1.getRowArray(), current1.getRowOffset(),
241             current1.getRowLength(), ROW_1, 0, ROW_1.length));
242           assertTrue(Bytes.equals(current1.getQualifier(), Q3));
243           assertTrue(Bytes.equals(current1.getValue(), value3));
244 
245           // Test scan with incorrect auth attribute for test user
246           Scan s2 = new Scan();
247           // test user is entitled to 'CONFIDENTIAL'.
248           // If we set 'SECRET', it will be dropped by the SLGs.
249           s2.setAuthorizations(new Authorizations(new String[] { SECRET }));
250           ResultScanner scanner2 = table.getScanner(s2);
251           Result next2 = scanner2.next();
252           CellScanner cellScanner2 = next2.cellScanner();
253           cellScanner2.advance();
254           Cell current2 = cellScanner2.current();
255           // This scan will only see value3 (no label)
256           assertTrue(Bytes.equals(current2.getRowArray(), current2.getRowOffset(),
257             current2.getRowLength(), ROW_1, 0, ROW_1.length));
258           assertTrue(Bytes.equals(current2.getQualifier(), Q3));
259           assertTrue(Bytes.equals(current2.getValue(), value3));
260 
261           assertFalse(cellScanner2.advance());
262         } finally {
263           table.close();
264         }
265         return null;
266       }
267     });
268 
269     // Clear 'testgroup' of CONFIDENTIAL label.
270     SUPERUSER.runAs(new PrivilegedExceptionAction<Void>() {
271       public Void run() throws Exception {
272         VisibilityLabelsResponse response = null;
273         try {
274           response = VisibilityClient.clearAuths(conf, new String[] { CONFIDENTIAL }, "@testgroup");
275         } catch (Throwable e) {
276           fail("Should not have failed");
277         }
278         return null;
279       }
280     });
281 
282     // Get testgroup's labels.  No label is returned.
283     SUPERUSER.runAs(new PrivilegedExceptionAction<Void>() {
284       public Void run() throws Exception {
285         GetAuthsResponse authsResponse = null;
286         try {
287           authsResponse = VisibilityClient.getAuths(conf, "@testgroup");
288         } catch (Throwable e) {
289           fail("Should not have failed");
290         }
291         List<String> authsList = new ArrayList<String>();
292         for (ByteString authBS : authsResponse.getAuthList()) {
293           authsList.add(Bytes.toString(authBS.toByteArray()));
294         }
295         assertEquals(0, authsList.size());
296         return null;
297       }
298     });
299 
300     // Test that test user cannot see the cells with the labels anymore.
301     TESTUSER.runAs(new PrivilegedExceptionAction<Void>() {
302       public Void run() throws Exception {
303         HTable table = new HTable(conf, tableName);
304         try {
305           Scan s1 = new Scan();
306           // test user is not entitled to 'CONFIDENTIAL' anymore since we dropped
307           // testgroup's label.  test user has no auth labels now.
308           // scan's labels will be dropped on the server side.
309           s1.setAuthorizations(new Authorizations(new String[] { SECRET, CONFIDENTIAL }));
310           ResultScanner scanner1 = table.getScanner(s1);
311           Result[] next1 = scanner1.next(1);
312 
313           assertTrue(next1.length == 1);
314           CellScanner cellScanner1 = next1[0].cellScanner();
315           cellScanner1.advance();
316           Cell current1 = cellScanner1.current();
317           // test user can only see value3 (no label)
318           assertTrue(Bytes.equals(current1.getRowArray(), current1.getRowOffset(),
319             current1.getRowLength(), ROW_1, 0, ROW_1.length));
320           assertTrue(Bytes.equals(current1.getQualifier(), Q3));
321           assertTrue(Bytes.equals(current1.getValue(), value3));
322 
323           assertFalse(cellScanner1.advance());
324         } finally {
325           table.close();
326         }
327         return null;
328       }
329     });
330 
331   }
332 
333   @AfterClass
334   public static void tearDownAfterClass() throws Exception {
335     TEST_UTIL.shutdownMiniCluster();
336   }
337 }