blob: a46196a0f8c006944fb3a7d41b95d3ec0cda377a [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.impala.analysis;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
import org.apache.impala.analysis.AnalysisContext.AnalysisResult;
import org.apache.impala.authorization.AuthorizationConfig;
import org.apache.impala.authorization.PrivilegeRequest;
import org.apache.impala.authorization.User;
import org.apache.impala.catalog.AuthorizationException;
import org.apache.impala.catalog.Role;
import org.apache.impala.catalog.RolePrivilege;
import org.apache.impala.common.FrontendTestBase;
import org.apache.impala.common.ImpalaException;
import org.apache.impala.common.RuntimeEnv;
import org.apache.impala.service.Frontend;
import org.apache.impala.testutil.ImpaladTestCatalog;
import org.apache.impala.thrift.TPrivilege;
import org.apache.impala.thrift.TPrivilegeLevel;
import org.apache.impala.thrift.TPrivilegeScope;
import org.apache.impala.util.SentryPolicyService;
import org.apache.sentry.provider.db.service.thrift.TSentryRole;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public class AuthorizationTestV2 extends FrontendTestBase {
private static final String SENTRY_SERVER = "server1";
private final static User USER = new User(System.getProperty("user.name"));
private final AnalysisContext analysisContext_;
private final SentryPolicyService sentryService_;
private final ImpaladTestCatalog authzCatalog_;
private final Frontend authzFrontend_;
public AuthorizationTestV2() {
AuthorizationConfig authzConfig = AuthorizationConfig.createHadoopGroupAuthConfig(
SENTRY_SERVER, null, System.getenv("IMPALA_HOME") +
"/fe/src/test/resources/sentry-site.xml");
authzConfig.validateConfig();
analysisContext_ = createAnalysisCtx(authzConfig, USER.getName());
authzCatalog_ = new ImpaladTestCatalog(authzConfig);
authzFrontend_ = new Frontend(authzConfig, authzCatalog_);
sentryService_ = new SentryPolicyService(authzConfig.getSentryConfig());
}
@BeforeClass
public static void setUp() {
RuntimeEnv.INSTANCE.setTestEnv(true);
}
@AfterClass
public static void cleanUp() {
RuntimeEnv.INSTANCE.reset();
}
@Before
public void before() throws ImpalaException {
// Remove existing roles in order to not interfere with these tests.
for (TSentryRole role : sentryService_.listAllRoles(USER)) {
authzCatalog_.removeRole(role.getRoleName());
}
}
@Test
public void testPrivilegeRequests() throws ImpalaException {
// Select *
Set<String> expectedPrivileges = Sets.newHashSet(
"functional.alltypes",
"functional.alltypes.id",
"functional.alltypes.bool_col",
"functional.alltypes.tinyint_col",
"functional.alltypes.smallint_col",
"functional.alltypes.int_col",
"functional.alltypes.bigint_col",
"functional.alltypes.float_col",
"functional.alltypes.double_col",
"functional.alltypes.date_string_col",
"functional.alltypes.string_col",
"functional.alltypes.timestamp_col",
"functional.alltypes.year",
"functional.alltypes.month"
);
verifyPrivilegeReqs("select * from functional.alltypes", expectedPrivileges);
verifyPrivilegeReqs("select alltypes.* from functional.alltypes", expectedPrivileges);
verifyPrivilegeReqs(createAnalysisCtx("functional"), "select * from alltypes",
expectedPrivileges);
verifyPrivilegeReqs(createAnalysisCtx("functional"),
"select alltypes.* from alltypes", expectedPrivileges);
verifyPrivilegeReqs("select a.* from functional.alltypes a", expectedPrivileges);
// Select a specific column.
expectedPrivileges = Sets.newHashSet(
"functional.alltypes",
"functional.alltypes.id"
);
verifyPrivilegeReqs("select id from functional.alltypes", expectedPrivileges);
verifyPrivilegeReqs("select alltypes.id from functional.alltypes",
expectedPrivileges);
verifyPrivilegeReqs(createAnalysisCtx("functional"),
"select alltypes.id from alltypes", expectedPrivileges);
verifyPrivilegeReqs(createAnalysisCtx("functional"), "select id from alltypes",
expectedPrivileges);
verifyPrivilegeReqs("select alltypes.id from functional.alltypes",
expectedPrivileges);
verifyPrivilegeReqs("select a.id from functional.alltypes a", expectedPrivileges);
}
@Test
public void testSelect() throws ImpalaException {
// Select a specific column on a table.
authorize("select id from functional.alltypes")
.ok(onServer(TPrivilegeLevel.ALL))
.ok(onServer(TPrivilegeLevel.SELECT))
.ok(onDatabase("functional", TPrivilegeLevel.ALL))
.ok(onDatabase("functional", TPrivilegeLevel.SELECT))
.ok(onTable("functional", "alltypes", TPrivilegeLevel.ALL))
.ok(onTable("functional", "alltypes", TPrivilegeLevel.SELECT))
.ok(onColumn("functional", "alltypes", "id", TPrivilegeLevel.SELECT))
.error(selectError("functional.alltypes"))
.error(selectError("functional.alltypes"), onServer(allExcept(
TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)))
.error(selectError("functional.alltypes"), onDatabase("functional",
allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)))
.error(selectError("functional.alltypes"), onTable("functional",
"alltypes", allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)))
.error(selectError("functional.alltypes"), onColumn("functional",
"alltypes", "id", allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)));
// Select a specific column on a view.
// Column-level privileges on views are not currently supported.
authorize("select id from functional.alltypes_view")
.ok(onServer(TPrivilegeLevel.ALL))
.ok(onServer(TPrivilegeLevel.SELECT))
.ok(onDatabase("functional", TPrivilegeLevel.ALL))
.ok(onDatabase("functional", TPrivilegeLevel.SELECT))
.ok(onTable("functional", "alltypes_view", TPrivilegeLevel.ALL))
.ok(onTable("functional", "alltypes_view", TPrivilegeLevel.SELECT))
.error(selectError("functional.alltypes_view"))
.error(selectError("functional.alltypes_view"), onServer(allExcept(
TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)))
.error(selectError("functional.alltypes_view"), onDatabase("functional",
allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)))
.error(selectError("functional.alltypes_view"), onTable("functional",
"alltypes_view", allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)));
// Constant select.
authorize("select 1").ok();
// Select on view and join table.
authorize("select a.id from functional.view_view a " +
"join functional.alltypesagg b ON (a.id = b.id)")
.ok(onServer(TPrivilegeLevel.ALL))
.ok(onServer(TPrivilegeLevel.SELECT))
.ok(onDatabase("functional", TPrivilegeLevel.ALL))
.ok(onDatabase("functional", TPrivilegeLevel.SELECT))
.ok(onTable("functional", "view_view", TPrivilegeLevel.ALL),
onTable("functional", "alltypesagg", TPrivilegeLevel.ALL))
.ok(onTable("functional", "view_view", TPrivilegeLevel.ALL),
onTable("functional", "alltypesagg", TPrivilegeLevel.SELECT))
.ok(onTable("functional", "view_view", TPrivilegeLevel.SELECT),
onTable("functional", "alltypesagg", TPrivilegeLevel.ALL))
.ok(onTable("functional", "view_view", TPrivilegeLevel.SELECT),
onTable("functional", "alltypesagg", TPrivilegeLevel.SELECT))
.error(selectError("functional.view_view"))
.error(selectError("functional.view_view"), onServer(allExcept(
TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)))
.error(selectError("functional.view_view"), onDatabase("functional",
allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)))
.error(selectError("functional.view_view"), onTable("functional", "view_view",
allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)), onTable("functional",
"alltypesagg", allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)));
// Tests authorization after a statement has been rewritten (IMPALA-3915).
authorize("select * from functional_seq_snap.subquery_view")
.ok(onServer(TPrivilegeLevel.ALL))
.ok(onServer(TPrivilegeLevel.SELECT))
.ok(onDatabase("functional_seq_snap", TPrivilegeLevel.ALL))
.ok(onDatabase("functional_seq_snap", TPrivilegeLevel.SELECT))
.ok(onTable("functional_seq_snap", "subquery_view", TPrivilegeLevel.ALL))
.ok(onTable("functional_seq_snap", "subquery_view", TPrivilegeLevel.SELECT))
.error(selectError("functional_seq_snap.subquery_view"))
.error(selectError("functional_seq_snap.subquery_view"), onServer(
allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)))
.error(selectError("functional_seq_snap.subquery_view"),
onDatabase("functional_seq_snap", allExcept(TPrivilegeLevel.ALL,
TPrivilegeLevel.SELECT)))
.error(selectError("functional_seq_snap.subquery_view"),
onTable("functional_seq_snap", "subquery_view", allExcept(
TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)));
// Select without referencing a column.
authorize("select 1 from functional.alltypes")
.ok(onServer(TPrivilegeLevel.ALL))
.ok(onServer(TPrivilegeLevel.SELECT))
.ok(onDatabase("functional", TPrivilegeLevel.ALL))
.ok(onDatabase("functional", TPrivilegeLevel.SELECT))
.ok(onTable("functional", "alltypes", TPrivilegeLevel.ALL))
.ok(onTable("functional", "alltypes", TPrivilegeLevel.SELECT))
.error(selectError("functional.alltypes"))
.error(selectError("functional.alltypes"), onServer(allExcept(
TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)))
.error(selectError("functional.alltypes"), onDatabase("functional",
allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)))
.error(selectError("functional.alltypes"), onTable("functional", "alltypes",
allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)));
// Select from non-existent database.
authorize("select 1 from nodb.alltypes")
.error(selectError("nodb.alltypes"));
// Select from non-existent table.
authorize("select 1 from functional.notbl")
.error(selectError("functional.notbl"));
// Select with inline view.
authorize("select a.* from (select * from functional.alltypes) a")
.ok(onServer(TPrivilegeLevel.ALL))
.ok(onServer(TPrivilegeLevel.SELECT))
.ok(onDatabase("functional", TPrivilegeLevel.ALL))
.ok(onDatabase("functional", TPrivilegeLevel.SELECT))
.ok(onTable("functional", "alltypes", TPrivilegeLevel.ALL))
.ok(onTable("functional", "alltypes", TPrivilegeLevel.SELECT))
.ok(onColumn("functional", "alltypes", new String[]{"id", "bool_col",
"tinyint_col", "smallint_col", "int_col", "bigint_col", "float_col",
"double_col", "date_string_col", "string_col", "timestamp_col", "year",
"month"}, TPrivilegeLevel.SELECT))
.error(selectError("functional.alltypes"))
.error(selectError("functional.alltypes"), onServer(allExcept(
TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)))
.error(selectError("functional.alltypes"), onDatabase("functional",
allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)))
.error(selectError("functional.alltypes"), onTable("functional", "alltypes",
allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)))
.error(selectError("functional.alltypes"), onColumn("functional", "alltypes",
new String[]{"id", "bool_col", "tinyint_col", "smallint_col", "int_col",
"bigint_col", "float_col", "double_col", "date_string_col", "string_col",
"timestamp_col", "year", "month"}, allExcept(TPrivilegeLevel.ALL,
TPrivilegeLevel.SELECT)));
// Select with columns referenced in function, where clause and group by.
authorize("select count(id), int_col from functional.alltypes where id = 10 " +
"group by id, int_col")
.ok(onServer(TPrivilegeLevel.ALL))
.ok(onServer(TPrivilegeLevel.SELECT))
.ok(onDatabase("functional", TPrivilegeLevel.ALL))
.ok(onDatabase("functional", TPrivilegeLevel.SELECT))
.ok(onTable("functional", "alltypes", TPrivilegeLevel.ALL))
.ok(onTable("functional", "alltypes", TPrivilegeLevel.SELECT))
.ok(onColumn("functional", "alltypes", new String[]{"id", "int_col"},
TPrivilegeLevel.SELECT))
.error(selectError("functional.alltypes"))
.error(selectError("functional.alltypes"), onServer(allExcept(
TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)))
.error(selectError("functional.alltypes"), onDatabase("functional",
allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)))
.error(selectError("functional.alltypes"), onTable("functional", "alltypes",
allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)))
.error(selectError("functional.alltypes"), onColumn("functional", "alltypes",
"id", allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)));
// Select on tables with complex types.
authorize("select a.int_struct_col.f1 from functional.allcomplextypes a " +
"where a.id = 1")
.ok(onServer(TPrivilegeLevel.ALL))
.ok(onServer(TPrivilegeLevel.SELECT))
.ok(onDatabase("functional", TPrivilegeLevel.ALL))
.ok(onDatabase("functional", TPrivilegeLevel.SELECT))
.ok(onTable("functional", "allcomplextypes", TPrivilegeLevel.ALL))
.ok(onTable("functional", "allcomplextypes", TPrivilegeLevel.SELECT))
.ok(onColumn("functional", "allcomplextypes",
new String[]{"id", "int_struct_col"}, TPrivilegeLevel.SELECT))
.error(selectError("functional.allcomplextypes"))
.error(selectError("functional.allcomplextypes"), onServer(
allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)))
.error(selectError("functional.allcomplextypes"), onDatabase("functional",
allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)))
.error(selectError("functional.allcomplextypes"), onTable("functional",
"allcomplextypes", allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)))
.error(selectError("functional.allcomplextypes"), onColumn("functional",
"allcomplextypes", new String[]{"id", "int_struct_col"}, allExcept(
TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)));
authorize("select key, pos, item.f1, f2 from functional.allcomplextypes t, " +
"t.struct_array_col, functional.allcomplextypes.int_map_col")
.ok(onServer(TPrivilegeLevel.ALL))
.ok(onServer(TPrivilegeLevel.SELECT))
.ok(onDatabase("functional", TPrivilegeLevel.ALL))
.ok(onDatabase("functional", TPrivilegeLevel.SELECT))
.ok(onTable("functional", "allcomplextypes", TPrivilegeLevel.ALL))
.ok(onTable("functional", "allcomplextypes", TPrivilegeLevel.SELECT))
.ok(onColumn("functional", "allcomplextypes",
new String[]{"struct_array_col", "int_map_col"}, TPrivilegeLevel.SELECT))
.error(selectError("functional.allcomplextypes"))
.error(selectError("functional.allcomplextypes"), onServer(allExcept(
TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)))
.error(selectError("functional.allcomplextypes"), onDatabase("functional",
allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)))
.error(selectError("functional.allcomplextypes"), onTable("functional",
"allcomplextypes", allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)))
.error(selectError("functional.allcomplextypes"), onColumn("functional",
"allcomplextypes", new String[]{"struct_array_col", "int_map_col"},
allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)));
// Select with cross join.
authorize("select * from functional.alltypes a cross join " +
"functional.alltypessmall b")
.ok(onServer(TPrivilegeLevel.ALL))
.ok(onServer(TPrivilegeLevel.SELECT))
.ok(onDatabase("functional", TPrivilegeLevel.ALL))
.ok(onDatabase("functional", TPrivilegeLevel.SELECT))
.ok(onTable("functional", "alltypes", TPrivilegeLevel.ALL),
onTable("functional", "alltypessmall", TPrivilegeLevel.ALL))
.ok(onTable("functional", "alltypes", TPrivilegeLevel.SELECT),
onTable("functional", "alltypessmall", TPrivilegeLevel.ALL))
.ok(onTable("functional", "alltypes", TPrivilegeLevel.ALL),
onTable("functional", "alltypessmall", TPrivilegeLevel.SELECT))
.ok(onTable("functional", "alltypes", TPrivilegeLevel.SELECT),
onTable("functional", "alltypessmall", TPrivilegeLevel.SELECT))
.ok(onColumn("functional", "alltypes", new String[]{"id", "bool_col",
"tinyint_col", "smallint_col", "int_col", "bigint_col", "float_col",
"double_col", "date_string_col", "string_col", "timestamp_col", "year",
"month"}, TPrivilegeLevel.SELECT),
onColumn("functional", "alltypessmall", new String[]{"id", "bool_col",
"tinyint_col", "smallint_col", "int_col", "bigint_col", "float_col",
"double_col", "date_string_col", "string_col", "timestamp_col", "year",
"month"}, TPrivilegeLevel.SELECT))
.error(selectError("functional.alltypes"))
.error(selectError("functional.alltypes"), onServer(
allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)))
.error(selectError("functional.alltypes"), onDatabase("functional",
allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)))
.error(selectError("functional.alltypes"), onTable("functional", "alltypes",
allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)), onTable("functional",
"alltypessmall", allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)))
.error(selectError("functional.alltypes"), onColumn("functional", "alltypes",
new String[]{"id", "bool_col", "tinyint_col", "smallint_col", "int_col",
"bigint_col", "float_col", "double_col", "date_string_col", "string_col",
"timestamp_col", "year", "month"}, allExcept(TPrivilegeLevel.ALL,
TPrivilegeLevel.SELECT)), onColumn("functional", "alltypessmall",
new String[]{"id", "bool_col", "tinyint_col", "smallint_col", "int_col",
"bigint_col", "float_col", "double_col", "date_string_col", "string_col",
"timestamp_col", "year", "month"}, allExcept(TPrivilegeLevel.ALL,
TPrivilegeLevel.SELECT)));
}
private static String selectError(String object) {
return "User '%s' does not have privileges to execute 'SELECT' on: " + object;
}
private static TPrivilegeLevel[] allExcept(TPrivilegeLevel... excludedPrivLevels) {
HashSet<TPrivilegeLevel> excludedSet = Sets.newHashSet(excludedPrivLevels);
List<TPrivilegeLevel> privLevels = new ArrayList<>();
for (TPrivilegeLevel level : TPrivilegeLevel.values()) {
if (!excludedSet.contains(level)) {
privLevels.add(level);
}
}
return privLevels.toArray(new TPrivilegeLevel[0]);
}
private class AuthzTest {
private final AnalysisContext context_;
private final String stmt_;
private final String role_ = "authz_test_role";
public AuthzTest(String stmt) {
this(null, stmt);
}
public AuthzTest(AnalysisContext context, String stmt) {
Preconditions.checkNotNull(stmt);
context_ = context;
stmt_ = stmt;
}
private void createRole(TPrivilege[]... privileges) throws ImpalaException {
Role role = authzCatalog_.addRole(role_);
authzCatalog_.addRoleGrantGroup(role_, USER.getName());
for (TPrivilege[] privs : privileges) {
for (TPrivilege privilege : privs) {
privilege.setRole_id(role.getId());
authzCatalog_.addRolePrivilege(role_, privilege);
}
}
}
private void dropRole() throws ImpalaException {
authzCatalog_.removeRole(role_);
}
/**
* This method runs with the specified privileges.
*
* A new temporary role will be created and assigned to the specified privileges
* into the new role. The new role will be dropped once this method finishes.
*/
public AuthzTest ok(TPrivilege[]... privileges) throws ImpalaException {
try {
createRole(privileges);
if (context_ != null) {
authzOk(context_, stmt_);
} else {
authzOk(stmt_);
}
} finally {
dropRole();
}
return this;
}
/**
* This method runs with the specified privileges.
*
* A new temporary role will be created and assigned to the specified privileges
* into the new role. The new role will be dropped once this method finishes.
*/
public AuthzTest error(String expectedError, TPrivilege[]... privileges)
throws ImpalaException {
try {
createRole(privileges);
if (context_ != null) {
authzError(context_, stmt_, expectedError);
} else {
authzError(stmt_, expectedError);
}
} finally {
dropRole();
}
return this;
}
}
private AuthzTest authorize(String stmt) {
return new AuthzTest(stmt);
}
private AuthzTest authorize(AnalysisContext ctx, String stmt) {
return new AuthzTest(ctx, stmt);
}
private TPrivilege[] onServer(TPrivilegeLevel... levels) {
TPrivilege[] privileges = new TPrivilege[levels.length];
for (int i = 0; i < levels.length; i++) {
privileges[i] = new TPrivilege("", levels[i], TPrivilegeScope.SERVER, false);
privileges[i].setServer_name(SENTRY_SERVER);
privileges[i].setPrivilege_name(RolePrivilege.buildRolePrivilegeName(
privileges[i]));
}
return privileges;
}
private TPrivilege[] onDatabase(String db, TPrivilegeLevel... levels) {
TPrivilege[] privileges = new TPrivilege[levels.length];
for (int i = 0; i < levels.length; i++) {
privileges[i] = new TPrivilege("", levels[i], TPrivilegeScope.DATABASE, false);
privileges[i].setServer_name(SENTRY_SERVER);
privileges[i].setDb_name(db);
privileges[i].setPrivilege_name(RolePrivilege.buildRolePrivilegeName(
privileges[i]));
}
return privileges;
}
private TPrivilege[] onTable(String db, String table, TPrivilegeLevel... levels) {
TPrivilege[] privileges = new TPrivilege[levels.length];
for (int i = 0; i < levels.length; i++) {
privileges[i] = new TPrivilege("", levels[i], TPrivilegeScope.TABLE, false);
privileges[i].setServer_name(SENTRY_SERVER);
privileges[i].setDb_name(db);
privileges[i].setTable_name(table);
privileges[i].setPrivilege_name(RolePrivilege.buildRolePrivilegeName(
privileges[i]));
}
return privileges;
}
private TPrivilege[] onColumn(String db, String table, String column,
TPrivilegeLevel... levels) {
return onColumn(db, table, new String[]{column}, levels);
}
private TPrivilege[] onColumn(String db, String table, String[] columns,
TPrivilegeLevel... levels) {
int size = columns.length * levels.length;
TPrivilege[] privileges = new TPrivilege[size];
int idx = 0;
for (int i = 0; i < levels.length; i++) {
for (String column : columns) {
privileges[idx] = new TPrivilege("", levels[i], TPrivilegeScope.COLUMN, false);
privileges[idx].setServer_name(SENTRY_SERVER);
privileges[idx].setDb_name(db);
privileges[idx].setTable_name(table);
privileges[idx].setColumn_name(column);
privileges[idx].setPrivilege_name(RolePrivilege.buildRolePrivilegeName(
privileges[idx]));
idx++;
}
}
return privileges;
}
private TPrivilege[] onUri(String uri, TPrivilegeLevel... levels) {
TPrivilege[] privileges = new TPrivilege[levels.length];
for (int i = 0; i < levels.length; i++) {
privileges[i] = new TPrivilege("", levels[i], TPrivilegeScope.URI, false);
privileges[i].setServer_name(SENTRY_SERVER);
privileges[i].setUri(uri);
privileges[i].setPrivilege_name(RolePrivilege.buildRolePrivilegeName(
privileges[i]));
}
return privileges;
}
private void authzOk(String stmt) throws ImpalaException {
authzOk(analysisContext_, stmt);
}
private void authzOk(AnalysisContext context, String stmt) throws ImpalaException {
authzOk(authzFrontend_, context, stmt);
}
private void authzOk(Frontend fe, AnalysisContext context, String stmt)
throws ImpalaException {
parseAndAnalyze(stmt, context, fe);
}
/**
* Verifies that a given statement fails authorization and the expected error
* string matches.
*/
private void authzError(String stmt, String expectedError, Matcher matcher)
throws ImpalaException {
authzError(analysisContext_, stmt, expectedError, matcher);
}
private void authzError(String stmt, String expectedError)
throws ImpalaException {
authzError(analysisContext_, stmt, expectedError, startsWith());
}
private void authzError(AnalysisContext ctx, String stmt, String expectedError,
Matcher matcher) throws ImpalaException {
authzError(authzFrontend_, ctx, stmt, expectedError, matcher);
}
private void authzError(AnalysisContext ctx, String stmt, String expectedError)
throws ImpalaException {
authzError(authzFrontend_, ctx, stmt, expectedError, startsWith());
}
private interface Matcher {
boolean match(String actual, String expected);
}
private static Matcher exact() {
return new Matcher() {
@Override
public boolean match(String actual, String expected) {
return actual.equals(expected);
}
};
}
private static Matcher startsWith() {
return new Matcher() {
@Override
public boolean match(String actual, String expected) {
return actual.startsWith(expected);
}
};
}
private void authzError(Frontend fe, AnalysisContext ctx,
String stmt, String expectedErrorString, Matcher matcher)
throws ImpalaException {
Preconditions.checkNotNull(expectedErrorString);
try {
parseAndAnalyze(stmt, ctx, fe);
} catch (AuthorizationException e) {
// Insert the username into the error.
expectedErrorString = String.format(expectedErrorString, ctx.getUser());
String errorString = e.getMessage();
assertTrue(
"got error:\n" + errorString + "\nexpected:\n" + expectedErrorString,
matcher.match(errorString, expectedErrorString));
return;
}
fail("Stmt didn't result in authorization error: " + stmt);
}
private void verifyPrivilegeReqs(String stmt, Set<String> expectedPrivilegeNames)
throws ImpalaException {
verifyPrivilegeReqs(createAnalysisCtx(), stmt, expectedPrivilegeNames);
}
private void verifyPrivilegeReqs(AnalysisContext ctx, String stmt,
Set<String> expectedPrivilegeNames) throws ImpalaException {
AnalysisResult analysisResult = parseAndAnalyze(stmt, ctx, frontend_);
ImmutableList<PrivilegeRequest> privilegeReqs =
analysisResult.getAnalyzer().getPrivilegeReqs();
assertEquals(expectedPrivilegeNames.size(), privilegeReqs.size());
for (PrivilegeRequest privilegeReq : privilegeReqs) {
assertTrue(String.format("Privilege on %s should not exist.",
privilegeReq.getName()),
expectedPrivilegeNames.contains(privilegeReq.getName()));
}
}
}