Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to you under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.phoenix.end2end; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.security.PrivilegedExceptionAction; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Properties; import java.util.Set; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.HBaseTestingUtility; import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.security.access.AccessControlClient; import org.apache.hadoop.hbase.security.access.Permission.Action; import org.apache.hadoop.security.UserGroupInformation; import org.apache.phoenix.query.QueryServices; import org.junit.After; import org.junit.BeforeClass; import org.junit.Test; import org.junit.experimental.categories.Category; /** * Test that verifies a user can read Phoenix tables with a minimal set of permissions. */ @Category(NeedsOwnMiniClusterTest.class) public class SystemTablePermissionsIT { private static String SUPERUSER; private static final Set<String> PHOENIX_SYSTEM_TABLES = new HashSet<>( Arrays.asList("SYSTEM.CATALOG", "SYSTEM.SEQUENCE", "SYSTEM.STATS", "SYSTEM.FUNCTION", "SYSTEM.MUTEX")); // PHOENIX-XXXX SYSTEM.MUTEX isn't being created in the SYSTEM namespace as it should be. private static final Set<String> PHOENIX_NAMESPACE_MAPPED_SYSTEM_TABLES = new HashSet<>( Arrays.asList("SYSTEM:CATALOG", "SYSTEM:SEQUENCE", "SYSTEM:STATS", "SYSTEM:FUNCTION", "SYSTEM.MUTEX")); private static final String TABLE_NAME = SystemTablePermissionsIT.class.getSimpleName().toUpperCase(); private static final int NUM_RECORDS = 5; private HBaseTestingUtility testUtil = null; private Properties clientProperties = null; @BeforeClass public static void setup() throws Exception { SUPERUSER = System.getProperty("user.name"); } private static void setCommonConfigProperties(Configuration conf) { conf.set("hbase.coprocessor.master.classes", "org.apache.hadoop.hbase.security.access.AccessController"); conf.set("hbase.coprocessor.region.classes", "org.apache.hadoop.hbase.security.access.AccessController"); conf.set("hbase.coprocessor.regionserver.classes", "org.apache.hadoop.hbase.security.access.AccessController"); conf.set("hbase.security.exec.permission.checks", "true"); conf.set("hbase.security.authorization", "true"); conf.set("hbase.superuser", SUPERUSER); } @After public void cleanup() throws Exception { if (null != testUtil) { testUtil.shutdownMiniCluster(); testUtil = null; } } @Test public void testSystemTablePermissions() throws Exception { testUtil = new HBaseTestingUtility(); clientProperties = new Properties(); Configuration conf = testUtil.getConfiguration(); setCommonConfigProperties(conf); conf.set(QueryServices.IS_NAMESPACE_MAPPING_ENABLED, "false"); clientProperties.setProperty(QueryServices.IS_NAMESPACE_MAPPING_ENABLED, "false"); testUtil.startMiniCluster(1); final UserGroupInformation superUser = UserGroupInformation.createUserForTesting(SUPERUSER, new String[0]); final UserGroupInformation regularUser = UserGroupInformation.createUserForTesting("user", new String[0]); superUser.doAs(new PrivilegedExceptionAction<Void>() { @Override public Void run() throws Exception { createTable(); readTable(); return null; } }); Set<String> tables = getHBaseTables(); assertTrue("HBase tables do not include expected Phoenix tables: " + tables, tables.containsAll(PHOENIX_SYSTEM_TABLES)); // Grant permission to the system tables for the unprivileged user superUser.doAs(new PrivilegedExceptionAction<Void>() { @Override public Void run() throws Exception { try { grantPermissions(regularUser.getShortUserName(), PHOENIX_SYSTEM_TABLES, Action.EXEC, Action.READ); grantPermissions(regularUser.getShortUserName(), Collections.singleton(TABLE_NAME), Action.READ); } catch (Throwable e) { if (e instanceof Exception) { throw (Exception) e; } else { throw new Exception(e); } } return null; } }); // Make sure that the unprivileged user can read the table regularUser.doAs(new PrivilegedExceptionAction<Void>() { @Override public Void run() throws Exception { // We expect this to not throw an error readTable(); return null; } }); } @Test public void testNamespaceMappedSystemTables() throws Exception { testUtil = new HBaseTestingUtility(); clientProperties = new Properties(); Configuration conf = testUtil.getConfiguration(); setCommonConfigProperties(conf); testUtil.getConfiguration().set(QueryServices.IS_NAMESPACE_MAPPING_ENABLED, "true"); clientProperties.setProperty(QueryServices.IS_NAMESPACE_MAPPING_ENABLED, "true"); testUtil.startMiniCluster(1); final UserGroupInformation superUser = UserGroupInformation.createUserForTesting(SUPERUSER, new String[0]); final UserGroupInformation regularUser = UserGroupInformation.createUserForTesting("user", new String[0]); superUser.doAs(new PrivilegedExceptionAction<Void>() { @Override public Void run() throws Exception { createTable(); readTable(); return null; } }); Set<String> tables = getHBaseTables(); assertTrue("HBase tables do not include expected Phoenix tables: " + tables, tables.containsAll(PHOENIX_NAMESPACE_MAPPED_SYSTEM_TABLES)); // Grant permission to the system tables for the unprivileged user // An unprivileged user should only need to be able to Read and eXecute on them. superUser.doAs(new PrivilegedExceptionAction<Void>() { @Override public Void run() throws Exception { try { grantPermissions(regularUser.getShortUserName(), PHOENIX_NAMESPACE_MAPPED_SYSTEM_TABLES, Action.EXEC, Action.READ); grantPermissions(regularUser.getShortUserName(), Collections.singleton(TABLE_NAME), Action.READ); } catch (Throwable e) { if (e instanceof Exception) { throw (Exception) e; } else { throw new Exception(e); } } return null; } }); regularUser.doAs(new PrivilegedExceptionAction<Void>() { @Override public Void run() throws Exception { // We expect this to not throw an error readTable(); return null; } }); } private String getJdbcUrl() { return "jdbc:phoenix:localhost:" + testUtil.getZkCluster().getClientPort() + ":/hbase"; } private void createTable() throws SQLException { try (Connection conn = DriverManager.getConnection(getJdbcUrl(), clientProperties); Statement stmt = conn.createStatement();) { assertFalse(stmt.execute("DROP TABLE IF EXISTS " + TABLE_NAME)); assertFalse( stmt.execute("CREATE TABLE " + TABLE_NAME + "(pk INTEGER not null primary key, data VARCHAR)")); try (PreparedStatement pstmt = conn.prepareStatement("UPSERT INTO " + TABLE_NAME + " values(?, ?)")) { for (int i = 0; i < NUM_RECORDS; i++) { pstmt.setInt(1, i); pstmt.setString(2, Integer.toString(i)); assertEquals(1, pstmt.executeUpdate()); } } conn.commit(); } } private void readTable() throws SQLException { try (Connection conn = DriverManager.getConnection(getJdbcUrl(), clientProperties); Statement stmt = conn.createStatement()) { ResultSet rs = stmt.executeQuery("SELECT pk, data FROM " + TABLE_NAME); assertNotNull(rs); int i = 0; while (rs.next()) { assertEquals(i, rs.getInt(1)); assertEquals(Integer.toString(i), rs.getString(2)); i++; } assertEquals(NUM_RECORDS, i); } } private void grantPermissions(String toUser, Set<String> tablesToGrant, Action... actions) throws Throwable { for (String table : tablesToGrant) { AccessControlClient.grant(testUtil.getConnection(), TableName.valueOf(table), toUser, null, null, actions); } } private Set<String> getHBaseTables() throws IOException { Set<String> tables = new HashSet<>(); for (TableName tn : testUtil.getHBaseAdmin().listTableNames()) { tables.add(tn.getNameAsString()); } return tables; } }