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