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 org.apache.hadoop.conf.Configuration; 026import org.apache.hadoop.hbase.HBaseTestingUtil; 027import org.apache.hadoop.hbase.HConstants; 028import org.apache.hadoop.hbase.TableName; 029import org.apache.hadoop.hbase.client.Admin; 030import org.apache.hadoop.hbase.client.Append; 031import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder; 032import org.apache.hadoop.hbase.client.Connection; 033import org.apache.hadoop.hbase.client.ConnectionFactory; 034import org.apache.hadoop.hbase.client.Put; 035import org.apache.hadoop.hbase.client.Table; 036import org.apache.hadoop.hbase.client.TableDescriptor; 037import org.apache.hadoop.hbase.client.TableDescriptorBuilder; 038import org.apache.hadoop.hbase.security.User; 039import org.apache.hadoop.hbase.testclassification.MediumTests; 040import org.apache.hadoop.hbase.testclassification.SecurityTests; 041import org.apache.hadoop.hbase.util.Bytes; 042import org.junit.jupiter.api.AfterAll; 043import org.junit.jupiter.api.Assertions; 044import org.junit.jupiter.api.BeforeAll; 045import org.junit.jupiter.api.Tag; 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 * Test visibility by setting 'hbase.security.visibility.mutations.checkauths' to true 053 */ 054@Tag(SecurityTests.TAG) 055@Tag(MediumTests.TAG) 056public class TestVisibilityWithCheckAuths { 057 058 private static final String TOPSECRET = "TOPSECRET"; 059 private static final String PUBLIC = "PUBLIC"; 060 public static final HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil(); 061 private static final byte[] row1 = Bytes.toBytes("row1"); 062 private final static byte[] fam = Bytes.toBytes("info"); 063 private final static byte[] qual = Bytes.toBytes("qual"); 064 private final static byte[] value = Bytes.toBytes("value"); 065 public static Configuration conf; 066 067 public static User SUPERUSER; 068 public static User USER; 069 070 @BeforeAll 071 public static void setupBeforeClass() throws Exception { 072 // setup configuration 073 conf = TEST_UTIL.getConfiguration(); 074 VisibilityTestUtil.enableVisiblityLabels(conf); 075 conf.setBoolean(VisibilityConstants.CHECK_AUTHS_FOR_MUTATION, true); 076 conf.setClass(VisibilityUtils.VISIBILITY_LABEL_GENERATOR_CLASS, SimpleScanLabelGenerator.class, 077 ScanLabelGenerator.class); 078 conf.set("hbase.superuser", "admin"); 079 TEST_UTIL.startMiniCluster(2); 080 SUPERUSER = User.createUserForTesting(conf, "admin", new String[] { "supergroup" }); 081 USER = User.createUserForTesting(conf, "user", new String[] {}); 082 // Wait for the labels table to become available 083 TEST_UTIL.waitTableEnabled(LABELS_TABLE_NAME.getName(), 50000); 084 addLabels(); 085 } 086 087 @AfterAll 088 public static void tearDownAfterClass() throws Exception { 089 TEST_UTIL.shutdownMiniCluster(); 090 } 091 092 public static void addLabels() throws Exception { 093 PrivilegedExceptionAction<VisibilityLabelsResponse> action = 094 new PrivilegedExceptionAction<VisibilityLabelsResponse>() { 095 @Override 096 public VisibilityLabelsResponse run() throws Exception { 097 String[] labels = { TOPSECRET }; 098 try (Connection conn = ConnectionFactory.createConnection(conf)) { 099 VisibilityClient.addLabels(conn, labels); 100 } catch (Throwable t) { 101 throw new IOException(t); 102 } 103 return null; 104 } 105 }; 106 SUPERUSER.runAs(action); 107 } 108 109 @Test 110 public void testVerifyAccessDeniedForInvalidUserAuths(TestInfo testInfo) throws Exception { 111 PrivilegedExceptionAction<VisibilityLabelsResponse> action = 112 new PrivilegedExceptionAction<VisibilityLabelsResponse>() { 113 @Override 114 public VisibilityLabelsResponse run() throws Exception { 115 try (Connection conn = ConnectionFactory.createConnection(conf)) { 116 return VisibilityClient.setAuths(conn, new String[] { TOPSECRET }, USER.getShortName()); 117 } catch (Throwable e) { 118 } 119 return null; 120 } 121 }; 122 SUPERUSER.runAs(action); 123 final TableName tableName = TableName.valueOf(testInfo.getTestMethod().get().getName()); 124 Admin hBaseAdmin = TEST_UTIL.getAdmin(); 125 TableDescriptor tableDescriptor = TableDescriptorBuilder.newBuilder(tableName) 126 .setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(fam).setMaxVersions(5).build()) 127 .build(); 128 hBaseAdmin.createTable(tableDescriptor); 129 try { 130 TEST_UTIL.getAdmin().flush(tableName); 131 PrivilegedExceptionAction<Void> actiona = new PrivilegedExceptionAction<Void>() { 132 @Override 133 public Void run() throws Exception { 134 try (Connection connection = ConnectionFactory.createConnection(conf); 135 Table table = connection.getTable(tableName)) { 136 Put p = new Put(row1); 137 p.setCellVisibility(new CellVisibility(PUBLIC + "&" + TOPSECRET)); 138 p.addColumn(fam, qual, 125L, value); 139 table.put(p); 140 Assertions.fail("Testcase should fail with AccesDeniedException"); 141 } catch (Throwable t) { 142 assertTrue(t.getMessage().contains("AccessDeniedException")); 143 } 144 return null; 145 } 146 }; 147 USER.runAs(actiona); 148 } catch (Exception e) { 149 throw new IOException(e); 150 } 151 } 152 153 @Test 154 public void testLabelsWithAppend(TestInfo testInfo) throws Throwable { 155 PrivilegedExceptionAction<VisibilityLabelsResponse> action = 156 new PrivilegedExceptionAction<VisibilityLabelsResponse>() { 157 @Override 158 public VisibilityLabelsResponse run() throws Exception { 159 try (Connection conn = ConnectionFactory.createConnection(conf)) { 160 return VisibilityClient.setAuths(conn, new String[] { TOPSECRET }, USER.getShortName()); 161 } catch (Throwable e) { 162 } 163 return null; 164 } 165 }; 166 SUPERUSER.runAs(action); 167 final TableName tableName = TableName.valueOf(testInfo.getTestMethod().get().getName()); 168 try (Table table = TEST_UTIL.createTable(tableName, fam)) { 169 final byte[] row1 = Bytes.toBytes("row1"); 170 final byte[] val = Bytes.toBytes("a"); 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 Put put = new Put(row1); 177 put.addColumn(fam, qual, HConstants.LATEST_TIMESTAMP, val); 178 put.setCellVisibility(new CellVisibility(TOPSECRET)); 179 table.put(put); 180 } 181 return null; 182 } 183 }; 184 USER.runAs(actiona); 185 actiona = new PrivilegedExceptionAction<Void>() { 186 @Override 187 public Void run() throws Exception { 188 try (Connection connection = ConnectionFactory.createConnection(conf); 189 Table table = connection.getTable(tableName)) { 190 Append append = new Append(row1); 191 append.addColumn(fam, qual, Bytes.toBytes("b")); 192 table.append(append); 193 } 194 return null; 195 } 196 }; 197 USER.runAs(actiona); 198 actiona = new PrivilegedExceptionAction<Void>() { 199 @Override 200 public Void run() throws Exception { 201 try (Connection connection = ConnectionFactory.createConnection(conf); 202 Table table = connection.getTable(tableName)) { 203 Append append = new Append(row1); 204 append.addColumn(fam, qual, Bytes.toBytes("c")); 205 append.setCellVisibility(new CellVisibility(PUBLIC)); 206 table.append(append); 207 Assertions.fail("Testcase should fail with AccesDeniedException"); 208 } catch (Throwable t) { 209 assertTrue(t.getMessage().contains("AccessDeniedException")); 210 } 211 return null; 212 } 213 }; 214 USER.runAs(actiona); 215 } 216 } 217}