IMPALA-2660: Respect auth_to_local configs from hdfs configs This patch implements a new feature to read the auth_to_local configs from hdfs configuration files, using the parameter hadoop.security.auth_to_local. This is done by modifying the User#getShortName() method to use its hdfs equivalent.
This patch includes an end to end authorization test using sentry where we add specific auth_to_local setting for a certain user and test if the sentry authorization passes for this user after applying these rules. Given we don't have tests that run on a kerberized min-cluster, this patch adds a hack to load this configuration during even on non-kerberized 'test runs'. However this feature is disabled by default to preserve the existing behavior. To enable it, 1. Use kerberos as authentication mechanism (by setting --principal) and 2. Add "--load_auth_to_local_rules=true" to the cluster startup args Change-Id: I76485b83c14ba26f6fce66e5f83e8014667829e0 Reviewed-on: http://gerrit.cloudera.org:8080/2800 Reviewed-by: Bharath Vissapragada <[email protected]> Tested-by: Internal Jenkins Project: http://git-wip-us.apache.org/repos/asf/incubator-impala/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-impala/commit/3092c966 Tree: http://git-wip-us.apache.org/repos/asf/incubator-impala/tree/3092c966 Diff: http://git-wip-us.apache.org/repos/asf/incubator-impala/diff/3092c966 Branch: refs/heads/master Commit: 3092c96619f54bd47d71c2bc19c99bb03807ec1a Parents: c0ee93b Author: Bharath Vissapragada <[email protected]> Authored: Fri Mar 4 09:46:16 2016 -0800 Committer: Tim Armstrong <[email protected]> Committed: Thu May 12 14:18:01 2016 -0700 ---------------------------------------------------------------------- be/src/catalog/catalog.cc | 11 +- be/src/common/global-flags.cc | 5 + be/src/service/frontend.cc | 9 +- .../impala/analysis/AnalysisContext.java | 9 +- .../impala/analysis/ShowGrantRoleStmt.java | 3 +- .../cloudera/impala/analysis/ShowRolesStmt.java | 5 +- .../authorization/AuthorizationChecker.java | 8 +- .../com/cloudera/impala/authorization/User.java | 81 +++++++-- .../cloudera/impala/service/BackendConfig.java | 11 +- .../com/cloudera/impala/service/Frontend.java | 9 +- .../com/cloudera/impala/service/JniCatalog.java | 6 +- .../cloudera/impala/service/JniFrontend.java | 4 +- .../impala/util/RequestPoolService.java | 10 +- .../cloudera/impala/analysis/AuditingTest.java | 3 +- .../impala/analysis/AuthorizationTest.java | 165 ++++++++++++++----- .../impala/util/TestRequestPoolService.java | 4 +- fe/src/test/resources/authz-policy.ini.template | 3 + .../common/etc/hadoop/conf/core-site.xml.tmpl | 11 ++ 18 files changed, 277 insertions(+), 80 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/3092c966/be/src/catalog/catalog.cc ---------------------------------------------------------------------- diff --git a/be/src/catalog/catalog.cc b/be/src/catalog/catalog.cc index 606aa8f..26810f1 100644 --- a/be/src/catalog/catalog.cc +++ b/be/src/catalog/catalog.cc @@ -25,6 +25,9 @@ using namespace impala; +DECLARE_bool(load_auth_to_local_rules); +DECLARE_string(principal); + DEFINE_bool(load_catalog_in_background, false, "If true, loads catalog metadata in the background. If false, metadata is loaded " "lazily (on access)."); @@ -38,7 +41,7 @@ DECLARE_int32(non_impala_java_vlog); Catalog::Catalog() { JniMethodDescriptor methods[] = { - {"<init>", "(ZILjava/lang/String;II)V", &catalog_ctor_}, + {"<init>", "(ZILjava/lang/String;IIZ)V", &catalog_ctor_}, {"updateCatalog", "([B)[B", &update_metastore_id_}, {"execDdl", "([B)[B", &exec_ddl_id_}, {"resetMetadata", "([B)[B", &reset_metadata_id_}, @@ -64,9 +67,13 @@ Catalog::Catalog() { jboolean load_in_background = FLAGS_load_catalog_in_background; jint num_metadata_loading_threads = FLAGS_num_metadata_loading_threads; jstring sentry_config = jni_env->NewStringUTF(FLAGS_sentry_config.c_str()); + // auth_to_local rules are read if --load_auth_to_local_rules is set to true + // and impala is kerberized. + jboolean auth_to_local = FLAGS_load_auth_to_local_rules && !FLAGS_principal.empty(); jobject catalog = jni_env->NewObject(catalog_class_, catalog_ctor_, load_in_background, num_metadata_loading_threads, sentry_config, - FlagToTLogLevel(FLAGS_v), FlagToTLogLevel(FLAGS_non_impala_java_vlog)); + FlagToTLogLevel(FLAGS_v), FlagToTLogLevel(FLAGS_non_impala_java_vlog), + auth_to_local); EXIT_IF_EXC(jni_env); ABORT_IF_ERROR(JniUtil::LocalToGlobalRef(jni_env, catalog, &catalog_)); } http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/3092c966/be/src/common/global-flags.cc ---------------------------------------------------------------------- diff --git a/be/src/common/global-flags.cc b/be/src/common/global-flags.cc index f0315ca..b3f83d9 100644 --- a/be/src/common/global-flags.cc +++ b/be/src/common/global-flags.cc @@ -76,6 +76,11 @@ DEFINE_string(minidump_path, "/tmp/impala-minidumps", "Directory to write minidu DEFINE_int32(max_minidumps, 9, "Maximum number of minidump files to keep per daemon. " "Older files are removed first. Set to 0 to keep all minidump files."); +DEFINE_bool(load_auth_to_local_rules, false, "If true, load auth_to_local configuration " + "from hdfs' core-site.xml. When enabled, impalad reads the rules from the property " + "hadoop.security.auth_to_local and applies them to translate the Kerberos principal " + "to its corresponding local user name for authorization."); + // Stress option for testing failed memory allocation. Debug builds only. #ifndef NDEBUG DEFINE_int32(stress_free_pool_alloc, 0, "A stress option which causes memory allocations " http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/3092c966/be/src/service/frontend.cc ---------------------------------------------------------------------- diff --git a/be/src/service/frontend.cc b/be/src/service/frontend.cc index a0b76c3..2b7c5b0 100644 --- a/be/src/service/frontend.cc +++ b/be/src/service/frontend.cc @@ -28,6 +28,8 @@ using namespace impala; DECLARE_string(sentry_config); DECLARE_int32(non_impala_java_vlog); +DECLARE_bool(load_auth_to_local_rules); +DECLARE_string(principal); DEFINE_bool(load_catalog_at_startup, false, "if true, load all catalog data at startup"); @@ -56,7 +58,7 @@ DEFINE_string(authorized_proxy_user_config_delimiter, ",", Frontend::Frontend() { JniMethodDescriptor methods[] = { {"<init>", "(ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;" - "Ljava/lang/String;II)V", &fe_ctor_}, + "Ljava/lang/String;IIZ)V", &fe_ctor_}, {"createExecRequest", "([B)[B", &create_exec_request_id_}, {"getExplainPlan", "([B)Ljava/lang/String;", &get_explain_plan_id_}, {"getHadoopConfig", "([B)[B", &get_hadoop_config_id_}, @@ -101,9 +103,12 @@ Frontend::Frontend() { jni_env->NewStringUTF(FLAGS_sentry_config.c_str()); jstring auth_provider_class = jni_env->NewStringUTF(FLAGS_authorization_policy_provider_class.c_str()); + // auth_to_local rules are read if --load_auth_to_local_rules is set to true + // and impala is kerberized. + jboolean auth_to_local = FLAGS_load_auth_to_local_rules && !FLAGS_principal.empty(); jobject fe = jni_env->NewObject(fe_class_, fe_ctor_, lazy, server_name, policy_file_path, sentry_config, auth_provider_class, FlagToTLogLevel(FLAGS_v), - FlagToTLogLevel(FLAGS_non_impala_java_vlog)); + FlagToTLogLevel(FLAGS_non_impala_java_vlog), auth_to_local); EXIT_IF_EXC(jni_env); ABORT_IF_ERROR(JniUtil::LocalToGlobalRef(jni_env, fe, &fe_)); } http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/3092c966/fe/src/main/java/com/cloudera/impala/analysis/AnalysisContext.java ---------------------------------------------------------------------- diff --git a/fe/src/main/java/com/cloudera/impala/analysis/AnalysisContext.java b/fe/src/main/java/com/cloudera/impala/analysis/AnalysisContext.java index 31c156c..098501c 100644 --- a/fe/src/main/java/com/cloudera/impala/analysis/AnalysisContext.java +++ b/fe/src/main/java/com/cloudera/impala/analysis/AnalysisContext.java @@ -32,6 +32,7 @@ import com.cloudera.impala.catalog.AuthorizationException; import com.cloudera.impala.catalog.Db; import com.cloudera.impala.catalog.ImpaladCatalog; import com.cloudera.impala.common.AnalysisException; +import com.cloudera.impala.common.InternalException; import com.cloudera.impala.common.Pair; import com.cloudera.impala.thrift.TAccessEvent; import com.cloudera.impala.thrift.TLineageGraph; @@ -384,7 +385,8 @@ public class AnalysisContext { * analyze() must have already been called. Throws an AuthorizationException if the * user doesn't have sufficient privileges to run this statement. */ - public void authorize(AuthorizationChecker authzChecker) throws AuthorizationException { + public void authorize(AuthorizationChecker authzChecker) + throws AuthorizationException, InternalException { Preconditions.checkNotNull(analysisResult_); Analyzer analyzer = getAnalyzer(); // Process statements for which column-level privilege requests may be registered. @@ -451,7 +453,7 @@ public class AnalysisContext { * this request. Also, checks if the request references a system database. */ private void authorizePrivilegeRequest(AuthorizationChecker authzChecker, - PrivilegeRequest request) throws AuthorizationException { + PrivilegeRequest request) throws AuthorizationException, InternalException { Preconditions.checkNotNull(request); String dbName = null; if (request.getAuthorizeable() != null) { @@ -474,7 +476,8 @@ public class AnalysisContext { * sufficient privileges. */ private void authorizeTableAccess(AuthorizationChecker authzChecker, - List<PrivilegeRequest> requests) throws AuthorizationException { + List<PrivilegeRequest> requests) + throws AuthorizationException, InternalException { Preconditions.checkState(!requests.isEmpty()); Analyzer analyzer = getAnalyzer(); boolean hasTableSelectPriv = true; http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/3092c966/fe/src/main/java/com/cloudera/impala/analysis/ShowGrantRoleStmt.java ---------------------------------------------------------------------- diff --git a/fe/src/main/java/com/cloudera/impala/analysis/ShowGrantRoleStmt.java b/fe/src/main/java/com/cloudera/impala/analysis/ShowGrantRoleStmt.java index b543a57..1d921c8 100644 --- a/fe/src/main/java/com/cloudera/impala/analysis/ShowGrantRoleStmt.java +++ b/fe/src/main/java/com/cloudera/impala/analysis/ShowGrantRoleStmt.java @@ -16,6 +16,7 @@ package com.cloudera.impala.analysis; import com.cloudera.impala.catalog.Role; import com.cloudera.impala.common.AnalysisException; +import com.cloudera.impala.common.InternalException; import com.cloudera.impala.thrift.TShowGrantRoleParams; import com.google.common.base.Preconditions; import com.google.common.base.Strings; @@ -36,7 +37,7 @@ public class ShowGrantRoleStmt extends AuthorizationStmt { privilegeSpec_ = privilegeSpec; } - public TShowGrantRoleParams toThrift() { + public TShowGrantRoleParams toThrift() throws InternalException { TShowGrantRoleParams params = new TShowGrantRoleParams(); params.setRole_name(roleName_); params.setRequesting_user(requestingUser_.getShortName()); http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/3092c966/fe/src/main/java/com/cloudera/impala/analysis/ShowRolesStmt.java ---------------------------------------------------------------------- diff --git a/fe/src/main/java/com/cloudera/impala/analysis/ShowRolesStmt.java b/fe/src/main/java/com/cloudera/impala/analysis/ShowRolesStmt.java index 54ad698..1e1b59e 100644 --- a/fe/src/main/java/com/cloudera/impala/analysis/ShowRolesStmt.java +++ b/fe/src/main/java/com/cloudera/impala/analysis/ShowRolesStmt.java @@ -16,6 +16,7 @@ package com.cloudera.impala.analysis; import com.cloudera.impala.authorization.User; import com.cloudera.impala.common.AnalysisException; +import com.cloudera.impala.common.InternalException; import com.cloudera.impala.thrift.TShowRolesParams; import com.google.common.base.Preconditions; @@ -50,7 +51,7 @@ public class ShowRolesStmt extends AuthorizationStmt { } } - public TShowRolesParams toThrift() { + public TShowRolesParams toThrift() throws InternalException { TShowRolesParams params = new TShowRolesParams(); params.setRequesting_user(requestingUser_.getShortName()); params.setIs_show_current_roles(isShowCurrentRoles_); @@ -65,4 +66,4 @@ public class ShowRolesStmt extends AuthorizationStmt { super.analyze(analyzer); requestingUser_ = analyzer.getUser(); } -} \ No newline at end of file +} http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/3092c966/fe/src/main/java/com/cloudera/impala/authorization/AuthorizationChecker.java ---------------------------------------------------------------------- diff --git a/fe/src/main/java/com/cloudera/impala/authorization/AuthorizationChecker.java b/fe/src/main/java/com/cloudera/impala/authorization/AuthorizationChecker.java index 6d978ab..a4a45ed 100644 --- a/fe/src/main/java/com/cloudera/impala/authorization/AuthorizationChecker.java +++ b/fe/src/main/java/com/cloudera/impala/authorization/AuthorizationChecker.java @@ -32,6 +32,7 @@ import org.apache.sentry.provider.file.SimpleFileProviderBackend; import com.cloudera.impala.catalog.AuthorizationException; import com.cloudera.impala.catalog.AuthorizationPolicy; +import com.cloudera.impala.common.InternalException; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; @@ -108,7 +109,7 @@ public class AuthorizationChecker { * that is in the AuthorizationProvider to properly resolve Hadoop groups or * local group mappings. */ - public Set<String> getUserGroups(User user) { + public Set<String> getUserGroups(User user) throws InternalException { return provider_.getGroupMapping().getGroups(user.getShortName()); } @@ -117,7 +118,7 @@ public class AuthorizationChecker { * the user does not have sufficient privileges. */ public void checkAccess(User user, PrivilegeRequest privilegeRequest) - throws AuthorizationException { + throws AuthorizationException, InternalException { Preconditions.checkNotNull(privilegeRequest); if (!hasAccess(user, privilegeRequest)) { @@ -145,7 +146,8 @@ public class AuthorizationChecker { * Returns true if the given user has permission to execute the given * request, false otherwise. Always returns true if authorization is disabled. */ - public boolean hasAccess(User user, PrivilegeRequest request) { + public boolean hasAccess(User user, PrivilegeRequest request) + throws InternalException { Preconditions.checkNotNull(user); Preconditions.checkNotNull(request); http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/3092c966/fe/src/main/java/com/cloudera/impala/authorization/User.java ---------------------------------------------------------------------- diff --git a/fe/src/main/java/com/cloudera/impala/authorization/User.java b/fe/src/main/java/com/cloudera/impala/authorization/User.java index 4f19813..d87944c 100644 --- a/fe/src/main/java/com/cloudera/impala/authorization/User.java +++ b/fe/src/main/java/com/cloudera/impala/authorization/User.java @@ -15,34 +15,87 @@ package com.cloudera.impala.authorization; import com.google.common.base.Preconditions; +import com.google.common.annotations.VisibleForTesting; +import com.cloudera.impala.common.InternalException; +import com.cloudera.impala.common.RuntimeEnv; +import com.cloudera.impala.service.BackendConfig; + +import java.io.IOException; + +import org.apache.hadoop.conf.Configuration; +import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTH_TO_LOCAL; +import org.apache.hadoop.security.authentication.util.KerberosName; /* * Class that represents a User of an Impala session. */ public class User { + + static { + // If auth_to_local is enabled, we read the configuration hadoop.security.auth_to_local + // from core-site.xml and use it for principal to short name conversion. If it is not, + // we use the defaultRule ("RULE:[1:$1] RULE:[2:$1]"), which just extracts the user + // name from any principal of form a@REALM or a/b@REALM. If auth_to_local is enabled + // and hadoop.security.auth_to_local is not specified in the hadoop configs, we use + // the "DEFAULT" rule that just extracts the username from any principal in the + // cluster's local realm. For more details on principal to short name translation, + // refer to org.apache.hadoop.security.KerberosName. + final String defaultRule = "RULE:[1:$1] RULE:[2:$1]"; + final Configuration conf = new Configuration(); + if (BackendConfig.isAuthToLocalEnabled()) { + KerberosName.setRules(conf.get(HADOOP_SECURITY_AUTH_TO_LOCAL, "DEFAULT")); + } else { + // just extract the simple user name + KerberosName.setRules(defaultRule); + } + } + private final String name_; + private KerberosName kerberosName_; + public User(String name) { Preconditions.checkNotNull(name); - this.name_ = name; + name_ = name; + this.kerberosName_ = new KerberosName(name); } public String getName() { return name_; } + public String getShortName() throws InternalException { + try { + return kerberosName_.getShortName(); + } catch (IOException e) { + throw new InternalException( + "Error calling getShortName() for user: " + getName(), e); + } + } + /* - * Get the short version of the user name (the user's name up to the first '/' or '@') - * from the full principal name. - * Similar to: org.apache.hadoop.security.UserGroupInformation.getShortName() + * Returns the shortname for the user after applying auth_to_local + * rules from string 'rules'. This is exposed for testing purposes only. + * Ideally these rules are populated from hdfs configuration files. */ - public String getShortName() { - int idx = name_.indexOf('/'); - int idx2 = name_.indexOf('@'); - int endIdx = Math.min(idx, idx2); - // At least one of them was not found. - if (endIdx == -1) endIdx = Math.max(idx, idx2); - - // If neither are found (or are found at the beginning of the user name), - // return the username. - return (endIdx <= 0) ? name_ : name_.substring(0, endIdx); + @VisibleForTesting + public String getShortNameForTesting(String rules) { + Preconditions.checkNotNull(rules); + Preconditions.checkState(RuntimeEnv.INSTANCE.isTestEnv()); + String currentRules = KerberosName.getRules(); + KerberosName.setRules(rules); + String shortName = null; + try { + shortName = getShortName(); + } catch (InternalException e) { + e.printStackTrace(); + } + // reset the rules + KerberosName.setRules(currentRules); + return shortName; + } + + @VisibleForTesting + public static void setRulesForTesting(String rules) { + Preconditions.checkState(RuntimeEnv.INSTANCE.isTestEnv()); + KerberosName.setRules(rules); } } http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/3092c966/fe/src/main/java/com/cloudera/impala/service/BackendConfig.java ---------------------------------------------------------------------- diff --git a/fe/src/main/java/com/cloudera/impala/service/BackendConfig.java b/fe/src/main/java/com/cloudera/impala/service/BackendConfig.java index 9d743c1..5dd6216 100644 --- a/fe/src/main/java/com/cloudera/impala/service/BackendConfig.java +++ b/fe/src/main/java/com/cloudera/impala/service/BackendConfig.java @@ -28,10 +28,19 @@ public class BackendConfig { // the default FLAGS_read_size used by the IO manager in the backend. private final long READ_SIZE; + // This is overriden by JniFrontend/JniCatalog classes with user set configuration. + // TODO: Read this from backend instead of using static variables. + private static boolean allowAuthToLocalRules_ = false; + private BackendConfig() { // TODO: Populate these by making calls to the backend instead of default constants. READ_SIZE = 8 * 1024 * 1024L; } public long getReadSize() { return READ_SIZE; } -} \ No newline at end of file + + public static boolean isAuthToLocalEnabled() { return allowAuthToLocalRules_; } + public static void setAuthToLocal(boolean authToLocal) { + allowAuthToLocalRules_ = authToLocal; + } +} http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/3092c966/fe/src/main/java/com/cloudera/impala/service/Frontend.java ---------------------------------------------------------------------- diff --git a/fe/src/main/java/com/cloudera/impala/service/Frontend.java b/fe/src/main/java/com/cloudera/impala/service/Frontend.java index fc1f2fc..9288c05 100644 --- a/fe/src/main/java/com/cloudera/impala/service/Frontend.java +++ b/fe/src/main/java/com/cloudera/impala/service/Frontend.java @@ -249,7 +249,7 @@ public class Frontend { * result argument. */ private void createCatalogOpRequest(AnalysisContext.AnalysisResult analysis, - TExecRequest result) { + TExecRequest result) throws InternalException { TCatalogOpRequest ddl = new TCatalogOpRequest(); TResultSetMetadata metadata = new TResultSetMetadata(); if (analysis.isUseStmt()) { @@ -614,7 +614,7 @@ public class Frontend { * the given user. If pattern is null, it matches all columns. */ public List<Column> getColumns(Table table, PatternMatcher columnPattern, - User user) { + User user) throws InternalException { Preconditions.checkNotNull(table); List<Column> columns = Lists.newArrayList(); for (Column column: table.getColumnsInHiveOrder()) { @@ -635,7 +635,7 @@ public class Frontend { * Returns all databases that match the pattern and * are accessible to the given user. If pattern is null, matches all dbs. */ - public List<Db> getDbs(String dbPattern, User user) { + public List<Db> getDbs(String dbPattern, User user) throws InternalException { List<Db> dbs = impaladCatalog_.getDbs(dbPattern); // If authorization is enabled, filter out the databases the user does not // have permissions on. @@ -652,7 +652,8 @@ public class Frontend { /** * Check whether database is accessible to given user. */ - private boolean isAccessibleToUser(Db db, User user) { + private boolean isAccessibleToUser(Db db, User user) + throws InternalException { if (db.getName().toLowerCase().equals(Catalog.DEFAULT_DB.toLowerCase())) { // Default DB should always be shown. return true; http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/3092c966/fe/src/main/java/com/cloudera/impala/service/JniCatalog.java ---------------------------------------------------------------------- diff --git a/fe/src/main/java/com/cloudera/impala/service/JniCatalog.java b/fe/src/main/java/com/cloudera/impala/service/JniCatalog.java index 64efd58..eb3ac92 100644 --- a/fe/src/main/java/com/cloudera/impala/service/JniCatalog.java +++ b/fe/src/main/java/com/cloudera/impala/service/JniCatalog.java @@ -33,6 +33,7 @@ import com.cloudera.impala.catalog.Function; import com.cloudera.impala.common.ImpalaException; import com.cloudera.impala.common.InternalException; import com.cloudera.impala.common.JniUtil; +import com.cloudera.impala.service.BackendConfig; import com.cloudera.impala.thrift.TCatalogObject; import com.cloudera.impala.thrift.TDatabase; import com.cloudera.impala.thrift.TDdlExecRequest; @@ -75,8 +76,9 @@ public class JniCatalog { } public JniCatalog(boolean loadInBackground, int numMetadataLoadingThreads, - String sentryServiceConfig, int impalaLogLevel, int otherLogLevel) - throws InternalException { + String sentryServiceConfig, int impalaLogLevel, int otherLogLevel, + boolean allowAuthToLocal) throws InternalException { + BackendConfig.setAuthToLocal(allowAuthToLocal); Preconditions.checkArgument(numMetadataLoadingThreads > 0); // This trick saves having to pass a TLogLevel enum, which is an object and more // complex to pass through JNI. http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/3092c966/fe/src/main/java/com/cloudera/impala/service/JniFrontend.java ---------------------------------------------------------------------- diff --git a/fe/src/main/java/com/cloudera/impala/service/JniFrontend.java b/fe/src/main/java/com/cloudera/impala/service/JniFrontend.java index cacefc0..b5fcbf3 100644 --- a/fe/src/main/java/com/cloudera/impala/service/JniFrontend.java +++ b/fe/src/main/java/com/cloudera/impala/service/JniFrontend.java @@ -49,6 +49,7 @@ import com.cloudera.impala.common.FileSystemUtil; import com.cloudera.impala.common.ImpalaException; import com.cloudera.impala.common.InternalException; import com.cloudera.impala.common.JniUtil; +import com.cloudera.impala.service.BackendConfig; import com.cloudera.impala.thrift.TCatalogObject; import com.cloudera.impala.thrift.TDatabase; import com.cloudera.impala.thrift.TDescribeDbParams; @@ -108,7 +109,8 @@ public class JniFrontend { */ public JniFrontend(boolean lazy, String serverName, String authorizationPolicyFile, String sentryConfigFile, String authPolicyProviderClass, int impalaLogLevel, - int otherLogLevel) throws InternalException { + int otherLogLevel, boolean allowAuthToLocal) throws InternalException { + BackendConfig.setAuthToLocal(allowAuthToLocal); GlogAppender.Install(TLogLevel.values()[impalaLogLevel], TLogLevel.values()[otherLogLevel]); http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/3092c966/fe/src/main/java/com/cloudera/impala/util/RequestPoolService.java ---------------------------------------------------------------------- diff --git a/fe/src/main/java/com/cloudera/impala/util/RequestPoolService.java b/fe/src/main/java/com/cloudera/impala/util/RequestPoolService.java index e41db76..5e5e0c2 100644 --- a/fe/src/main/java/com/cloudera/impala/util/RequestPoolService.java +++ b/fe/src/main/java/com/cloudera/impala/util/RequestPoolService.java @@ -283,7 +283,7 @@ public class RequestPoolService { @VisibleForTesting TResolveRequestPoolResult resolveRequestPool( - TResolveRequestPoolParams resolvePoolParams) { + TResolveRequestPoolParams resolvePoolParams) throws InternalException { String requestedPool = resolvePoolParams.getRequested_pool(); String user = resolvePoolParams.getUser(); TResolveRequestPoolResult result = new TResolveRequestPoolResult(); @@ -410,7 +410,7 @@ public class RequestPoolService { */ @VisibleForTesting String assignToPool(String requestedPool, String user) - throws IOException { + throws InternalException, IOException { Preconditions.checkState(running_.get()); Preconditions.checkNotNull(requestedPool); Preconditions.checkArgument(!Strings.isNullOrEmpty(user)); @@ -432,14 +432,16 @@ public class RequestPoolService { * @return True if the user has access to the pool. */ @VisibleForTesting - boolean hasAccess(String pool, String user) { + boolean hasAccess(String pool, String user) throws InternalException { Preconditions.checkState(running_.get()); Preconditions.checkArgument(!Strings.isNullOrEmpty(pool)); Preconditions.checkArgument(!Strings.isNullOrEmpty(user)); // Convert the user name to a short name (e.g. 'user1@domain' to 'user1') because // the UserGroupInformation will check group membership which should always be done // on the short name of the principal. - String shortName = new User(user).getShortName(); + String shortName; + User requestingUser = new User(user); + shortName = requestingUser.getShortName(); UserGroupInformation ugi = UserGroupInformation.createRemoteUser(shortName); return allocationConf_.get().hasAccess(pool, QueueACL.SUBMIT_APPLICATIONS, ugi); } http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/3092c966/fe/src/test/java/com/cloudera/impala/analysis/AuditingTest.java ---------------------------------------------------------------------- diff --git a/fe/src/test/java/com/cloudera/impala/analysis/AuditingTest.java b/fe/src/test/java/com/cloudera/impala/analysis/AuditingTest.java index 4258994..6b3c426 100644 --- a/fe/src/test/java/com/cloudera/impala/analysis/AuditingTest.java +++ b/fe/src/test/java/com/cloudera/impala/analysis/AuditingTest.java @@ -24,6 +24,7 @@ import com.cloudera.impala.catalog.AuthorizationException; import com.cloudera.impala.catalog.Catalog; import com.cloudera.impala.catalog.ImpaladCatalog; import com.cloudera.impala.common.AnalysisException; +import com.cloudera.impala.common.InternalException; import com.cloudera.impala.service.Frontend; import com.cloudera.impala.testutil.ImpaladTestCatalog; import com.cloudera.impala.testutil.TestUtils; @@ -327,7 +328,7 @@ public class AuditingTest extends AnalyzerTest { @Test public void TestAccessEventsOnAuthFailure() throws AuthorizationException, - AnalysisException { + AnalysisException, InternalException { // The policy file doesn't exist so all operations will result in // an AuthorizationError AuthorizationConfig config = AuthorizationConfig.createHadoopGroupAuthConfig( http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/3092c966/fe/src/test/java/com/cloudera/impala/analysis/AuthorizationTest.java ---------------------------------------------------------------------- diff --git a/fe/src/test/java/com/cloudera/impala/analysis/AuthorizationTest.java b/fe/src/test/java/com/cloudera/impala/analysis/AuthorizationTest.java index 499fdf7..b82d5d4 100644 --- a/fe/src/test/java/com/cloudera/impala/analysis/AuthorizationTest.java +++ b/fe/src/test/java/com/cloudera/impala/analysis/AuthorizationTest.java @@ -21,15 +21,20 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.UUID; +import org.apache.hadoop.conf.Configuration; +import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTH_TO_LOCAL; import org.apache.hive.service.cli.thrift.TGetColumnsReq; import org.apache.hive.service.cli.thrift.TGetSchemasReq; import org.apache.hive.service.cli.thrift.TGetTablesReq; import org.apache.sentry.provider.common.ResourceAuthorizationProvider; import org.apache.sentry.provider.file.LocalGroupResourceAuthorizationProvider; import org.junit.After; +import org.junit.AfterClass; import org.junit.Assert; +import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -49,6 +54,7 @@ import com.cloudera.impala.catalog.Type; import com.cloudera.impala.common.AnalysisException; import com.cloudera.impala.common.ImpalaException; import com.cloudera.impala.common.InternalException; +import com.cloudera.impala.common.RuntimeEnv; import com.cloudera.impala.service.Frontend; import com.cloudera.impala.testutil.ImpaladTestCatalog; import com.cloudera.impala.testutil.TestUtils; @@ -65,6 +71,7 @@ import com.cloudera.impala.thrift.TSessionState; import com.cloudera.impala.util.SentryPolicyService; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; +import com.google.common.collect.Maps; @RunWith(Parameterized.class) public class AuthorizationTest { @@ -155,6 +162,16 @@ public class AuthorizationTest { testCtxs_.add(new TestContext(sentryServiceAuthzConfig, sentryServiceCatalog)); } + @BeforeClass + public static void setUp() throws Exception { + RuntimeEnv.INSTANCE.setTestEnv(true); + } + + @AfterClass + public static void cleanUp() { + RuntimeEnv.INSTANCE.reset(); + } + public AuthorizationTest(TestContext ctx) throws Exception { ctx_ = ctx; queryCtx_ = TestUtils.createQueryContext(Catalog.DEFAULT_DB, USER.getName()); @@ -421,7 +438,7 @@ public class AuthorizationTest { } @Test - public void TestSelect() throws AuthorizationException, AnalysisException { + public void TestSelect() throws ImpalaException { // Can select from table that user has privileges on. AuthzOk("select * from functional.alltypesagg"); @@ -535,7 +552,7 @@ public class AuthorizationTest { } @Test - public void TestUnion() throws AuthorizationException, AnalysisException { + public void TestUnion() throws ImpalaException { AuthzOk("select * from functional.alltypesagg union all " + "select * from functional.alltypesagg"); @@ -553,7 +570,7 @@ public class AuthorizationTest { } @Test - public void TestInsert() throws AuthorizationException, AnalysisException { + public void TestInsert() throws ImpalaException { AuthzOk("insert into functional_parquet.alltypes " + "partition(month,year) select * from functional_seq_snap.alltypes"); @@ -613,7 +630,7 @@ public class AuthorizationTest { } @Test - public void TestWithClause() throws AuthorizationException, AnalysisException { + public void TestWithClause() throws ImpalaException { // User has SELECT privileges on table in WITH-clause view. AuthzOk("with t as (select * from functional.alltypesagg) select * from t"); // User doesn't have SELECT privileges on table in WITH-clause view. @@ -648,7 +665,7 @@ public class AuthorizationTest { } @Test - public void TestExplain() throws AuthorizationException, AnalysisException { + public void TestExplain() throws ImpalaException { AuthzOk("explain select * from functional.alltypesagg"); AuthzOk("explain insert into functional_parquet.alltypes " + "partition(month,year) select * from functional_seq_snap.alltypes"); @@ -727,7 +744,7 @@ public class AuthorizationTest { } @Test - public void TestUseDb() throws AnalysisException, AuthorizationException { + public void TestUseDb() throws ImpalaException { // Positive cases (user has privileges on these tables). AuthzOk("use functional"); AuthzOk("use tpcds"); @@ -804,7 +821,7 @@ public class AuthorizationTest { } @Test - public void TestCreateTable() throws AnalysisException, AuthorizationException { + public void TestCreateTable() throws ImpalaException { AuthzOk("create table tpch.new_table (i int)"); AuthzOk("create table tpch.new_lineitem like tpch.lineitem"); // Create table IF NOT EXISTS, user has permission and table exists. @@ -903,7 +920,7 @@ public class AuthorizationTest { } @Test - public void TestCreateView() throws AuthorizationException, AnalysisException { + public void TestCreateView() throws ImpalaException { AuthzOk("create view tpch.new_view as select * from functional.alltypesagg"); AuthzOk("create view tpch.new_view (a, b, c) as " + "select int_col, string_col, timestamp_col from functional.alltypesagg"); @@ -1003,7 +1020,7 @@ public class AuthorizationTest { } @Test - public void TestDropDatabase() throws AnalysisException, AuthorizationException { + public void TestDropDatabase() throws ImpalaException { // User has permissions. AuthzOk("drop database tpch"); AuthzOk("drop database tpch cascade"); @@ -1057,7 +1074,7 @@ public class AuthorizationTest { } @Test - public void TestDropTable() throws AnalysisException, AuthorizationException { + public void TestDropTable() throws ImpalaException { // Drop table (user has permission). AuthzOk("drop table tpch.lineitem"); AuthzOk("drop table if exists tpch.lineitem"); @@ -1093,7 +1110,7 @@ public class AuthorizationTest { } @Test - public void TestDropView() throws AnalysisException, AuthorizationException { + public void TestDropView() throws ImpalaException { // Drop view (user has permission). AuthzOk("drop view functional_seq_snap.alltypes_view"); AuthzOk("drop view if exists functional_seq_snap.alltypes_view"); @@ -1126,7 +1143,7 @@ public class AuthorizationTest { } @Test - public void TestTruncate() throws AuthorizationException, AnalysisException { + public void TestTruncate() throws ImpalaException { AuthzOk("truncate table functional_parquet.alltypes"); // User doesn't have INSERT permissions in the target table. @@ -1147,7 +1164,7 @@ public class AuthorizationTest { } @Test - public void TestAlterTable() throws AnalysisException, AuthorizationException { + public void TestAlterTable() throws ImpalaException { // User has permissions to modify tables. AuthzOk("ALTER TABLE functional_seq_snap.alltypes ADD COLUMNS (c1 int)"); AuthzOk("ALTER TABLE functional_seq_snap.alltypes REPLACE COLUMNS (c1 int)"); @@ -1274,7 +1291,7 @@ public class AuthorizationTest { } @Test - public void TestAlterView() throws AnalysisException, AuthorizationException { + public void TestAlterView() throws ImpalaException { AuthzOk("ALTER VIEW functional_seq_snap.alltypes_view rename to " + "functional_seq_snap.v1"); @@ -1330,7 +1347,7 @@ public class AuthorizationTest { } @Test - public void TestComputeStatsTable() throws AnalysisException, AuthorizationException { + public void TestComputeStatsTable() throws ImpalaException { AuthzOk("compute stats functional_seq_snap.alltypes"); AuthzError("compute stats functional.alltypes", @@ -1344,7 +1361,7 @@ public class AuthorizationTest { } @Test - public void TestDropStats() throws AnalysisException, AuthorizationException { + public void TestDropStats() throws ImpalaException { AuthzOk("drop stats functional_seq_snap.alltypes"); AuthzError("drop stats functional.alltypes", @@ -1358,7 +1375,7 @@ public class AuthorizationTest { } @Test - public void TestDescribeDb() throws AuthorizationException, AnalysisException { + public void TestDescribeDb() throws ImpalaException { AuthzOk("describe database functional_seq_snap"); // Database doesn't exist. @@ -1370,7 +1387,7 @@ public class AuthorizationTest { } @Test - public void TestDescribe() throws AuthorizationException, AnalysisException { + public void TestDescribe() throws ImpalaException { AuthzOk("describe functional.alltypesagg"); AuthzOk("describe functional.alltypes"); AuthzOk("describe functional.complex_view"); @@ -1406,7 +1423,7 @@ public class AuthorizationTest { } @Test - public void TestLoad() throws AuthorizationException, AnalysisException { + public void TestLoad() throws ImpalaException { // User has permission on table and URI. AuthzOk("load data inpath 'hdfs://localhost:20500/test-warehouse/tpch.lineitem'" + " into table functional.alltypes partition(month=10, year=2009)"); @@ -1453,7 +1470,7 @@ public class AuthorizationTest { } @Test - public void TestShowPermissions() throws AuthorizationException, AnalysisException { + public void TestShowPermissions() throws ImpalaException { AuthzOk("show tables in functional"); AuthzOk("show databases"); AuthzOk("show tables in _impala_builtins"); @@ -1657,11 +1674,10 @@ public class AuthorizationTest { } @Test - public void TestShortUsernameUsed() throws AnalysisException, - AuthorizationException { + public void TestShortUsernameUsed() throws Exception { // Different long variations of the same username. List<User> users = Lists.newArrayList( - new User(USER.getName() + "/abc.host.com"), + new User(USER.getName() + "/abc.host.com@"), new User(USER.getName() + "/[email protected]"), new User(USER.getName() + "@REAL.COM")); for (User user: users) { @@ -1677,14 +1693,84 @@ public class AuthorizationTest { "User '%s' does not have privileges to execute 'SELECT' on: default.alltypes", user); } - // If the first character is '/' or '@', the short username should be the same as + // If the first character is '/', the short username should be the same as // the full username. assertEquals("/" + USER.getName(), new User("/" + USER.getName()).getShortName()); - assertEquals("@" + USER.getName(), new User("@" + USER.getName()).getShortName()); } @Test - public void TestFunction() throws ImpalaException { + public void TestShortUsernameWithAuthToLocal() throws ImpalaException { + // We load the auth_to_local configs from core-site.xml in the test mode even if + // kerberos is disabled. We use the following configuration for tests + // <property> + // <name>hadoop.security.auth_to_local</name> + // <value>RULE:[2:$1@$0]([email protected])s/(.*)@REALM.COM/auth_to_local_user/ + // RULE:[1:$1] + // RULE:[2:$1] + // DEFAULT + // </value> + // </property> + AuthorizationConfig authzConfig = new AuthorizationConfig("server1", + AUTHZ_POLICY_FILE, "", + LocalGroupResourceAuthorizationProvider.class.getName()); + ImpaladCatalog catalog = new ImpaladTestCatalog(authzConfig); + + // This test relies on the auth_to_local rule - + // "RULE:[2:$1@$0]([email protected])s/(.*)@REALM.COM/auth_to_local_user/" + // which converts any principal of type authtest/<hostname>@REALM.COM to user + // auth_to_local_user. We have a sentry privilege in place that grants 'SELECT' + // privilege on tpcds.* to user auth_to_local_user. To test the integration, we try + // running the query with authtest/[email protected] user which is converted to user + // 'auth_to_local_user' and the authz should pass. + User.setRulesForTesting( + new Configuration().get(HADOOP_SECURITY_AUTH_TO_LOCAL, "DEFAULT")); + User user = new User("authtest/[email protected]"); + AnalysisContext context = new AnalysisContext(catalog, + TestUtils.createQueryContext(Catalog.DEFAULT_DB, user.getName()), authzConfig); + Frontend fe = new Frontend(authzConfig, catalog); + + // Can select from table that user has privileges on. + AuthzOk(fe, context, "select * from tpcds.customer"); + // Does not have privileges to execute a query + AuthzError(fe, context, "select * from functional.alltypes", + "User '%s' does not have privileges to execute 'SELECT' on: functional.alltypes", + user); + + // Unit tests for User#getShortName() + // Different auth_to_local rules to apply on the username. + List<String> rules = Lists.newArrayList( + // Expects user@REALM and returns 'usera' (appends a in the end) + "RULE:[1:$1@$0](.*@REALM.COM)s/(.*)@REALM.COM/$1a/g", + // Same as above but expects user/host@REALM + "RULE:[2:$1@$0](.*@REALM.COM)s/(.*)@REALM.COM/$1a/g"); + + // Map from the user to the expected getShortName() output after applying + // the corresponding rule from 'rules' list. + List<Map.Entry<User, String>> users = Lists.newArrayList( + Maps.immutableEntry(new User(USER.getName() + "@REALM.COM"), USER.getName() + + "a"), + Maps.immutableEntry(new User(USER.getName() + "/[email protected]"), + USER.getName() + "a")); + + for (int idx = 0; idx < users.size(); ++idx) { + Map.Entry<User, String> userObj = users.get(idx); + assertEquals(userObj.getKey().getShortNameForTesting(rules.get(idx)), + userObj.getValue()); + } + + // Test malformed rules. RuleParser throws an IllegalArgumentException. + String malformedRule = "{((()"; + try { + user.getShortNameForTesting(malformedRule); + } catch (IllegalArgumentException e) { + Assert.assertTrue(e.getMessage().contains("Invalid rule")); + return; + } + Assert.fail("No exception caught while using getShortName() on a malformed rule"); + } + + @Test + public void TestFunction() throws Exception { // First try with the less privileged user. User currentUser = USER; AnalysisContext context = new AnalysisContext(ctx_.catalog, @@ -1771,7 +1857,8 @@ public class AuthorizationTest { } @Test - public void TestServerNameAuthorized() throws AnalysisException { + public void TestServerNameAuthorized() + throws AnalysisException, InternalException { if (ctx_.authzConfig.isFileBasedPolicy()) { // Authorization config that has a different server name from policy file. TestWithIncorrectConfig(AuthorizationConfig.createHadoopGroupAuthConfig( @@ -1781,7 +1868,8 @@ public class AuthorizationTest { } @Test - public void TestNoPermissionsWhenPolicyFileDoesNotExist() throws AnalysisException { + public void TestNoPermissionsWhenPolicyFileDoesNotExist() + throws AnalysisException, InternalException { // Test doesn't make sense except for file based policies. if (!ctx_.authzConfig.isFileBasedPolicy()) return; @@ -1894,8 +1982,7 @@ public class AuthorizationTest { } @Test - public void TestLocalGroupPolicyProvider() throws AnalysisException, - AuthorizationException { + public void TestLocalGroupPolicyProvider() throws ImpalaException { if (!ctx_.authzConfig.isFileBasedPolicy()) return; // Use an authorization configuration that uses the // LocalGroupResourceAuthorizationProvider. @@ -1930,7 +2017,7 @@ public class AuthorizationTest { } private void TestWithIncorrectConfig(AuthorizationConfig authzConfig, User user) - throws AnalysisException { + throws AnalysisException, InternalException { Frontend fe = new Frontend(authzConfig, ctx_.catalog); AnalysisContext ac = new AnalysisContext(new ImpaladTestCatalog(), TestUtils.createQueryContext(Catalog.DEFAULT_DB, user.getName()), authzConfig); @@ -1947,18 +2034,16 @@ public class AuthorizationTest { "User '%s' does not have privileges to access: functional.*", user); } - private void AuthzOk(String stmt) throws AuthorizationException, - AnalysisException { + private void AuthzOk(String stmt) throws ImpalaException { AuthzOk(analysisContext_, stmt); } - private void AuthzOk(AnalysisContext context, String stmt) - throws AuthorizationException, AnalysisException { + private void AuthzOk(AnalysisContext context, String stmt) throws ImpalaException { AuthzOk(fe_, context, stmt); } private static void AuthzOk(Frontend fe, AnalysisContext context, String stmt) - throws AuthorizationException, AnalysisException { + throws ImpalaException { context.analyze(stmt); context.authorize(fe.getAuthzChecker()); } @@ -1968,17 +2053,19 @@ public class AuthorizationTest { * string matches. */ private void AuthzError(String stmt, String expectedErrorString) - throws AnalysisException { + throws AnalysisException, InternalException { AuthzError(analysisContext_, stmt, expectedErrorString, USER); } private void AuthzError(AnalysisContext analysisContext, - String stmt, String expectedErrorString, User user) throws AnalysisException { + String stmt, String expectedErrorString, User user) + throws AnalysisException, InternalException { AuthzError(fe_, analysisContext, stmt, expectedErrorString, user); } private static void AuthzError(Frontend fe, AnalysisContext analysisContext, - String stmt, String expectedErrorString, User user) throws AnalysisException { + String stmt, String expectedErrorString, User user) + throws AnalysisException, InternalException { Preconditions.checkNotNull(expectedErrorString); try { try { http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/3092c966/fe/src/test/java/com/cloudera/impala/util/TestRequestPoolService.java ---------------------------------------------------------------------- diff --git a/fe/src/test/java/com/cloudera/impala/util/TestRequestPoolService.java b/fe/src/test/java/com/cloudera/impala/util/TestRequestPoolService.java index 34255bd..c40ca0f 100644 --- a/fe/src/test/java/com/cloudera/impala/util/TestRequestPoolService.java +++ b/fe/src/test/java/com/cloudera/impala/util/TestRequestPoolService.java @@ -27,6 +27,7 @@ import org.junit.Test; import org.junit.rules.TemporaryFolder; import com.cloudera.impala.common.ByteUnits; +import com.cloudera.impala.common.InternalException; import com.cloudera.impala.thrift.TErrorCode; import com.cloudera.impala.thrift.TPoolConfig; import com.cloudera.impala.thrift.TResolveRequestPoolParams; @@ -233,7 +234,8 @@ public class TestRequestPoolService { checkPoolConfigResult("root.queueC", -1, 200, 128 * ByteUnits.MEGABYTE); } - private void checkModifiedConfigResults() throws IOException { + private void checkModifiedConfigResults() + throws InternalException, IOException { // Test pool resolution: now there's a queueC Assert.assertEquals("root.queueA", poolService_.assignToPool("queueA", "userA")); Assert.assertNull(poolService_.assignToPool("queueX", "userA")); http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/3092c966/fe/src/test/resources/authz-policy.ini.template ---------------------------------------------------------------------- diff --git a/fe/src/test/resources/authz-policy.ini.template b/fe/src/test/resources/authz-policy.ini.template index e07cad5..4c11bc4 100644 --- a/fe/src/test/resources/authz-policy.ini.template +++ b/fe/src/test/resources/authz-policy.ini.template @@ -8,6 +8,7 @@ ${USER} = all_tpch, all_newdb, all_functional_seq_snap, select_tpcds,\ select_functional_complex_view, select_functional_view_view,\ insert_parquet, new_table_uri, tpch_data_uri, select_column_level_functional,\ upper_case_uri +auth_to_local_group = test_role server_admin = all_server # The [roles] section defines privileges for objects in the authorizeable hierarchy. @@ -20,6 +21,7 @@ all_tpch = server=server1->db=tpch all_newdb = server=server1->db=newdb all_functional_seq_snap = server=server1->db=functional_seq_snap select_tpcds = server=server1->db=tpcds->table=*->action=select +test_role = server=server1->db=tpcds->table=*->action=select select_functional_alltypesagg =\ server=server1->db=functional->table=alltypesagg->action=select insert_functional_alltypes = server=server1->db=functional->table=alltypes->action=insert @@ -59,4 +61,5 @@ upper_case_uri = server=server1->uri=hdfs://localhost:20500/test-warehouse/UPPER # HadoopGroupResourcePolicyProvider. [users] test_user = ${USER} +auth_to_local_user = auth_to_local_group admin_user = server_admin http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/3092c966/testdata/cluster/node_templates/common/etc/hadoop/conf/core-site.xml.tmpl ---------------------------------------------------------------------- diff --git a/testdata/cluster/node_templates/common/etc/hadoop/conf/core-site.xml.tmpl b/testdata/cluster/node_templates/common/etc/hadoop/conf/core-site.xml.tmpl index 4f858f1..ab86878 100644 --- a/testdata/cluster/node_templates/common/etc/hadoop/conf/core-site.xml.tmpl +++ b/testdata/cluster/node_templates/common/etc/hadoop/conf/core-site.xml.tmpl @@ -35,6 +35,16 @@ </property> <property> + <!-- AuthorizationTest depends on auth_to_local configs. These tests are run + irrespective of whether kerberos is enabled. --> + <name>hadoop.security.auth_to_local</name> + <value>RULE:[2:$1@$0]([email protected])s/(.*)@REALM.COM/auth_to_local_user/ +RULE:[1:$1] +RULE:[2:$1] +DEFAULT</value> + </property> + + <property> <name>hadoop.proxyuser.${USER}.groups</name> <value>*</value> </property> @@ -104,6 +114,7 @@ <name>hadoop.proxyuser.llama.groups</name> <value>*</value> </property> + <!-- END Kerberos settings --> </configuration>
