blob: 8f3427e0f968a436f58746cc71f98b6785d5d8a8 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.impala.analysis;
import java.util.HashSet;
import org.apache.impala.authorization.NoopAuthorizationFactory;
import org.apache.impala.authorization.ranger.RangerAuthorizationConfig;
import org.apache.impala.authorization.ranger.RangerAuthorizationFactory;
import org.apache.impala.catalog.Catalog;
import org.apache.impala.catalog.Role;
import org.apache.impala.catalog.User;
import org.apache.impala.common.AnalysisException;
import org.apache.impala.common.FrontendTestBase;
import org.apache.impala.testutil.TestUtils;
import org.apache.impala.thrift.TQueryCtx;
import org.apache.impala.util.EventSequence;
import org.junit.Test;
public class AnalyzeAuthStmtsTest extends FrontendTestBase {
protected static final String SERVER_NAME = "server1";
protected static final String RANGER_SERVICE_TYPE = "hive";
protected static final String RANGER_APP_ID = "impala";
// TODO: Change this to a @BeforeClass method. Then, clean up these
// items in @AfterClass, else we've made a global change that may affect
// other tests in random ways.
public AnalyzeAuthStmtsTest() {
catalog_.getAuthPolicy().addPrincipal(
new Role("myRole", new HashSet<>()));
catalog_.getAuthPolicy().addPrincipal(
new User("myUser", new HashSet<>()));
}
// TODO: Switch to use a fixture with custom settings rather than the
// current patchwork of base and derived class methods.
/**
* Analyze 'stmt', expecting it to pass. Asserts in case of analysis error.
*/
@Override
public ParseNode AnalyzesOk(String stmt) {
return AnalyzesOk(stmt, createAnalysisCtx(Catalog.DEFAULT_DB), null);
}
/**
* Asserts if stmt passes analysis or the error string doesn't match and it
* is non-null.
*/
@Override
public void AnalysisError(String stmt, String expectedErrorString) {
AnalysisError(stmt, createAnalysisCtx(Catalog.DEFAULT_DB), expectedErrorString);
}
@Override
protected AnalysisContext createAnalysisCtx(String defaultDb) {
TQueryCtx queryCtx = TestUtils.createQueryContext(
defaultDb, System.getProperty("user.name"));
EventSequence timeline = new EventSequence("Authorization Test");
AnalysisContext analysisCtx = new AnalysisContext(queryCtx,
new RangerAuthorizationFactory(
new RangerAuthorizationConfig(RANGER_SERVICE_TYPE, RANGER_APP_ID,
SERVER_NAME, null, null, null)),
timeline);
return analysisCtx;
}
private AnalysisContext createAuthDisabledAnalysisCtx() {
TQueryCtx queryCtx = TestUtils.createQueryContext(
Catalog.DEFAULT_DB, System.getProperty("user.name"));
EventSequence timeline = new EventSequence("Authorization Test");
AnalysisContext analysisCtx = new AnalysisContext(queryCtx,
new NoopAuthorizationFactory(), timeline);
return analysisCtx;
}
@Test
public void AnalyzeShowRoles() {
AnalyzesOk("SHOW ROLES");
AnalyzesOk("SHOW ROLE GRANT GROUP myGroup");
AnalyzesOk("SHOW CURRENT ROLES");
AnalysisContext authDisabledCtx = createAuthDisabledAnalysisCtx();
AnalysisError("SHOW ROLES", authDisabledCtx,
"Authorization is not enabled.");
AnalysisError("SHOW ROLE GRANT GROUP myGroup", authDisabledCtx,
"Authorization is not enabled.");
AnalysisError("SHOW CURRENT ROLES", authDisabledCtx,
"Authorization is not enabled.");
}
@Test
public void AnalyzeShowGrantPrincipal() {
for (String type: new String[]{"ROLE myRole", "USER myUser", "GROUP myGroup"}) {
AnalyzesOk(String.format("SHOW GRANT %s", type));
AnalyzesOk(String.format("SHOW GRANT %s ON SERVER", type));
AnalyzesOk(String.format("SHOW GRANT %s ON DATABASE functional", type));
AnalyzesOk(String.format("SHOW GRANT %s ON TABLE functional.alltypes", type));
AnalyzesOk(String.format("SHOW GRANT %s ON COLUMN functional.alltypes.year", type));
AnalyzesOk(String.format("SHOW GRANT %s ON URI 'hdfs:////test-warehouse//foo'",
type));
AnalysisContext authDisabledCtx = createAuthDisabledAnalysisCtx();
AnalysisError("SHOW GRANT ROLE myRole", authDisabledCtx,
"Authorization is not enabled.");
AnalysisError("SHOW GRANT ROLE myRole ON SERVER", authDisabledCtx,
"Authorization is not enabled.");
// Database, table, and column do not exist.
AnalysisError(String.format("SHOW GRANT %s on DATABASE foo", type),
"Error setting/showing privileges for database 'foo'. " +
"Verify that the database exists and that you have permissions to issue " +
"a GRANT/REVOKE/SHOW GRANT statement.");
AnalysisError(String.format("SHOW GRANT %s on TABLE foo.bar", type),
"Error setting/showing privileges for table 'foo.bar'. Verify that the " +
"table exists and that you have permissions to issue a " +
"GRANT/REVOKE/SHOW GRANT statement.");
AnalysisError(String.format("SHOW GRANT %s on COLUMN foo.bar.baz", type),
"Error setting/showing privileges for table 'foo.bar'. Verify that the " +
"table exists and that you have permissions to issue a " +
"GRANT/REVOKE/SHOW GRANT statement.");
}
// Determining if a user exists on the system is done in the AuthorizationPolicy and
// these tests run with authorization disabled. The SHOW GRANT USER will be tested
// in the custom cluster tests test_grant_revoke.
}
@Test
public void AnalyzeCreateDropRole() throws AnalysisException {
AnalyzesOk("DROP ROLE myRole");
AnalyzesOk("CREATE ROLE doesNotExist");
// Role names are case-insensitive
AnalyzesOk("DROP ROLE MYrole");
AnalysisContext authDisabledCtx = createAuthDisabledAnalysisCtx();
AnalysisError("DROP ROLE myRole", authDisabledCtx,
"Authorization is not enabled.");
AnalysisError("CREATE ROLE doesNotExist", authDisabledCtx,
"Authorization is not enabled.");
}
@Test
public void AnalyzeGrantRevokeRole() throws AnalysisException {
AnalyzesOk("GRANT ROLE myrole TO GROUP abc");
AnalyzesOk("REVOKE ROLE myrole FROM GROUP abc");
AnalysisContext authDisabledCtx = createAuthDisabledAnalysisCtx();
AnalysisError("GRANT ROLE myrole TO GROUP abc", authDisabledCtx,
"Authorization is not enabled.");
AnalysisError("REVOKE ROLE myrole FROM GROUP abc", authDisabledCtx,
"Authorization is not enabled.");
}
@Test
public void AnalyzeGrantRevokePriv() throws AnalysisException {
String[] idents = {"myRole", "ROLE myRole", "GROUP myGroup", "USER myUser"};
boolean[] isGrantVals = {true, false};
for (String ident : idents) {
for (boolean isGrant : isGrantVals) {
Object[] formatArgs = new String[]{"REVOKE", "FROM", ident};
if (isGrant) formatArgs = new String[]{"GRANT", "TO", ident};
// ALL privileges
AnalyzesOk(String.format("%s ALL ON TABLE alltypes %s %s", formatArgs),
createAnalysisCtx("functional"));
AnalyzesOk(String.format("%s ALL ON TABLE functional.alltypes %s %s",
formatArgs));
AnalyzesOk(String.format("%s ALL ON TABLE functional_kudu.alltypes %s %s",
formatArgs));
AnalyzesOk(String.format("%s ALL ON DATABASE functional %s %s", formatArgs));
AnalyzesOk(String.format("%s ALL ON SERVER %s %s", formatArgs));
AnalyzesOk(String.format("%s ALL ON SERVER server1 %s %s", formatArgs));
AnalyzesOk(String.format("%s ALL ON URI 'hdfs:////abc//123' %s %s",
formatArgs));
AnalysisError(String.format("%s ALL ON URI 'xxxx:////abc//123' %s %s",
formatArgs), "No FileSystem for scheme: xxxx");
AnalysisError(String.format("%s ALL ON DATABASE does_not_exist %s %s",
formatArgs), "Error setting/showing privileges for " +
"database 'does_not_exist'. Verify that the database exists and that you " +
"have permissions to issue a GRANT/REVOKE/SHOW GRANT statement.");
AnalysisError(String.format("%s ALL ON TABLE does_not_exist %s %s",
formatArgs), "Error setting/showing privileges for table 'does_not_exist'. " +
"Verify that the table exists and that you have permissions to issue " +
"a GRANT/REVOKE/SHOW GRANT statement.");
AnalysisError(String.format("%s ALL ON SERVER does_not_exist %s %s",
formatArgs), "Specified server name 'does_not_exist' does not match the " +
"configured server name 'server1'");
// INSERT privilege
AnalyzesOk(String.format("%s INSERT ON TABLE alltypesagg %s %s", formatArgs),
createAnalysisCtx("functional"));
AnalyzesOk(String.format(
"%s INSERT ON TABLE functional_kudu.alltypessmall %s %s", formatArgs));
AnalyzesOk(String.format("%s INSERT ON TABLE functional.alltypesagg %s %s",
formatArgs));
AnalyzesOk(String.format("%s INSERT ON DATABASE functional %s %s",
formatArgs));
AnalyzesOk(String.format("%s INSERT ON SERVER %s %s", formatArgs));
AnalysisError(String.format("%s INSERT ON URI 'hdfs:////abc//123' %s %s",
formatArgs), "Only 'ALL' privilege may be applied at URI scope in " +
"privilege spec.");
// SELECT privilege
AnalyzesOk(String.format("%s SELECT ON TABLE alltypessmall %s %s", formatArgs),
createAnalysisCtx("functional"));
AnalyzesOk(String.format("%s SELECT ON TABLE functional.alltypessmall %s %s",
formatArgs));
AnalyzesOk(String.format(
"%s SELECT ON TABLE functional_kudu.alltypessmall %s %s", formatArgs));
AnalyzesOk(String.format("%s SELECT ON DATABASE functional %s %s",
formatArgs));
AnalyzesOk(String.format("%s SELECT ON SERVER %s %s", formatArgs));
AnalysisError(String.format("%s SELECT ON URI 'hdfs:////abc//123' %s %s",
formatArgs), "Only 'ALL' privilege may be applied at URI scope in " +
"privilege spec.");
// SELECT privileges on columns
AnalyzesOk(String.format("%s SELECT (id, int_col) ON TABLE functional.alltypes " +
"%s %s", formatArgs));
AnalyzesOk(String.format("%s SELECT (id, id) ON TABLE functional.alltypes " +
"%s %s", formatArgs));
// SELECT privilege on both regular and partition columns
AnalyzesOk(String.format("%s SELECT (id, int_col, year, month) ON TABLE " +
"alltypes %s %s", formatArgs), createAnalysisCtx("functional"));
AnalyzesOk(String.format("%s SELECT (id, bool_col) ON TABLE " +
"functional_kudu.alltypessmall %s %s", formatArgs));
// Column-level privileges on a VIEW
AnalyzesOk(String.format("%s SELECT (id, bool_col) ON TABLE " +
"functional.alltypes_hive_view %s %s", formatArgs));
// Empty column list
AnalysisError(String.format("%s SELECT () ON TABLE functional.alltypes " +
"%s %s", formatArgs), "Empty column list in column privilege spec.");
// INSERT/ALL privileges on columns
AnalysisError(String.format("%s INSERT (id, tinyint_col) ON TABLE " +
"functional.alltypes %s %s", formatArgs), "Only 'SELECT' privileges " +
"are allowed in a column privilege spec.");
AnalysisError(String.format("%s ALL (id, tinyint_col) ON TABLE " +
"functional.alltypes %s %s", formatArgs), "Only 'SELECT' privileges " +
"are allowed in a column privilege spec.");
// Columns/table that don't exist
AnalysisError(String.format("%s SELECT (invalid_col) ON TABLE " +
"functional.alltypes %s %s", formatArgs), "Error setting/showing " +
"column-level privileges for table 'functional.alltypes'. Verify that " +
"both table and columns exist and that you have permissions to issue a " +
"GRANT/REVOKE/SHOW GRANT statement.");
AnalysisError(String.format("%s SELECT (id, int_col) ON TABLE " +
"functional.does_not_exist %s %s", formatArgs), "Error setting/showing " +
"privileges for table 'functional.does_not_exist'. Verify that the table " +
"exists and that you have permissions to issue a " +
"GRANT/REVOKE/SHOW GRANT statement.");
// REFRESH privilege
AnalyzesOk(String.format(
"%s REFRESH ON TABLE functional.alltypes %s %s", formatArgs));
AnalyzesOk(String.format(
"%s REFRESH ON DATABASE functional %s %s", formatArgs));
AnalyzesOk(String.format("%s REFRESH ON SERVER %s %s", formatArgs));
AnalyzesOk(String.format("%s REFRESH ON SERVER server1 %s %s",
formatArgs));
AnalysisError(String.format(
"%s REFRESH ON URI 'hdfs:////abc//123' %s %s", formatArgs),
"Only 'ALL' privilege may be applied at URI scope in privilege spec.");
// CREATE privilege
AnalyzesOk(String.format("%s CREATE ON SERVER %s %s", formatArgs));
AnalyzesOk(String.format("%s CREATE ON SERVER server1 %s %s", formatArgs));
AnalyzesOk(String.format(
"%s CREATE ON DATABASE functional %s %s", formatArgs));
AnalysisError(String.format(
"%s CREATE ON TABLE functional.alltypes %s %s", formatArgs),
"Create-level privileges on tables are not supported.");
AnalysisError(String.format(
"%s CREATE ON URI 'hdfs:////abc//123' %s %s", formatArgs),
"Only 'ALL' privilege may be applied at URI scope in privilege spec.");
// ALTER privilege
AnalyzesOk(String.format("%s ALTER ON SERVER %s %s", formatArgs));
AnalyzesOk(String.format("%s ALTER ON SERVER server1 %s %s", formatArgs));
AnalyzesOk(String.format("%s ALTER ON DATABASE functional %s %s", formatArgs));
AnalyzesOk(String.format(
"%s ALTER ON TABLE functional.alltypes %s %s", formatArgs));
AnalysisError(String.format(
"%s ALTER ON URI 'hdfs:////abc/123' %s %s", formatArgs),
"Only 'ALL' privilege may be applied at URI scope in privilege spec.");
// DROP privilege
AnalyzesOk(String.format("%s DROP ON SERVER %s %s", formatArgs));
AnalyzesOk(String.format("%s DROP ON SERVER server1 %s %s", formatArgs));
AnalyzesOk(String.format("%s DROP ON DATABASE functional %s %s", formatArgs));
AnalyzesOk(String.format(
"%s DROP ON TABLE functional.alltypes %s myrole", formatArgs));
AnalysisError(String.format(
"%s DROP ON URI 'hdfs:////abc/123' %s %s", formatArgs),
"Only 'ALL' privilege may be applied at URI scope in privilege spec.");
}
AnalysisContext authDisabledCtx = createAuthDisabledAnalysisCtx();
AnalysisError("GRANT ALL ON SERVER TO myRole", authDisabledCtx,
"Authorization is not enabled.");
AnalysisError("REVOKE ALL ON SERVER FROM myRole", authDisabledCtx,
"Authorization is not enabled.");
TQueryCtx noUserNameQueryCtx = TestUtils.createQueryContext(
Catalog.DEFAULT_DB, "");
EventSequence timeline = new EventSequence("Authorization Test");
AnalysisContext noUserNameCtx = new AnalysisContext(noUserNameQueryCtx,
new RangerAuthorizationFactory(
new RangerAuthorizationConfig(RANGER_SERVICE_TYPE, RANGER_APP_ID,
SERVER_NAME, null, null, null)),
timeline);
AnalysisError("GRANT ALL ON SERVER TO myRole", noUserNameCtx,
"Cannot execute authorization statement with an empty username.");
}
}
}