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.rest; 019 020import static org.junit.Assert.assertEquals; 021import static org.junit.Assert.assertNotNull; 022 023import java.io.ByteArrayInputStream; 024import java.io.IOException; 025import java.io.StringWriter; 026import java.security.PrivilegedExceptionAction; 027import java.util.ArrayList; 028import java.util.Iterator; 029import java.util.List; 030import javax.xml.bind.JAXBContext; 031import javax.xml.bind.JAXBException; 032import javax.xml.bind.Marshaller; 033import javax.xml.bind.Unmarshaller; 034import org.apache.hadoop.conf.Configuration; 035import org.apache.hadoop.hbase.CellUtil; 036import org.apache.hadoop.hbase.HBaseClassTestRule; 037import org.apache.hadoop.hbase.HBaseTestingUtil; 038import org.apache.hadoop.hbase.TableName; 039import org.apache.hadoop.hbase.client.Admin; 040import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor; 041import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder; 042import org.apache.hadoop.hbase.client.Connection; 043import org.apache.hadoop.hbase.client.ConnectionFactory; 044import org.apache.hadoop.hbase.client.Durability; 045import org.apache.hadoop.hbase.client.Put; 046import org.apache.hadoop.hbase.client.Table; 047import org.apache.hadoop.hbase.client.TableDescriptorBuilder; 048import org.apache.hadoop.hbase.rest.client.Client; 049import org.apache.hadoop.hbase.rest.client.Cluster; 050import org.apache.hadoop.hbase.rest.client.Response; 051import org.apache.hadoop.hbase.rest.model.CellModel; 052import org.apache.hadoop.hbase.rest.model.CellSetModel; 053import org.apache.hadoop.hbase.rest.model.RowModel; 054import org.apache.hadoop.hbase.rest.model.ScannerModel; 055import org.apache.hadoop.hbase.security.User; 056import org.apache.hadoop.hbase.security.visibility.CellVisibility; 057import org.apache.hadoop.hbase.security.visibility.ScanLabelGenerator; 058import org.apache.hadoop.hbase.security.visibility.SimpleScanLabelGenerator; 059import org.apache.hadoop.hbase.security.visibility.VisibilityClient; 060import org.apache.hadoop.hbase.security.visibility.VisibilityConstants; 061import org.apache.hadoop.hbase.security.visibility.VisibilityTestUtil; 062import org.apache.hadoop.hbase.security.visibility.VisibilityUtils; 063import org.apache.hadoop.hbase.testclassification.MediumTests; 064import org.apache.hadoop.hbase.testclassification.RestTests; 065import org.apache.hadoop.hbase.util.Bytes; 066import org.junit.AfterClass; 067import org.junit.BeforeClass; 068import org.junit.ClassRule; 069import org.junit.Test; 070import org.junit.experimental.categories.Category; 071 072import org.apache.hadoop.hbase.shaded.protobuf.generated.VisibilityLabelsProtos.VisibilityLabelsResponse; 073 074@Category({ RestTests.class, MediumTests.class }) 075public class TestScannersWithLabels { 076 @ClassRule 077 public static final HBaseClassTestRule CLASS_RULE = 078 HBaseClassTestRule.forClass(TestScannersWithLabels.class); 079 080 private static final TableName TABLE = TableName.valueOf("TestScannersWithLabels"); 081 private static final String CFA = "a"; 082 private static final String CFB = "b"; 083 private static final String COLUMN_1 = CFA + ":1"; 084 private static final String COLUMN_2 = CFB + ":2"; 085 private final static String TOPSECRET = "topsecret"; 086 private final static String PUBLIC = "public"; 087 private final static String PRIVATE = "private"; 088 private final static String CONFIDENTIAL = "confidential"; 089 private final static String SECRET = "secret"; 090 private static User SUPERUSER; 091 092 private static final HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil(); 093 private static final HBaseRESTTestingUtility REST_TEST_UTIL = new HBaseRESTTestingUtility(); 094 private static Client client; 095 private static JAXBContext context; 096 private static Marshaller marshaller; 097 private static Unmarshaller unmarshaller; 098 private static Configuration conf; 099 100 private static int insertData(TableName tableName, String column, double prob) 101 throws IOException { 102 byte[] k = new byte[3]; 103 byte[][] famAndQf = CellUtil.parseColumn(Bytes.toBytes(column)); 104 105 List<Put> puts = new ArrayList<>(9); 106 for (int i = 0; i < 9; i++) { 107 Put put = new Put(Bytes.toBytes("row" + i)); 108 put.setDurability(Durability.SKIP_WAL); 109 put.addColumn(famAndQf[0], famAndQf[1], k); 110 put.setCellVisibility( 111 new CellVisibility("(" + SECRET + "|" + CONFIDENTIAL + ")" + "&" + "!" + TOPSECRET)); 112 puts.add(put); 113 } 114 try (Table table = TEST_UTIL.getConnection().getTable(tableName)) { 115 table.put(puts); 116 } 117 return puts.size(); 118 } 119 120 private static int countCellSet(CellSetModel model) { 121 int count = 0; 122 Iterator<RowModel> rows = model.getRows().iterator(); 123 while (rows.hasNext()) { 124 RowModel row = rows.next(); 125 Iterator<CellModel> cells = row.getCells().iterator(); 126 while (cells.hasNext()) { 127 cells.next(); 128 count++; 129 } 130 } 131 return count; 132 } 133 134 @BeforeClass 135 public static void setUpBeforeClass() throws Exception { 136 SUPERUSER = User.createUserForTesting(conf, "admin", new String[] { "supergroup" }); 137 conf = TEST_UTIL.getConfiguration(); 138 conf.setClass(VisibilityUtils.VISIBILITY_LABEL_GENERATOR_CLASS, SimpleScanLabelGenerator.class, 139 ScanLabelGenerator.class); 140 conf.set("hbase.superuser", SUPERUSER.getShortName()); 141 VisibilityTestUtil.enableVisiblityLabels(conf); 142 TEST_UTIL.startMiniCluster(1); 143 // Wait for the labels table to become available 144 TEST_UTIL.waitTableEnabled(VisibilityConstants.LABELS_TABLE_NAME.getName(), 50000); 145 createLabels(); 146 setAuths(); 147 REST_TEST_UTIL.startServletContainer(conf); 148 client = new Client(new Cluster().add("localhost", REST_TEST_UTIL.getServletPort())); 149 context = JAXBContext.newInstance(CellModel.class, CellSetModel.class, RowModel.class, 150 ScannerModel.class); 151 marshaller = context.createMarshaller(); 152 unmarshaller = context.createUnmarshaller(); 153 Admin admin = TEST_UTIL.getAdmin(); 154 if (admin.tableExists(TABLE)) { 155 return; 156 } 157 TableDescriptorBuilder tableDescriptorBuilder = TableDescriptorBuilder.newBuilder(TABLE); 158 ColumnFamilyDescriptor columnFamilyDescriptor = 159 ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes(CFA)).build(); 160 tableDescriptorBuilder.setColumnFamily(columnFamilyDescriptor); 161 columnFamilyDescriptor = ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes(CFB)).build(); 162 tableDescriptorBuilder.setColumnFamily(columnFamilyDescriptor); 163 admin.createTable(tableDescriptorBuilder.build()); 164 insertData(TABLE, COLUMN_1, 1.0); 165 insertData(TABLE, COLUMN_2, 0.5); 166 } 167 168 @AfterClass 169 public static void tearDownAfterClass() throws Exception { 170 REST_TEST_UTIL.shutdownServletContainer(); 171 TEST_UTIL.shutdownMiniCluster(); 172 } 173 174 private static void createLabels() throws IOException, InterruptedException { 175 PrivilegedExceptionAction<VisibilityLabelsResponse> action = () -> { 176 String[] labels = { SECRET, CONFIDENTIAL, PRIVATE, PUBLIC, TOPSECRET }; 177 try (Connection conn = ConnectionFactory.createConnection(conf)) { 178 VisibilityClient.addLabels(conn, labels); 179 } catch (Throwable t) { 180 throw new IOException(t); 181 } 182 return null; 183 }; 184 SUPERUSER.runAs(action); 185 } 186 187 private static void setAuths() throws Exception { 188 String[] labels = { SECRET, CONFIDENTIAL, PRIVATE, PUBLIC, TOPSECRET }; 189 try (Connection conn = ConnectionFactory.createConnection(conf)) { 190 VisibilityClient.setAuths(conn, labels, User.getCurrent().getShortName()); 191 } catch (Throwable t) { 192 throw new IOException(t); 193 } 194 } 195 196 @Test 197 public void testSimpleScannerXMLWithLabelsThatReceivesNoData() throws IOException, JAXBException { 198 final int BATCH_SIZE = 5; 199 // new scanner 200 ScannerModel model = new ScannerModel(); 201 model.setBatch(BATCH_SIZE); 202 model.addColumn(Bytes.toBytes(COLUMN_1)); 203 model.addLabel(PUBLIC); 204 StringWriter writer = new StringWriter(); 205 marshaller.marshal(model, writer); 206 byte[] body = Bytes.toBytes(writer.toString()); 207 // recall previous put operation with read-only off 208 conf.set("hbase.rest.readonly", "false"); 209 Response response = client.put("/" + TABLE + "/scanner", Constants.MIMETYPE_XML, body); 210 assertEquals(201, response.getCode()); 211 String scannerURI = response.getLocation(); 212 assertNotNull(scannerURI); 213 214 // get a cell set 215 response = client.get(scannerURI, Constants.MIMETYPE_XML); 216 // Respond with 204 as there are no cells to be retrieved 217 assertEquals(204, response.getCode()); 218 // With no content in the payload, the 'Content-Type' header is not echo back 219 } 220 221 @Test 222 public void testSimpleScannerXMLWithLabelsThatReceivesData() throws IOException, JAXBException { 223 // new scanner 224 ScannerModel model = new ScannerModel(); 225 model.setBatch(5); 226 model.addColumn(Bytes.toBytes(COLUMN_1)); 227 model.addLabel(SECRET); 228 StringWriter writer = new StringWriter(); 229 marshaller.marshal(model, writer); 230 byte[] body = Bytes.toBytes(writer.toString()); 231 232 // recall previous put operation with read-only off 233 conf.set("hbase.rest.readonly", "false"); 234 Response response = client.put("/" + TABLE + "/scanner", Constants.MIMETYPE_XML, body); 235 assertEquals(201, response.getCode()); 236 String scannerURI = response.getLocation(); 237 assertNotNull(scannerURI); 238 239 // get a cell set 240 response = client.get(scannerURI, Constants.MIMETYPE_XML); 241 // Respond with 204 as there are no cells to be retrieved 242 assertEquals(200, response.getCode()); 243 assertEquals(Constants.MIMETYPE_XML, response.getHeader("content-type")); 244 CellSetModel cellSet = 245 (CellSetModel) unmarshaller.unmarshal(new ByteArrayInputStream(response.getBody())); 246 assertEquals(5, countCellSet(cellSet)); 247 } 248}