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.assertTrue; 022 023import java.io.IOException; 024import java.security.PrivilegedExceptionAction; 025import java.util.ArrayList; 026import java.util.List; 027import org.apache.hadoop.conf.Configuration; 028import org.apache.hadoop.hbase.Cell; 029import org.apache.hadoop.hbase.CellScanner; 030import org.apache.hadoop.hbase.HBaseTestingUtil; 031import org.apache.hadoop.hbase.HConstants; 032import org.apache.hadoop.hbase.TableName; 033import org.apache.hadoop.hbase.TableNameTestExtension; 034import org.apache.hadoop.hbase.client.Connection; 035import org.apache.hadoop.hbase.client.ConnectionFactory; 036import org.apache.hadoop.hbase.client.Delete; 037import org.apache.hadoop.hbase.client.Put; 038import org.apache.hadoop.hbase.client.Result; 039import org.apache.hadoop.hbase.client.ResultScanner; 040import org.apache.hadoop.hbase.client.Scan; 041import org.apache.hadoop.hbase.client.Table; 042import org.apache.hadoop.hbase.security.User; 043import org.apache.hadoop.hbase.util.Bytes; 044import org.junit.jupiter.api.AfterAll; 045import org.junit.jupiter.api.BeforeAll; 046import org.junit.jupiter.api.Test; 047import org.junit.jupiter.api.TestInfo; 048 049import org.apache.hadoop.hbase.shaded.protobuf.generated.VisibilityLabelsProtos.VisibilityLabelsResponse; 050 051/** 052 * Tests visibility labels with deletes 053 */ 054public abstract class VisibilityLabelsWithDeletesTestBase { 055 056 protected static final String TOPSECRET = "TOPSECRET"; 057 protected static final String PUBLIC = "PUBLIC"; 058 protected static final String PRIVATE = "PRIVATE"; 059 protected static final String CONFIDENTIAL = "CONFIDENTIAL"; 060 protected static final String SECRET = "SECRET"; 061 protected static final HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil(); 062 protected static final byte[] row1 = Bytes.toBytes("row1"); 063 protected static final byte[] row2 = Bytes.toBytes("row2"); 064 protected final static byte[] fam = Bytes.toBytes("info"); 065 protected final static byte[] qual = Bytes.toBytes("qual"); 066 protected final static byte[] qual1 = Bytes.toBytes("qual1"); 067 protected final static byte[] qual2 = Bytes.toBytes("qual2"); 068 protected final static byte[] value = Bytes.toBytes("value"); 069 protected final static byte[] value1 = Bytes.toBytes("value1"); 070 protected static Configuration conf; 071 072 protected static User SUPERUSER; 073 074 @BeforeAll 075 public static void setupBeforeClass() throws Exception { 076 // setup configuration 077 conf = TEST_UTIL.getConfiguration(); 078 VisibilityTestUtil.enableVisiblityLabels(conf); 079 conf.setClass(VisibilityUtils.VISIBILITY_LABEL_GENERATOR_CLASS, SimpleScanLabelGenerator.class, 080 ScanLabelGenerator.class); 081 conf.set("hbase.superuser", "admin"); 082 TEST_UTIL.startMiniCluster(2); 083 SUPERUSER = User.createUserForTesting(conf, "admin", new String[] { "supergroup" }); 084 085 // Wait for the labels table to become available 086 TEST_UTIL.waitTableEnabled(LABELS_TABLE_NAME.getName(), 50000); 087 addLabels(); 088 } 089 090 @AfterAll 091 public static void tearDownAfterClass() throws Exception { 092 TEST_UTIL.shutdownMiniCluster(); 093 } 094 095 public static void addLabels() throws Exception { 096 PrivilegedExceptionAction<VisibilityLabelsResponse> action = 097 new PrivilegedExceptionAction<VisibilityLabelsResponse>() { 098 @Override 099 public VisibilityLabelsResponse run() throws Exception { 100 String[] labels = { SECRET, TOPSECRET, CONFIDENTIAL, PUBLIC, PRIVATE }; 101 try (Connection conn = ConnectionFactory.createConnection(conf)) { 102 VisibilityClient.addLabels(conn, labels); 103 } catch (Throwable t) { 104 throw new IOException(t); 105 } 106 return null; 107 } 108 }; 109 SUPERUSER.runAs(action); 110 } 111 112 protected abstract Table createTable(byte[] fam, TestInfo testInfo) throws IOException; 113 114 protected final void setAuths() throws IOException, InterruptedException { 115 PrivilegedExceptionAction<VisibilityLabelsResponse> action = 116 new PrivilegedExceptionAction<VisibilityLabelsResponse>() { 117 @Override 118 public VisibilityLabelsResponse run() throws Exception { 119 try (Connection conn = ConnectionFactory.createConnection(conf)) { 120 return VisibilityClient.setAuths(conn, 121 new String[] { CONFIDENTIAL, PRIVATE, SECRET, TOPSECRET }, SUPERUSER.getShortName()); 122 } catch (Throwable e) { 123 } 124 return null; 125 } 126 }; 127 SUPERUSER.runAs(action); 128 } 129 130 private Table createTableAndWriteDataWithLabels(TestInfo testInfo, String... labelExps) 131 throws Exception { 132 Table table = createTable(fam, testInfo); 133 int i = 1; 134 List<Put> puts = new ArrayList<>(labelExps.length); 135 for (String labelExp : labelExps) { 136 Put put = new Put(Bytes.toBytes("row" + i)); 137 put.addColumn(fam, qual, HConstants.LATEST_TIMESTAMP, value); 138 put.setCellVisibility(new CellVisibility(labelExp)); 139 puts.add(put); 140 table.put(put); 141 i++; 142 } 143 // table.put(puts); 144 return table; 145 } 146 147 private Table createTableAndWriteDataWithLabels(long[] timestamp, TestInfo testInfo, 148 String... labelExps) throws Exception { 149 Table table = createTable(fam, testInfo); 150 int i = 1; 151 List<Put> puts = new ArrayList<>(labelExps.length); 152 for (String labelExp : labelExps) { 153 Put put = new Put(Bytes.toBytes("row" + i)); 154 put.addColumn(fam, qual, timestamp[i - 1], value); 155 put.setCellVisibility(new CellVisibility(labelExp)); 156 puts.add(put); 157 table.put(put); 158 TEST_UTIL.getAdmin().flush(table.getName()); 159 i++; 160 } 161 return table; 162 } 163 164 @Test 165 public void testVisibilityLabelsWithDeleteColumns(TestInfo testInfo) throws Throwable { 166 setAuths(); 167 final TableName tableName = TableName 168 .valueOf(TableNameTestExtension.cleanUpTestName(testInfo.getTestMethod().get().getName())); 169 170 try ( 171 Table table = createTableAndWriteDataWithLabels(testInfo, SECRET + "&" + TOPSECRET, SECRET)) { 172 PrivilegedExceptionAction<Void> actiona = new PrivilegedExceptionAction<Void>() { 173 @Override 174 public Void run() throws Exception { 175 try (Connection connection = ConnectionFactory.createConnection(conf); 176 Table table = connection.getTable(tableName)) { 177 Delete d = new Delete(row1); 178 d.setCellVisibility(new CellVisibility(TOPSECRET + "&" + SECRET)); 179 d.addColumns(fam, qual); 180 table.delete(d); 181 } catch (Throwable t) { 182 throw new IOException(t); 183 } 184 return null; 185 } 186 }; 187 SUPERUSER.runAs(actiona); 188 189 TEST_UTIL.getAdmin().flush(tableName); 190 Scan s = new Scan(); 191 s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL)); 192 ResultScanner scanner = table.getScanner(s); 193 Result[] next = scanner.next(3); 194 assertTrue(next.length == 1); 195 CellScanner cellScanner = next[0].cellScanner(); 196 cellScanner.advance(); 197 Cell current = cellScanner.current(); 198 assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(), 199 row2, 0, row2.length)); 200 201 } 202 } 203 204 @Test 205 public void testVisibilityLabelsWithDeleteFamily(TestInfo testInfo) throws Exception { 206 setAuths(); 207 final TableName tableName = TableName 208 .valueOf(TableNameTestExtension.cleanUpTestName(testInfo.getTestMethod().get().getName())); 209 try (Table table = 210 createTableAndWriteDataWithLabels(testInfo, SECRET, CONFIDENTIAL + "|" + TOPSECRET)) { 211 PrivilegedExceptionAction<Void> actiona = new PrivilegedExceptionAction<Void>() { 212 @Override 213 public Void run() throws Exception { 214 try (Connection connection = ConnectionFactory.createConnection(conf); 215 Table table = connection.getTable(tableName)) { 216 Delete d = new Delete(row2); 217 d.setCellVisibility(new CellVisibility(TOPSECRET + "|" + CONFIDENTIAL)); 218 d.addFamily(fam); 219 table.delete(d); 220 } catch (Throwable t) { 221 throw new IOException(t); 222 } 223 return null; 224 } 225 }; 226 SUPERUSER.runAs(actiona); 227 228 TEST_UTIL.getAdmin().flush(tableName); 229 Scan s = new Scan(); 230 s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL)); 231 ResultScanner scanner = table.getScanner(s); 232 Result[] next = scanner.next(3); 233 assertTrue(next.length == 1); 234 CellScanner cellScanner = next[0].cellScanner(); 235 cellScanner.advance(); 236 Cell current = cellScanner.current(); 237 assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(), 238 row1, 0, row1.length)); 239 } 240 } 241 242 @Test 243 public void testVisibilityLabelsWithDeleteFamilyVersion(TestInfo testInfo) throws Exception { 244 setAuths(); 245 final TableName tableName = TableName 246 .valueOf(TableNameTestExtension.cleanUpTestName(testInfo.getTestMethod().get().getName())); 247 long[] ts = new long[] { 123L, 125L }; 248 try (Table table = 249 createTableAndWriteDataWithLabels(ts, testInfo, CONFIDENTIAL + "|" + TOPSECRET, SECRET)) { 250 PrivilegedExceptionAction<Void> actiona = new PrivilegedExceptionAction<Void>() { 251 @Override 252 public Void run() throws Exception { 253 try (Connection connection = ConnectionFactory.createConnection(conf); 254 Table table = connection.getTable(tableName)) { 255 Delete d = new Delete(row1); 256 d.setCellVisibility(new CellVisibility(TOPSECRET + "|" + CONFIDENTIAL)); 257 d.addFamilyVersion(fam, 123L); 258 table.delete(d); 259 } catch (Throwable t) { 260 throw new IOException(t); 261 } 262 return null; 263 } 264 }; 265 SUPERUSER.runAs(actiona); 266 267 TEST_UTIL.getAdmin().flush(tableName); 268 Scan s = new Scan(); 269 s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL)); 270 ResultScanner scanner = table.getScanner(s); 271 Result[] next = scanner.next(3); 272 assertTrue(next.length == 1); 273 CellScanner cellScanner = next[0].cellScanner(); 274 cellScanner.advance(); 275 Cell current = cellScanner.current(); 276 assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(), 277 row2, 0, row2.length)); 278 } 279 } 280 281 @Test 282 public void testVisibilityLabelsWithDeleteColumnExactVersion(TestInfo testInfo) throws Exception { 283 setAuths(); 284 final TableName tableName = TableName 285 .valueOf(TableNameTestExtension.cleanUpTestName(testInfo.getTestMethod().get().getName())); 286 long[] ts = new long[] { 123L, 125L }; 287 try (Table table = 288 createTableAndWriteDataWithLabels(ts, testInfo, CONFIDENTIAL + "|" + TOPSECRET, SECRET)) { 289 PrivilegedExceptionAction<Void> actiona = new PrivilegedExceptionAction<Void>() { 290 @Override 291 public Void run() throws Exception { 292 try (Connection connection = ConnectionFactory.createConnection(conf); 293 Table table = connection.getTable(tableName)) { 294 Delete d = new Delete(row1); 295 d.setCellVisibility(new CellVisibility(TOPSECRET + "|" + CONFIDENTIAL)); 296 d.addColumn(fam, qual, 123L); 297 table.delete(d); 298 } catch (Throwable t) { 299 throw new IOException(t); 300 } 301 return null; 302 } 303 }; 304 SUPERUSER.runAs(actiona); 305 306 TEST_UTIL.getAdmin().flush(tableName); 307 Scan s = new Scan(); 308 s.setAuthorizations(new Authorizations(SECRET, PRIVATE, CONFIDENTIAL)); 309 ResultScanner scanner = table.getScanner(s); 310 Result[] next = scanner.next(3); 311 assertTrue(next.length == 1); 312 CellScanner cellScanner = next[0].cellScanner(); 313 cellScanner.advance(); 314 Cell current = cellScanner.current(); 315 assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(), current.getRowLength(), 316 row2, 0, row2.length)); 317 } 318 } 319}