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