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