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.access;
019
020import static org.junit.Assert.assertFalse;
021import static org.junit.Assert.assertTrue;
022
023import java.util.ArrayList;
024import java.util.List;
025import java.util.concurrent.atomic.AtomicBoolean;
026import org.apache.hadoop.conf.Configuration;
027import org.apache.hadoop.hbase.Abortable;
028import org.apache.hadoop.hbase.HBaseClassTestRule;
029import org.apache.hadoop.hbase.HBaseTestingUtility;
030import org.apache.hadoop.hbase.TableName;
031import org.apache.hadoop.hbase.Waiter.Predicate;
032import org.apache.hadoop.hbase.security.User;
033import org.apache.hadoop.hbase.testclassification.LargeTests;
034import org.apache.hadoop.hbase.testclassification.SecurityTests;
035import org.apache.hadoop.hbase.zookeeper.ZKWatcher;
036import org.junit.AfterClass;
037import org.junit.BeforeClass;
038import org.junit.ClassRule;
039import org.junit.Test;
040import org.junit.experimental.categories.Category;
041import org.slf4j.Logger;
042import org.slf4j.LoggerFactory;
043
044import org.apache.hbase.thirdparty.com.google.common.collect.ArrayListMultimap;
045import org.apache.hbase.thirdparty.com.google.common.collect.ListMultimap;
046
047/**
048 * Test the reading and writing of access permissions to and from zookeeper.
049 */
050@Category({SecurityTests.class, LargeTests.class})
051public class TestZKPermissionWatcher {
052
053  @ClassRule
054  public static final HBaseClassTestRule CLASS_RULE =
055      HBaseClassTestRule.forClass(TestZKPermissionWatcher.class);
056
057  private static final Logger LOG = LoggerFactory.getLogger(TestZKPermissionWatcher.class);
058  private static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
059  private static AuthManager AUTH_A;
060  private static AuthManager AUTH_B;
061  private final static Abortable ABORTABLE = new Abortable() {
062    private final AtomicBoolean abort = new AtomicBoolean(false);
063
064    @Override
065    public void abort(String why, Throwable e) {
066      LOG.info(why, e);
067      abort.set(true);
068    }
069
070    @Override
071    public boolean isAborted() {
072      return abort.get();
073    }
074  };
075
076  private static TableName TEST_TABLE =
077      TableName.valueOf("perms_test");
078
079  @BeforeClass
080  public static void beforeClass() throws Exception {
081    // setup configuration
082    Configuration conf = UTIL.getConfiguration();
083    SecureTestUtil.enableSecurity(conf);
084
085    // start minicluster
086    UTIL.startMiniCluster();
087    AUTH_A = AuthManager.getOrCreate(new ZKWatcher(conf,
088      "TestZKPermissionsWatcher_1", ABORTABLE), conf);
089    AUTH_B = AuthManager.getOrCreate(new ZKWatcher(conf,
090      "TestZKPermissionsWatcher_2", ABORTABLE), conf);
091  }
092
093  @AfterClass
094  public static void afterClass() throws Exception {
095    UTIL.shutdownMiniCluster();
096  }
097
098  @Test
099  public void testPermissionsWatcher() throws Exception {
100    Configuration conf = UTIL.getConfiguration();
101    User george = User.createUserForTesting(conf, "george", new String[] { });
102    User hubert = User.createUserForTesting(conf, "hubert", new String[] { });
103
104    assertFalse(AUTH_A.authorizeUserTable(george, TEST_TABLE, Permission.Action.READ));
105    assertFalse(AUTH_A.authorizeUserTable(george, TEST_TABLE, Permission.Action.WRITE));
106    assertFalse(AUTH_A.authorizeUserTable(hubert, TEST_TABLE, Permission.Action.READ));
107    assertFalse(AUTH_A.authorizeUserTable(hubert, TEST_TABLE, Permission.Action.WRITE));
108
109    assertFalse(AUTH_B.authorizeUserTable(george, TEST_TABLE, Permission.Action.READ));
110    assertFalse(AUTH_B.authorizeUserTable(george, TEST_TABLE, Permission.Action.WRITE));
111    assertFalse(AUTH_B.authorizeUserTable(hubert, TEST_TABLE, Permission.Action.READ));
112    assertFalse(AUTH_B.authorizeUserTable(hubert, TEST_TABLE, Permission.Action.WRITE));
113
114    // update ACL: george RW
115    List<UserPermission> acl = new ArrayList<>(1);
116    acl.add(new UserPermission(george.getShortName(), Permission.newBuilder(TEST_TABLE)
117        .withActions(Permission.Action.READ, Permission.Action.WRITE).build()));
118    ListMultimap<String, UserPermission> multimap = ArrayListMultimap.create();
119    multimap.putAll(george.getShortName(), acl);
120    byte[] serialized = AccessControlLists.writePermissionsAsBytes(multimap, conf);
121    AUTH_A.getZKPermissionWatcher().writeToZookeeper(TEST_TABLE.getName(), serialized);
122    final long mtimeB = AUTH_B.getMTime();
123    // Wait for the update to propagate
124    UTIL.waitFor(10000, 100, new Predicate<Exception>() {
125      @Override
126      public boolean evaluate() throws Exception {
127        return AUTH_B.getMTime() > mtimeB;
128      }
129    });
130    Thread.sleep(1000);
131
132    // check it
133    assertTrue(AUTH_A.authorizeUserTable(george, TEST_TABLE, Permission.Action.READ));
134    assertTrue(AUTH_A.authorizeUserTable(george, TEST_TABLE, Permission.Action.WRITE));
135    assertTrue(AUTH_B.authorizeUserTable(george, TEST_TABLE, Permission.Action.READ));
136    assertTrue(AUTH_B.authorizeUserTable(george, TEST_TABLE, Permission.Action.WRITE));
137    assertFalse(AUTH_A.authorizeUserTable(hubert, TEST_TABLE, Permission.Action.READ));
138    assertFalse(AUTH_A.authorizeUserTable(hubert, TEST_TABLE, Permission.Action.WRITE));
139    assertFalse(AUTH_B.authorizeUserTable(hubert, TEST_TABLE, Permission.Action.READ));
140    assertFalse(AUTH_B.authorizeUserTable(hubert, TEST_TABLE, Permission.Action.WRITE));
141
142    // update ACL: hubert R
143    List<UserPermission> acl2 = new ArrayList<>(1);
144    acl2.add(new UserPermission(hubert.getShortName(),
145        Permission.newBuilder(TEST_TABLE).withActions(TablePermission.Action.READ).build()));
146    final long mtimeA = AUTH_A.getMTime();
147    multimap.putAll(hubert.getShortName(), acl2);
148    byte[] serialized2 = AccessControlLists.writePermissionsAsBytes(multimap, conf);
149    AUTH_B.getZKPermissionWatcher().writeToZookeeper(TEST_TABLE.getName(), serialized2);
150    // Wait for the update to propagate
151    UTIL.waitFor(10000, 100, new Predicate<Exception>() {
152      @Override
153      public boolean evaluate() throws Exception {
154        return AUTH_A.getMTime() > mtimeA;
155      }
156    });
157    Thread.sleep(1000);
158
159    // check it
160    assertTrue(AUTH_A.authorizeUserTable(george, TEST_TABLE, Permission.Action.READ));
161    assertTrue(AUTH_A.authorizeUserTable(george, TEST_TABLE, Permission.Action.WRITE));
162    assertTrue(AUTH_B.authorizeUserTable(george, TEST_TABLE, Permission.Action.READ));
163    assertTrue(AUTH_B.authorizeUserTable(george, TEST_TABLE, Permission.Action.WRITE));
164    assertTrue(AUTH_A.authorizeUserTable(hubert, TEST_TABLE, Permission.Action.READ));
165    assertFalse(AUTH_A.authorizeUserTable(hubert, TEST_TABLE, Permission.Action.WRITE));
166    assertTrue(AUTH_B.authorizeUserTable(hubert, TEST_TABLE, Permission.Action.READ));
167    assertFalse(AUTH_B.authorizeUserTable(hubert, TEST_TABLE, Permission.Action.WRITE));
168  }
169}