You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@impala.apache.org by ta...@apache.org on 2018/06/26 14:48:57 UTC
[4/6] impala git commit: IMPALA-6802 (part 5): Clean up authorization
tests
http://git-wip-us.apache.org/repos/asf/impala/blob/011acd07/fe/src/test/java/org/apache/impala/analysis/AuthorizationStmtTest.java
----------------------------------------------------------------------
diff --git a/fe/src/test/java/org/apache/impala/analysis/AuthorizationStmtTest.java b/fe/src/test/java/org/apache/impala/analysis/AuthorizationStmtTest.java
new file mode 100644
index 0000000..1d4c593
--- /dev/null
+++ b/fe/src/test/java/org/apache/impala/analysis/AuthorizationStmtTest.java
@@ -0,0 +1,1935 @@
+// 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.Sets;
+import org.apache.commons.lang.ArrayUtils;
+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.catalog.ScalarFunction;
+import org.apache.impala.catalog.Type;
+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.TColumnValue;
+import org.apache.impala.thrift.TDescribeOutputStyle;
+import org.apache.impala.thrift.TDescribeResult;
+import org.apache.impala.thrift.TFunctionBinaryType;
+import org.apache.impala.thrift.TPrivilege;
+import org.apache.impala.thrift.TPrivilegeLevel;
+import org.apache.impala.thrift.TPrivilegeScope;
+import org.apache.impala.thrift.TResultRow;
+import org.apache.impala.thrift.TTableName;
+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.Arrays;
+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;
+
+/**
+ * This class contains authorization tests for SQL statements.
+ */
+public class AuthorizationStmtTest 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 AuthorizationStmtTest() {
+ 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());
+ }
+ }
+
+ private static final String[] ALLTYPES_COLUMNS_WITHOUT_ID = new String[]{"bool_col",
+ "tinyint_col", "smallint_col", "int_col", "bigint_col", "float_col", "double_col",
+ "date_string_col", "string_col", "timestamp_col", "year", "month"};
+
+ private static final String[] ALLTYPES_COLUMNS = (String[]) ArrayUtils.addAll(
+ new String[]{"id"}, ALLTYPES_COLUMNS_WITHOUT_ID);
+
+ @Test
+ public void testPrivilegeRequests() throws ImpalaException {
+ // Used for select *, with, and union
+ Set<String> expectedAuthorizables = 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"
+ );
+ // Select *
+ verifyPrivilegeReqs("select * from functional.alltypes", expectedAuthorizables);
+ verifyPrivilegeReqs("select alltypes.* from functional.alltypes",
+ expectedAuthorizables);
+ verifyPrivilegeReqs(createAnalysisCtx("functional"), "select * from alltypes",
+ expectedAuthorizables);
+ verifyPrivilegeReqs(createAnalysisCtx("functional"),
+ "select alltypes.* from alltypes", expectedAuthorizables);
+ verifyPrivilegeReqs("select a.* from functional.alltypes a", expectedAuthorizables);
+
+ // With clause.
+ verifyPrivilegeReqs("with t as (select * from functional.alltypes) select * from t",
+ expectedAuthorizables);
+ verifyPrivilegeReqs(createAnalysisCtx("functional"),
+ "with t as (select * from alltypes) select * from t", expectedAuthorizables);
+
+ // Union.
+ verifyPrivilegeReqs("select * from functional.alltypes union all " +
+ "select * from functional.alltypes", expectedAuthorizables);
+ verifyPrivilegeReqs(createAnalysisCtx("functional"),
+ "select * from alltypes union all select * from alltypes",
+ expectedAuthorizables);
+
+ // Describe
+ expectedAuthorizables = Sets.newHashSet("functional.alltypes.*");
+ verifyPrivilegeReqs("describe functional.alltypes", expectedAuthorizables);
+ verifyPrivilegeReqs(createAnalysisCtx("functional"), "describe alltypes",
+ expectedAuthorizables);
+
+ // Select a specific column.
+ expectedAuthorizables = Sets.newHashSet(
+ "functional.alltypes",
+ "functional.alltypes.id"
+ );
+ verifyPrivilegeReqs("select id from functional.alltypes", expectedAuthorizables);
+ verifyPrivilegeReqs("select alltypes.id from functional.alltypes",
+ expectedAuthorizables);
+ verifyPrivilegeReqs(createAnalysisCtx("functional"),
+ "select alltypes.id from alltypes", expectedAuthorizables);
+ verifyPrivilegeReqs(createAnalysisCtx("functional"), "select id from alltypes",
+ expectedAuthorizables);
+ verifyPrivilegeReqs("select alltypes.id from functional.alltypes",
+ expectedAuthorizables);
+ verifyPrivilegeReqs("select a.id from functional.alltypes a", expectedAuthorizables);
+
+ // Insert.
+ expectedAuthorizables = Sets.newHashSet("functional.alltypes");
+ verifyPrivilegeReqs("insert into functional.alltypes(id) partition(month, year) " +
+ "values(1, 1, 2018)", expectedAuthorizables);
+ verifyPrivilegeReqs(createAnalysisCtx("functional"), "insert into alltypes(id) " +
+ "partition(month, year) values(1, 1, 2018)", expectedAuthorizables);
+
+ // Insert with constant select.
+ expectedAuthorizables = Sets.newHashSet("functional.zipcode_incomes");
+ verifyPrivilegeReqs("insert into functional.zipcode_incomes(id) select '123'",
+ expectedAuthorizables);
+ verifyPrivilegeReqs(createAnalysisCtx("functional"),
+ "insert into zipcode_incomes(id) select '123'", expectedAuthorizables);
+
+ // Truncate.
+ expectedAuthorizables = Sets.newHashSet("functional.alltypes");
+ verifyPrivilegeReqs("truncate table functional.alltypes", expectedAuthorizables);
+ verifyPrivilegeReqs(createAnalysisCtx("functional"),
+ "truncate table alltypes", expectedAuthorizables);
+
+
+ // Load
+ expectedAuthorizables = Sets.newHashSet(
+ "functional.alltypes",
+ "hdfs://localhost:20500/test-warehouse/tpch.lineitem"
+ );
+ verifyPrivilegeReqs("load data inpath " +
+ "'hdfs://localhost:20500/test-warehouse/tpch.lineitem' " +
+ "into table functional.alltypes partition(month=10, year=2009)",
+ expectedAuthorizables);
+ verifyPrivilegeReqs(createAnalysisCtx("functional"), "load data inpath " +
+ "'hdfs://localhost:20500/test-warehouse/tpch.lineitem' " +
+ "into table alltypes partition(month=10, year=2009)",
+ expectedAuthorizables);
+
+ // Reset metadata.
+ expectedAuthorizables = Sets.newHashSet("functional.alltypes");
+ verifyPrivilegeReqs("invalidate metadata functional.alltypes", expectedAuthorizables);
+ verifyPrivilegeReqs(createAnalysisCtx("functional"), "invalidate metadata alltypes",
+ expectedAuthorizables);
+ verifyPrivilegeReqs("refresh functional.alltypes", expectedAuthorizables);
+ verifyPrivilegeReqs(createAnalysisCtx("functional"), "refresh alltypes",
+ expectedAuthorizables);
+
+ // Show tables.
+ expectedAuthorizables = Sets.newHashSet("functional.*.*");
+ verifyPrivilegeReqs("show tables in functional", expectedAuthorizables);
+ verifyPrivilegeReqs(createAnalysisCtx("functional"), "show tables",
+ expectedAuthorizables);
+
+ // Show partitions.
+ expectedAuthorizables = Sets.newHashSet("functional.alltypes");
+ verifyPrivilegeReqs("show partitions functional.alltypes", expectedAuthorizables);
+ verifyPrivilegeReqs(createAnalysisCtx("functional"), "show partitions alltypes",
+ expectedAuthorizables);
+
+ // Show range partitions.
+ expectedAuthorizables = Sets.newHashSet("functional_kudu.dimtbl");
+ verifyPrivilegeReqs("show range partitions functional_kudu.dimtbl",
+ expectedAuthorizables);
+ verifyPrivilegeReqs(createAnalysisCtx("functional_kudu"),
+ "show range partitions dimtbl", expectedAuthorizables);
+
+ // Show table stats.
+ expectedAuthorizables = Sets.newHashSet("functional.alltypes");
+ verifyPrivilegeReqs("show table stats functional.alltypes",
+ expectedAuthorizables);
+ verifyPrivilegeReqs(createAnalysisCtx("functional"), "show table stats alltypes",
+ expectedAuthorizables);
+
+ // Show column stats.
+ expectedAuthorizables = Sets.newHashSet("functional.alltypes");
+ verifyPrivilegeReqs("show column stats functional.alltypes", expectedAuthorizables);
+ verifyPrivilegeReqs(createAnalysisCtx("functional"), "show column stats alltypes",
+ expectedAuthorizables);
+
+ // Show create table.
+ expectedAuthorizables = Sets.newHashSet("functional.alltypes");
+ verifyPrivilegeReqs("show create table functional.alltypes", expectedAuthorizables);
+ verifyPrivilegeReqs(createAnalysisCtx("functional"),
+ "show create table functional.alltypes", expectedAuthorizables);
+
+ // Show create view.
+ expectedAuthorizables = Sets.newHashSet("functional.alltypes_view");
+ verifyPrivilegeReqs("show create view functional.alltypes_view",
+ expectedAuthorizables);
+ verifyPrivilegeReqs(createAnalysisCtx("functional"),
+ "show create view functional.alltypes_view", expectedAuthorizables);
+
+ // Compute stats.
+ expectedAuthorizables = Sets.newHashSet("functional.alltypes");
+ verifyPrivilegeReqs("compute stats functional.alltypes", expectedAuthorizables);
+ verifyPrivilegeReqs(createAnalysisCtx("functional"), "compute stats alltypes",
+ expectedAuthorizables);
+
+ // Drop stats.
+ expectedAuthorizables = Sets.newHashSet("functional.alltypes");
+ verifyPrivilegeReqs("drop stats functional.alltypes", expectedAuthorizables);
+ verifyPrivilegeReqs(createAnalysisCtx("functional"), "drop stats alltypes",
+ expectedAuthorizables);
+
+ // Create table.
+ expectedAuthorizables = Sets.newHashSet("functional.new_table");
+ verifyPrivilegeReqs("create table functional.new_table(i int)",
+ expectedAuthorizables);
+ verifyPrivilegeReqs(createAnalysisCtx("functional"), "create table new_table(i int)",
+ expectedAuthorizables);
+
+ // Create view.
+ expectedAuthorizables = Sets.newHashSet("functional.new_view");
+ verifyPrivilegeReqs("create view functional.new_view as select 1",
+ expectedAuthorizables);
+ verifyPrivilegeReqs(createAnalysisCtx("functional"),
+ "create view new_view as select 1", expectedAuthorizables);
+
+ // Drop table.
+ expectedAuthorizables = Sets.newHashSet("functional.alltypes");
+ verifyPrivilegeReqs("drop table functional.alltypes", expectedAuthorizables);
+ verifyPrivilegeReqs(createAnalysisCtx("functional"), "drop table alltypes",
+ expectedAuthorizables);
+
+ // Drop view.
+ expectedAuthorizables = Sets.newHashSet("functional.alltypes_view");
+ verifyPrivilegeReqs("drop view functional.alltypes_view", expectedAuthorizables);
+ verifyPrivilegeReqs(createAnalysisCtx("functional"), "drop view alltypes_view",
+ expectedAuthorizables);
+ }
+
+ @Test
+ public void testSelect() throws ImpalaException {
+ for (AuthzTest authzTest: new AuthzTest[]{
+ // Select a specific column on a table.
+ authorize("select id from functional.alltypes"),
+ // With clause with select.
+ authorize("with t as (select id from functional.alltypes) select * from t")}) {
+ authzTest.ok(onServer(TPrivilegeLevel.ALL))
+ .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)));
+ }
+
+
+ // 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 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 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", ALLTYPES_COLUMNS, 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 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)));
+
+ // 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)));
+
+ 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)));
+
+ for (AuthzTest authzTest: new AuthzTest[]{
+ // Select with cross join.
+ authorize("select * from functional.alltypes union all " +
+ "select * from functional.alltypessmall"),
+ // Union on tables.
+ authorize("select * from functional.alltypes a cross join " +
+ "functional.alltypessmall b")}) {
+ authzTest.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", ALLTYPES_COLUMNS,
+ TPrivilegeLevel.SELECT), onColumn("functional", "alltypessmall",
+ ALLTYPES_COLUMNS, 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.alltypessmall"), onColumn("functional",
+ "alltypes", ALLTYPES_COLUMNS, TPrivilegeLevel.SELECT))
+ .error(selectError("functional.alltypes"), onColumn("functional",
+ "alltypessmall", ALLTYPES_COLUMNS, TPrivilegeLevel.SELECT));
+ }
+
+ // Union on views.
+ // Column-level privileges on views are not currently supported.
+ authorize("select id from functional.alltypes_view union all " +
+ "select x from functional.alltypes_view_sub")
+ .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),
+ onTable("functional", "alltypes_view_sub", TPrivilegeLevel.ALL))
+ .ok(onTable("functional", "alltypes_view", TPrivilegeLevel.SELECT),
+ onTable("functional", "alltypes_view_sub", 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)),
+ onTable("functional", "alltypes_view_sub", TPrivilegeLevel.SELECT))
+ .error(selectError("functional.alltypes_view_sub"), onTable("functional",
+ "alltypes_view_sub", allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)),
+ onTable("functional", "alltypes_view", TPrivilegeLevel.SELECT));
+
+ // Union from non-existent databases.
+ authorize("select id from nodb.alltypes union all " +
+ "select id from functional.alltypesagg").error(selectError("nodb.alltypes"));
+
+ // Union from non-existent tables.
+ authorize("select id from functional.notbl union all " +
+ "select id from functional.alltypesagg").error(selectError("functional.notbl"));
+ }
+
+ @Test
+ public void testInsert() throws ImpalaException {
+ // Basic insert into a table.
+ authorize("insert into functional.zipcode_incomes(id) values('123')")
+ .ok(onServer(TPrivilegeLevel.ALL))
+ .ok(onServer(TPrivilegeLevel.INSERT))
+ .ok(onDatabase("functional", TPrivilegeLevel.ALL))
+ .ok(onDatabase("functional", TPrivilegeLevel.INSERT))
+ .ok(onTable("functional", "zipcode_incomes", TPrivilegeLevel.ALL))
+ .ok(onTable("functional", "zipcode_incomes", TPrivilegeLevel.INSERT))
+ .error(insertError("functional.zipcode_incomes"))
+ .error(insertError("functional.zipcode_incomes"), onServer(allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.INSERT)))
+ .error(insertError("functional.zipcode_incomes"), onDatabase("functional",
+ allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.INSERT)))
+ .error(insertError("functional.zipcode_incomes"), onTable("functional",
+ "zipcode_incomes", allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.INSERT)));
+
+ for (AuthzTest test: new AuthzTest[]{
+ // With clause with insert.
+ authorize("with t as (select * from functional.alltypestiny) " +
+ "insert into functional.alltypes partition(month, year) " +
+ "select * from t"),
+ // Insert with select on a target table.
+ authorize("insert into functional.alltypes partition(month, year) " +
+ "select * from functional.alltypestiny where id < 100")}) {
+ test.ok(onServer(TPrivilegeLevel.ALL))
+ .ok(onServer(TPrivilegeLevel.INSERT, TPrivilegeLevel.SELECT))
+ .ok(onDatabase("functional", TPrivilegeLevel.ALL))
+ .ok(onDatabase("functional", TPrivilegeLevel.INSERT, TPrivilegeLevel.SELECT))
+ .ok(onTable("functional", "alltypes", TPrivilegeLevel.ALL),
+ onTable("functional", "alltypestiny", TPrivilegeLevel.ALL))
+ .ok(onTable("functional", "alltypes", TPrivilegeLevel.INSERT),
+ onTable("functional", "alltypestiny", TPrivilegeLevel.SELECT))
+ .ok(onTable("functional", "alltypes", TPrivilegeLevel.INSERT),
+ onColumn("functional", "alltypestiny", ALLTYPES_COLUMNS,
+ TPrivilegeLevel.SELECT))
+ .error(selectError("functional.alltypestiny"))
+ .error(selectError("functional.alltypestiny"), onServer(allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.INSERT, TPrivilegeLevel.SELECT)))
+ .error(selectError("functional.alltypestiny"), onDatabase("functional",
+ allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.INSERT,
+ TPrivilegeLevel.SELECT)))
+ .error(insertError("functional.alltypes"), onTable("functional",
+ "alltypestiny", TPrivilegeLevel.SELECT), onTable("functional",
+ "alltypes", allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.INSERT)))
+ .error(selectError("functional.alltypestiny"), onTable("functional",
+ "alltypestiny", allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)),
+ onTable("functional", "alltypes", TPrivilegeLevel.INSERT));
+ }
+
+ // Insert with select on a target view.
+ // Column-level privileges on views are not currently supported.
+ authorize("insert into functional.alltypes partition(month, year) " +
+ "select * from functional.alltypes_view where id < 100")
+ .ok(onServer(TPrivilegeLevel.ALL))
+ .ok(onServer(TPrivilegeLevel.INSERT, TPrivilegeLevel.SELECT))
+ .ok(onDatabase("functional", TPrivilegeLevel.ALL))
+ .ok(onDatabase("functional", TPrivilegeLevel.INSERT, TPrivilegeLevel.SELECT))
+ .ok(onTable("functional", "alltypes", TPrivilegeLevel.ALL),
+ onTable("functional", "alltypes_view", TPrivilegeLevel.ALL))
+ .ok(onTable("functional", "alltypes", TPrivilegeLevel.INSERT),
+ onTable("functional", "alltypes_view", TPrivilegeLevel.SELECT))
+ .error(selectError("functional.alltypes_view"))
+ .error(selectError("functional.alltypes_view"), onServer(allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.INSERT, TPrivilegeLevel.SELECT)))
+ .error(selectError("functional.alltypes_view"), onDatabase("functional",
+ allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.INSERT,
+ TPrivilegeLevel.SELECT)))
+ .error(insertError("functional.alltypes"), onTable("functional",
+ "alltypes_view", TPrivilegeLevel.SELECT), onTable("functional",
+ "alltypes", allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.INSERT)))
+ .error(selectError("functional.alltypes_view"), onTable("functional",
+ "alltypes_view", allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)),
+ onTable("functional", "alltypes", TPrivilegeLevel.INSERT));
+
+ // Insert with inline view.
+ authorize("insert into functional.alltypes partition(month, year) " +
+ "select b.* from functional.alltypesagg a join (select * from " +
+ "functional.alltypestiny) b on (a.int_col = b.int_col)")
+ .ok(onServer(TPrivilegeLevel.ALL))
+ .ok(onServer(TPrivilegeLevel.INSERT, TPrivilegeLevel.SELECT))
+ .ok(onDatabase("functional", TPrivilegeLevel.ALL))
+ .ok(onDatabase("functional", TPrivilegeLevel.INSERT, TPrivilegeLevel.SELECT))
+ .ok(onTable("functional", "alltypes", TPrivilegeLevel.ALL),
+ onTable("functional", "alltypesagg", TPrivilegeLevel.ALL),
+ onTable("functional", "alltypestiny", TPrivilegeLevel.ALL))
+ .ok(onTable("functional", "alltypes", TPrivilegeLevel.INSERT),
+ onTable("functional", "alltypesagg", TPrivilegeLevel.SELECT),
+ onTable("functional", "alltypestiny", TPrivilegeLevel.SELECT))
+ .error(selectError("functional.alltypesagg"))
+ .error(selectError("functional.alltypesagg"), onServer(allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.INSERT, TPrivilegeLevel.SELECT)))
+ .error(selectError("functional.alltypesagg"), onDatabase("functional", allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.INSERT, TPrivilegeLevel.SELECT)))
+ .error(insertError("functional.alltypes"), onTable("functional",
+ "alltypesagg", TPrivilegeLevel.SELECT), onTable("functional",
+ "alltypestiny", TPrivilegeLevel.SELECT), onTable("functional",
+ "alltypes", allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.INSERT)))
+ .error(selectError("functional.alltypesagg"), onTable("functional",
+ "alltypesagg", allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)),
+ onTable("functional", "alltypestiny", TPrivilegeLevel.SELECT),
+ onTable("functional", "alltypes", TPrivilegeLevel.INSERT))
+ .error(selectError("functional.alltypestiny"), onTable("functional",
+ "alltypesagg", TPrivilegeLevel.SELECT), onTable("functional",
+ "alltypestiny", allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)),
+ onTable("functional", "alltypes", TPrivilegeLevel.INSERT));
+
+ // Inserting into a view is not allowed.
+ authorize("insert into functional.alltypes_view(id) values(123)")
+ .error(insertError("functional.alltypes_view"));
+
+ // Inserting into a non-existent database.
+ authorize("insert into nodb.alltypes(id) values(1)")
+ .error(insertError("nodb.alltypes"));
+
+ // Inserting into a non-existent table.
+ authorize("insert into functional.notbl(id) values(1)")
+ .error(insertError("functional.notbl"));
+ }
+
+ @Test
+ public void testUseDb() throws ImpalaException {
+ AuthzTest test = authorize("use functional");
+ for (TPrivilegeLevel privilege: TPrivilegeLevel.values()) {
+ test.ok(onServer(privilege))
+ .ok(onDatabase("functional", privilege))
+ .ok(onTable("functional", "alltypes", privilege))
+ .ok(onColumn("functional", "alltypes", "id", privilege));
+ }
+ test.error(accessError("functional.*.*"));
+
+ // Accessing default database should always be allowed.
+ authorize("use default").ok();
+
+ // Accessing system database should always be allowed.
+ authorize("use _impala_builtins").ok();
+
+ // Use a non-existent database.
+ authorize("use nodb").error(accessError("nodb.*.*"));
+ }
+
+ @Test
+ public void testTruncate() throws ImpalaException {
+ // Truncate a table.
+ authorize("truncate table functional.alltypes")
+ .ok(onServer(TPrivilegeLevel.ALL))
+ .ok(onServer(TPrivilegeLevel.INSERT))
+ .ok(onDatabase("functional", TPrivilegeLevel.ALL))
+ .ok(onDatabase("functional", TPrivilegeLevel.INSERT))
+ .ok(onTable("functional", "alltypes", TPrivilegeLevel.ALL))
+ .ok(onTable("functional", "alltypes", TPrivilegeLevel.INSERT))
+ .error(insertError("functional.alltypes"))
+ .error(insertError("functional.alltypes"), onServer(allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.INSERT)))
+ .error(insertError("functional.alltypes"), onDatabase("functional", allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.INSERT)))
+ .error(insertError("functional.alltypes"), onTable("functional", "alltypes",
+ allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.INSERT)));
+
+ // Truncate a non-existent database.
+ authorize("truncate table nodb.alltypes")
+ .error(insertError("nodb.alltypes"));
+
+ // Truncate a non-existent table.
+ authorize("truncate table functional.notbl")
+ .error(insertError("functional.notbl"));
+
+ // Truncating a view is not supported.
+ authorize("truncate table functional.alltypes_view")
+ .error(insertError("functional.alltypes_view"));
+ }
+
+ @Test
+ public void testLoad() throws ImpalaException {
+ // Load into a table.
+ authorize("load data inpath 'hdfs://localhost:20500/test-warehouse/tpch.lineitem' " +
+ "into table functional.alltypes partition(month=10, year=2009)")
+ .ok(onServer(TPrivilegeLevel.ALL))
+ .ok(onDatabase("functional", TPrivilegeLevel.ALL),
+ onUri("hdfs://localhost:20500/test-warehouse/tpch.lineitem",
+ TPrivilegeLevel.ALL))
+ .ok(onDatabase("functional", TPrivilegeLevel.INSERT),
+ onUri("hdfs://localhost:20500/test-warehouse/tpch.lineitem",
+ TPrivilegeLevel.ALL))
+ .ok(onTable("functional", "alltypes", TPrivilegeLevel.ALL),
+ onUri("hdfs://localhost:20500/test-warehouse/tpch.lineitem",
+ TPrivilegeLevel.ALL))
+ .ok(onTable("functional", "alltypes", TPrivilegeLevel.INSERT),
+ onUri("hdfs://localhost:20500/test-warehouse/tpch.lineitem",
+ TPrivilegeLevel.ALL))
+ .error(insertError("functional.alltypes"))
+ .error(accessError("hdfs://localhost:20500/test-warehouse/tpch.lineitem"),
+ onDatabase("functional", TPrivilegeLevel.INSERT))
+ .error(accessError("hdfs://localhost:20500/test-warehouse/tpch.lineitem"),
+ onTable("functional", "alltypes", TPrivilegeLevel.INSERT))
+ .error(insertError("functional.alltypes"),
+ onUri("hdfs://localhost:20500/test-warehouse/tpch.lineitem",
+ TPrivilegeLevel.ALL));
+
+ // Load from non-existent URI.
+ authorize("load data inpath 'hdfs://localhost:20500/test-warehouse/nouri' " +
+ "into table functional.alltypes partition(month=10, year=2009)")
+ .error(insertError("functional.alltypes"))
+ .error(accessError("hdfs://localhost:20500/test-warehouse/nouri"),
+ onDatabase("functional", TPrivilegeLevel.INSERT))
+ .error(accessError("hdfs://localhost:20500/test-warehouse/nouri"),
+ onTable("functional", "alltypes", TPrivilegeLevel.INSERT));
+
+ // Load into non-existent database.
+ authorize("load data inpath 'hdfs://localhost:20500/test-warehouse/tpch.lineitem' " +
+ "into table nodb.alltypes partition(month=10, year=2009)")
+ .error(insertError("nodb.alltypes"))
+ .error(insertError("nodb.alltypes"), onUri(
+ "hdfs://localhost:20500/test-warehouse/tpch.nouri", TPrivilegeLevel.ALL));
+
+ // Load into non-existent table.
+ authorize("load data inpath 'hdfs://localhost:20500/test-warehouse/tpch.lineitem' " +
+ "into table functional.notbl partition(month=10, year=2009)")
+ .error(insertError("functional.notbl"))
+ .error(insertError("functional.notbl"), onUri(
+ "hdfs://localhost:20500/test-warehouse/tpch.nouri", TPrivilegeLevel.ALL));
+
+ // Load into a view is not supported.
+ authorize("load data inpath 'hdfs://localhost:20500/test-warehouse/tpch.lineitem' " +
+ "into table functional.alltypes_view")
+ .error(insertError("functional.alltypes_view"));
+ }
+
+ @Test
+ public void testResetMetadata() throws ImpalaException {
+ // Invalidate metadata on server.
+ authorize("invalidate metadata")
+ .ok(onServer(TPrivilegeLevel.ALL))
+ .ok(onServer(TPrivilegeLevel.REFRESH))
+ .error(refreshError("server"));
+
+ // Invalidate metadata/refresh on a table / view
+ for(String name: new String[] {"alltypes", "alltypes_view"}) {
+ for (AuthzTest test: new AuthzTest[]{
+ authorize("invalidate metadata functional." + name),
+ authorize("refresh functional." + name)}) {
+ test.ok(onServer(TPrivilegeLevel.ALL))
+ .ok(onServer(TPrivilegeLevel.REFRESH))
+ .ok(onDatabase("functional", TPrivilegeLevel.ALL))
+ .ok(onDatabase("functional", TPrivilegeLevel.REFRESH))
+ .ok(onTable("functional", name, TPrivilegeLevel.ALL))
+ .ok(onTable("functional", name, TPrivilegeLevel.REFRESH))
+ .error(refreshError("functional." + name))
+ .error(refreshError("functional." + name), onDatabase("functional", allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.REFRESH)))
+ .error(refreshError("functional." + name), onTable("functional", name,
+ allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.REFRESH)));
+ }
+ }
+
+ authorize("refresh functions functional")
+ .ok(onServer(TPrivilegeLevel.REFRESH))
+ .ok(onDatabase("functional", TPrivilegeLevel.ALL))
+ .ok(onDatabase("functional", TPrivilegeLevel.REFRESH))
+ .error(refreshError("functional"))
+ .error(refreshError("functional"), onServer(allExcept(TPrivilegeLevel.ALL,
+ TPrivilegeLevel.REFRESH)))
+ .error(refreshError("functional"), onDatabase("functional", allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.REFRESH)));
+
+ // Reset metadata in non-existent database.
+ authorize("invalidate metadata nodb").error(refreshError("default.nodb"));
+ authorize("refresh nodb").error(refreshError("default.nodb"));
+ authorize("refresh functions nodb").error(refreshError("nodb"));
+ }
+
+ @Test
+ public void testShow() throws ImpalaException {
+ // Show databases should always be allowed.
+ authorize("show databases").ok();
+
+ // Show tables.
+ AuthzTest test = authorize("show tables in functional");
+ for (TPrivilegeLevel privilege: TPrivilegeLevel.values()) {
+ test.ok(onServer(privilege))
+ .ok(onDatabase("functional", privilege))
+ .ok(onTable("functional", "alltypes", privilege));
+ }
+ test.error(accessError("functional.*.*"));
+
+ // Show functions.
+ test = authorize("show functions in functional");
+ for (TPrivilegeLevel privilege: viewMetadataPrivileges()) {
+ test.ok(onServer(privilege))
+ .ok(onDatabase("functional", privilege));
+ }
+ test.error(accessError("functional"));
+
+ // Show tables in system database should always be allowed.
+ authorize("show tables in _impala_builtins").ok();
+
+ // Show tables for non-existent database.
+ authorize("show tables in nodb").error(accessError("nodb"));
+
+ // Show partitions, table stats, and column stats
+ for (AuthzTest authzTest: new AuthzTest[]{
+ authorize("show partitions functional.alltypes"),
+ authorize("show table stats functional.alltypes"),
+ authorize("show column stats functional.alltypes")}) {
+ for (TPrivilegeLevel privilege: viewMetadataPrivileges()) {
+ authzTest.ok(onServer(privilege))
+ .ok(onDatabase("functional", privilege))
+ .ok(onTable("functional", "alltypes", privilege))
+ .error(accessError("functional.alltypes"), onColumn("functional", "alltypes",
+ "id", TPrivilegeLevel.SELECT));
+ }
+ authzTest.error(accessError("functional"));
+ }
+
+ // Show range partitions.dimtbl
+ for (TPrivilegeLevel privilege: viewMetadataPrivileges()) {
+ authorize("show range partitions functional_kudu.dimtbl")
+ .ok(onServer(privilege))
+ .ok(onDatabase("functional_kudu", privilege))
+ .ok(onTable("functional_kudu", "dimtbl", privilege))
+ .error(accessError("functional_kudu.dimtbl"), onColumn("functional_kudu",
+ "dimtbl", "id", TPrivilegeLevel.SELECT))
+ .error(accessError("functional_kudu"));
+ }
+
+ // Show files.
+ for (AuthzTest authzTest: new AuthzTest[]{
+ authorize("show files in functional.alltypes"),
+ authorize("show files in functional.alltypes partition(month=10, year=2010)")}) {
+ for (TPrivilegeLevel privilege: viewMetadataPrivileges()) {
+ authzTest.ok(onServer(privilege))
+ .ok(onDatabase("functional", privilege))
+ .ok(onTable("functional", "alltypes", privilege));
+ }
+ authzTest.error(accessError("functional"));
+ }
+
+ // Show current roles should always be allowed.
+ authorize("show current roles").ok();
+
+ // Show roles should always be allowed.
+ authorize("show roles").ok();
+
+ // Show role grant group should always be allowed.
+ authorize(String.format("show role grant group %s", USER.getName())).ok();
+
+ // Show grant role should always be allowed.
+ authorize(String.format("show grant role authz_test_role")).ok();
+
+ // Show create table.
+ test = authorize("show create table functional.alltypes");
+ for (TPrivilegeLevel privilege: viewMetadataPrivileges()) {
+ test.ok(onServer(privilege))
+ .ok(onDatabase("functional", privilege))
+ .ok(onTable("functional", "alltypes", privilege));
+ }
+ test.error(accessError("functional"));
+ // Show create table on non-existent database.
+ authorize("show create table nodb.alltypes").error(accessError("nodb.alltypes"));
+ // Show create table on non-existent table.
+ authorize("show create table functional.notbl")
+ .error(accessError("functional.notbl"));
+
+ // Show create view.
+ test = authorize("show create view functional.alltypes_view");
+ for (TPrivilegeLevel privilege: viewMetadataPrivileges()) {
+ test.ok(onServer(privilege, TPrivilegeLevel.SELECT))
+ .ok(onDatabase("functional", privilege, TPrivilegeLevel.SELECT))
+ .ok(onTable("functional", "alltypes_view", privilege),
+ onTable("functional", "alltypes", TPrivilegeLevel.SELECT));
+ }
+ test.error(accessError("functional"));
+ // Show create view on non-existent database.
+ authorize("show create view nodb.alltypes").error(accessError("nodb.alltypes"));
+ // Show create view on non-existent table.
+ authorize("show create view functional.notbl").error(accessError("functional.notbl"));
+
+ // Show create function.
+ ScalarFunction fn = addFunction("functional", "f");
+ try {
+ test = authorize("show create function functional.f");
+ for (TPrivilegeLevel privilege: viewMetadataPrivileges()) {
+ test.ok(onServer(privilege))
+ .ok(onDatabase("functional", privilege));
+ }
+ test.error(accessError("functional"));
+ // Show create function on non-existent database.
+ authorize("show create function nodb.f").error(accessError("nodb"));
+ // Show create function on non-existent function.
+ authorize("show create function functional.nofn").error(accessError("functional"));
+ } finally {
+ removeFunction(fn);
+ }
+ // Show create function in system database should always be allowed.
+ authorize("show create function _impala_builtins.pi").ok();
+
+ // Show data sources should always be allowed.
+ authorize("show data sources").ok();
+ }
+
+ /**
+ * Test describe output of Databases and tables.
+ * From https://issues.apache.org/jira/browse/IMPALA-6479
+ * Column level select privileges should limit output.
+ */
+ @Test
+ public void testDescribe() throws ImpalaException {
+ // Describe database.
+ AuthzTest authzTest = authorize("describe database functional");
+ for (TPrivilegeLevel privilege: viewMetadataPrivileges()) {
+ authzTest.ok(onServer(privilege))
+ .ok(onDatabase("functional", privilege));
+ }
+ authzTest.error(accessError("functional"))
+ .error(accessError("functional"), onServer(allExcept(viewMetadataPrivileges())))
+ .error(accessError("functional"), onDatabase("functional",
+ allExcept(viewMetadataPrivileges())));
+
+ // Describe on non-existent database.
+ authorize("describe database nodb").error(accessError("nodb"));
+
+ // Describe table.
+ TTableName tableName = new TTableName("functional", "alltypes");
+ TDescribeOutputStyle style = TDescribeOutputStyle.MINIMAL;
+ authzTest = authorize("describe functional.alltypes");
+ for (TPrivilegeLevel privilege: new TPrivilegeLevel[]{
+ TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT}) {
+ authzTest.okDescribe(tableName, style, ALLTYPES_COLUMNS, null, onServer(privilege))
+ .okDescribe(tableName, style, ALLTYPES_COLUMNS, null, onDatabase("functional",
+ privilege))
+ .okDescribe(tableName, style, ALLTYPES_COLUMNS, null, onTable("functional",
+ "alltypes", privilege));
+ }
+ authzTest.okDescribe(tableName, style, null, ALLTYPES_COLUMNS, onServer(allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)))
+ .okDescribe(tableName, style, null, ALLTYPES_COLUMNS, onDatabase("functional",
+ allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)))
+ .okDescribe(tableName, style, null, ALLTYPES_COLUMNS, onTable("functional",
+ "alltypes", allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)))
+ // In this test, since we only have column level privileges on "id", then
+ // only the "id" column should show and the others should not.
+ .okDescribe(tableName, style, new String[]{"id"}, ALLTYPES_COLUMNS_WITHOUT_ID,
+ onColumn("functional", "alltypes", "id", TPrivilegeLevel.SELECT))
+ .error(accessError("functional.alltypes"));
+
+ // Describe table extended.
+ tableName = new TTableName("functional", "alltypes");
+ style = TDescribeOutputStyle.EXTENDED;
+ String[] locationString = new String[]{"Location:"};
+ String[] checkStrings = (String[]) ArrayUtils.addAll(ALLTYPES_COLUMNS,
+ locationString);
+ authzTest = authorize("describe functional.alltypes");
+ for (TPrivilegeLevel privilege: new TPrivilegeLevel[]{
+ TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT}) {
+ authzTest.okDescribe(tableName, style, checkStrings, null, onServer(privilege))
+ .okDescribe(tableName, style, checkStrings, null, onDatabase("functional",
+ privilege))
+ .okDescribe(tableName, style, checkStrings, null, onTable("functional",
+ "alltypes", privilege));
+ }
+ authzTest.okDescribe(tableName, style, locationString, ALLTYPES_COLUMNS,
+ onServer(allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)))
+ .okDescribe(tableName, style, locationString, ALLTYPES_COLUMNS,
+ onDatabase("functional", allExcept(TPrivilegeLevel.ALL,
+ TPrivilegeLevel.SELECT)))
+ .okDescribe(tableName, style, locationString, ALLTYPES_COLUMNS,
+ onTable("functional", "alltypes", allExcept(TPrivilegeLevel.ALL,
+ TPrivilegeLevel.SELECT)))
+ // Location should not appear with only column level auth.
+ .okDescribe(tableName, style, new String[]{"id"},
+ (String[]) ArrayUtils.addAll(ALLTYPES_COLUMNS_WITHOUT_ID,
+ new String[]{"Location:"}), onColumn("functional", "alltypes", "id",
+ TPrivilegeLevel.SELECT))
+ .error(accessError("functional.alltypes"));
+
+ // Describe view.
+ tableName = new TTableName("functional", "alltypes_view");
+ style = TDescribeOutputStyle.MINIMAL;
+ authzTest = authorize("describe functional.alltypes_view");
+ for (TPrivilegeLevel privilege: new TPrivilegeLevel[]{
+ TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT}) {
+ authzTest.okDescribe(tableName, style, ALLTYPES_COLUMNS, null, onServer(privilege))
+ .okDescribe(tableName, style, ALLTYPES_COLUMNS, null, onDatabase("functional",
+ privilege))
+ .okDescribe(tableName, style, ALLTYPES_COLUMNS, null, onTable("functional",
+ "alltypes_view", privilege));
+ }
+ authzTest.okDescribe(tableName, style, null, ALLTYPES_COLUMNS, onServer(allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)))
+ .okDescribe(tableName, style, null, ALLTYPES_COLUMNS, onDatabase("functional",
+ allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)))
+ .okDescribe(tableName, style, null, ALLTYPES_COLUMNS, onTable("functional",
+ "alltypes_view", TPrivilegeLevel.INSERT))
+ .error(accessError("functional.alltypes_view"));
+
+ // Describe view extended.
+ tableName = new TTableName("functional", "alltypes_view");
+ style = TDescribeOutputStyle.EXTENDED;
+ // Views have extra output to explicitly check
+ String[] viewStrings = new String[]{"View Original Text:", "View Expanded Text:"};
+ checkStrings = (String[]) ArrayUtils.addAll(ALLTYPES_COLUMNS, viewStrings);
+ authzTest = authorize("describe functional.alltypes_view");
+ for (TPrivilegeLevel privilege: new TPrivilegeLevel[]{
+ TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT}) {
+ authzTest.okDescribe(tableName, style, checkStrings, null, onServer(privilege))
+ .okDescribe(tableName, style, checkStrings, null, onDatabase("functional",
+ privilege))
+ .okDescribe(tableName, style, checkStrings, null, onTable("functional",
+ "alltypes_view", privilege));
+ }
+ authzTest.okDescribe(tableName, style, null, ALLTYPES_COLUMNS, onServer(allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)))
+ .okDescribe(tableName, style, null, ALLTYPES_COLUMNS, onDatabase("functional",
+ allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)))
+ .okDescribe(tableName, style, viewStrings, ALLTYPES_COLUMNS, onTable("functional",
+ "alltypes_view", TPrivilegeLevel.INSERT))
+ .error(accessError("functional.alltypes_view"));
+
+ // Describe specific column on a table.
+ authzTest = authorize("describe functional.allcomplextypes.int_struct_col");
+ for (TPrivilegeLevel privilege: TPrivilegeLevel.values()) {
+ authzTest.ok(onServer(privilege))
+ .ok(onDatabase("functional", privilege))
+ .ok(onTable("functional", "allcomplextypes", privilege));
+ }
+ authzTest.ok(onColumn("functional", "allcomplextypes", "int_struct_col",
+ TPrivilegeLevel.SELECT))
+ .error(accessError("functional.allcomplextypes"));
+
+ for (AuthzTest test: new AuthzTest[]{
+ // User has access to a different column.
+ authorize("describe functional.allcomplextypes.int_struct_col"),
+ // Insufficient privileges on complex type column, accessing member
+ authorize("describe functional.allcomplextypes.complex_struct_col.f2"),
+ // Insufficient privileges on non-complex type column, accessing member
+ authorize("describe functional.allcomplextypes.nested_struct_col.f1")}) {
+ test.error(accessError("functional.allcomplextypes"), onColumn("functional",
+ "allcomplextypes", "id", TPrivilegeLevel.SELECT));
+ }
+ }
+
+ @Test
+ public void testStats() throws ImpalaException {
+ for (String statsType: new String[]{"compute", "drop"}) {
+ authorize(String.format("%s stats functional.alltypes", statsType))
+ .ok(onServer(TPrivilegeLevel.ALL))
+ .ok(onServer(TPrivilegeLevel.ALTER))
+ .ok(onDatabase("functional", TPrivilegeLevel.ALL))
+ .ok(onDatabase("functional", TPrivilegeLevel.ALTER))
+ .ok(onTable("functional", "alltypes", TPrivilegeLevel.ALL))
+ .ok(onTable("functional", "alltypes", TPrivilegeLevel.ALTER))
+ .error(alterError("functional.alltypes"))
+ .error(alterError("functional.alltypes"), onServer(allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.ALTER)))
+ .error(alterError("functional.alltypes"), onDatabase("functional",
+ allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.ALTER)))
+ .error(alterError("functional.alltypes"), onTable("functional", "alltypes",
+ allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.ALTER)));
+
+ // Database does not exist.
+ authorize(String.format("%s stats nodb.notbl", statsType))
+ .error(alterError("nodb.notbl"))
+ .error(alterError("nodb.notbl"), onServer(allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.ALTER)))
+ .error(alterError("default.nodb"), onDatabase("nodb", allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.ALL)));
+
+ // Table does not exist.
+ authorize(String.format("%s stats functional.notbl", statsType))
+ .error(alterError("functional.notbl"))
+ .error(alterError("functional.notbl"), onServer(allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.ALTER)))
+ .error(alterError("default.functional"), onDatabase("functional", allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.ALL)));
+ }
+ }
+
+ @Test
+ public void testCreateDatabase() throws ImpalaException {
+ for (AuthzTest test: new AuthzTest[]{
+ authorize("create database newdb"),
+ authorize("create database if not exists newdb")}) {
+ test.ok(onServer(TPrivilegeLevel.ALL))
+ .ok(onServer(TPrivilegeLevel.CREATE))
+ .error(createError("newdb"))
+ .error(createError("newdb"), onServer(allExcept(TPrivilegeLevel.ALL,
+ TPrivilegeLevel.CREATE)));
+ }
+
+ // Create a database with a specific location.
+ authorize("create database newdb location " +
+ "'hdfs://localhost:20500/test-warehouse/new_location'")
+ .ok(onServer(TPrivilegeLevel.ALL))
+ .ok(onServer(TPrivilegeLevel.CREATE), onUri(
+ "hdfs://localhost:20500/test-warehouse/new_location", TPrivilegeLevel.ALL))
+ .error(createError("newdb"))
+ .error(createError("newdb"), onServer(allExcept(TPrivilegeLevel.ALL,
+ TPrivilegeLevel.CREATE)), onUri(
+ "hdfs://localhost:20500/test-warehouse/new_location", TPrivilegeLevel.ALL))
+ .error(accessError("hdfs://localhost:20500/test-warehouse/new_location"),
+ onServer(TPrivilegeLevel.CREATE));
+
+ // Database already exists.
+ for (AuthzTest test: new AuthzTest[]{
+ authorize("create database functional"),
+ authorize("create database if not exists functional")}) {
+ test.error(createError("functional"))
+ .error(createError("functional"), onServer(allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.CREATE)));
+ }
+
+ authorize("create database if not exists _impala_builtins")
+ .error(systemDbError(), onServer(TPrivilegeLevel.ALL));
+ }
+
+ @Test
+ public void testCreateTable() throws ImpalaException {
+ for (AuthzTest test: new AuthzTest[]{
+ authorize("create table functional.new_table(i int)"),
+ authorize("create external table functional.new_table(i int)")}) {
+ test.ok(onServer(TPrivilegeLevel.ALL))
+ .ok(onServer(TPrivilegeLevel.CREATE))
+ .ok(onDatabase("functional", TPrivilegeLevel.ALL))
+ .ok(onDatabase("functional", TPrivilegeLevel.CREATE))
+ .error(createError("functional.new_table"), onServer(allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.CREATE)))
+ .error(createError("functional.new_table"), onDatabase("functional", allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.CREATE)));
+ }
+
+ // Create table like.
+ authorize("create table functional.new_table like functional.alltypes")
+ .ok(onServer(TPrivilegeLevel.ALL))
+ .ok(onServer(join(viewMetadataPrivileges(), TPrivilegeLevel.CREATE)))
+ .ok(onDatabase("functional", TPrivilegeLevel.ALL))
+ .ok(onDatabase("functional", join(viewMetadataPrivileges(),
+ TPrivilegeLevel.CREATE)))
+ .ok(onDatabase("functional"), onDatabase("functional", TPrivilegeLevel.CREATE),
+ onTable("functional", "alltypes", viewMetadataPrivileges()))
+ .error(accessError("functional.alltypes"))
+ .error(accessError("functional.alltypes"), onServer(allExcept(
+ join(viewMetadataPrivileges(), TPrivilegeLevel.CREATE))))
+ .error(createError("functional.new_table"), onDatabase("functional", allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.CREATE, TPrivilegeLevel.SELECT)))
+ .error(createError("functional.new_table"), onDatabase("functional", allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.CREATE)), onTable(
+ "functional", "alltypes", viewMetadataPrivileges()))
+ .error(accessError("functional.alltypes"), onDatabase("functional",
+ TPrivilegeLevel.CREATE), onTable("functional", "alltypes", allExcept(
+ viewMetadataPrivileges())));
+
+ // Table already exists.
+ for (AuthzTest test : new AuthzTest[]{
+ authorize("create table functional.alltypes(i int)"),
+ authorize("create table if not exists functional.alltypes(i int)")}) {
+ test.error(createError("functional.alltypes"))
+ .error(createError("functional.alltypes"), onServer(allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.CREATE)))
+ .error(createError("functional.alltypes"), onDatabase("functional", allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.CREATE)));
+ }
+
+ // CTAS.
+ authorize("create table functional.new_table as " +
+ "select int_col from functional.alltypes")
+ .ok(onServer(TPrivilegeLevel.ALL))
+ .ok(onServer(TPrivilegeLevel.CREATE, TPrivilegeLevel.INSERT,
+ TPrivilegeLevel.SELECT))
+ .ok(onDatabase("functional", TPrivilegeLevel.ALL))
+ .ok(onDatabase("functional", TPrivilegeLevel.CREATE, TPrivilegeLevel.INSERT,
+ TPrivilegeLevel.SELECT))
+ .ok(onDatabase("functional"), onDatabase("functional", TPrivilegeLevel.CREATE,
+ TPrivilegeLevel.INSERT), onTable("functional", "alltypes",
+ TPrivilegeLevel.SELECT))
+ .ok(onDatabase("functional"), onDatabase("functional", TPrivilegeLevel.CREATE,
+ TPrivilegeLevel.INSERT), onColumn("functional", "alltypes", "int_col",
+ TPrivilegeLevel.ALL))
+ .error(createError("functional.new_table"))
+ .error(createError("functional.new_table"), onServer(allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.CREATE, TPrivilegeLevel.INSERT,
+ TPrivilegeLevel.SELECT)))
+ .error(createError("functional.new_table"), onDatabase("functional", allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.CREATE, TPrivilegeLevel.INSERT,
+ TPrivilegeLevel.SELECT)))
+ .error(createError("functional.new_table"), onDatabase("functional", allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.CREATE, TPrivilegeLevel.INSERT)),
+ onTable("functional", "alltypes", TPrivilegeLevel.SELECT))
+ .error(selectError("functional.alltypes"), onDatabase("functional",
+ TPrivilegeLevel.CREATE, TPrivilegeLevel.INSERT), onTable("functional",
+ "alltypes", allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)));
+
+ // Table with a specific location.
+ authorize("create table functional.new_table(i int) location " +
+ "'hdfs://localhost:20500/test-warehouse/new_table'")
+ .ok(onServer(TPrivilegeLevel.ALL))
+ .ok(onServer(TPrivilegeLevel.CREATE),
+ onUri("hdfs://localhost:20500/test-warehouse/new_table", TPrivilegeLevel.ALL))
+ .error(createError("functional.new_table"), onServer(allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.CREATE)))
+ .error(createError("functional.new_table"), onDatabase("functional", allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.CREATE)), onUri(
+ "hdfs://localhost:20500/test-warehouse/new_table", TPrivilegeLevel.ALL))
+ .error(accessError("hdfs://localhost:20500/test-warehouse/new_table"),
+ onDatabase("functional", TPrivilegeLevel.CREATE));
+
+ // External table with URI location.
+ authorize("create external table functional.new_table(i int) location " +
+ "'hdfs://localhost:20500/test-warehouse/UPPER_CASE/test'")
+ .ok(onServer(TPrivilegeLevel.ALL))
+ .ok(onServer(TPrivilegeLevel.CREATE),
+ onUri("hdfs://localhost:20500/test-warehouse/UPPER_CASE/test",
+ TPrivilegeLevel.ALL))
+ // Wrong case letters on URI.
+ .error(accessError("hdfs://localhost:20500/test-warehouse/UPPER_CASE/test"),
+ onServer(TPrivilegeLevel.CREATE),
+ onUri("hdfs://localhost:20500/test-warehouse/upper_case/test",
+ TPrivilegeLevel.ALL))
+ .error(createError("functional.new_table"), onServer(allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.CREATE)))
+ .error(createError("functional.new_table"), onDatabase("functional", allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.CREATE)), onUri(
+ "hdfs://localhost:20500/test-warehouse/UPPER_CASE/test", TPrivilegeLevel.ALL))
+ .error(accessError("hdfs://localhost:20500/test-warehouse/UPPER_CASE/test"),
+ onDatabase("functional", TPrivilegeLevel.CREATE));
+
+ authorize("create table functional.new_table like parquet "
+ + "'hdfs://localhost:20500/test-warehouse/schemas/alltypestiny.parquet'")
+ .ok(onServer(TPrivilegeLevel.ALL))
+ .ok(onServer(TPrivilegeLevel.CREATE),
+ onUri("hdfs://localhost:20500/test-warehouse/schemas/alltypestiny.parquet",
+ TPrivilegeLevel.ALL))
+ .error(accessError(
+ "hdfs://localhost:20500/test-warehouse/schemas/alltypestiny.parquet"),
+ onServer(allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.CREATE)))
+ .error(createError("functional.new_table"), onDatabase("functional", allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.CREATE)), onUri(
+ "hdfs://localhost:20500/test-warehouse/schemas/alltypestiny.parquet",
+ TPrivilegeLevel.ALL))
+ .error(accessError(
+ "hdfs://localhost:20500/test-warehouse/schemas/alltypestiny.parquet"),
+ onDatabase("functional", TPrivilegeLevel.CREATE));
+
+ authorize("create table if not exists _impala_builtins.new_table(i int)")
+ .error(systemDbError(), onServer(TPrivilegeLevel.ALL));
+
+ // IMPALA-4000: Only users with ALL privileges on SERVER may create external Kudu
+ // tables.
+ authorize("create external table functional.kudu_tbl stored as kudu " +
+ "tblproperties ('kudu.master_addresses'='127.0.0.1', 'kudu.table_name'='tbl')")
+ .ok(onServer(TPrivilegeLevel.ALL))
+ .error(createError("functional.kudu_tbl"))
+ .error(accessError("server1"), onServer(allExcept(TPrivilegeLevel.ALL)))
+ .error(accessError("server1"), onDatabase("functional", TPrivilegeLevel.ALL));
+
+ // IMPALA-4000: ALL privileges on SERVER are not required to create managed tables.
+ authorize("create table functional.kudu_tbl (i int, j int, primary key (i))" +
+ " partition by hash (i) partitions 9 stored as kudu")
+ .ok(onServer(TPrivilegeLevel.ALL))
+ .ok(onDatabase("functional", TPrivilegeLevel.ALL))
+ .ok(onDatabase("functional", TPrivilegeLevel.CREATE))
+ .error(createError("functional.kudu_tbl"))
+ .error(createError("functional.kudu_tbl"), onServer(allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.CREATE)))
+ .error(createError("functional.kudu_tbl"), onDatabase("functional", allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.CREATE)));
+
+ // IMPALA-6451: CTAS for Kudu tables on non-external tables and without
+ // TBLPROPERTIES ('kudu.master_addresses') should not require ALL privileges
+ // on SERVER.
+ // The statement below causes the SQL statement to be rewritten.
+ authorize("create table functional.kudu_tbl primary key (bigint_col) " +
+ "stored as kudu as " +
+ "select bigint_col, string_col, current_timestamp() as ins_date " +
+ "from functional.alltypes " +
+ "where exists (select 1 from functional.alltypes)")
+ .ok(onServer(TPrivilegeLevel.ALL))
+ .ok(onDatabase("functional", TPrivilegeLevel.CREATE, TPrivilegeLevel.INSERT,
+ TPrivilegeLevel.SELECT))
+ .error(createError("functional.kudu_tbl"))
+ .error(createError("functional.kudu_tbl"), onServer(allExcept(TPrivilegeLevel.ALL,
+ TPrivilegeLevel.CREATE, TPrivilegeLevel.INSERT, TPrivilegeLevel.SELECT)))
+ .error(createError("functional.kudu_tbl"), onDatabase("functional", allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.CREATE, TPrivilegeLevel.INSERT,
+ TPrivilegeLevel.SELECT)));
+
+ // Database does not exist.
+ authorize("create table nodb.new_table(i int)")
+ .error(createError("nodb.new_table"))
+ .error(createError("nodb.new_table"), onServer(allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.CREATE)))
+ .error(createError("nodb.new_table"), onDatabase("functional", allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.CREATE)));
+ }
+
+ @Test
+ public void testCreateView() throws ImpalaException {
+ for (AuthzTest test: new AuthzTest[]{
+ authorize("create view functional.new_view as " +
+ "select int_col from functional.alltypes"),
+ authorize("create view functional.new_view(a) as " +
+ "select int_col from functional.alltypes")}) {
+ test.ok(onServer(TPrivilegeLevel.ALL))
+ .ok(onServer(TPrivilegeLevel.CREATE, TPrivilegeLevel.SELECT))
+ .ok(onDatabase("functional", TPrivilegeLevel.ALL))
+ .ok(onDatabase("functional", TPrivilegeLevel.CREATE, TPrivilegeLevel.SELECT))
+ .ok(onDatabase("functional", TPrivilegeLevel.CREATE), onTable(
+ "functional", "alltypes", TPrivilegeLevel.SELECT))
+ .ok(onDatabase("functional", TPrivilegeLevel.CREATE), onColumn(
+ "functional", "alltypes", "int_col", TPrivilegeLevel.ALL))
+ .error(selectError("functional.alltypes"))
+ .error(selectError("functional.alltypes"), onServer(allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.CREATE, TPrivilegeLevel.SELECT)))
+ .error(createError("functional.new_view"), onDatabase("functional", allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.CREATE)))
+ .error(selectError("functional.alltypes"), onDatabase("functional", allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)))
+ .error(selectError("functional.alltypes"), onTable("functional", "alltypes",
+ allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)));
+ }
+
+ // View with constant select.
+ authorize("create view functional.new_view as select 1")
+ .ok(onServer(TPrivilegeLevel.ALL))
+ .ok(onServer(TPrivilegeLevel.CREATE))
+ .ok(onDatabase("functional", TPrivilegeLevel.ALL))
+ .ok(onDatabase("functional", TPrivilegeLevel.CREATE))
+ .error(createError("functional.new_view"))
+ .error(createError("functional.new_view"), onServer(allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.CREATE, TPrivilegeLevel.SELECT)))
+ .error(createError("functional.new_view"), onDatabase("functional", allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.CREATE)));
+
+ // View already exists.
+ for (AuthzTest test: new AuthzTest[]{
+ authorize("create view functional.alltypes_view as " +
+ "select int_col from functional.alltypes"),
+ authorize("create view if not exists functional.alltypes_view as " +
+ "select int_col from functional.alltypes")}) {
+ test.error(selectError("functional.alltypes"))
+ .error(selectError("functional.alltypes"), onServer(allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.CREATE, TPrivilegeLevel.SELECT)))
+ .error(createError("functional.alltypes_view"), onDatabase("functional", allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.CREATE)))
+ .error(selectError("functional.alltypes"), onDatabase("functional", allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)))
+ .error(selectError("functional.alltypes"), onTable("functional", "alltypes",
+ allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT)));
+ }
+
+ authorize("create view if not exists _impala_builtins.new_view as select 1")
+ .error(systemDbError(), onServer(TPrivilegeLevel.ALL));
+
+ // Database does not exist.
+ authorize("create view nodb.new_view as select 1")
+ .error(createError("nodb.new_view"))
+ .error(createError("nodb.new_view"), onServer(allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.CREATE)))
+ .error(createError("nodb.new_view"), onDatabase("functional", allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.CREATE)));
+ }
+
+ @Test
+ public void testDropDatabase() throws ImpalaException {
+ for (AuthzTest test: new AuthzTest[]{
+ authorize("drop database functional"),
+ authorize("drop database functional cascade"),
+ authorize("drop database functional restrict")}) {
+ test.ok(onServer(TPrivilegeLevel.ALL))
+ .ok(onServer(TPrivilegeLevel.DROP))
+ .ok(onDatabase("functional", TPrivilegeLevel.ALL))
+ .ok(onDatabase("functional", TPrivilegeLevel.DROP))
+ .error(dropError("functional"))
+ .error(dropError("functional"), onServer(allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.DROP)))
+ .error(dropError("functional"), onDatabase("functional",
+ allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.DROP)));
+ }
+
+ // Database does not exist.
+ for (AuthzTest test: new AuthzTest[]{
+ authorize("drop database nodb"),
+ authorize("drop database nodb cascade"),
+ authorize("drop database nodb restrict")}) {
+ test.error(dropError("nodb"))
+ .error(dropError("nodb"), onServer(
+ allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.DROP)));
+ }
+
+ // Database does not exist but with if exists clause.
+ for (AuthzTest test: new AuthzTest[]{
+ authorize("drop database if exists nodb"),
+ authorize("drop database if exists nodb cascade"),
+ authorize("drop database if exists nodb restrict")}) {
+ test.ok(onServer(TPrivilegeLevel.ALL))
+ .ok(onServer(TPrivilegeLevel.DROP))
+ .error(dropError("nodb"))
+ .error(dropError("nodb"), onServer(allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.DROP)));
+ }
+
+ // Dropping system database is not allowed even if with ALL privilege on server.
+ authorize("drop database _impala_builtins")
+ .error(systemDbError(), onServer(TPrivilegeLevel.ALL));
+ }
+
+ @Test
+ public void testDropTable() throws ImpalaException {
+ authorize("drop table functional.alltypes")
+ .ok(onServer(TPrivilegeLevel.ALL))
+ .ok(onServer(TPrivilegeLevel.DROP))
+ .ok(onDatabase("functional", TPrivilegeLevel.ALL))
+ .ok(onDatabase("functional", TPrivilegeLevel.DROP))
+ .ok(onTable("functional", "alltypes", TPrivilegeLevel.ALL))
+ .ok(onTable("functional", "alltypes", TPrivilegeLevel.DROP))
+ .error(dropError("functional.alltypes"))
+ .error(dropError("functional.alltypes"), onServer(allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.DROP)))
+ .error(dropError("functional.alltypes"), onDatabase("functional",
+ allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.DROP)))
+ .error(dropError("functional.alltypes"), onTable("functional", "alltypes",
+ allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.DROP)));
+
+ // Database/Table does not exist.
+ authorize("drop table nodb.notbl")
+ .error(dropError("nodb.notbl"))
+ .error(dropError("nodb.notbl"), onServer(allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.DROP)))
+ .error(dropError("nodb.notbl"), onDatabase("functional",
+ allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.DROP)));
+
+ // Table does not exist.
+ authorize("drop table functional.notbl")
+ .error(dropError("functional.notbl"))
+ .error(dropError("functional.notbl"), onServer(allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.DROP)))
+ .error(dropError("functional.notbl"), onDatabase("functional",
+ allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.DROP)));
+
+ // Table does not exist but with if exists clause.
+ authorize("drop table if exists functional.notbl")
+ .ok(onServer(TPrivilegeLevel.ALL))
+ .ok(onServer(TPrivilegeLevel.DROP))
+ .ok(onDatabase("functional", TPrivilegeLevel.ALL))
+ .ok(onDatabase("functional", TPrivilegeLevel.DROP))
+ .error(dropError("functional.notbl"))
+ .error(dropError("functional.notbl"), onServer(allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.DROP)))
+ .error(dropError("functional.notbl"), onDatabase("functional",
+ allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.DROP)));
+
+ // Dropping any tables in the system database is not allowed even with ALL privilege
+ // on server.
+ authorize("drop table _impala_builtins.tbl")
+ .error(systemDbError(), onServer(TPrivilegeLevel.ALL));
+ }
+
+ @Test
+ public void testDropView() throws ImpalaException {
+ authorize("drop view functional.alltypes_view")
+ .ok(onServer(TPrivilegeLevel.ALL))
+ .ok(onServer(TPrivilegeLevel.DROP))
+ .ok(onDatabase("functional", TPrivilegeLevel.ALL))
+ .ok(onDatabase("functional", TPrivilegeLevel.DROP))
+ .ok(onTable("functional", "alltypes_view", TPrivilegeLevel.ALL))
+ .ok(onTable("functional", "alltypes_view", TPrivilegeLevel.DROP))
+ .error(dropError("functional.alltypes_view"))
+ .error(dropError("functional.alltypes_view"), onServer(allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.DROP)))
+ .error(dropError("functional.alltypes_view"), onDatabase("functional",
+ allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.DROP)))
+ .error(dropError("functional.alltypes_view"), onTable("functional",
+ "alltypes_view", allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.DROP)));
+
+ // Database does not exist.
+ authorize("drop view nodb.noview")
+ .error(dropError("nodb.noview"))
+ .error(dropError("nodb.noview"), onServer(allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.DROP)))
+ .error(dropError("nodb.noview"), onDatabase("functional",
+ allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.DROP)));
+
+ // View does not exist.
+ authorize("drop table functional.noview")
+ .error(dropError("functional.noview"))
+ .error(dropError("functional.noview"), onServer(allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.DROP)))
+ .error(dropError("functional.noview"), onDatabase("functional",
+ allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.DROP)));
+
+ // View does not exist but with if exists clause.
+ authorize("drop table if exists functional.noview")
+ .ok(onServer(TPrivilegeLevel.ALL))
+ .ok(onServer(TPrivilegeLevel.DROP))
+ .ok(onDatabase("functional", TPrivilegeLevel.ALL))
+ .ok(onDatabase("functional", TPrivilegeLevel.DROP))
+ .error(dropError("functional.noview"))
+ .error(dropError("functional.noview"), onServer(allExcept(
+ TPrivilegeLevel.ALL, TPrivilegeLevel.DROP)))
+ .error(dropError("functional.noview"), onDatabase("functional",
+ allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.DROP)));
+
+ // Dropping any views in the system database is not allowed even with ALL privilege
+ // on server.
+ authorize("drop table _impala_builtins.v")
+ .error(systemDbError(), onServer(TPrivilegeLevel.ALL));
+ }
+
+ // Convert TDescribeResult to list of strings.
+ private static List<String> resultToStringList(TDescribeResult result) {
+ List<String> list = new ArrayList<>();
+ for (TResultRow row: result.getResults()) {
+ for (TColumnValue col: row.getColVals()) {
+ list.add(col.getString_val() == null ? "NULL": col.getString_val().trim());
+ }
+ }
+ return list;
+ }
+
+ private static String selectError(String object) {
+ return "User '%s' does not have privileges to execute 'SELECT' on: " + object;
+ }
+
+ private static String insertError(String object) {
+ return "User '%s' does not have privileges to execute 'INSERT' on: " + object;
+ }
+
+ private static String createError(String object) {
+ return "User '%s' does not have privileges to execute 'CREATE' on: " + object;
+ }
+
+ private static String alterError(String object) {
+ return "User '%s' does not have privileges to execute 'ALTER' on: " + object;
+ }
+
+ private static String dropError(String object) {
+ return "User '%s' does not have privileges to execute 'DROP' on: " + object;
+ }
+
+ private static String accessError(String object) {
+ return "User '%s' does not have privileges to access: " + object;
+ }
+
+ private static String refreshError(String object) {
+ return "User '%s' does not have privileges to execute " +
+ "'INVALIDATE METADATA/REFRESH' on: " + object;
+ }
+
+ private static String systemDbError() {
+ return "Cannot modify system database.";
+ }
+
+ private ScalarFunction addFunction(String db, String fnName) {
+ ScalarFunction fn = ScalarFunction.createForTesting(db, fnName,
+ new ArrayList<Type>(), Type.INT, "/dummy", "dummy.class", null,
+ null, TFunctionBinaryType.NATIVE);
+ authzCatalog_.addFunction(fn);
+ return fn;
+ }
+
+ private void removeFunction(ScalarFunction fn) {
+ authzCatalog_.removeFunction(fn);
+ }
+
+ private TPrivilegeLevel[] join(TPrivilegeLevel[] level1, TPrivilegeLevel... level2) {
+ TPrivilegeLevel[] levels = new TPrivilegeLevel[level1.length + level2.length];
+ int index = 0;
+ for (TPrivilegeLevel level: level1) {
+ levels[index++] = level;
+ }
+ for (TPrivilegeLevel level: level2) {
+ levels[index++] = level;
+ }
+ return levels;
+ }
+
+ private TPrivilegeLevel[] viewMetadataPrivileges() {
+ return new TPrivilegeLevel[]{TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT,
+ TPrivilegeLevel.INSERT, TPrivilegeLevel.REFRESH};
+ }
+
+ 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_);
+ }
+ } catch (AuthorizationException ae) {
+ // Because the same test can be called from multiple statements
+ // it is useful to know which statement caused the exception.
+ throw new AuthorizationException(stmt_ + ": " + ae.getMessage(), ae);
+ } finally {
+ dropRole();
+ }
+ return this;
+ }
+
+ /**
+ * This method runs with the specified privileges and checks describe output.
+ *
+ * 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 okDescribe(TTableName table, TDescribeOutputStyle style,
+ String[] requiredStrings, String[] excludedStrings, TPrivilege[]... privileges)
+ throws ImpalaException {
+ try {
+ createRole(privileges);
+ if (context_ != null) {
+ authzOk(context_, stmt_);
+ } else {
+ authzOk(stmt_);
+ }
+ List<String> result = resultToStringList(authzFrontend_.describeTable(table,
+ style, USER));
+ if (requiredStrings != null) {
+ for (String str: requiredStrings) {
+ assertTrue(String.format("\"%s\" is not in the describe output.\n" +
+ "Expected : %s\n" +
+ "Actual : %s", str, Arrays.toString(requiredStrings), result),
+ result.contains(str));
+ }
+ }
+ if (excludedStrings != null) {
+ for (String str: excludedStrings) {
+ assertTrue(String.format("\"%s\" should not be in the describe output.", str),
+ !result.contains(str));
+ }
+ }
+ } 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
<TRUNCATED>