View Javadoc

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