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.assertFalse;
022import static org.junit.Assert.assertTrue;
023
024import java.io.IOException;
025import java.security.PrivilegedExceptionAction;
026import org.apache.hadoop.conf.Configuration;
027import org.apache.hadoop.hbase.HBaseClassTestRule;
028import org.apache.hadoop.hbase.HBaseTestingUtil;
029import org.apache.hadoop.hbase.HConstants;
030import org.apache.hadoop.hbase.TableName;
031import org.apache.hadoop.hbase.client.Connection;
032import org.apache.hadoop.hbase.client.ConnectionFactory;
033import org.apache.hadoop.hbase.client.Get;
034import org.apache.hadoop.hbase.client.Put;
035import org.apache.hadoop.hbase.client.Result;
036import org.apache.hadoop.hbase.client.Table;
037import org.apache.hadoop.hbase.security.User;
038import org.apache.hadoop.hbase.testclassification.MediumTests;
039import org.apache.hadoop.hbase.testclassification.SecurityTests;
040import org.apache.hadoop.hbase.util.Bytes;
041import org.junit.AfterClass;
042import org.junit.BeforeClass;
043import org.junit.ClassRule;
044import org.junit.Rule;
045import org.junit.Test;
046import org.junit.experimental.categories.Category;
047import org.junit.rules.TestName;
048
049@Category({ SecurityTests.class, MediumTests.class })
050public class TestEnforcingScanLabelGenerator {
051
052  @ClassRule
053  public static final HBaseClassTestRule CLASS_RULE =
054    HBaseClassTestRule.forClass(TestEnforcingScanLabelGenerator.class);
055
056  public static final String CONFIDENTIAL = "confidential";
057  private static final String SECRET = "secret";
058  public static final HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil();
059  private static final byte[] ROW_1 = Bytes.toBytes("row1");
060  private final static byte[] CF = Bytes.toBytes("f");
061  private final static byte[] Q1 = Bytes.toBytes("q1");
062  private final static byte[] Q2 = Bytes.toBytes("q2");
063  private final static byte[] Q3 = Bytes.toBytes("q3");
064  private final static byte[] value = Bytes.toBytes("value");
065  public static Configuration conf;
066
067  @Rule
068  public final TestName TEST_NAME = new TestName();
069  public static User SUPERUSER;
070  public static User TESTUSER;
071
072  @BeforeClass
073  public static void setupBeforeClass() throws Exception {
074    // setup configuration
075    conf = TEST_UTIL.getConfiguration();
076    VisibilityTestUtil.enableVisiblityLabels(conf);
077    String classes = DefinedSetFilterScanLabelGenerator.class.getCanonicalName() + " , "
078      + EnforcingScanLabelGenerator.class.getCanonicalName();
079    conf.setStrings(VisibilityUtils.VISIBILITY_LABEL_GENERATOR_CLASS, classes);
080    conf.set("hbase.superuser", "admin");
081    TEST_UTIL.startMiniCluster(1);
082    SUPERUSER = User.createUserForTesting(conf, "admin", new String[] { "supergroup" });
083    TESTUSER = User.createUserForTesting(conf, "test", new String[] {});
084
085    // Wait for the labels table to become available
086    TEST_UTIL.waitTableEnabled(LABELS_TABLE_NAME.getName(), 50000);
087
088    // Set up for the test
089    SUPERUSER.runAs(new PrivilegedExceptionAction<Void>() {
090      @Override
091      public Void run() throws Exception {
092        try (Connection conn = ConnectionFactory.createConnection(conf)) {
093          VisibilityClient.addLabels(conn, new String[] { SECRET, CONFIDENTIAL });
094          VisibilityClient.setAuths(conn, new String[] { CONFIDENTIAL, }, TESTUSER.getShortName());
095        } catch (Throwable t) {
096          throw new IOException(t);
097        }
098        return null;
099      }
100    });
101  }
102
103  @Test
104  public void testEnforcingScanLabelGenerator() throws Exception {
105    final TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
106
107    SUPERUSER.runAs(new PrivilegedExceptionAction<Void>() {
108      @Override
109      public Void run() throws Exception {
110        try (Connection connection = ConnectionFactory.createConnection(conf);
111          Table table = TEST_UTIL.createTable(tableName, CF)) {
112          Put put = new Put(ROW_1);
113          put.addColumn(CF, Q1, HConstants.LATEST_TIMESTAMP, value);
114          put.setCellVisibility(new CellVisibility(SECRET));
115          table.put(put);
116          put = new Put(ROW_1);
117          put.addColumn(CF, Q2, HConstants.LATEST_TIMESTAMP, value);
118          put.setCellVisibility(new CellVisibility(CONFIDENTIAL));
119          table.put(put);
120          put = new Put(ROW_1);
121          put.addColumn(CF, Q3, HConstants.LATEST_TIMESTAMP, value);
122          table.put(put);
123          return null;
124        }
125      }
126    });
127
128    // Test that super user can see all the cells.
129    SUPERUSER.runAs(new PrivilegedExceptionAction<Void>() {
130      @Override
131      public Void run() throws Exception {
132        try (Connection connection = ConnectionFactory.createConnection(conf);
133          Table table = connection.getTable(tableName)) {
134          // Test that super user can see all the cells.
135          Get get = new Get(ROW_1);
136          Result result = table.get(get);
137          assertTrue("Missing authorization", result.containsColumn(CF, Q1));
138          assertTrue("Missing authorization", result.containsColumn(CF, Q2));
139          assertTrue("Missing authorization", result.containsColumn(CF, Q3));
140          return null;
141        }
142      }
143    });
144
145    TESTUSER.runAs(new PrivilegedExceptionAction<Void>() {
146      @Override
147      public Void run() throws Exception {
148        try (Connection connection = ConnectionFactory.createConnection(conf);
149          Table table = connection.getTable(tableName)) {
150          // Test that we enforce the defined set
151          Get get = new Get(ROW_1);
152          get.setAuthorizations(new Authorizations(new String[] { SECRET, CONFIDENTIAL }));
153          Result result = table.get(get);
154          assertFalse("Inappropriate authorization", result.containsColumn(CF, Q1));
155          assertTrue("Missing authorization", result.containsColumn(CF, Q2));
156          assertTrue("Inappropriate filtering", result.containsColumn(CF, Q3));
157          // Test that we also enforce the defined set for the user if no auths are provided
158          get = new Get(ROW_1);
159          result = table.get(get);
160          assertFalse("Inappropriate authorization", result.containsColumn(CF, Q1));
161          assertTrue("Missing authorization", result.containsColumn(CF, Q2));
162          assertTrue("Inappropriate filtering", result.containsColumn(CF, Q3));
163          return null;
164        }
165      }
166    });
167
168  }
169
170  @AfterClass
171  public static void tearDownAfterClass() throws Exception {
172    TEST_UTIL.shutdownMiniCluster();
173  }
174}