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.assertEquals;
022import static org.junit.Assert.assertTrue;
023
024import java.io.IOException;
025import java.security.PrivilegedExceptionAction;
026import java.util.ArrayList;
027import java.util.List;
028import org.apache.hadoop.conf.Configuration;
029import org.apache.hadoop.hbase.HBaseClassTestRule;
030import org.apache.hadoop.hbase.HBaseTestingUtil;
031import org.apache.hadoop.hbase.client.Connection;
032import org.apache.hadoop.hbase.client.ConnectionFactory;
033import org.apache.hadoop.hbase.security.User;
034import org.apache.hadoop.hbase.testclassification.MediumTests;
035import org.apache.hadoop.hbase.testclassification.SecurityTests;
036import org.apache.hadoop.hbase.util.Bytes;
037import org.junit.AfterClass;
038import org.junit.BeforeClass;
039import org.junit.ClassRule;
040import org.junit.Rule;
041import org.junit.Test;
042import org.junit.experimental.categories.Category;
043import org.junit.rules.TestName;
044
045import org.apache.hbase.thirdparty.com.google.protobuf.ByteString;
046
047import org.apache.hadoop.hbase.shaded.protobuf.generated.VisibilityLabelsProtos.GetAuthsResponse;
048import org.apache.hadoop.hbase.shaded.protobuf.generated.VisibilityLabelsProtos.VisibilityLabelsResponse;
049
050@Category({ SecurityTests.class, MediumTests.class })
051public class TestVisibilityLabelsOpWithDifferentUsersNoACL {
052
053  @ClassRule
054  public static final HBaseClassTestRule CLASS_RULE =
055    HBaseClassTestRule.forClass(TestVisibilityLabelsOpWithDifferentUsersNoACL.class);
056
057  private static final String PRIVATE = "private";
058  private static final String CONFIDENTIAL = "confidential";
059  private static final String SECRET = "secret";
060  private static final HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil();
061  private static Configuration conf;
062
063  @Rule
064  public final TestName TEST_NAME = new TestName();
065  private static User SUPERUSER;
066  private static User NORMAL_USER;
067  private static User NORMAL_USER1;
068
069  @BeforeClass
070  public static void setupBeforeClass() throws Exception {
071    // setup configuration
072    conf = TEST_UTIL.getConfiguration();
073    VisibilityTestUtil.enableVisiblityLabels(conf);
074    String currentUser = User.getCurrent().getName();
075    conf.set("hbase.superuser", "admin," + currentUser);
076    TEST_UTIL.startMiniCluster(2);
077
078    // Wait for the labels table to become available
079    TEST_UTIL.waitTableEnabled(LABELS_TABLE_NAME.getName(), 50000);
080    SUPERUSER = User.createUserForTesting(conf, "admin", new String[] { "supergroup" });
081    NORMAL_USER = User.createUserForTesting(conf, "user1", new String[] {});
082    NORMAL_USER1 = User.createUserForTesting(conf, "user2", new String[] {});
083    addLabels();
084  }
085
086  @AfterClass
087  public static void tearDownAfterClass() throws Exception {
088    TEST_UTIL.shutdownMiniCluster();
089  }
090
091  @Test
092  public void testLabelsTableOpsWithDifferentUsers() throws Throwable {
093    PrivilegedExceptionAction<VisibilityLabelsResponse> action =
094      new PrivilegedExceptionAction<VisibilityLabelsResponse>() {
095        @Override
096        public VisibilityLabelsResponse run() throws Exception {
097          try (Connection conn = ConnectionFactory.createConnection(conf)) {
098            return VisibilityClient.setAuths(conn, new String[] { CONFIDENTIAL, PRIVATE }, "user1");
099          } catch (Throwable e) {
100          }
101          return null;
102        }
103      };
104    VisibilityLabelsResponse response = SUPERUSER.runAs(action);
105    assertTrue(response.getResult(0).getException().getValue().isEmpty());
106    assertTrue(response.getResult(1).getException().getValue().isEmpty());
107
108    // Ideally this should not be allowed. this operation should fail or do nothing.
109    action = new PrivilegedExceptionAction<VisibilityLabelsResponse>() {
110      @Override
111      public VisibilityLabelsResponse run() throws Exception {
112        try (Connection conn = ConnectionFactory.createConnection(conf)) {
113          return VisibilityClient.setAuths(conn, new String[] { CONFIDENTIAL, PRIVATE }, "user3");
114        } catch (Throwable e) {
115        }
116        return null;
117      }
118    };
119    response = NORMAL_USER1.runAs(action);
120    assertEquals("org.apache.hadoop.hbase.security.AccessDeniedException",
121      response.getResult(0).getException().getName());
122    assertEquals("org.apache.hadoop.hbase.security.AccessDeniedException",
123      response.getResult(1).getException().getName());
124
125    PrivilegedExceptionAction<GetAuthsResponse> action1 =
126      new PrivilegedExceptionAction<GetAuthsResponse>() {
127        @Override
128        public GetAuthsResponse run() throws Exception {
129          try (Connection conn = ConnectionFactory.createConnection(conf)) {
130            return VisibilityClient.getAuths(conn, "user1");
131          } catch (Throwable e) {
132          }
133          return null;
134        }
135      };
136    GetAuthsResponse authsResponse = NORMAL_USER.runAs(action1);
137    assertTrue(authsResponse.getAuthList().isEmpty());
138    authsResponse = NORMAL_USER1.runAs(action1);
139    assertTrue(authsResponse.getAuthList().isEmpty());
140    authsResponse = SUPERUSER.runAs(action1);
141    List<String> authsList = new ArrayList<>(authsResponse.getAuthList().size());
142    for (ByteString authBS : authsResponse.getAuthList()) {
143      authsList.add(Bytes.toString(authBS.toByteArray()));
144    }
145    assertEquals(2, authsList.size());
146    assertTrue(authsList.contains(CONFIDENTIAL));
147    assertTrue(authsList.contains(PRIVATE));
148
149    PrivilegedExceptionAction<VisibilityLabelsResponse> action2 =
150      new PrivilegedExceptionAction<VisibilityLabelsResponse>() {
151        @Override
152        public VisibilityLabelsResponse run() throws Exception {
153          try (Connection conn = ConnectionFactory.createConnection(conf)) {
154            return VisibilityClient.clearAuths(conn, new String[] { CONFIDENTIAL, PRIVATE },
155              "user1");
156          } catch (Throwable e) {
157          }
158          return null;
159        }
160      };
161    response = NORMAL_USER1.runAs(action2);
162    assertEquals("org.apache.hadoop.hbase.security.AccessDeniedException",
163      response.getResult(0).getException().getName());
164    assertEquals("org.apache.hadoop.hbase.security.AccessDeniedException",
165      response.getResult(1).getException().getName());
166    response = SUPERUSER.runAs(action2);
167    assertTrue(response.getResult(0).getException().getValue().isEmpty());
168    assertTrue(response.getResult(1).getException().getValue().isEmpty());
169    authsResponse = SUPERUSER.runAs(action1);
170    assertTrue(authsResponse.getAuthList().isEmpty());
171  }
172
173  private static void addLabels() throws Exception {
174    PrivilegedExceptionAction<VisibilityLabelsResponse> action =
175      new PrivilegedExceptionAction<VisibilityLabelsResponse>() {
176        @Override
177        public VisibilityLabelsResponse run() throws Exception {
178          String[] labels = { SECRET, CONFIDENTIAL, PRIVATE };
179          try (Connection conn = ConnectionFactory.createConnection(conf)) {
180            VisibilityClient.addLabels(conn, labels);
181          } catch (Throwable t) {
182            throw new IOException(t);
183          }
184          return null;
185        }
186      };
187    SUPERUSER.runAs(action);
188  }
189}