blob: 4c087e5e5af6bb36c77aefd0a1eb56f83858eaad [file] [log] [blame]
/*
* 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 org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.security.AccessDeniedException;
import org.apache.hadoop.hbase.security.access.AccessControlClient;
import org.apache.hadoop.hbase.security.access.Permission;
import org.apache.phoenix.exception.SQLExceptionCode;
import org.apache.phoenix.util.SchemaUtil;
import org.junit.BeforeClass;
import org.junit.Test;
import java.security.PrivilegedExceptionAction;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Collections;
import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.PK_NAME;
import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SYSTEM_CATALOG_TABLE;
import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SYSTEM_CHILD_LINK_TABLE;
import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SYSTEM_SCHEMA_NAME;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public class PermissionNSEnabledIT extends BasePermissionsIT {
public PermissionNSEnabledIT() throws Exception {
super(true);
}
@BeforeClass
public static synchronized void doSetup() throws Exception {
BasePermissionsIT.initCluster(true);
}
@Test
public void testSchemaPermissions() throws Throwable{
try {
grantSystemTableAccess();
final String schemaName = "S_" + generateUniqueName();
superUser1.runAs(new PrivilegedExceptionAction<Void>() {
@Override
public Void run() throws Exception {
try {
AccessControlClient.grant(getUtility().getConnection(), regularUser1.getShortName(),
Permission.Action.ADMIN);
} catch (Throwable e) {
if (e instanceof Exception) {
throw (Exception)e;
} else {
throw new Exception(e);
}
}
return null;
}
});
verifyAllowed(createSchema(schemaName), regularUser1);
// Unprivileged user cannot drop a schema
verifyDenied(dropSchema(schemaName), AccessDeniedException.class, unprivilegedUser);
verifyDenied(createSchema(schemaName), AccessDeniedException.class, unprivilegedUser);
verifyAllowed(dropSchema(schemaName), regularUser1);
} finally {
revokeAll();
}
}
@Test
public void testConnectionCreationFailsWhenNoExecPermsOnSystemCatalog() throws Throwable {
try {
grantSystemTableAccess();
superUser1.runAs(new PrivilegedExceptionAction<Void>() {
@Override
public Void run() throws Exception {
TableName systemCatalogTableName =
TableName.valueOf(SchemaUtil.getPhysicalHBaseTableName(SYSTEM_SCHEMA_NAME,
SYSTEM_CATALOG_TABLE, true).getString());
try {
// Revoke Exec permissions for SYSTEM CATALOG for the unprivileged user
AccessControlClient
.revoke(getUtility().getConnection(), systemCatalogTableName,
unprivilegedUser.getShortName(), null, null, Permission.Action.EXEC);
} catch (Throwable t) {
if (t instanceof Exception) {
throw (Exception) t;
} else {
throw new Exception(t);
}
}
return null;
}
});
unprivilegedUser.runAs(new PrivilegedExceptionAction<Void>() {
@Override
public Void run() throws Exception {
try (Connection ignored = getConnection()) {
// We expect this to throw a wrapped AccessDeniedException.
fail("Should have failed with a wrapped AccessDeniedException");
} catch (Throwable ex) {
assertTrue("Should not get an incompatible jars exception",
ex instanceof SQLException && ((SQLException)ex).getErrorCode() !=
SQLExceptionCode.INCOMPATIBLE_CLIENT_SERVER_JAR.getErrorCode());
assertTrue("Expected a wrapped AccessDeniedException",
ex.getCause() instanceof AccessDeniedException);
}
return null;
}
});
} finally {
revokeAll();
}
}
// After PHOENIX-4810, a user requires Exec permissions on SYSTEM.CHILD_LINK to create views
// since the user must invoke the ChildLinkMetaDataEndpoint to create parent->child links
@Test
public void testViewCreationFailsWhenNoExecPermsOnSystemChildLink() throws Throwable {
try {
grantSystemTableAccess();
final TableName systemChildLink = TableName.valueOf(SchemaUtil.getPhysicalHBaseTableName(
SYSTEM_SCHEMA_NAME, SYSTEM_CHILD_LINK_TABLE, true).getString());
final String schemaName = "S_" + generateUniqueName();
final String tableName = "T_" + generateUniqueName();
final String fullTableName = schemaName + "." + tableName;
final String viewName = "V_" + generateUniqueName();
verifyAllowed(createSchema(schemaName), superUser1);
verifyAllowed(createTable(fullTableName), superUser1);
superUser1.runAs(new PrivilegedExceptionAction<Object>() {
@Override public Object run() throws Exception {
try {
// Revoke Exec permissions for SYSTEM CHILD_LINK for the unprivileged user
AccessControlClient.revoke(getUtility().getConnection(), systemChildLink,
unprivilegedUser.getShortName(), null, null,
Permission.Action.EXEC);
// Grant read and exec permissions to the user on the parent table so it
// doesn't fail to getTable when resolving the parent
PermissionNSEnabledIT.this.grantPermissions(unprivilegedUser.getShortName(),
Collections.singleton(SchemaUtil
.getPhysicalHBaseTableName(schemaName, tableName, true)
.getString()), Permission.Action.READ,
Permission.Action.EXEC);
} catch (Throwable t) {
if (t instanceof Exception) {
throw (Exception) t;
} else {
throw new Exception(t);
}
}
return null;
}
});
// Adding parent->child links fails for the unprivileged user thus failing view creation
verifyDenied(createView(viewName, fullTableName), AccessDeniedException.class,
unprivilegedUser);
superUser1.runAs(new PrivilegedExceptionAction<Object>() {
@Override public Object run() throws Exception {
try {
// Grant Exec permissions for SYSTEM CHILD_LINK for the unprivileged user
PermissionNSEnabledIT.this.grantPermissions(unprivilegedUser.getShortName(),
Collections.singleton(systemChildLink.getNameAsString()),
Permission.Action.EXEC);
} catch (Throwable t) {
if (t instanceof Exception) {
throw (Exception) t;
} else {
throw new Exception(t);
}
}
return null;
}
});
verifyAllowed(createView(viewName, fullTableName), unprivilegedUser);
} finally {
revokeAll();
}
}
}