Repository: impala Updated Branches: refs/heads/master 147e962f2 -> 5c3f06c72
IMPALA-6802 (part 4): Clean up authorization tests The fourth part of this patch is to rewrite the following authorization tests: - describe Testing: - Added new authorization tests - Ran all front-end tests Cherry-picks: not for 2.x Change-Id: Ic4cf3a4751b41908ef81ec35d89a2713d9fa0dc4 Reviewed-on: http://gerrit.cloudera.org:8080/10442 Tested-by: Impala Public Jenkins <[email protected]> Reviewed-by: Vuk Ercegovac <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/impala/repo Commit: http://git-wip-us.apache.org/repos/asf/impala/commit/4cfd40ce Tree: http://git-wip-us.apache.org/repos/asf/impala/tree/4cfd40ce Diff: http://git-wip-us.apache.org/repos/asf/impala/diff/4cfd40ce Branch: refs/heads/master Commit: 4cfd40cef8ff1df1efe301894dc7425513dd1f74 Parents: 147e962 Author: Adam Holley <[email protected]> Authored: Thu May 17 13:02:52 2018 -0500 Committer: Tim Armstrong <[email protected]> Committed: Mon Jun 18 22:42:01 2018 +0000 ---------------------------------------------------------------------- .../impala/analysis/AuthorizationTestV2.java | 336 +++++++++++++++---- 1 file changed, 279 insertions(+), 57 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/impala/blob/4cfd40ce/fe/src/test/java/org/apache/impala/analysis/AuthorizationTestV2.java ---------------------------------------------------------------------- diff --git a/fe/src/test/java/org/apache/impala/analysis/AuthorizationTestV2.java b/fe/src/test/java/org/apache/impala/analysis/AuthorizationTestV2.java index 59ea4a1..ba097ca 100644 --- a/fe/src/test/java/org/apache/impala/analysis/AuthorizationTestV2.java +++ b/fe/src/test/java/org/apache/impala/analysis/AuthorizationTestV2.java @@ -19,6 +19,7 @@ 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; @@ -33,18 +34,25 @@ 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.Assert; 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; @@ -85,11 +93,18 @@ public class AuthorizationTestV2 extends FrontendTestBase { @Before public void before() throws ImpalaException { // Remove existing roles in order to not interfere with these tests. - for (TSentryRole role : sentryService_.listAllRoles(USER)) { + 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 @@ -111,7 +126,8 @@ public class AuthorizationTestV2 extends FrontendTestBase { ); // Select * verifyPrivilegeReqs("select * from functional.alltypes", expectedAuthorizables); - verifyPrivilegeReqs("select alltypes.* from functional.alltypes", expectedAuthorizables); + verifyPrivilegeReqs("select alltypes.* from functional.alltypes", + expectedAuthorizables); verifyPrivilegeReqs(createAnalysisCtx("functional"), "select * from alltypes", expectedAuthorizables); verifyPrivilegeReqs(createAnalysisCtx("functional"), @@ -131,6 +147,12 @@ public class AuthorizationTestV2 extends FrontendTestBase { "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", @@ -167,6 +189,7 @@ public class AuthorizationTestV2 extends FrontendTestBase { verifyPrivilegeReqs(createAnalysisCtx("functional"), "truncate table alltypes", expectedAuthorizables); + // Load expectedAuthorizables = Sets.newHashSet( "functional.alltypes", @@ -238,13 +261,11 @@ public class AuthorizationTestV2 extends FrontendTestBase { @Test public void testSelect() throws ImpalaException { - for (AuthzTest authzTest : new AuthzTest[]{ + 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"), - // Select without referencing a column. - authorize("select 1 from functional.alltypes")}) { + 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)) @@ -262,6 +283,24 @@ public class AuthorizationTestV2 extends FrontendTestBase { "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") @@ -340,10 +379,7 @@ public class AuthorizationTestV2 extends FrontendTestBase { .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)) + .ok(onColumn("functional", "alltypes", ALLTYPES_COLUMNS, TPrivilegeLevel.SELECT)) .error(selectError("functional.alltypes")) .error(selectError("functional.alltypes"), onServer(allExcept( TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT))) @@ -408,7 +444,7 @@ public class AuthorizationTestV2 extends FrontendTestBase { .error(selectError("functional.allcomplextypes"), onTable("functional", "allcomplextypes", allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.SELECT))); - for (AuthzTest authzTest : new AuthzTest[]{ + for (AuthzTest authzTest: new AuthzTest[]{ // Select with cross join. authorize("select * from functional.alltypes union all " + "select * from functional.alltypessmall"), @@ -427,30 +463,22 @@ public class AuthorizationTestV2 extends FrontendTestBase { 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)) + .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", - 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)) + 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", 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)); + "alltypessmall", ALLTYPES_COLUMNS, TPrivilegeLevel.SELECT)); } // Union on views. @@ -504,7 +532,7 @@ public class AuthorizationTestV2 extends FrontendTestBase { .error(insertError("functional.zipcode_incomes"), onTable("functional", "zipcode_incomes", allExcept(TPrivilegeLevel.ALL, TPrivilegeLevel.INSERT))); - for (AuthzTest test : new AuthzTest[]{ + for (AuthzTest test: new AuthzTest[]{ // With clause with insert. authorize("with t as (select * from functional.alltypestiny) " + "insert into functional.alltypes partition(month, year) " + @@ -521,15 +549,14 @@ public class AuthorizationTestV2 extends FrontendTestBase { .ok(onTable("functional", "alltypes", TPrivilegeLevel.INSERT), onTable("functional", "alltypestiny", TPrivilegeLevel.SELECT)) .ok(onTable("functional", "alltypes", TPrivilegeLevel.INSERT), - onColumn("functional", "alltypestiny", 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", "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(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))) @@ -553,8 +580,9 @@ public class AuthorizationTestV2 extends FrontendTestBase { .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(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))) @@ -610,7 +638,7 @@ public class AuthorizationTestV2 extends FrontendTestBase { @Test public void testUseDb() throws ImpalaException { AuthzTest test = authorize("use functional"); - for (TPrivilegeLevel privilege : TPrivilegeLevel.values()) { + for (TPrivilegeLevel privilege: TPrivilegeLevel.values()) { test.ok(onServer(privilege)) .ok(onDatabase("functional", privilege)) .ok(onTable("functional", "alltypes", privilege)) @@ -724,8 +752,8 @@ public class AuthorizationTestV2 extends FrontendTestBase { .error(refreshError("server")); // Invalidate metadata/refresh on a table / view - for(String name : new String[] {"alltypes", "alltypes_view"}) { - for (AuthzTest test : new AuthzTest[]{ + 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)) @@ -765,7 +793,7 @@ public class AuthorizationTestV2 extends FrontendTestBase { // Show tables. AuthzTest test = authorize("show tables in functional"); - for (TPrivilegeLevel privilege : TPrivilegeLevel.values()) { + for (TPrivilegeLevel privilege: TPrivilegeLevel.values()) { test.ok(onServer(privilege)) .ok(onDatabase("functional", privilege)) .ok(onTable("functional", "alltypes", privilege)); @@ -774,7 +802,7 @@ public class AuthorizationTestV2 extends FrontendTestBase { // Show functions. test = authorize("show functions in functional"); - for (TPrivilegeLevel privilege : viewMetadataPrivileges()) { + for (TPrivilegeLevel privilege: viewMetadataPrivileges()) { test.ok(onServer(privilege)) .ok(onDatabase("functional", privilege)); } @@ -791,7 +819,7 @@ public class AuthorizationTestV2 extends FrontendTestBase { authorize("show partitions functional.alltypes"), authorize("show table stats functional.alltypes"), authorize("show column stats functional.alltypes")}) { - for (TPrivilegeLevel privilege : viewMetadataPrivileges()) { + for (TPrivilegeLevel privilege: viewMetadataPrivileges()) { authzTest.ok(onServer(privilege)) .ok(onDatabase("functional", privilege)) .ok(onTable("functional", "alltypes", privilege)) @@ -802,7 +830,7 @@ public class AuthorizationTestV2 extends FrontendTestBase { } // Show range partitions.dimtbl - for (TPrivilegeLevel privilege : viewMetadataPrivileges()) { + for (TPrivilegeLevel privilege: viewMetadataPrivileges()) { authorize("show range partitions functional_kudu.dimtbl") .ok(onServer(privilege)) .ok(onDatabase("functional_kudu", privilege)) @@ -813,10 +841,10 @@ public class AuthorizationTestV2 extends FrontendTestBase { } // Show files. - for (AuthzTest authzTest : new AuthzTest[]{ + 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()) { + for (TPrivilegeLevel privilege: viewMetadataPrivileges()) { authzTest.ok(onServer(privilege)) .ok(onDatabase("functional", privilege)) .ok(onTable("functional", "alltypes", privilege)); @@ -838,7 +866,7 @@ public class AuthorizationTestV2 extends FrontendTestBase { // Show create table. test = authorize("show create table functional.alltypes"); - for (TPrivilegeLevel privilege : viewMetadataPrivileges()) { + for (TPrivilegeLevel privilege: viewMetadataPrivileges()) { test.ok(onServer(privilege)) .ok(onDatabase("functional", privilege)) .ok(onTable("functional", "alltypes", privilege)); @@ -847,11 +875,12 @@ public class AuthorizationTestV2 extends FrontendTestBase { // 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")); + 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()) { + for (TPrivilegeLevel privilege: viewMetadataPrivileges()) { test.ok(onServer(privilege, TPrivilegeLevel.SELECT)) .ok(onDatabase("functional", privilege, TPrivilegeLevel.SELECT)) .ok(onTable("functional", "alltypes_view", privilege), @@ -867,7 +896,7 @@ public class AuthorizationTestV2 extends FrontendTestBase { ScalarFunction fn = addFunction("functional", "f"); try { test = authorize("show create function functional.f"); - for (TPrivilegeLevel privilege : viewMetadataPrivileges()) { + for (TPrivilegeLevel privilege: viewMetadataPrivileges()) { test.ok(onServer(privilege)) .ok(onDatabase("functional", privilege)); } @@ -882,10 +911,162 @@ public class AuthorizationTestV2 extends FrontendTestBase { // Show create function in system database should always be allowed. authorize("show create function _impala_builtins.pi").ok(); - // Show data sourcs should always be allowed. + // Show data sources should always be allowed. authorize("show data sources").ok(); } + @Test + /** + * Test describe output of Databases and tables. + * From https://issues.apache.org/jira/browse/IMPALA-6479 + * Column level select privileges should limit output. + */ + 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)); + } + } + + // 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; } @@ -923,7 +1104,7 @@ public class AuthorizationTestV2 extends FrontendTestBase { private static TPrivilegeLevel[] allExcept(TPrivilegeLevel... excludedPrivLevels) { HashSet<TPrivilegeLevel> excludedSet = Sets.newHashSet(excludedPrivLevels); List<TPrivilegeLevel> privLevels = new ArrayList<>(); - for (TPrivilegeLevel level : TPrivilegeLevel.values()) { + for (TPrivilegeLevel level: TPrivilegeLevel.values()) { if (!excludedSet.contains(level)) { privLevels.add(level); } @@ -949,8 +1130,8 @@ public class AuthorizationTestV2 extends FrontendTestBase { 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) { + for (TPrivilege[] privs: privileges) { + for (TPrivilege privilege: privs) { privilege.setRole_id(role.getId()); authzCatalog_.addRolePrivilege(role_, privilege); } @@ -975,6 +1156,48 @@ public class AuthorizationTestV2 extends FrontendTestBase { } 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(); } @@ -1058,7 +1281,7 @@ public class AuthorizationTestV2 extends FrontendTestBase { TPrivilege[] privileges = new TPrivilege[size]; int idx = 0; for (int i = 0; i < levels.length; i++) { - for (String column : columns) { + for (String column: columns) { privileges[idx] = new TPrivilege("", levels[i], TPrivilegeScope.COLUMN, false); privileges[idx].setServer_name(SENTRY_SERVER); privileges[idx].setDb_name(db); @@ -1161,7 +1384,6 @@ public class AuthorizationTestV2 extends FrontendTestBase { fail("Stmt didn't result in authorization error: " + stmt); } - private void verifyPrivilegeReqs(String stmt, Set<String> expectedPrivilegeNames) throws ImpalaException { verifyPrivilegeReqs(createAnalysisCtx(), stmt, expectedPrivilegeNames); @@ -1171,7 +1393,7 @@ public class AuthorizationTestV2 extends FrontendTestBase { Set<String> expectedPrivilegeNames) throws ImpalaException { AnalysisResult analysisResult = parseAndAnalyze(stmt, ctx, frontend_); Set<String> actualPrivilegeNames = Sets.newHashSet(); - for (PrivilegeRequest privReq : analysisResult.getAnalyzer().getPrivilegeReqs()) { + for (PrivilegeRequest privReq: analysisResult.getAnalyzer().getPrivilegeReqs()) { actualPrivilegeNames.add(privReq.getName()); } assertEquals(expectedPrivilegeNames, actualPrivilegeNames);
