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