1 /**
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 package org.apache.hadoop.hbase.security.visibility;
19 
20 import static org.apache.hadoop.hbase.security.visibility.VisibilityConstants.LABELS_TABLE_NAME;
21 import static org.junit.Assert.assertFalse;
22 import static org.junit.Assert.assertTrue;
23 
24 import java.io.IOException;
25 import java.security.PrivilegedExceptionAction;
26 
27 import org.apache.hadoop.conf.Configuration;
28 import org.apache.hadoop.hbase.Cell;
29 import org.apache.hadoop.hbase.CellScanner;
30 import org.apache.hadoop.hbase.HBaseTestingUtility;
31 import org.apache.hadoop.hbase.HConstants;
32 import org.apache.hadoop.hbase.testclassification.MediumTests;
33 import org.apache.hadoop.hbase.TableName;
34 import org.apache.hadoop.hbase.client.Connection;
35 import org.apache.hadoop.hbase.client.ConnectionFactory;
36 import org.apache.hadoop.hbase.client.Put;
37 import org.apache.hadoop.hbase.client.Result;
38 import org.apache.hadoop.hbase.client.ResultScanner;
39 import org.apache.hadoop.hbase.client.Scan;
40 import org.apache.hadoop.hbase.client.Table;
41 import org.apache.hadoop.hbase.security.User;
42 import org.apache.hadoop.hbase.util.Bytes;
43 import org.junit.AfterClass;
44 import org.junit.BeforeClass;
45 import org.junit.Rule;
46 import org.junit.Test;
47 import org.junit.experimental.categories.Category;
48 import org.junit.rules.TestName;
49 
50 @Category(MediumTests.class)
51 public class TestDefaultScanLabelGeneratorStack {
52 
53   public static final String CONFIDENTIAL = "confidential";
54   private static final String SECRET = "secret";
55   public static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
56   private static final byte[] ROW_1 = Bytes.toBytes("row1");
57   private final static byte[] CF = Bytes.toBytes("f");
58   private final static byte[] Q1 = Bytes.toBytes("q1");
59   private final static byte[] Q2 = Bytes.toBytes("q2");
60   private final static byte[] Q3 = Bytes.toBytes("q3");
61   private final static byte[] value1 = Bytes.toBytes("value1");
62   private final static byte[] value2 = Bytes.toBytes("value2");
63   private final static byte[] value3 = Bytes.toBytes("value3");
64   public static Configuration conf;
65 
66   @Rule
67   public final TestName TEST_NAME = new TestName();
68   public static User SUPERUSER;
69   public static User TESTUSER;
70 
71   @BeforeClass
setupBeforeClass()72   public static void setupBeforeClass() throws Exception {
73     // setup configuration
74     conf = TEST_UTIL.getConfiguration();
75     VisibilityTestUtil.enableVisiblityLabels(conf);
76     // Not setting any SLG class. This means to use the default behavior.
77     conf.set("hbase.superuser", "admin");
78     TEST_UTIL.startMiniCluster(1);
79     SUPERUSER = User.createUserForTesting(conf, "admin", new String[] { "supergroup" });
80     TESTUSER = User.createUserForTesting(conf, "test", new String[] { });
81 
82     // Wait for the labels table to become available
83     TEST_UTIL.waitTableEnabled(LABELS_TABLE_NAME.getName(), 50000);
84 
85     // Set up for the test
86     SUPERUSER.runAs(new PrivilegedExceptionAction<Void>() {
87       public Void run() throws Exception {
88         try (Connection conn = ConnectionFactory.createConnection(conf)) {
89           VisibilityClient.addLabels(conn, new String[] { SECRET, CONFIDENTIAL });
90           VisibilityClient.setAuths(conn, new String[] { CONFIDENTIAL }, TESTUSER.getShortName());
91         } catch (Throwable t) {
92           throw new IOException(t);
93         }
94         return null;
95       }
96     });
97   }
98 
99   @Test
testDefaultScanLabelGeneratorStack()100   public void testDefaultScanLabelGeneratorStack() throws Exception {
101     final TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
102 
103     SUPERUSER.runAs(new PrivilegedExceptionAction<Void>() {
104       public Void run() throws Exception {
105         try (Connection connection = ConnectionFactory.createConnection(conf);
106              Table table = TEST_UTIL.createTable(tableName, CF)) {
107           Put put = new Put(ROW_1);
108           put.add(CF, Q1, HConstants.LATEST_TIMESTAMP, value1);
109           put.setCellVisibility(new CellVisibility(SECRET));
110           table.put(put);
111           put = new Put(ROW_1);
112           put.add(CF, Q2, HConstants.LATEST_TIMESTAMP, value2);
113           put.setCellVisibility(new CellVisibility(CONFIDENTIAL));
114           table.put(put);
115           put = new Put(ROW_1);
116           put.add(CF, Q3, HConstants.LATEST_TIMESTAMP, value3);
117           table.put(put);
118           return null;
119         }
120       }
121     });
122 
123     // Test that super user can see all the cells.
124     SUPERUSER.runAs(new PrivilegedExceptionAction<Void>() {
125       public Void run() throws Exception {
126         try (Connection connection = ConnectionFactory.createConnection(conf);
127              Table table = connection.getTable(tableName)) {
128           Scan s = new Scan();
129           ResultScanner scanner = table.getScanner(s);
130           Result[] next = scanner.next(1);
131 
132           // Test that super user can see all the cells.
133           assertTrue(next.length == 1);
134           CellScanner cellScanner = next[0].cellScanner();
135           cellScanner.advance();
136           Cell current = cellScanner.current();
137           assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(),
138               current.getRowLength(), ROW_1, 0, ROW_1.length));
139           assertTrue(Bytes.equals(current.getQualifier(), Q1));
140           assertTrue(Bytes.equals(current.getValue(), value1));
141           cellScanner.advance();
142           current = cellScanner.current();
143           assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(),
144               current.getRowLength(), ROW_1, 0, ROW_1.length));
145           assertTrue(Bytes.equals(current.getQualifier(), Q2));
146           assertTrue(Bytes.equals(current.getValue(), value2));
147           cellScanner.advance();
148           current = cellScanner.current();
149           assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(),
150               current.getRowLength(), ROW_1, 0, ROW_1.length));
151           assertTrue(Bytes.equals(current.getQualifier(), Q3));
152           assertTrue(Bytes.equals(current.getValue(), value3));
153 
154           return null;
155         }
156       }
157     });
158 
159     TESTUSER.runAs(new PrivilegedExceptionAction<Void>() {
160       public Void run() throws Exception {
161         try (Connection connection = ConnectionFactory.createConnection(conf);
162              Table table = connection.getTable(tableName)) {
163           // Test scan with no auth attribute
164           Scan s = new Scan();
165           ResultScanner scanner = table.getScanner(s);
166           Result[] next = scanner.next(1);
167 
168           assertTrue(next.length == 1);
169           CellScanner cellScanner = next[0].cellScanner();
170           cellScanner.advance();
171           Cell current = cellScanner.current();
172           // test user can see value2 (CONFIDENTIAL) and value3 (no label)
173           assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(),
174               current.getRowLength(), ROW_1, 0, ROW_1.length));
175           assertTrue(Bytes.equals(current.getQualifier(), Q2));
176           assertTrue(Bytes.equals(current.getValue(), value2));
177           cellScanner.advance();
178           current = cellScanner.current();
179           // test user can see value2 (CONFIDENTIAL) and value3 (no label)
180           assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(),
181               current.getRowLength(), ROW_1, 0, ROW_1.length));
182           assertTrue(Bytes.equals(current.getQualifier(), Q3));
183           assertTrue(Bytes.equals(current.getValue(), value3));
184 
185           // Test scan with correct auth attribute for test user
186           Scan s1 = new Scan();
187           // test user is entitled to 'CONFIDENTIAL'.
188           // If we set both labels in the scan, 'SECRET' will be dropped by the SLGs.
189           s1.setAuthorizations(new Authorizations(new String[] { SECRET, CONFIDENTIAL }));
190           ResultScanner scanner1 = table.getScanner(s1);
191           Result[] next1 = scanner1.next(1);
192 
193           assertTrue(next1.length == 1);
194           CellScanner cellScanner1 = next1[0].cellScanner();
195           cellScanner1.advance();
196           Cell current1 = cellScanner1.current();
197           // test user can see value2 (CONFIDENTIAL) and value3 (no label)
198           assertTrue(Bytes.equals(current1.getRowArray(), current1.getRowOffset(),
199             current1.getRowLength(), ROW_1, 0, ROW_1.length));
200           assertTrue(Bytes.equals(current1.getQualifier(), Q2));
201           assertTrue(Bytes.equals(current1.getValue(), value2));
202           cellScanner1.advance();
203           current1 = cellScanner1.current();
204           // test user can see value2 (CONFIDENTIAL) and value3 (no label)
205           assertTrue(Bytes.equals(current1.getRowArray(), current1.getRowOffset(),
206             current1.getRowLength(), ROW_1, 0, ROW_1.length));
207           assertTrue(Bytes.equals(current1.getQualifier(), Q3));
208           assertTrue(Bytes.equals(current1.getValue(), value3));
209 
210           // Test scan with incorrect auth attribute for test user
211           Scan s2 = new Scan();
212           // test user is entitled to 'CONFIDENTIAL'.
213           // If we set 'SECRET', it will be dropped by the SLGs.
214           s2.setAuthorizations(new Authorizations(new String[] { SECRET }));
215           ResultScanner scanner2 = table.getScanner(s2);
216           Result next2 = scanner2.next();
217           CellScanner cellScanner2 = next2.cellScanner();
218           cellScanner2.advance();
219           Cell current2 = cellScanner2.current();
220           // This scan will only see value3 (no label)
221           assertTrue(Bytes.equals(current2.getRowArray(), current2.getRowOffset(),
222             current2.getRowLength(), ROW_1, 0, ROW_1.length));
223           assertTrue(Bytes.equals(current2.getQualifier(), Q3));
224           assertTrue(Bytes.equals(current2.getValue(), value3));
225 
226           assertFalse(cellScanner2.advance());
227 
228           return null;
229         }
230       }
231     });
232 
233   }
234 
235   @AfterClass
tearDownAfterClass()236   public static void tearDownAfterClass() throws Exception {
237     TEST_UTIL.shutdownMiniCluster();
238   }
239 }
240