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