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}