001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.security.visibility;
019
020import static org.apache.hadoop.hbase.security.visibility.VisibilityConstants.LABELS_TABLE_NAME;
021import static org.junit.Assert.assertFalse;
022import static org.junit.Assert.assertTrue;
023
024import java.io.IOException;
025import java.security.PrivilegedExceptionAction;
026import org.apache.hadoop.conf.Configuration;
027import org.apache.hadoop.hbase.Cell;
028import org.apache.hadoop.hbase.CellScanner;
029import org.apache.hadoop.hbase.HBaseClassTestRule;
030import org.apache.hadoop.hbase.HBaseTestingUtility;
031import org.apache.hadoop.hbase.HConstants;
032import org.apache.hadoop.hbase.TableName;
033import org.apache.hadoop.hbase.client.Connection;
034import org.apache.hadoop.hbase.client.ConnectionFactory;
035import org.apache.hadoop.hbase.client.Put;
036import org.apache.hadoop.hbase.client.Result;
037import org.apache.hadoop.hbase.client.ResultScanner;
038import org.apache.hadoop.hbase.client.Scan;
039import org.apache.hadoop.hbase.client.Table;
040import org.apache.hadoop.hbase.security.User;
041import org.apache.hadoop.hbase.testclassification.MediumTests;
042import org.apache.hadoop.hbase.testclassification.SecurityTests;
043import org.apache.hadoop.hbase.util.Bytes;
044import org.junit.AfterClass;
045import org.junit.BeforeClass;
046import org.junit.ClassRule;
047import org.junit.Rule;
048import org.junit.Test;
049import org.junit.experimental.categories.Category;
050import org.junit.rules.TestName;
051
052@Category({ SecurityTests.class, MediumTests.class })
053public class TestDefaultScanLabelGeneratorStack {
054
055  @ClassRule
056  public static final HBaseClassTestRule CLASS_RULE =
057    HBaseClassTestRule.forClass(TestDefaultScanLabelGeneratorStack.class);
058
059  public static final String CONFIDENTIAL = "confidential";
060  private static final String SECRET = "secret";
061  public static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
062  private static final byte[] ROW_1 = Bytes.toBytes("row1");
063  private final static byte[] CF = Bytes.toBytes("f");
064  private final static byte[] Q1 = Bytes.toBytes("q1");
065  private final static byte[] Q2 = Bytes.toBytes("q2");
066  private final static byte[] Q3 = Bytes.toBytes("q3");
067  private final static byte[] value1 = Bytes.toBytes("value1");
068  private final static byte[] value2 = Bytes.toBytes("value2");
069  private final static byte[] value3 = Bytes.toBytes("value3");
070  public static Configuration conf;
071
072  @Rule
073  public final TestName TEST_NAME = new TestName();
074  public static User SUPERUSER;
075  public static User TESTUSER;
076
077  @BeforeClass
078  public static void setupBeforeClass() throws Exception {
079    // setup configuration
080    conf = TEST_UTIL.getConfiguration();
081    VisibilityTestUtil.enableVisiblityLabels(conf);
082    // Not setting any SLG class. This means to use the default behavior.
083    conf.set("hbase.superuser", "admin");
084    TEST_UTIL.startMiniCluster(1);
085    SUPERUSER = User.createUserForTesting(conf, "admin", new String[] { "supergroup" });
086    TESTUSER = User.createUserForTesting(conf, "test", new String[] {});
087
088    // Wait for the labels table to become available
089    TEST_UTIL.waitTableEnabled(LABELS_TABLE_NAME.getName(), 50000);
090
091    // Set up for the test
092    SUPERUSER.runAs(new PrivilegedExceptionAction<Void>() {
093      @Override
094      public Void run() throws Exception {
095        try (Connection conn = ConnectionFactory.createConnection(conf)) {
096          VisibilityClient.addLabels(conn, new String[] { SECRET, CONFIDENTIAL });
097          VisibilityClient.setAuths(conn, new String[] { CONFIDENTIAL }, TESTUSER.getShortName());
098        } catch (Throwable t) {
099          throw new IOException(t);
100        }
101        return null;
102      }
103    });
104  }
105
106  @Test
107  public void testDefaultScanLabelGeneratorStack() throws Exception {
108    final TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
109
110    SUPERUSER.runAs(new PrivilegedExceptionAction<Void>() {
111      @Override
112      public Void run() throws Exception {
113        try (Connection connection = ConnectionFactory.createConnection(conf);
114          Table table = TEST_UTIL.createTable(tableName, CF)) {
115          Put put = new Put(ROW_1);
116          put.addColumn(CF, Q1, HConstants.LATEST_TIMESTAMP, value1);
117          put.setCellVisibility(new CellVisibility(SECRET));
118          table.put(put);
119          put = new Put(ROW_1);
120          put.addColumn(CF, Q2, HConstants.LATEST_TIMESTAMP, value2);
121          put.setCellVisibility(new CellVisibility(CONFIDENTIAL));
122          table.put(put);
123          put = new Put(ROW_1);
124          put.addColumn(CF, Q3, HConstants.LATEST_TIMESTAMP, value3);
125          table.put(put);
126          return null;
127        }
128      }
129    });
130
131    // Test that super user can see all the cells.
132    SUPERUSER.runAs(new PrivilegedExceptionAction<Void>() {
133      @Override
134      public Void run() throws Exception {
135        try (Connection connection = ConnectionFactory.createConnection(conf);
136          Table table = connection.getTable(tableName)) {
137          Result[] next = getResult(table, new Scan());
138
139          // Test that super user can see all the cells.
140          CellScanner cellScanner = next[0].cellScanner();
141          cellScanner.advance();
142          Cell 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.getQualifierArray(), current.getQualifierOffset(),
146            current.getQualifierLength(), Q1, 0, Q1.length));
147          assertTrue(Bytes.equals(current.getValueArray(), current.getValueOffset(),
148            current.getValueLength(), value1, 0, value1.length));
149          cellScanner.advance();
150          current = cellScanner.current();
151          assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(),
152            current.getRowLength(), ROW_1, 0, ROW_1.length));
153          assertTrue(Bytes.equals(current.getQualifierArray(), current.getQualifierOffset(),
154            current.getQualifierLength(), Q2, 0, Q2.length));
155          assertTrue(Bytes.equals(current.getValueArray(), current.getValueOffset(),
156            current.getValueLength(), value2, 0, value2.length));
157          cellScanner.advance();
158          current = cellScanner.current();
159          assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(),
160            current.getRowLength(), ROW_1, 0, ROW_1.length));
161          assertTrue(Bytes.equals(current.getQualifierArray(), current.getQualifierOffset(),
162            current.getQualifierLength(), Q3, 0, Q3.length));
163          assertTrue(Bytes.equals(current.getValueArray(), current.getValueOffset(),
164            current.getValueLength(), value3, 0, value3.length));
165
166          return null;
167        }
168      }
169    });
170
171    TESTUSER.runAs(new PrivilegedExceptionAction<Void>() {
172      @Override
173      public Void run() throws Exception {
174        try (Connection connection = ConnectionFactory.createConnection(conf);
175          Table table = connection.getTable(tableName)) {
176          // Test scan with no auth attribute
177          Result[] next = getResult(table, new Scan());
178          CellScanner cellScanner = next[0].cellScanner();
179          cellScanner.advance();
180          Cell current = cellScanner.current();
181          // test user can see value2 (CONFIDENTIAL) and value3 (no label)
182          assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(),
183            current.getRowLength(), ROW_1, 0, ROW_1.length));
184          assertTrue(Bytes.equals(current.getQualifierArray(), current.getQualifierOffset(),
185            current.getQualifierLength(), Q2, 0, Q2.length));
186          assertTrue(Bytes.equals(current.getValueArray(), current.getValueOffset(),
187            current.getValueLength(), value2, 0, value2.length));
188          cellScanner.advance();
189          current = cellScanner.current();
190          // test user can see value2 (CONFIDENTIAL) and value3 (no label)
191          assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(),
192            current.getRowLength(), ROW_1, 0, ROW_1.length));
193          assertTrue(Bytes.equals(current.getQualifierArray(), current.getQualifierOffset(),
194            current.getQualifierLength(), Q3, 0, Q3.length));
195          assertTrue(Bytes.equals(current.getValueArray(), current.getValueOffset(),
196            current.getValueLength(), value3, 0, value3.length));
197
198          // Test scan with correct auth attribute for test user
199          Scan s1 = new Scan();
200          // test user is entitled to 'CONFIDENTIAL'.
201          // If we set both labels in the scan, 'SECRET' will be dropped by the SLGs.
202          s1.setAuthorizations(new Authorizations(new String[] { SECRET, CONFIDENTIAL }));
203          ResultScanner scanner1 = table.getScanner(s1);
204          Result[] next1 = scanner1.next(1);
205
206          assertTrue(next1.length == 1);
207          CellScanner cellScanner1 = next1[0].cellScanner();
208          cellScanner1.advance();
209          Cell current1 = cellScanner1.current();
210          // test user can see value2 (CONFIDENTIAL) and value3 (no label)
211          assertTrue(Bytes.equals(current1.getRowArray(), current1.getRowOffset(),
212            current1.getRowLength(), ROW_1, 0, ROW_1.length));
213          assertTrue(Bytes.equals(current1.getQualifierArray(), current1.getQualifierOffset(),
214            current1.getQualifierLength(), Q2, 0, Q2.length));
215          assertTrue(Bytes.equals(current1.getValueArray(), current1.getValueOffset(),
216            current1.getValueLength(), value2, 0, value2.length));
217          cellScanner1.advance();
218          current1 = cellScanner1.current();
219          // test user can see value2 (CONFIDENTIAL) and value3 (no label)
220          assertTrue(Bytes.equals(current1.getRowArray(), current1.getRowOffset(),
221            current1.getRowLength(), ROW_1, 0, ROW_1.length));
222          assertTrue(Bytes.equals(current1.getQualifierArray(), current1.getQualifierOffset(),
223            current1.getQualifierLength(), Q3, 0, Q3.length));
224          assertTrue(Bytes.equals(current1.getValueArray(), current1.getValueOffset(),
225            current1.getValueLength(), value3, 0, value3.length));
226
227          // Test scan with incorrect auth attribute for test user
228          Scan s2 = new Scan();
229          // test user is entitled to 'CONFIDENTIAL'.
230          // If we set 'SECRET', it will be dropped by the SLGs.
231          s2.setAuthorizations(new Authorizations(new String[] { SECRET }));
232          ResultScanner scanner2 = table.getScanner(s2);
233          Result next2 = scanner2.next();
234          CellScanner cellScanner2 = next2.cellScanner();
235          cellScanner2.advance();
236          Cell current2 = cellScanner2.current();
237          // This scan will only see value3 (no label)
238          assertTrue(Bytes.equals(current2.getRowArray(), current2.getRowOffset(),
239            current2.getRowLength(), ROW_1, 0, ROW_1.length));
240          assertTrue(Bytes.equals(current2.getQualifierArray(), current2.getQualifierOffset(),
241            current2.getQualifierLength(), Q3, 0, Q3.length));
242          assertTrue(Bytes.equals(current2.getValueArray(), current2.getValueOffset(),
243            current2.getValueLength(), value3, 0, value3.length));
244
245          assertFalse(cellScanner2.advance());
246
247          return null;
248        }
249      }
250    });
251
252  }
253
254  private static Result[] getResult(Table table, Scan scan) throws IOException {
255    ResultScanner scanner = table.getScanner(scan);
256    Result[] next = scanner.next(1);
257    assertTrue(next.length == 1);
258    return next;
259  }
260
261  @AfterClass
262  public static void tearDownAfterClass() throws Exception {
263    TEST_UTIL.shutdownMiniCluster();
264  }
265}