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_FAMILY;
21  import static org.apache.hadoop.hbase.security.visibility.VisibilityConstants.LABELS_TABLE_NAME;
22  import static org.apache.hadoop.hbase.security.visibility.VisibilityConstants.LABEL_QUALIFIER;
23  import static org.junit.Assert.assertEquals;
24  import static org.junit.Assert.assertFalse;
25  import static org.junit.Assert.assertNotNull;
26  import static org.junit.Assert.assertNull;
27  import static org.junit.Assert.assertTrue;
28  import static org.junit.Assert.fail;
29  
30  import java.io.IOException;
31  import java.security.PrivilegedExceptionAction;
32  import java.util.ArrayList;
33  import java.util.List;
34  
35  import org.apache.hadoop.conf.Configuration;
36  import org.apache.hadoop.hbase.Cell;
37  import org.apache.hadoop.hbase.CellScanner;
38  import org.apache.hadoop.hbase.HBaseTestingUtility;
39  import org.apache.hadoop.hbase.HColumnDescriptor;
40  import org.apache.hadoop.hbase.HConstants;
41  import org.apache.hadoop.hbase.HTableDescriptor;
42  import org.apache.hadoop.hbase.TableName;
43  import org.apache.hadoop.hbase.client.Append;
44  import org.apache.hadoop.hbase.client.Get;
45  import org.apache.hadoop.hbase.client.HBaseAdmin;
46  import org.apache.hadoop.hbase.client.HTable;
47  import org.apache.hadoop.hbase.client.Increment;
48  import org.apache.hadoop.hbase.client.Put;
49  import org.apache.hadoop.hbase.client.Result;
50  import org.apache.hadoop.hbase.client.ResultScanner;
51  import org.apache.hadoop.hbase.client.RowMutations;
52  import org.apache.hadoop.hbase.client.Scan;
53  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionActionResult;
54  import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.GetAuthsResponse;
55  import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.VisibilityLabelsResponse;
56  import org.apache.hadoop.hbase.regionserver.BloomType;
57  import org.apache.hadoop.hbase.regionserver.HRegion;
58  import org.apache.hadoop.hbase.regionserver.HRegionServer;
59  import org.apache.hadoop.hbase.security.User;
60  import org.apache.hadoop.hbase.util.Bytes;
61  import org.apache.hadoop.hbase.util.JVMClusterUtil.RegionServerThread;
62  import org.junit.After;
63  import org.junit.AfterClass;
64  import org.junit.Rule;
65  import org.junit.Test;
66  import org.junit.rules.TestName;
67  
68  import com.google.protobuf.ByteString;
69  
70  /**
71   * Base test class for visibility labels basic features
72   */
73  public abstract class TestVisibilityLabels {
74  
75    public static final String TOPSECRET = "topsecret";
76    public static final String PUBLIC = "public";
77    public static final String PRIVATE = "private";
78    public static final String CONFIDENTIAL = "confidential";
79    public static final String SECRET = "secret";
80    public static final String COPYRIGHT = "\u00A9ABC";
81    public static final String ACCENT = "\u0941";
82    public static final String UNICODE_VIS_TAG = COPYRIGHT + "\"" + ACCENT + "\\" + SECRET + "\""
83        + "\u0027&\\";
84    public static final String UC1 = "\u0027\"\u002b";
85    public static final String UC2 = "\u002d\u003f";
86    public static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
87    public static final byte[] row1 = Bytes.toBytes("row1");
88    public static final byte[] row2 = Bytes.toBytes("row2");
89    public static final byte[] row3 = Bytes.toBytes("row3");
90    public static final byte[] row4 = Bytes.toBytes("row4");
91    public final static byte[] fam = Bytes.toBytes("info");
92    public final static byte[] qual = Bytes.toBytes("qual");
93    public final static byte[] value = Bytes.toBytes("value");
94    public static Configuration conf;
95  
96    private volatile boolean killedRS = false;
97    @Rule 
98    public final TestName TEST_NAME = new TestName();
99    public static User SUPERUSER, USER1;
100 
101   @AfterClass
102   public static void tearDownAfterClass() throws Exception {
103     TEST_UTIL.shutdownMiniCluster();
104   }
105 
106   @After
107   public void tearDown() throws Exception {
108     killedRS = false;
109   }
110 
111   @Test
112   public void testSimpleVisibilityLabels() throws Exception {
113     TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
114     HTable table = createTableAndWriteDataWithLabels(tableName, SECRET + "|" + CONFIDENTIAL,
115         PRIVATE + "|" + CONFIDENTIAL);
116     try {
117       Scan s = new Scan();
118       s.setAuthorizations(new Authorizations(SECRET, CONFIDENTIAL, PRIVATE));
119       ResultScanner scanner = table.getScanner(s);
120       Result[] next = scanner.next(3);
121 
122       assertTrue(next.length == 2);
123       CellScanner cellScanner = next[0].cellScanner();
124       cellScanner.advance();
125       Cell current = cellScanner.current();
126       assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(),
127           current.getRowLength(), row1, 0, row1.length));
128       cellScanner = next[1].cellScanner();
129       cellScanner.advance();
130       current = cellScanner.current();
131       assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(),
132           current.getRowLength(), row2, 0, row2.length));
133     } finally {
134       if (table != null) {
135         table.close();
136       }
137     }
138   }
139   
140   @Test
141   public void testSimpleVisibilityLabelsWithUniCodeCharacters() throws Exception {
142     TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
143     HTable table = createTableAndWriteDataWithLabels(tableName,
144         SECRET + "|" + CellVisibility.quote(COPYRIGHT), "(" + CellVisibility.quote(COPYRIGHT) + "&"
145             + CellVisibility.quote(ACCENT) + ")|" + CONFIDENTIAL,
146         CellVisibility.quote(UNICODE_VIS_TAG) + "&" + SECRET);
147     try {
148       Scan s = new Scan();
149       s.setAuthorizations(new Authorizations(SECRET, CONFIDENTIAL, PRIVATE, COPYRIGHT, ACCENT,
150           UNICODE_VIS_TAG));
151       ResultScanner scanner = table.getScanner(s);
152       Result[] next = scanner.next(3);
153       assertTrue(next.length == 3);
154       CellScanner cellScanner = next[0].cellScanner();
155       cellScanner.advance();
156       Cell current = cellScanner.current();
157       assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(),
158           current.getRowLength(), row1, 0, row1.length));
159       cellScanner = next[1].cellScanner();
160       cellScanner.advance();
161       current = cellScanner.current();
162       assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(),
163           current.getRowLength(), row2, 0, row2.length));
164       cellScanner = next[2].cellScanner();
165       cellScanner.advance();
166       current = cellScanner.current();
167       assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(),
168           current.getRowLength(), row3, 0, row3.length));
169     } finally {
170       if (table != null) {
171         table.close();
172       }
173     }
174   }
175 
176   @Test
177   public void testAuthorizationsWithSpecialUnicodeCharacters() throws Exception {
178     TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
179     HTable table = createTableAndWriteDataWithLabels(tableName,
180         CellVisibility.quote(UC1) + "|" + CellVisibility.quote(UC2), CellVisibility.quote(UC1),
181         CellVisibility.quote(UNICODE_VIS_TAG));
182     try {
183       Scan s = new Scan();
184       s.setAuthorizations(new Authorizations(UC1, UC2, ACCENT,
185           UNICODE_VIS_TAG));
186       ResultScanner scanner = table.getScanner(s);
187       Result[] next = scanner.next(3);
188       assertTrue(next.length == 3);
189       CellScanner cellScanner = next[0].cellScanner();
190       cellScanner.advance();
191       Cell current = cellScanner.current();
192       assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(),
193           current.getRowLength(), row1, 0, row1.length));
194       cellScanner = next[1].cellScanner();
195       cellScanner.advance();
196       current = cellScanner.current();
197       assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(),
198           current.getRowLength(), row2, 0, row2.length));
199       cellScanner = next[2].cellScanner();
200       cellScanner.advance();
201       current = cellScanner.current();
202       assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(),
203           current.getRowLength(), row3, 0, row3.length));
204     } finally {
205       if (table != null) {
206         table.close();
207       }
208     }
209   }
210 
211   @Test
212   public void testVisibilityLabelsWithComplexLabels() throws Exception {
213     TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
214     HTable table = createTableAndWriteDataWithLabels(tableName, "(" + SECRET + "|" + CONFIDENTIAL
215         + ")" + "&" + "!" + TOPSECRET, "(" + PRIVATE + "&" + CONFIDENTIAL + "&" + SECRET + ")", "("
216         + PRIVATE + "&" + CONFIDENTIAL + "&" + SECRET + ")", "(" + PRIVATE + "&" + CONFIDENTIAL
217         + "&" + SECRET + ")");
218     try {
219       Scan s = new Scan();
220       s.setAuthorizations(new Authorizations(TOPSECRET, CONFIDENTIAL, PRIVATE, PUBLIC, SECRET));
221       ResultScanner scanner = table.getScanner(s);
222       Result[] next = scanner.next(4);
223       assertEquals(3, next.length);
224       CellScanner cellScanner = next[0].cellScanner();
225       cellScanner.advance();
226       Cell current = cellScanner.current();
227       assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(),
228           current.getRowLength(), row2, 0, row2.length));
229       cellScanner = next[1].cellScanner();
230       cellScanner.advance();
231       current = cellScanner.current();
232       assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(),
233           current.getRowLength(), row3, 0, row3.length));
234       cellScanner = next[2].cellScanner();
235       cellScanner.advance();
236       current = cellScanner.current();
237       assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(),
238           current.getRowLength(), row4, 0, row4.length));
239     } finally {
240       if (table != null) {
241         table.close();
242       }
243     }
244   }
245 
246   @Test
247   public void testVisibilityLabelsThatDoesNotPassTheCriteria() throws Exception {
248     TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
249     HTable table = createTableAndWriteDataWithLabels(tableName, "(" + SECRET + "|" + CONFIDENTIAL
250         + ")", PRIVATE);
251     try {
252       Scan s = new Scan();
253       s.setAuthorizations(new Authorizations(PUBLIC));
254       ResultScanner scanner = table.getScanner(s);
255       Result[] next = scanner.next(3);
256       assertTrue(next.length == 0);
257     } finally {
258       if (table != null) {
259         table.close();
260       }
261     }
262   }
263 
264   @Test
265   public void testVisibilityLabelsInPutsThatDoesNotMatchAnyDefinedLabels() throws Exception {
266     TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
267     try {
268       createTableAndWriteDataWithLabels(tableName, "SAMPLE_LABEL", "TEST");
269       fail("Should have failed with failed sanity check exception");
270     } catch (Exception e) {
271     }
272   }
273 
274   @Test
275   public void testVisibilityLabelsInScanThatDoesNotMatchAnyDefinedLabels() throws Exception {
276     TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
277     HTable table = createTableAndWriteDataWithLabels(tableName, "(" + SECRET + "|" + CONFIDENTIAL
278         + ")", PRIVATE);
279     try {
280       Scan s = new Scan();
281       s.setAuthorizations(new Authorizations("SAMPLE"));
282       ResultScanner scanner = table.getScanner(s);
283       Result[] next = scanner.next(3);
284       assertTrue(next.length == 0);
285     } finally {
286       if (table != null) {
287         table.close();
288       }
289     }
290   }
291 
292   @Test
293   public void testVisibilityLabelsWithGet() throws Exception {
294     TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
295     HTable table = createTableAndWriteDataWithLabels(tableName, SECRET + "&" + CONFIDENTIAL + "&!"
296         + PRIVATE, SECRET + "&" + CONFIDENTIAL + "&" + PRIVATE);
297     try {
298       Get get = new Get(row1);
299       get.setAuthorizations(new Authorizations(SECRET, CONFIDENTIAL));
300       Result result = table.get(get);
301       assertTrue(!result.isEmpty());
302       Cell cell = result.getColumnLatestCell(fam, qual);
303       assertTrue(Bytes.equals(value, 0, value.length, cell.getValueArray(), cell.getValueOffset(),
304           cell.getValueLength()));
305     } finally {
306       if (table != null) {
307         table.close();
308       }
309     }
310   }
311 
312   @Test
313   public void testVisibilityLabelsOnKillingOfRSContainingLabelsTable() throws Exception {
314     List<RegionServerThread> regionServerThreads = TEST_UTIL.getHBaseCluster()
315         .getRegionServerThreads();
316     int liveRS = 0;
317     for (RegionServerThread rsThreads : regionServerThreads) {
318       if (!rsThreads.getRegionServer().isAborted()) {
319         liveRS++;
320       }
321     }
322     if (liveRS == 1) {
323       TEST_UTIL.getHBaseCluster().startRegionServer();
324     }
325     Thread t1 = new Thread() {
326       public void run() {
327         List<RegionServerThread> regionServerThreads = TEST_UTIL.getHBaseCluster()
328             .getRegionServerThreads();
329         for (RegionServerThread rsThread : regionServerThreads) {
330           List<HRegion> onlineRegions = rsThread.getRegionServer().getOnlineRegions(
331               LABELS_TABLE_NAME);
332           if (onlineRegions.size() > 0) {
333             rsThread.getRegionServer().abort("Aborting ");
334             killedRS = true;
335             break;
336           }
337         }
338       }
339 
340     };
341     t1.start();
342     final TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
343     Thread t = new Thread() {
344       public void run() {
345         try {
346           while (!killedRS) {
347             Thread.sleep(1);
348           }
349           createTableAndWriteDataWithLabels(tableName, "(" + SECRET + "|" + CONFIDENTIAL + ")",
350               PRIVATE);
351         } catch (Exception e) {
352         }
353       }
354     };
355     t.start();
356     regionServerThreads = TEST_UTIL.getHBaseCluster().getRegionServerThreads();
357     while (!killedRS) {
358       Thread.sleep(10);
359     }
360     regionServerThreads = TEST_UTIL.getHBaseCluster().getRegionServerThreads();
361     for (RegionServerThread rsThread : regionServerThreads) {
362       while (true) {
363         if (!rsThread.getRegionServer().isAborted()) {
364           List<HRegion> onlineRegions = rsThread.getRegionServer().getOnlineRegions(
365               LABELS_TABLE_NAME);
366           if (onlineRegions.size() > 0) {
367             break;
368           } else {
369             Thread.sleep(10);
370           }
371         } else {
372           break;
373         }
374       }
375     }
376     TEST_UTIL.waitTableEnabled(LABELS_TABLE_NAME.getName(), 50000);
377     t.join();
378     HTable table = null;
379     try {
380       table = new HTable(TEST_UTIL.getConfiguration(), tableName);
381       Scan s = new Scan();
382       s.setAuthorizations(new Authorizations(SECRET));
383       ResultScanner scanner = table.getScanner(s);
384       Result[] next = scanner.next(3);
385       assertTrue(next.length == 1);
386     } finally {
387       if (table != null) {
388         table.close();
389       }
390     }
391   }
392 
393   @Test(timeout = 60 * 1000)
394   public void testVisibilityLabelsOnRSRestart() throws Exception {
395     final TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
396     HTable table = createTableAndWriteDataWithLabels(tableName, "(" + SECRET + "|" + CONFIDENTIAL
397         + ")", PRIVATE);
398     List<RegionServerThread> regionServerThreads = TEST_UTIL.getHBaseCluster()
399         .getRegionServerThreads();
400     for (RegionServerThread rsThread : regionServerThreads) {
401       rsThread.getRegionServer().abort("Aborting ");
402     }
403     // Start one new RS
404     RegionServerThread rs = TEST_UTIL.getHBaseCluster().startRegionServer();
405     waitForLabelsRegionAvailability(rs.getRegionServer());
406     try {
407       Scan s = new Scan();
408       s.setAuthorizations(new Authorizations(SECRET));
409       ResultScanner scanner = table.getScanner(s);
410       Result[] next = scanner.next(3);
411       assertTrue(next.length == 1);
412     } finally {
413       if (table != null) {
414         table.close();
415       }
416     }
417   }
418 
419   protected void waitForLabelsRegionAvailability(HRegionServer regionServer) {
420     while (!regionServer.isOnline()) {
421       try {
422         Thread.sleep(10);
423       } catch (InterruptedException e) {
424       }
425     }
426     while (regionServer.getOnlineRegions(LABELS_TABLE_NAME).isEmpty()) {
427       try {
428         Thread.sleep(10);
429       } catch (InterruptedException e) {
430       }
431     }
432     HRegion labelsTableRegion = regionServer.getOnlineRegions(LABELS_TABLE_NAME).get(0);
433     while (labelsTableRegion.isRecovering()) {
434       try {
435         Thread.sleep(10);
436       } catch (InterruptedException e) {
437       }
438     }
439   }
440 
441   @Test
442   public void testVisibilityLabelsInGetThatDoesNotMatchAnyDefinedLabels() throws Exception {
443     TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
444     HTable table = createTableAndWriteDataWithLabels(tableName, "(" + SECRET + "|" + CONFIDENTIAL
445         + ")", PRIVATE);
446     try {
447       Get get = new Get(row1);
448       get.setAuthorizations(new Authorizations("SAMPLE"));
449       Result result = table.get(get);
450       assertTrue(result.isEmpty());
451     } finally {
452       if (table != null) {
453         table.close();
454       }
455     }
456   }
457 
458   @Test
459   public void testSetAndGetUserAuths() throws Throwable {
460     final String user = "user1";
461     PrivilegedExceptionAction<Void> action = new PrivilegedExceptionAction<Void>() {
462       public Void run() throws Exception {
463         String[] auths = { SECRET, CONFIDENTIAL };
464         try {
465           VisibilityClient.setAuths(conf, auths, user);
466         } catch (Throwable e) {
467         }
468         return null;
469       }
470     };
471     SUPERUSER.runAs(action);
472     HTable ht = null;
473     try {
474       ht = new HTable(conf, LABELS_TABLE_NAME);
475       Scan scan = new Scan();
476       scan.setAuthorizations(new Authorizations(VisibilityUtils.SYSTEM_LABEL));
477       ResultScanner scanner = ht.getScanner(scan);
478       Result result = null;
479       List<Result> results = new ArrayList<Result>();
480       while ((result = scanner.next()) != null) {
481         results.add(result);
482       }
483       List<String> auths = extractAuths(user, results);
484       assertTrue(auths.contains(SECRET));
485       assertTrue(auths.contains(CONFIDENTIAL));
486       assertEquals(2, auths.size());
487     } finally {
488       if (ht != null) {
489         ht.close();
490       }
491     }
492 
493     action = new PrivilegedExceptionAction<Void>() {
494       public Void run() throws Exception {
495         GetAuthsResponse authsResponse = null;
496         try {
497           authsResponse = VisibilityClient.getAuths(conf, user);
498         } catch (Throwable e) {
499           fail("Should not have failed");
500         }
501         List<String> authsList = new ArrayList<String>();
502         for (ByteString authBS : authsResponse.getAuthList()) {
503           authsList.add(Bytes.toString(authBS.toByteArray()));
504         }
505         assertEquals(2, authsList.size());
506         assertTrue(authsList.contains(SECRET));
507         assertTrue(authsList.contains(CONFIDENTIAL));
508         return null;
509       }
510     };
511     SUPERUSER.runAs(action);
512 
513     // Try doing setAuths once again and there should not be any duplicates
514     action = new PrivilegedExceptionAction<Void>() {
515       public Void run() throws Exception {
516         String[] auths1 = { SECRET, CONFIDENTIAL };
517         GetAuthsResponse authsResponse = null;
518         try {
519           VisibilityClient.setAuths(conf, auths1, user);
520           try {
521             authsResponse = VisibilityClient.getAuths(conf, user);
522           } catch (Throwable e) {
523             fail("Should not have failed");
524           }
525         } catch (Throwable e) {
526         }
527         List<String> authsList = new ArrayList<String>();
528         for (ByteString authBS : authsResponse.getAuthList()) {
529           authsList.add(Bytes.toString(authBS.toByteArray()));
530         }
531         assertEquals(2, authsList.size());
532         assertTrue(authsList.contains(SECRET));
533         assertTrue(authsList.contains(CONFIDENTIAL));
534         return null;
535       }
536     };
537     SUPERUSER.runAs(action);
538   }
539 
540   protected List<String> extractAuths(String user, List<Result> results) {
541     List<String> auths = new ArrayList<String>();
542     for (Result result : results) {
543       Cell labelCell = result.getColumnLatestCell(LABELS_TABLE_FAMILY, LABEL_QUALIFIER);
544       Cell userAuthCell = result.getColumnLatestCell(LABELS_TABLE_FAMILY, user.getBytes());
545       if (userAuthCell != null) {
546         auths.add(Bytes.toString(labelCell.getValueArray(), labelCell.getValueOffset(),
547             labelCell.getValueLength()));
548       }
549     }
550     return auths;
551   }
552 
553   @Test
554   public void testClearUserAuths() throws Throwable {
555     PrivilegedExceptionAction<Void> action = new PrivilegedExceptionAction<Void>() {
556       public Void run() throws Exception {
557         String[] auths = { SECRET, CONFIDENTIAL, PRIVATE };
558         String user = "testUser";
559         try {
560           VisibilityClient.setAuths(conf, auths, user);
561         } catch (Throwable e) {
562           fail("Should not have failed");
563         }
564         // Removing the auths for SECRET and CONFIDENTIAL for the user.
565         // Passing a non existing auth also.
566         auths = new String[] { SECRET, PUBLIC, CONFIDENTIAL };
567         VisibilityLabelsResponse response = null;
568         try {
569           response = VisibilityClient.clearAuths(conf, auths, user);
570         } catch (Throwable e) {
571           fail("Should not have failed");
572         }
573         List<RegionActionResult> resultList = response.getResultList();
574         assertEquals(3, resultList.size());
575         assertTrue(resultList.get(0).getException().getValue().isEmpty());
576         assertEquals("org.apache.hadoop.hbase.DoNotRetryIOException",
577             resultList.get(1).getException().getName());
578         assertTrue(Bytes.toString(resultList.get(1).getException().getValue().toByteArray())
579             .contains(
580                 "org.apache.hadoop.hbase.security.visibility.InvalidLabelException: "
581                     + "Label 'public' is not set for the user testUser"));
582         assertTrue(resultList.get(2).getException().getValue().isEmpty());
583         HTable ht = null;
584         try {
585           ht = new HTable(conf, LABELS_TABLE_NAME);
586           ResultScanner scanner = ht.getScanner(new Scan());
587           Result result = null;
588           List<Result> results = new ArrayList<Result>();
589           while ((result = scanner.next()) != null) {
590             results.add(result);
591           }
592           List<String> curAuths = extractAuths(user, results);
593           assertTrue(curAuths.contains(PRIVATE));
594           assertEquals(1, curAuths.size());
595         } finally {
596           if (ht != null) {
597             ht.close();
598           }
599         }
600 
601         GetAuthsResponse authsResponse = null;
602         try {
603           authsResponse = VisibilityClient.getAuths(conf, user);
604         } catch (Throwable e) {
605           fail("Should not have failed");
606         }
607         List<String> authsList = new ArrayList<String>();
608         for (ByteString authBS : authsResponse.getAuthList()) {
609           authsList.add(Bytes.toString(authBS.toByteArray()));
610         }
611         assertEquals(1, authsList.size());
612         assertTrue(authsList.contains(PRIVATE));
613         return null;
614       }
615     };
616     SUPERUSER.runAs(action);
617   }
618 
619   @Test
620   public void testLabelsWithCheckAndPut() throws Throwable {
621     TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
622     HTable table = null;
623     try {
624       table = TEST_UTIL.createTable(tableName, fam);
625       byte[] row1 = Bytes.toBytes("row1");
626       Put put = new Put(row1);
627       put.add(fam, qual, HConstants.LATEST_TIMESTAMP, value);
628       put.setCellVisibility(new CellVisibility(SECRET + " & " + CONFIDENTIAL));
629       table.checkAndPut(row1, fam, qual, null, put);
630       byte[] row2 = Bytes.toBytes("row2");
631       put = new Put(row2);
632       put.add(fam, qual, HConstants.LATEST_TIMESTAMP, value);
633       put.setCellVisibility(new CellVisibility(SECRET));
634       table.checkAndPut(row2, fam, qual, null, put);
635       
636       Scan scan = new Scan();
637       scan.setAuthorizations(new Authorizations(SECRET));
638       ResultScanner scanner = table.getScanner(scan);
639       Result result = scanner.next();
640       assertTrue(!result.isEmpty());
641       assertTrue(Bytes.equals(row2, result.getRow()));
642       result = scanner.next();
643       assertNull(result);
644     } finally {
645       if (table != null) {
646         table.close();
647       }
648     }
649   }
650 
651   @Test
652   public void testLabelsWithIncrement() throws Throwable {
653     TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
654     HTable table = null;
655     try {
656       table = TEST_UTIL.createTable(tableName, fam);
657       byte[] row1 = Bytes.toBytes("row1");
658       byte[] val = Bytes.toBytes(1L);
659       Put put = new Put(row1);
660       put.add(fam, qual, HConstants.LATEST_TIMESTAMP, val);
661       put.setCellVisibility(new CellVisibility(SECRET + " & " + CONFIDENTIAL));
662       table.put(put);
663       Get get = new Get(row1);
664       get.setAuthorizations(new Authorizations(SECRET));
665       Result result = table.get(get);
666       assertTrue(result.isEmpty());
667       table.incrementColumnValue(row1, fam, qual, 2L);
668       result = table.get(get);
669       assertTrue(result.isEmpty());
670       Increment increment = new Increment(row1);
671       increment.addColumn(fam, qual, 2L);
672       increment.setCellVisibility(new CellVisibility(SECRET));
673       table.increment(increment);
674       result = table.get(get);
675       assertTrue(!result.isEmpty());
676     } finally {
677       if (table != null) {
678         table.close();
679       }
680     }
681   }
682 
683   @Test
684   public void testLabelsWithAppend() throws Throwable {
685     TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
686     HTable table = null;
687     try {
688       table = TEST_UTIL.createTable(tableName, fam);
689       byte[] row1 = Bytes.toBytes("row1");
690       byte[] val = Bytes.toBytes("a");
691       Put put = new Put(row1);
692       put.add(fam, qual, HConstants.LATEST_TIMESTAMP, val);
693       put.setCellVisibility(new CellVisibility(SECRET + " & " + CONFIDENTIAL));
694       table.put(put);
695       Get get = new Get(row1);
696       get.setAuthorizations(new Authorizations(SECRET));
697       Result result = table.get(get);
698       assertTrue(result.isEmpty());
699       Append append = new Append(row1);
700       append.add(fam, qual, Bytes.toBytes("b"));
701       table.append(append);
702       result = table.get(get);
703       assertTrue(result.isEmpty());
704       append = new Append(row1);
705       append.add(fam, qual, Bytes.toBytes("c"));
706       append.setCellVisibility(new CellVisibility(SECRET));
707       table.append(append);
708       result = table.get(get);
709       assertTrue(!result.isEmpty());
710     } finally {
711       if (table != null) {
712         table.close();
713       }
714     }
715   }
716 
717   @Test
718   public void testUserShouldNotDoDDLOpOnLabelsTable() throws Exception {
719     HBaseAdmin admin = TEST_UTIL.getHBaseAdmin();
720     try {
721       admin.disableTable(LABELS_TABLE_NAME);
722       fail("Lables table should not get disabled by user.");
723     } catch (Exception e) {
724     }
725     try {
726       admin.deleteTable(LABELS_TABLE_NAME);
727       fail("Lables table should not get disabled by user.");
728     } catch (Exception e) {
729     }
730     try {
731       HColumnDescriptor hcd = new HColumnDescriptor("testFamily");
732       admin.addColumn(LABELS_TABLE_NAME, hcd);
733       fail("Lables table should not get altered by user.");
734     } catch (Exception e) {
735     }
736     try {
737       admin.deleteColumn(LABELS_TABLE_NAME, VisibilityConstants.LABELS_TABLE_FAMILY);
738       fail("Lables table should not get altered by user.");
739     } catch (Exception e) {
740     }
741     try {
742       HColumnDescriptor hcd = new HColumnDescriptor(VisibilityConstants.LABELS_TABLE_FAMILY);
743       hcd.setBloomFilterType(BloomType.ROWCOL);
744       admin.modifyColumn(LABELS_TABLE_NAME, hcd);
745       fail("Lables table should not get altered by user.");
746     } catch (Exception e) {
747     }
748     try {
749       HTableDescriptor htd = new HTableDescriptor(LABELS_TABLE_NAME);
750       htd.addFamily(new HColumnDescriptor("f1"));
751       htd.addFamily(new HColumnDescriptor("f2"));
752       admin.modifyTable(LABELS_TABLE_NAME, htd);
753       fail("Lables table should not get altered by user.");
754     } catch (Exception e) {
755     }
756   }
757 
758   @Test
759   public void testMultipleVersions() throws Exception {
760     final byte[] r1 = Bytes.toBytes("row1");
761     final byte[] r2 = Bytes.toBytes("row2");
762     final byte[] v1 = Bytes.toBytes("100");
763     final byte[] v2 = Bytes.toBytes("101");
764     final byte[] fam2 = Bytes.toBytes("info2");
765     final byte[] qual2 = Bytes.toBytes("qual2");
766     TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
767     HTableDescriptor desc = new HTableDescriptor(tableName);
768     HColumnDescriptor col = new HColumnDescriptor(fam);// Default max versions is 1.
769     desc.addFamily(col);
770     col = new HColumnDescriptor(fam2);
771     col.setMaxVersions(5);
772     desc.addFamily(col);
773     TEST_UTIL.getHBaseAdmin().createTable(desc);
774     HTable table = null;
775     try {
776       table = new HTable(TEST_UTIL.getConfiguration(), tableName);
777       Put put = new Put(r1);
778       put.add(fam, qual, 3l, v1);
779       put.add(fam, qual2, 3l, v1);
780       put.add(fam2, qual, 3l, v1);
781       put.add(fam2, qual2, 3l, v1);
782       put.setCellVisibility(new CellVisibility(SECRET));
783       table.put(put);
784       put = new Put(r1);
785       put.add(fam, qual, 4l, v2);
786       put.add(fam, qual2, 4l, v2);
787       put.add(fam2, qual, 4l, v2);
788       put.add(fam2, qual2, 4l, v2);
789       put.setCellVisibility(new CellVisibility(PRIVATE));
790       table.put(put);
791 
792       put = new Put(r2);
793       put.add(fam, qual, 3l, v1);
794       put.add(fam, qual2, 3l, v1);
795       put.add(fam2, qual, 3l, v1);
796       put.add(fam2, qual2, 3l, v1);
797       put.setCellVisibility(new CellVisibility(SECRET));
798       table.put(put);
799       put = new Put(r2);
800       put.add(fam, qual, 4l, v2);
801       put.add(fam, qual2, 4l, v2);
802       put.add(fam2, qual, 4l, v2);
803       put.add(fam2, qual2, 4l, v2);
804       put.setCellVisibility(new CellVisibility(SECRET));
805       table.put(put);
806 
807       Scan s = new Scan();
808       s.setMaxVersions(1);
809       s.setAuthorizations(new Authorizations(SECRET));
810       ResultScanner scanner = table.getScanner(s);
811       Result result = scanner.next();
812       assertTrue(Bytes.equals(r1, result.getRow()));
813       // for cf 'fam' max versions in HCD is 1. So the old version cells, which are having matching
814       // CellVisibility with Authorizations, should not get considered in the label evaluation at
815       // all.
816       assertNull(result.getColumnLatestCell(fam, qual));
817       assertNull(result.getColumnLatestCell(fam, qual2));
818       // for cf 'fam2' max versions in HCD is > 1. So we can consider the old version cells, which
819       // are having matching CellVisibility with Authorizations, in the label evaluation. It can
820       // just skip those recent versions for which visibility is not there as per the new version's
821       // CellVisibility. The old versions which are having visibility can be send back
822       Cell cell = result.getColumnLatestCell(fam2, qual);
823       assertNotNull(cell);
824       assertTrue(Bytes.equals(v1, 0, v1.length, cell.getValueArray(), cell.getValueOffset(),
825           cell.getValueLength()));
826       cell = result.getColumnLatestCell(fam2, qual2);
827       assertNotNull(cell);
828       assertTrue(Bytes.equals(v1, 0, v1.length, cell.getValueArray(), cell.getValueOffset(),
829           cell.getValueLength()));
830 
831       result = scanner.next();
832       assertTrue(Bytes.equals(r2, result.getRow()));
833       cell = result.getColumnLatestCell(fam, qual);
834       assertNotNull(cell);
835       assertTrue(Bytes.equals(v2, 0, v2.length, cell.getValueArray(), cell.getValueOffset(),
836           cell.getValueLength()));
837       cell = result.getColumnLatestCell(fam, qual2);
838       assertNotNull(cell);
839       assertTrue(Bytes.equals(v2, 0, v2.length, cell.getValueArray(), cell.getValueOffset(),
840           cell.getValueLength()));
841       cell = result.getColumnLatestCell(fam2, qual);
842       assertNotNull(cell);
843       assertTrue(Bytes.equals(v2, 0, v2.length, cell.getValueArray(), cell.getValueOffset(),
844           cell.getValueLength()));
845       cell = result.getColumnLatestCell(fam2, qual2);
846       assertNotNull(cell);
847       assertTrue(Bytes.equals(v2, 0, v2.length, cell.getValueArray(), cell.getValueOffset(),
848           cell.getValueLength()));
849     } finally {
850       if (table != null) {
851         table.close();
852       }
853     }
854   }
855 
856   @Test
857   public void testMutateRow() throws Exception {
858     final byte[] qual2 = Bytes.toBytes("qual2");
859     TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
860     HTableDescriptor desc = new HTableDescriptor(tableName);
861     HColumnDescriptor col = new HColumnDescriptor(fam);
862     desc.addFamily(col);
863     TEST_UTIL.getHBaseAdmin().createTable(desc);
864     HTable table = new HTable(TEST_UTIL.getConfiguration(), tableName);
865     try {
866       Put p1 = new Put(row1);
867       p1.add(fam, qual, value);
868       p1.setCellVisibility(new CellVisibility(CONFIDENTIAL));
869 
870       Put p2 = new Put(row1);
871       p2.add(fam, qual2, value);
872       p2.setCellVisibility(new CellVisibility(SECRET));
873 
874       RowMutations rm = new RowMutations(row1);
875       rm.add(p1);
876       rm.add(p2);
877 
878       table.mutateRow(rm);
879 
880       Get get = new Get(row1);
881       get.setAuthorizations(new Authorizations(CONFIDENTIAL));
882       Result result = table.get(get);
883       assertTrue(result.containsColumn(fam, qual));
884       assertFalse(result.containsColumn(fam, qual2));
885 
886       get.setAuthorizations(new Authorizations(SECRET));
887       result = table.get(get);
888       assertFalse(result.containsColumn(fam, qual));
889       assertTrue(result.containsColumn(fam, qual2));
890     } finally {
891       table.close();
892     }
893   }
894 
895   static HTable createTableAndWriteDataWithLabels(TableName tableName, String... labelExps)
896       throws Exception {
897     HTable table = null;
898     try {
899       table = TEST_UTIL.createTable(tableName, fam);
900       int i = 1;
901       List<Put> puts = new ArrayList<Put>();
902       for (String labelExp : labelExps) {
903         Put put = new Put(Bytes.toBytes("row" + i));
904         put.add(fam, qual, HConstants.LATEST_TIMESTAMP, value);
905         put.setCellVisibility(new CellVisibility(labelExp));
906         puts.add(put);
907         i++;
908       }
909       table.put(puts);
910     } finally {
911       if (table != null) {
912         table.close();
913       }
914     }
915     return table;
916   }
917 
918   public static void addLabels() throws Exception {
919     PrivilegedExceptionAction<VisibilityLabelsResponse> action =
920         new PrivilegedExceptionAction<VisibilityLabelsResponse>() {
921       public VisibilityLabelsResponse run() throws Exception {
922         String[] labels = { SECRET, TOPSECRET, CONFIDENTIAL, PUBLIC, PRIVATE, COPYRIGHT, ACCENT,
923             UNICODE_VIS_TAG, UC1, UC2 };
924         try {
925           VisibilityClient.addLabels(conf, labels);
926         } catch (Throwable t) {
927           throw new IOException(t);
928         }
929         return null;
930       }
931     };
932     SUPERUSER.runAs(action);
933   }
934 }