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.jupiter.api.Assertions.assertFalse; 022import static org.junit.jupiter.api.Assertions.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.HBaseTestingUtil; 030import org.apache.hadoop.hbase.HConstants; 031import org.apache.hadoop.hbase.TableName; 032import org.apache.hadoop.hbase.TableNameTestExtension; 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.jupiter.api.AfterAll; 045import org.junit.jupiter.api.BeforeAll; 046import org.junit.jupiter.api.Tag; 047import org.junit.jupiter.api.Test; 048import org.junit.jupiter.api.TestInfo; 049 050@Tag(SecurityTests.TAG) 051@Tag(MediumTests.TAG) 052public class TestDefaultScanLabelGeneratorStack { 053 054 public static final String CONFIDENTIAL = "confidential"; 055 private static final String SECRET = "secret"; 056 public static final HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil(); 057 private static final byte[] ROW_1 = Bytes.toBytes("row1"); 058 private final static byte[] CF = Bytes.toBytes("f"); 059 private final static byte[] Q1 = Bytes.toBytes("q1"); 060 private final static byte[] Q2 = Bytes.toBytes("q2"); 061 private final static byte[] Q3 = Bytes.toBytes("q3"); 062 private final static byte[] value1 = Bytes.toBytes("value1"); 063 private final static byte[] value2 = Bytes.toBytes("value2"); 064 private final static byte[] value3 = Bytes.toBytes("value3"); 065 public static Configuration conf; 066 067 public static User SUPERUSER; 068 public static User TESTUSER; 069 070 @BeforeAll 071 public static void setupBeforeClass() throws Exception { 072 // setup configuration 073 conf = TEST_UTIL.getConfiguration(); 074 VisibilityTestUtil.enableVisiblityLabels(conf); 075 // Not setting any SLG class. This means to use the default behavior. 076 conf.set("hbase.superuser", "admin"); 077 TEST_UTIL.startMiniCluster(1); 078 SUPERUSER = User.createUserForTesting(conf, "admin", new String[] { "supergroup" }); 079 TESTUSER = User.createUserForTesting(conf, "test", new String[] {}); 080 081 // Wait for the labels table to become available 082 TEST_UTIL.waitTableEnabled(LABELS_TABLE_NAME.getName(), 50000); 083 084 // Set up for the test 085 SUPERUSER.runAs(new PrivilegedExceptionAction<Void>() { 086 @Override 087 public Void run() throws Exception { 088 try (Connection conn = ConnectionFactory.createConnection(conf)) { 089 VisibilityClient.addLabels(conn, new String[] { SECRET, CONFIDENTIAL }); 090 VisibilityClient.setAuths(conn, new String[] { CONFIDENTIAL }, TESTUSER.getShortName()); 091 } catch (Throwable t) { 092 throw new IOException(t); 093 } 094 return null; 095 } 096 }); 097 } 098 099 @Test 100 public void testDefaultScanLabelGeneratorStack(TestInfo testInfo) throws Exception { 101 final TableName tableName = TableName 102 .valueOf(TableNameTestExtension.cleanUpTestName(testInfo.getTestMethod().get().getName())); 103 104 SUPERUSER.runAs(new PrivilegedExceptionAction<Void>() { 105 @Override 106 public Void run() throws Exception { 107 try (Connection connection = ConnectionFactory.createConnection(conf); 108 Table table = TEST_UTIL.createTable(tableName, CF)) { 109 Put put = new Put(ROW_1); 110 put.addColumn(CF, Q1, HConstants.LATEST_TIMESTAMP, value1); 111 put.setCellVisibility(new CellVisibility(SECRET)); 112 table.put(put); 113 put = new Put(ROW_1); 114 put.addColumn(CF, Q2, HConstants.LATEST_TIMESTAMP, value2); 115 put.setCellVisibility(new CellVisibility(CONFIDENTIAL)); 116 table.put(put); 117 put = new Put(ROW_1); 118 put.addColumn(CF, Q3, HConstants.LATEST_TIMESTAMP, value3); 119 table.put(put); 120 return null; 121 } 122 } 123 }); 124 125 // Test that super user can see all the cells. 126 SUPERUSER.runAs(new PrivilegedExceptionAction<Void>() { 127 @Override 128 public Void run() throws Exception { 129 try (Connection connection = ConnectionFactory.createConnection(conf); 130 Table table = connection.getTable(tableName)) { 131 Result[] next = getResult(table, new Scan()); 132 133 // Test that super user can see all the cells. 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.getQualifierArray(), current.getQualifierOffset(), 140 current.getQualifierLength(), Q1, 0, Q1.length)); 141 assertTrue(Bytes.equals(current.getValueArray(), current.getValueOffset(), 142 current.getValueLength(), value1, 0, value1.length)); 143 cellScanner.advance(); 144 current = cellScanner.current(); 145 assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), 146 current.getRowLength(), ROW_1, 0, ROW_1.length)); 147 assertTrue(Bytes.equals(current.getQualifierArray(), current.getQualifierOffset(), 148 current.getQualifierLength(), Q2, 0, Q2.length)); 149 assertTrue(Bytes.equals(current.getValueArray(), current.getValueOffset(), 150 current.getValueLength(), value2, 0, value2.length)); 151 cellScanner.advance(); 152 current = cellScanner.current(); 153 assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), 154 current.getRowLength(), ROW_1, 0, ROW_1.length)); 155 assertTrue(Bytes.equals(current.getQualifierArray(), current.getQualifierOffset(), 156 current.getQualifierLength(), Q3, 0, Q3.length)); 157 assertTrue(Bytes.equals(current.getValueArray(), current.getValueOffset(), 158 current.getValueLength(), value3, 0, value3.length)); 159 160 return null; 161 } 162 } 163 }); 164 165 TESTUSER.runAs(new PrivilegedExceptionAction<Void>() { 166 @Override 167 public Void run() throws Exception { 168 try (Connection connection = ConnectionFactory.createConnection(conf); 169 Table table = connection.getTable(tableName)) { 170 // Test scan with no auth attribute 171 Result[] next = getResult(table, new Scan()); 172 CellScanner cellScanner = next[0].cellScanner(); 173 cellScanner.advance(); 174 Cell current = cellScanner.current(); 175 // test user can see value2 (CONFIDENTIAL) and value3 (no label) 176 assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), 177 current.getRowLength(), ROW_1, 0, ROW_1.length)); 178 assertTrue(Bytes.equals(current.getQualifierArray(), current.getQualifierOffset(), 179 current.getQualifierLength(), Q2, 0, Q2.length)); 180 assertTrue(Bytes.equals(current.getValueArray(), current.getValueOffset(), 181 current.getValueLength(), value2, 0, value2.length)); 182 cellScanner.advance(); 183 current = cellScanner.current(); 184 // test user can see value2 (CONFIDENTIAL) and value3 (no label) 185 assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), 186 current.getRowLength(), ROW_1, 0, ROW_1.length)); 187 assertTrue(Bytes.equals(current.getQualifierArray(), current.getQualifierOffset(), 188 current.getQualifierLength(), Q3, 0, Q3.length)); 189 assertTrue(Bytes.equals(current.getValueArray(), current.getValueOffset(), 190 current.getValueLength(), value3, 0, value3.length)); 191 192 // Test scan with correct auth attribute for test user 193 Scan s1 = new Scan(); 194 // test user is entitled to 'CONFIDENTIAL'. 195 // If we set both labels in the scan, 'SECRET' will be dropped by the SLGs. 196 s1.setAuthorizations(new Authorizations(new String[] { SECRET, CONFIDENTIAL })); 197 ResultScanner scanner1 = table.getScanner(s1); 198 Result[] next1 = scanner1.next(1); 199 200 assertTrue(next1.length == 1); 201 CellScanner cellScanner1 = next1[0].cellScanner(); 202 cellScanner1.advance(); 203 Cell 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.getQualifierArray(), current1.getQualifierOffset(), 208 current1.getQualifierLength(), Q2, 0, Q2.length)); 209 assertTrue(Bytes.equals(current1.getValueArray(), current1.getValueOffset(), 210 current1.getValueLength(), value2, 0, value2.length)); 211 cellScanner1.advance(); 212 current1 = cellScanner1.current(); 213 // test user can see value2 (CONFIDENTIAL) and value3 (no label) 214 assertTrue(Bytes.equals(current1.getRowArray(), current1.getRowOffset(), 215 current1.getRowLength(), ROW_1, 0, ROW_1.length)); 216 assertTrue(Bytes.equals(current1.getQualifierArray(), current1.getQualifierOffset(), 217 current1.getQualifierLength(), Q3, 0, Q3.length)); 218 assertTrue(Bytes.equals(current1.getValueArray(), current1.getValueOffset(), 219 current1.getValueLength(), value3, 0, value3.length)); 220 221 // Test scan with incorrect auth attribute for test user 222 Scan s2 = new Scan(); 223 // test user is entitled to 'CONFIDENTIAL'. 224 // If we set 'SECRET', it will be dropped by the SLGs. 225 s2.setAuthorizations(new Authorizations(new String[] { SECRET })); 226 ResultScanner scanner2 = table.getScanner(s2); 227 Result next2 = scanner2.next(); 228 CellScanner cellScanner2 = next2.cellScanner(); 229 cellScanner2.advance(); 230 Cell current2 = cellScanner2.current(); 231 // This scan will only see value3 (no label) 232 assertTrue(Bytes.equals(current2.getRowArray(), current2.getRowOffset(), 233 current2.getRowLength(), ROW_1, 0, ROW_1.length)); 234 assertTrue(Bytes.equals(current2.getQualifierArray(), current2.getQualifierOffset(), 235 current2.getQualifierLength(), Q3, 0, Q3.length)); 236 assertTrue(Bytes.equals(current2.getValueArray(), current2.getValueOffset(), 237 current2.getValueLength(), value3, 0, value3.length)); 238 239 assertFalse(cellScanner2.advance()); 240 241 return null; 242 } 243 } 244 }); 245 246 } 247 248 private static Result[] getResult(Table table, Scan scan) throws IOException { 249 ResultScanner scanner = table.getScanner(scan); 250 Result[] next = scanner.next(1); 251 assertTrue(next.length == 1); 252 return next; 253 } 254 255 @AfterAll 256 public static void tearDownAfterClass() throws Exception { 257 TEST_UTIL.shutdownMiniCluster(); 258 } 259}