You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ranger.apache.org by ma...@apache.org on 2022/02/11 19:50:24 UTC
[ranger] branch ranger-2.3 updated: RANGER-3609: plugins to automatically add userStoreEnricher when any policy has references to user/group attributes
This is an automated email from the ASF dual-hosted git repository.
madhan pushed a commit to branch ranger-2.3
in repository https://gitbox.apache.org/repos/asf/ranger.git
The following commit(s) were added to refs/heads/ranger-2.3 by this push:
new 6cca6db RANGER-3609: plugins to automatically add userStoreEnricher when any policy has references to user/group attributes
6cca6db is described below
commit 6cca6db3d11601e04faaeee95d796e2ca2d59570
Author: Madhan Neethiraj <ma...@apache.org>
AuthorDate: Sun Feb 6 12:05:19 2022 -0800
RANGER-3609: plugins to automatically add userStoreEnricher when any policy has references to user/group attributes
(cherry picked from commit 07c6875a859a4ac4a5b1feb66b6f7bdc83d99878)
---
.../ranger/admin/client/RangerAdminRESTClient.java | 2 +-
.../contextenricher/RangerUserStoreEnricher.java | 27 +-
.../policyengine/RangerRequestScriptEvaluator.java | 76 ++++-
.../ranger/plugin/service/RangerBasePlugin.java | 43 +++
.../plugin/util/RangerAccessRequestUtil.java | 1 +
.../ranger/plugin/util/RangerPluginCapability.java | 3 +-
.../apache/ranger/plugin/util/RangerRESTUtils.java | 3 +-
.../plugin/util/RangerRequestExprResolver.java | 100 ++++++
.../apache/ranger/plugin/util/ServiceDefUtil.java | 249 ++++++++++++++-
.../ranger/plugin/util/ServiceDefUtilTest.java | 355 +++++++++++++++++++++
.../admin/client/RangerAdminJersey2RESTClient.java | 99 ++++++
.../java/org/apache/ranger/rest/XUserREST.java | 83 ++++-
.../conf.dist/security-applicationContext.xml | 1 +
13 files changed, 1015 insertions(+), 27 deletions(-)
diff --git a/agents-common/src/main/java/org/apache/ranger/admin/client/RangerAdminRESTClient.java b/agents-common/src/main/java/org/apache/ranger/admin/client/RangerAdminRESTClient.java
index a787c78..8edb3cb 100644
--- a/agents-common/src/main/java/org/apache/ranger/admin/client/RangerAdminRESTClient.java
+++ b/agents-common/src/main/java/org/apache/ranger/admin/client/RangerAdminRESTClient.java
@@ -786,7 +786,7 @@ public class RangerAdminRESTClient extends AbstractRangerAdminClient {
if (LOG.isDebugEnabled()) {
LOG.debug("Checking UserStore updated as user : " + user);
}
- String relativeURL = RangerRESTUtils.REST_URL_SERVICE_SERCURE_GET_USERSTORE + serviceNameUrlParam;
+ String relativeURL = RangerRESTUtils.REST_URL_SERVICE_GET_USERSTORE + serviceNameUrlParam;
response = restClient.get(relativeURL, queryParams);
}
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerUserStoreEnricher.java b/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerUserStoreEnricher.java
index 9a39b2f..e7a3174 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerUserStoreEnricher.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/contextenricher/RangerUserStoreEnricher.java
@@ -35,21 +35,18 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RangerUserStoreEnricher extends RangerAbstractContextEnricher {
- private static final Logger LOG = LoggerFactory.getLogger(RangerUserStoreEnricher.class);
-
- private static final Logger PERF_SET_USERSTORE_LOG = RangerPerfTracer.getPerfLogger("userstoreenricher.setuserstore");
-
-
- private static final String USERSTORE_REFRESHER_POLLINGINTERVAL_OPTION = "userStoreRefresherPollingInterval";
- private static final String USERSTORE_RETRIEVER_CLASSNAME_OPTION = "userStoreRetrieverClassName";
-
- private RangerUserStoreRefresher userStoreRefresher;
- private RangerUserStoreRetriever userStoreRetriever;
- private RangerUserStore rangerUserStore;
- private boolean disableCacheIfServiceNotFound = true;
-
- private final BlockingQueue<DownloadTrigger> userStoreDownloadQueue = new LinkedBlockingQueue<>();
- private Timer userStoreDownloadTimer;
+ private static final Logger LOG = LoggerFactory.getLogger(RangerUserStoreEnricher.class);
+ private static final Logger PERF_SET_USERSTORE_LOG = RangerPerfTracer.getPerfLogger("userstoreenricher.setuserstore");
+
+ public static final String USERSTORE_REFRESHER_POLLINGINTERVAL_OPTION = "userStoreRefresherPollingInterval";
+ public static final String USERSTORE_RETRIEVER_CLASSNAME_OPTION = "userStoreRetrieverClassName";
+
+ private RangerUserStoreRefresher userStoreRefresher;
+ private RangerUserStoreRetriever userStoreRetriever;
+ private RangerUserStore rangerUserStore;
+ private boolean disableCacheIfServiceNotFound = true;
+ private final BlockingQueue<DownloadTrigger> userStoreDownloadQueue = new LinkedBlockingQueue<>();
+ private Timer userStoreDownloadTimer;
@Override
public void init() {
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerRequestScriptEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerRequestScriptEvaluator.java
index 46d8739..4e312f8 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerRequestScriptEvaluator.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerRequestScriptEvaluator.java
@@ -77,7 +77,9 @@ public final class RangerRequestScriptEvaluator {
SCRIPT_VAR_TAG + "=" + SCRIPT_VAR__CTX + "." + SCRIPT_FIELD_TAG + ";" +
SCRIPT_VAR_TAGS + "=" + SCRIPT_VAR__CTX + "." + SCRIPT_FIELD_TAGS + ";" +
SCRIPT_VAR_TAGNAMES + "=" + SCRIPT_VAR__CTX + "." + SCRIPT_FIELD_TAG_NAMES + ";";
- private static final Pattern JSON_VAR_NAMES_PATTERN = Pattern.compile(getJsonVarNamesPattern());
+ private static final Pattern JSON_VAR_NAMES_PATTERN = Pattern.compile(getJsonVarNamesPattern());
+ private static final Pattern USER_ATTRIBUTES_PATTERN = Pattern.compile(getUserAttributesPattern());
+ private static final Pattern GROUP_ATTRIBUTES_PATTERN = Pattern.compile(getGroupAttributesPattern());
private static final Character CHAR_QUOTE = '\'';
private static final Character CHAR_COMMA = ',';
@@ -128,7 +130,43 @@ public final class RangerRequestScriptEvaluator {
public static boolean needsJsonCtxEnabled(String script) {
Matcher matcher = JSON_VAR_NAMES_PATTERN.matcher(script);
- boolean ret = matcher.matches();
+ boolean ret = matcher.find();
+
+ return ret;
+ }
+
+ public static boolean hasUserAttributeReference(String script) {
+ Matcher matcher = USER_ATTRIBUTES_PATTERN.matcher(script);
+
+ boolean ret = matcher.find();
+
+ return ret;
+ }
+
+ public static boolean hasGroupAttributeReference(String script) {
+ Matcher matcher = GROUP_ATTRIBUTES_PATTERN.matcher(script);
+
+ boolean ret = matcher.find();
+
+ return ret;
+ }
+
+ public static boolean hasUserGroupAttributeReference(String script) {
+ return hasUserAttributeReference(script) || hasGroupAttributeReference(script);
+ }
+
+ public static boolean hasUserGroupAttributeReference(Collection<String> scripts) {
+ boolean ret = false;
+
+ if (scripts != null) {
+ for (String script : scripts) {
+ if (hasUserGroupAttributeReference(script)) {
+ ret = true;
+
+ break;
+ }
+ }
+ }
return ret;
}
@@ -890,7 +928,39 @@ public final class RangerRequestScriptEvaluator {
varNames.add(SCRIPT_VAR_URNAMES);
varNames.add(SCRIPT_VAR_USER);
- return ".*(" + StringUtils.join(varNames, '|') + ").*";
+ return "\\b(" + StringUtils.join(varNames, '|') + ")\\b";
+ }
+
+ private static String getUserAttributesPattern() {
+ List<String> varNames = new ArrayList<>();
+
+ varNames.add(SCRIPT_VAR_USER);
+ varNames.add(SCRIPT_MACRO_USER_ATTR_NAMES_CSV);
+ varNames.add(SCRIPT_MACRO_USER_ATTR_NAMES_Q_CSV);
+
+ varNames.add("userAttrNamesCsv");
+ varNames.add("userAttrNamesCsvQ");
+
+ return "\\b(" + StringUtils.join(varNames, '|') + ")\\b";
+ }
+
+ private static String getGroupAttributesPattern() {
+ List<String> varNames = new ArrayList<>();
+
+ varNames.add(SCRIPT_VAR_UG);
+ varNames.add(SCRIPT_VAR_UGA);
+
+ varNames.add(SCRIPT_MACRO_GET_UG_ATTR_CSV);
+ varNames.add(SCRIPT_MACRO_GET_UG_ATTR_Q_CSV);
+ varNames.add(SCRIPT_MACRO_UG_ATTR_NAMES_CSV);
+ varNames.add(SCRIPT_MACRO_UG_ATTR_NAMES_Q_CSV);
+
+ varNames.add("ugAttrCsv");
+ varNames.add("ugAttrCsvQ");
+ varNames.add("ugAttrNamesCsv");
+ varNames.add("ugAttrNamesCsvQ");
+
+ return "\\b(" + StringUtils.join(varNames, '|') + ")\\b";
}
private static Map<String, String> getMacrosMap() {
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBasePlugin.java b/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBasePlugin.java
index 827fb1f..12fecd0 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBasePlugin.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBasePlugin.java
@@ -31,6 +31,8 @@ import org.apache.ranger.audit.provider.StandAloneAuditProviderFactory;
import org.apache.ranger.authorization.hadoop.config.RangerAuditConfig;
import org.apache.ranger.authorization.hadoop.config.RangerPluginConfig;
import org.apache.ranger.authorization.utils.StringUtil;
+import org.apache.ranger.plugin.contextenricher.RangerAdminUserStoreRetriever;
+import org.apache.ranger.plugin.contextenricher.RangerUserStoreEnricher;
import org.apache.ranger.plugin.policyengine.RangerRequestScriptEvaluator;
import org.apache.ranger.plugin.contextenricher.RangerContextEnricher;
import org.apache.ranger.plugin.contextenricher.RangerTagEnricher;
@@ -68,6 +70,8 @@ public class RangerBasePlugin {
private RangerAccessResultProcessor resultProcessor;
private RangerRoles roles;
private final List<RangerChainedPlugin> chainedPlugins;
+ private final boolean enableImplicitUserStoreEnricher;
+ private boolean isUserStoreEnricherAddedImplcitly = false;
public RangerBasePlugin(String serviceType, String appId) {
@@ -96,6 +100,8 @@ public class RangerBasePlugin {
RangerRequestScriptEvaluator.init(pluginConfig);
+ this.enableImplicitUserStoreEnricher = pluginConfig.getBoolean(pluginConfig.getPropertyPrefix() + ".enable.implicit.userstore.enricher", false);
+
this.chainedPlugins = initChainedPlugins();
}
@@ -254,6 +260,18 @@ public class RangerBasePlugin {
LOG.debug("==> setPolicies(" + policies + ")");
}
+ if (enableImplicitUserStoreEnricher && policies != null && !ServiceDefUtil.isUserStoreEnricherPresent(policies)) {
+ String retrieverClassName = getConfig().get(RangerUserStoreEnricher.USERSTORE_RETRIEVER_CLASSNAME_OPTION, RangerAdminUserStoreRetriever.class.getCanonicalName());
+ String retrieverPollIntMs = getConfig().get(RangerUserStoreEnricher.USERSTORE_REFRESHER_POLLINGINTERVAL_OPTION, Integer.toString(60 * 1000));
+
+ // in case of delta, policies will only have changes; hence add userStoreEnricher if it was implicitly added previous calls to setPolicies()
+ if (RangerPolicyDeltaUtil.hasPolicyDeltas(policies) == Boolean.TRUE && isUserStoreEnricherAddedImplcitly) {
+ ServiceDefUtil.addUserStoreEnricher(policies, retrieverClassName, retrieverPollIntMs);
+ } else {
+ isUserStoreEnricherAddedImplcitly = ServiceDefUtil.addUserStoreEnricherIfNeeded(policies, retrieverClassName, retrieverPollIntMs);
+ }
+ }
+
// guard against catastrophic failure during policy engine Initialization or
try {
RangerPolicyEngine oldPolicyEngine = this.policyEngine;
@@ -994,6 +1012,31 @@ public class RangerBasePlugin {
return ret;
}
+ public RangerUserStoreEnricher getUserStoreEnricher() {
+ RangerUserStoreEnricher ret = null;
+ RangerAuthContext authContext = getCurrentRangerAuthContext();
+
+ if (authContext != null) {
+ Map<RangerContextEnricher, Object> contextEnricherMap = authContext.getRequestContextEnrichers();
+
+ if (MapUtils.isNotEmpty(contextEnricherMap)) {
+ Set<RangerContextEnricher> contextEnrichers = contextEnricherMap.keySet();
+
+ for (RangerContextEnricher enricher : contextEnrichers) {
+ if (enricher instanceof RangerUserStoreEnricher) {
+ ret = (RangerUserStoreEnricher) enricher;
+
+ ret.getRangerUserStore();
+
+ break;
+ }
+ }
+ }
+ }
+
+ return ret;
+ }
+
public static RangerResourceACLs getMergedResourceACLs(RangerResourceACLs baseACLs, RangerResourceACLs chainedACLs) {
if (LOG.isDebugEnabled()) {
LOG.debug("==> RangerBasePlugin.getMergedResourceACLs()");
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerAccessRequestUtil.java b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerAccessRequestUtil.java
index 4415b6c..c4beabf 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerAccessRequestUtil.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerAccessRequestUtil.java
@@ -130,6 +130,7 @@ public class RangerAccessRequestUtil {
ret.remove(KEY_CONTEXT_TAGS);
ret.remove(KEY_CONTEXT_TAG_OBJECT);
ret.remove(KEY_CONTEXT_RESOURCE);
+ ret.remove(KEY_CONTEXT_REQUEST);
// don't remove REQUESTED_RESOURCES
}
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerPluginCapability.java b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerPluginCapability.java
index b2cecc1..bac6e26 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerPluginCapability.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerPluginCapability.java
@@ -69,7 +69,8 @@ public class RangerPluginCapability {
RANGER_PLUGIN_CAPABILITY_CHAINED_PLUGINS("Chained Plugins"),
RANGER_PLUGIN_CAPABILITY_SUPERUSER_PERMISSIONS("Super-user Permissions"),
RANGER_PLUGIN_CAPABILITY_USERSTORE_DOWNLOAD("UserStore Download"),
- RANGER_PLUGIN_CAPABILITY_AUDIT_POLICY("Audit Policy");
+ RANGER_PLUGIN_CAPABILITY_AUDIT_POLICY("Audit Policy"),
+ RANGER_PLUGIN_CAPABILITY_UGT_ATTRIBUTES_IN_POLICY("User/group/tag attributes in policy");
private final String name;
RangerPluginFeature(String name) {
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRESTUtils.java b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRESTUtils.java
index ba57f70..207ef6f 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRESTUtils.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRESTUtils.java
@@ -73,7 +73,8 @@ public class RangerRESTUtils {
public static final String REST_PARAM_LAST_KNOWN_ROLE_VERSION = "lastKnownRoleVersion";
public static final String REST_PARAM_LAST_KNOWN_USERSTORE_VERSION = "lastKnownUserStoreVersion";
- public static final String REST_URL_SERVICE_SERCURE_GET_USERSTORE = "/service/xusers/secure/download/";
+ public static final String REST_URL_SERVICE_GET_USERSTORE = "/service/xusers/download/";
+ public static final String REST_URL_SERVICE_SERCURE_GET_USERSTORE = "/service/xusers/secure/download/";
private static final int MAX_PLUGIN_ID_LEN = 255;
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRequestExprResolver.java b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRequestExprResolver.java
index 2e486ed..4e5d949 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRequestExprResolver.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRequestExprResolver.java
@@ -25,6 +25,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.script.ScriptEngine;
+import java.util.Collection;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -86,4 +87,103 @@ public class RangerRequestExprResolver {
return matcher.find();
}
+
+ public static boolean hasUserAttributeInExpression(String str) {
+ boolean ret = false;
+ Matcher matcher = PATTERN.matcher(str);
+
+ while (matcher.find()) {
+ String expr = matcher.group(REGEX_GROUP_EXPR);
+
+ if (RangerRequestScriptEvaluator.hasUserAttributeReference(expr)) {
+ ret = true;
+
+ break;
+ }
+ }
+
+ return ret;
+ }
+
+ public static boolean hasGroupAttributeInExpression(String str) {
+ boolean ret = false;
+ Matcher matcher = PATTERN.matcher(str);
+
+ while (matcher.find()) {
+ String expr = matcher.group(REGEX_GROUP_EXPR);
+
+ if (RangerRequestScriptEvaluator.hasGroupAttributeReference(expr)) {
+ ret = true;
+
+ break;
+ }
+ }
+
+ return ret;
+ }
+
+ public static boolean hasUserGroupAttributeInExpression(String str) {
+ boolean ret = false;
+ Matcher matcher = PATTERN.matcher(str);
+
+ while (matcher.find()) {
+ String expr = matcher.group(REGEX_GROUP_EXPR);
+
+ if (RangerRequestScriptEvaluator.hasUserGroupAttributeReference(expr)) {
+ ret = true;
+
+ break;
+ }
+ }
+
+ return ret;
+ }
+
+ public static boolean hasUserAttributeInExpression(Collection<String> values) {
+ boolean ret = false;
+
+ if (values != null) {
+ for (String value : values) {
+ if (hasUserAttributeInExpression(value)) {
+ ret = true;
+
+ break;
+ }
+ }
+ }
+
+ return ret;
+ }
+
+ public static boolean hasGroupAttributeInExpression(Collection<String> values) {
+ boolean ret = false;
+
+ if (values != null) {
+ for (String value : values) {
+ if (hasGroupAttributeInExpression(value)) {
+ ret = true;
+
+ break;
+ }
+ }
+ }
+
+ return ret;
+ }
+
+ public static boolean hasUserGroupAttributeInExpression(Collection<String> values) {
+ boolean ret = false;
+
+ if (values != null) {
+ for (String value : values) {
+ if (hasUserGroupAttributeInExpression(value)) {
+ ret = true;
+
+ break;
+ }
+ }
+ }
+
+ return ret;
+ }
}
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/util/ServiceDefUtil.java b/agents-common/src/main/java/org/apache/ranger/plugin/util/ServiceDefUtil.java
index b76c96e..fe1cf92 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/util/ServiceDefUtil.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/util/ServiceDefUtil.java
@@ -23,14 +23,26 @@ import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.conf.Configuration;
+import org.apache.ranger.plugin.contextenricher.RangerUserStoreEnricher;
import org.apache.ranger.plugin.model.RangerPolicy;
+import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItem;
+import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItemCondition;
+import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItemRowFilterInfo;
+import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyResource;
+import org.apache.ranger.plugin.model.RangerPolicy.RangerRowFilterPolicyItem;
+import org.apache.ranger.plugin.model.RangerPolicyDelta;
import org.apache.ranger.plugin.model.RangerServiceDef;
import org.apache.ranger.plugin.model.RangerServiceDef.RangerAccessTypeDef;
+import org.apache.ranger.plugin.model.RangerServiceDef.RangerContextEnricherDef;
import org.apache.ranger.plugin.model.RangerServiceDef.RangerDataMaskTypeDef;
import org.apache.ranger.plugin.model.RangerServiceDef.RangerResourceDef;
import org.apache.ranger.plugin.policyengine.RangerPluginContext;
+import org.apache.ranger.plugin.policyengine.RangerRequestScriptEvaluator;
import org.apache.ranger.plugin.store.AbstractServiceStore;
import org.apache.ranger.plugin.store.EmbeddedServiceDefsUtil;
+import org.apache.ranger.plugin.util.ServicePolicies.SecurityZoneInfo;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collection;
@@ -41,6 +53,9 @@ import java.util.HashMap;
import java.util.Map;
public class ServiceDefUtil {
+ private static final Logger LOG = LoggerFactory.getLogger(ServiceDefUtil.class);
+
+ private static final String USER_STORE_ENRICHER = RangerUserStoreEnricher.class.getCanonicalName();
public static boolean getOption_enableDenyAndExceptionsInPolicies(RangerServiceDef serviceDef, RangerPluginContext pluginContext) {
boolean ret = false;
@@ -97,7 +112,7 @@ public class ServiceDefUtil {
return ret;
}
- public static Integer getLeafResourceLevel(RangerServiceDef serviceDef, Map<String, RangerPolicy.RangerPolicyResource> policyResource) {
+ public static Integer getLeafResourceLevel(RangerServiceDef serviceDef, Map<String, RangerPolicyResource> policyResource) {
Integer ret = null;
RangerResourceDef resourceDef = getLeafResourceDef(serviceDef, policyResource);
@@ -109,11 +124,11 @@ public class ServiceDefUtil {
return ret;
}
- public static RangerResourceDef getLeafResourceDef(RangerServiceDef serviceDef, Map<String, RangerPolicy.RangerPolicyResource> policyResource) {
+ public static RangerResourceDef getLeafResourceDef(RangerServiceDef serviceDef, Map<String, RangerPolicyResource> policyResource) {
RangerResourceDef ret = null;
if(serviceDef != null && policyResource != null) {
- for(Map.Entry<String, RangerPolicy.RangerPolicyResource> entry : policyResource.entrySet()) {
+ for(Map.Entry<String, RangerPolicyResource> entry : policyResource.entrySet()) {
if (!isEmpty(entry.getValue())) {
String resource = entry.getKey();
RangerResourceDef resourceDef = ServiceDefUtil.getResourceDef(serviceDef, resource);
@@ -150,7 +165,7 @@ public class ServiceDefUtil {
return ret;
}
- public static boolean isEmpty(RangerPolicy.RangerPolicyResource policyResource) {
+ public static boolean isEmpty(RangerPolicyResource policyResource) {
boolean ret = true;
if (policyResource != null) {
List<String> resourceValues = policyResource.getValues();
@@ -466,4 +481,230 @@ public class ServiceDefUtil {
return ret;
}
+ public static boolean isUserStoreEnricherPresent(ServicePolicies policies) {
+ boolean ret = false;
+ RangerServiceDef serviceDef = policies != null ? policies.getServiceDef() : null;
+ List<RangerContextEnricherDef> enricherDefs = serviceDef != null ? serviceDef.getContextEnrichers() : null;
+
+ if (enricherDefs != null) {
+ for (RangerContextEnricherDef enricherDef : enricherDefs) {
+ if (StringUtils.equals(enricherDef.getEnricher(), USER_STORE_ENRICHER)) {
+ ret = true;
+
+ break;
+ }
+ }
+ }
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("isUserStoreEnricherPresent(service={}): ret={}", policies.getServiceName(), ret);
+ }
+
+ return ret;
+ }
+
+ public static boolean addUserStoreEnricher(ServicePolicies policies, String retrieverClassName, String retrieverPollIntMs) {
+ boolean ret = false;
+ RangerServiceDef serviceDef = policies != null ? policies.getServiceDef() : null;
+
+ if (serviceDef != null && !isUserStoreEnricherPresent(policies)) {
+ List<RangerContextEnricherDef> enricherDefs = serviceDef.getContextEnrichers();
+
+ if (enricherDefs == null) {
+ enricherDefs = new ArrayList<>();
+ }
+
+ long enricherItemId = enricherDefs.size() + 1;
+
+ for (RangerServiceDef.RangerContextEnricherDef enricherDef : enricherDefs) {
+ if (enricherDef.getItemId() >= enricherItemId) {
+ enricherItemId = enricherDef.getItemId() + 1;
+ }
+ }
+
+ Map<String, String> enricherOptions = new HashMap<>();
+
+ enricherOptions.put(RangerUserStoreEnricher.USERSTORE_RETRIEVER_CLASSNAME_OPTION, retrieverClassName);
+ enricherOptions.put(RangerUserStoreEnricher.USERSTORE_REFRESHER_POLLINGINTERVAL_OPTION, retrieverPollIntMs);
+
+ RangerServiceDef.RangerContextEnricherDef userStoreEnricher = new RangerServiceDef.RangerContextEnricherDef(enricherItemId, "userStoreEnricher", USER_STORE_ENRICHER, enricherOptions);
+
+ enricherDefs.add(userStoreEnricher);
+
+ serviceDef.setContextEnrichers(enricherDefs);
+
+ LOG.info("addUserStoreEnricher(serviceName={}): added userStoreEnricher {}", policies.getServiceName(), userStoreEnricher);
+ }
+
+ return ret;
+ }
+
+
+ public static boolean addUserStoreEnricherIfNeeded(ServicePolicies policies, String retrieverClassName, String retrieverPollIntMs) {
+ boolean ret = false;
+ RangerServiceDef serviceDef = policies != null ? policies.getServiceDef() : null;
+
+ if (serviceDef != null && !isUserStoreEnricherPresent(policies)) {
+ boolean addEnricher = anyPolicyHasUserGroupAttributeExpression(policies.getPolicies());
+
+ if (!addEnricher) {
+ List<RangerPolicy> tagPolicies = policies.getTagPolicies() != null ? policies.getTagPolicies().getPolicies() : null;
+
+ addEnricher = anyPolicyHasUserGroupAttributeExpression(tagPolicies);
+ }
+
+ if (!addEnricher) {
+ addEnricher = anyPolicyDeltaHasUserGroupAttributeExpression(policies.getPolicyDeltas());
+ }
+
+ if (!addEnricher) {
+ Map<String, SecurityZoneInfo> zoneInfos = policies.getSecurityZones();
+
+ if (zoneInfos != null) {
+ for (SecurityZoneInfo zoneInfo : zoneInfos.values()) {
+ addEnricher = anyPolicyHasUserGroupAttributeExpression(zoneInfo.getPolicies());
+
+ if (!addEnricher) {
+ addEnricher = anyPolicyDeltaHasUserGroupAttributeExpression(zoneInfo.getPolicyDeltas());
+ }
+
+ if (addEnricher) {
+ break;
+ }
+ }
+ }
+ }
+
+ if (addEnricher) {
+ addUserStoreEnricher(policies, retrieverClassName, retrieverPollIntMs);
+
+ ret = true;
+ }
+ }
+
+ return ret;
+ }
+
+ private static boolean anyPolicyHasUserGroupAttributeExpression(List<RangerPolicy> policies) {
+ boolean ret = false;
+
+ if (policies != null) {
+ for (RangerPolicy policy : policies) {
+ if (policyHasUserGroupAttributeExpression(policy)) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("addUserStoreEnricherIfNeeded(service={}): policy(id={}, name={}) has reference to user/group attribute. Adding enricher", policy.getService(), policy.getId(), policy.getName());
+ }
+
+ ret = true;
+
+ break;
+ }
+ }
+ }
+
+ return ret;
+ }
+
+ private static boolean anyPolicyDeltaHasUserGroupAttributeExpression(List<RangerPolicyDelta> policyDeltas) {
+ boolean ret = false;
+
+ if (policyDeltas != null) {
+ for (RangerPolicyDelta policyDelta : policyDeltas) {
+ RangerPolicy policy = policyDelta.getPolicy();
+
+ if (policyHasUserGroupAttributeExpression(policy)) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("addUserStoreEnricherIfNeeded(service={}): policy(id={}, name={}) has reference to user/group attribute. Adding enricher", policy.getService(), policy.getId(), policy.getName());
+ }
+
+ ret = true;
+
+ break;
+ }
+ }
+ }
+
+ return ret;
+ }
+
+ private static boolean policyHasUserGroupAttributeExpression(RangerPolicy policy) {
+ boolean ret = false;
+
+ if (policy != null) {
+ if (MapUtils.isNotEmpty(policy.getResources())) {
+ for (RangerPolicyResource resource : policy.getResources().values()) {
+ ret = RangerRequestExprResolver.hasUserGroupAttributeInExpression(resource.getValues());
+
+ if (ret) {
+ break;
+ }
+ }
+ }
+
+ if (!ret) {
+ ret = anyPolicyConditionHasUserGroupAttributeReference(policy.getConditions());
+ }
+
+ if (!ret) {
+ ret = anyPolicyItemHasUserGroupAttributeExpression(policy.getPolicyItems()) ||
+ anyPolicyItemHasUserGroupAttributeExpression(policy.getDenyPolicyItems()) ||
+ anyPolicyItemHasUserGroupAttributeExpression(policy.getAllowExceptions()) ||
+ anyPolicyItemHasUserGroupAttributeExpression(policy.getDenyExceptions()) ||
+ anyPolicyItemHasUserGroupAttributeExpression(policy.getDataMaskPolicyItems()) ||
+ anyPolicyItemHasUserGroupAttributeExpression(policy.getRowFilterPolicyItems());
+ }
+ }
+
+ return ret;
+ }
+
+ private static boolean anyPolicyItemHasUserGroupAttributeExpression(List<? extends RangerPolicyItem> policyItems) {
+ boolean ret = false;
+
+ if (policyItems != null) {
+ for (RangerPolicyItem policyItem : policyItems) {
+ if (policyItemHasUserGroupAttributeExpression(policyItem)) {
+ ret = true;
+
+ break;
+ }
+ }
+ }
+
+ return ret;
+ }
+
+ private static boolean policyItemHasUserGroupAttributeExpression(RangerPolicyItem policyItem) {
+ boolean ret = false;
+
+ if (policyItem != null) {
+ ret = anyPolicyConditionHasUserGroupAttributeReference(policyItem.getConditions());
+
+ if (!ret && policyItem instanceof RangerRowFilterPolicyItem) {
+ RangerRowFilterPolicyItem rowFilterPolicyItem = (RangerRowFilterPolicyItem) policyItem;
+ RangerPolicyItemRowFilterInfo rowFilterInfo = rowFilterPolicyItem.getRowFilterInfo();
+ String filterExpr = rowFilterInfo != null ? rowFilterInfo.getFilterExpr() : "";
+
+ ret = RangerRequestExprResolver.hasUserGroupAttributeInExpression(filterExpr);
+ }
+ }
+
+ return ret;
+ }
+
+ private static boolean anyPolicyConditionHasUserGroupAttributeReference(List<RangerPolicyItemCondition> conditions) {
+ boolean ret = false;
+
+ if (conditions != null) {
+ for (RangerPolicyItemCondition condition : conditions) {
+ if (RangerRequestScriptEvaluator.hasUserGroupAttributeReference(condition.getValues())) {
+ ret = true;
+
+ break;
+ }
+ }
+ }
+
+ return ret;
+ }
}
diff --git a/agents-common/src/test/java/org/apache/ranger/plugin/util/ServiceDefUtilTest.java b/agents-common/src/test/java/org/apache/ranger/plugin/util/ServiceDefUtilTest.java
new file mode 100644
index 0000000..3cd42f4
--- /dev/null
+++ b/agents-common/src/test/java/org/apache/ranger/plugin/util/ServiceDefUtilTest.java
@@ -0,0 +1,355 @@
+/*
+ * 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.ranger.plugin.util;
+
+import org.apache.ranger.plugin.contextenricher.RangerAdminUserStoreRetriever;
+import org.apache.ranger.plugin.model.RangerPolicy;
+import org.apache.ranger.plugin.model.RangerPolicy.RangerDataMaskPolicyItem;
+import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItem;
+import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItemCondition;
+import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItemDataMaskInfo;
+import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItemRowFilterInfo;
+import org.apache.ranger.plugin.model.RangerPolicy.RangerRowFilterPolicyItem;
+import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyResource;
+import org.apache.ranger.plugin.model.RangerPolicyDelta;
+import org.apache.ranger.plugin.model.RangerServiceDef;
+import org.apache.ranger.plugin.store.EmbeddedServiceDefsUtil;
+import org.apache.ranger.plugin.util.ServicePolicies.SecurityZoneInfo;
+import org.junit.Test;
+
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class ServiceDefUtilTest {
+ private static final String REF_USER = "USER.dept";
+ private static final String REF_UG = "UG['test-group1'].dept";
+ private static final String REF_UGA = "UGA.sVal['dept']";
+ private static final String REF_GET_UG_ATTR_CSV = "GET_UG_ATTR_CSV('dept')";
+ private static final String REF_GET_UG_ATTR_Q_CSV = "GET_UG_ATTR_Q_CSV('dept')";
+ private static final String REF_UG_ATTR_NAMES_CSV = "UG_ATTR_NAMES_CSV";
+ private static final String REF_UG_ATTR_NAMES_Q_CSV = "UG_ATTR_NAMES_Q_CSV";
+ private static final String REF_USER_ATTR_NAMES_CSV = "USER_ATTR_NAMES_CSV";
+ private static final String REF_USER_ATTR_NAMES_Q_CSV = "USER_ATTR_NAMES_Q_CSV";
+ private static final String REF_GET_UG_ATTR_CSV_F = "ctx.ugAttrCsv('dept')";
+ private static final String REF_GET_UG_ATTR_Q_CSV_F = "ctx.ugAttrCsvQ('dept')";
+ private static final String REF_UG_ATTR_NAMES_CSV_F = "ctx.ugAttrNamesCsv()";
+ private static final String REF_UG_ATTR_NAMES_Q_CSV_F = "ctx.ugAttrNamesCsvQ()";
+ private static final String REF_USER_ATTR_NAMES_CSV_F = "ctx.userAttrNamesCsv()";
+ private static final String REF_USER_ATTR_NAMES_Q_CSV_F = "ctx.userAttrNamesCsvQ()";
+
+ private static final String[] UGA_ATTR_EXPRESSIONS = new String[] {
+ REF_USER, REF_UG, REF_UGA,
+ REF_GET_UG_ATTR_CSV, REF_GET_UG_ATTR_Q_CSV,
+ REF_UG_ATTR_NAMES_CSV, REF_UG_ATTR_NAMES_Q_CSV,
+ REF_USER_ATTR_NAMES_CSV, REF_USER_ATTR_NAMES_Q_CSV,
+ REF_GET_UG_ATTR_CSV_F, REF_GET_UG_ATTR_Q_CSV_F,
+ REF_UG_ATTR_NAMES_CSV_F, REF_UG_ATTR_NAMES_Q_CSV_F,
+ REF_USER_ATTR_NAMES_CSV_F, REF_USER_ATTR_NAMES_Q_CSV_F
+ };
+
+ @Test
+ public void testNoUserGroupAttrRef() {
+ ServicePolicies svcPolicies = getServicePolicies();
+ RangerPolicy policy = getPolicy(svcPolicies);
+
+ svcPolicies.getPolicies().add(policy);
+ assertFalse("policy doesn't have any reference to user/group attribute", ServiceDefUtil.addUserStoreEnricherIfNeeded(svcPolicies, RangerAdminUserStoreRetriever.class.getCanonicalName(), "60000"));
+
+ policy.getResources().put("database", new RangerPolicyResource("/departments/USER.dept/")); // expressions must be within ${{}}
+ assertFalse("policy doesn't have any reference to user/group attribute", ServiceDefUtil.addUserStoreEnricherIfNeeded(svcPolicies, RangerAdminUserStoreRetriever.class.getCanonicalName(), "60000"));
+
+ policy.getRowFilterPolicyItems().get(0).getRowFilterInfo().setFilterExpr("dept in USER.dept"); // expressions must be within ${{}}
+ assertFalse("policy doesn't have any reference to user/group attribute", ServiceDefUtil.addUserStoreEnricherIfNeeded(svcPolicies, RangerAdminUserStoreRetriever.class.getCanonicalName(), "60000"));
+ }
+
+ @Test
+ public void testResourceUserGroupAttrRef() {
+ for (String attrExpr : UGA_ATTR_EXPRESSIONS) {
+ String resource = "test_" + "${{" + attrExpr + "}}";
+ ServicePolicies svcPolicies = getServicePolicies();
+ RangerPolicy policy = getPolicy(svcPolicies);
+
+ policy.getResources().put("database", new RangerPolicyResource(resource));
+
+ svcPolicies.getPolicies().add(policy);
+ assertTrue("policy resource refers to user/group attribute: " + resource, ServiceDefUtil.addUserStoreEnricherIfNeeded(svcPolicies, RangerAdminUserStoreRetriever.class.getCanonicalName(), "60000"));
+
+ svcPolicies.getServiceDef().getContextEnrichers().clear();
+ svcPolicies.getPolicies().clear();
+ svcPolicies.getPolicyDeltas().add(new RangerPolicyDelta(1L, RangerPolicyDelta.CHANGE_TYPE_POLICY_CREATE, 1L, policy));
+ assertTrue("policy-delta resource refers to user/group attribute: " + resource, ServiceDefUtil.addUserStoreEnricherIfNeeded(svcPolicies, RangerAdminUserStoreRetriever.class.getCanonicalName(), "60000"));
+
+ svcPolicies.getServiceDef().getContextEnrichers().clear();
+ svcPolicies.getPolicyDeltas().clear();
+ svcPolicies.getSecurityZones().put("zone1", getSecurityZoneInfo("zone1"));
+ svcPolicies.getSecurityZones().get("zone1").getPolicies().add(policy);
+ assertTrue("zone-policy resource refers to user/group attribute: " + resource, ServiceDefUtil.addUserStoreEnricherIfNeeded(svcPolicies, RangerAdminUserStoreRetriever.class.getCanonicalName(), "60000"));
+
+ svcPolicies.getServiceDef().getContextEnrichers().clear();
+ svcPolicies.getSecurityZones().get("zone1").getPolicies().clear();
+ svcPolicies.getSecurityZones().get("zone1").getPolicyDeltas().add(new RangerPolicyDelta(1L, RangerPolicyDelta.CHANGE_TYPE_POLICY_CREATE, 1L, policy));
+ assertTrue("zone-policy-delta resource refers to user/group attribute: " + resource, ServiceDefUtil.addUserStoreEnricherIfNeeded(svcPolicies, RangerAdminUserStoreRetriever.class.getCanonicalName(), "60000"));
+ }
+ }
+
+ @Test
+ public void testPolicyConditionUserGroupAttrRef() {
+ for (String attrExpr : UGA_ATTR_EXPRESSIONS) {
+ String condExpr = attrExpr + " != null";
+ ServicePolicies svcPolicies = getServicePolicies();
+ RangerPolicy policy = getPolicy(svcPolicies);
+
+ policy.getConditions().add(new RangerPolicyItemCondition("expr", Collections.singletonList(condExpr)));
+
+ svcPolicies.getPolicies().add(policy);
+ assertTrue("policy condition refers to user/group attribute: " + condExpr, ServiceDefUtil.addUserStoreEnricherIfNeeded(svcPolicies, RangerAdminUserStoreRetriever.class.getCanonicalName(), "60000"));
+
+ svcPolicies.getServiceDef().getContextEnrichers().clear();
+ svcPolicies.getPolicies().clear();
+ svcPolicies.getPolicyDeltas().add(new RangerPolicyDelta(1L, RangerPolicyDelta.CHANGE_TYPE_POLICY_CREATE, 1L, policy));
+ assertTrue("policy-delta condition refers to user/group attribute: " + condExpr, ServiceDefUtil.addUserStoreEnricherIfNeeded(svcPolicies, RangerAdminUserStoreRetriever.class.getCanonicalName(), "60000"));
+
+ svcPolicies.getServiceDef().getContextEnrichers().clear();
+ svcPolicies.getPolicyDeltas().clear();
+ svcPolicies.getSecurityZones().put("zone1", getSecurityZoneInfo("zone1"));
+ svcPolicies.getSecurityZones().get("zone1").getPolicies().add(policy);
+ assertTrue("zone-policy condition refers to user/group attribute: " + condExpr, ServiceDefUtil.addUserStoreEnricherIfNeeded(svcPolicies, RangerAdminUserStoreRetriever.class.getCanonicalName(), "60000"));
+
+ svcPolicies.getServiceDef().getContextEnrichers().clear();
+ svcPolicies.getSecurityZones().get("zone1").getPolicies().clear();
+ svcPolicies.getSecurityZones().get("zone1").getPolicyDeltas().add(new RangerPolicyDelta(1L, RangerPolicyDelta.CHANGE_TYPE_POLICY_CREATE, 1L, policy));
+ assertTrue("zone-policy-delta condition refers to user/group attribute: " + condExpr, ServiceDefUtil.addUserStoreEnricherIfNeeded(svcPolicies, RangerAdminUserStoreRetriever.class.getCanonicalName(), "60000"));
+
+ svcPolicies.getServiceDef().getContextEnrichers().clear();
+ svcPolicies.getPolicies().clear();
+ svcPolicies.getPolicyDeltas().clear();
+ svcPolicies.getSecurityZones().clear();
+ svcPolicies.getTagPolicies().getPolicies().add(policy);
+ assertTrue("tag-policy condition refers to user/group attribute: " + condExpr, ServiceDefUtil.addUserStoreEnricherIfNeeded(svcPolicies, RangerAdminUserStoreRetriever.class.getCanonicalName(), "60000"));
+ }
+ }
+
+ @Test
+ public void testPolicyItemConditionUserGroupRef() {
+ int i = 0;
+
+ for (String attrExpr : UGA_ATTR_EXPRESSIONS) {
+ String condExpr = attrExpr + " != null";
+ ServicePolicies svcPolicies = getServicePolicies();
+ RangerPolicy policy = getPolicy(svcPolicies);
+
+ final List<? extends RangerPolicyItem> policyItems;
+
+ switch (i % 6) {
+ case 0:
+ policyItems = policy.getPolicyItems();
+ break;
+
+ case 1:
+ policyItems = policy.getDenyPolicyItems();
+ break;
+
+ case 2:
+ policyItems = policy.getAllowExceptions();
+ break;
+
+ case 3:
+ policyItems = policy.getDenyExceptions();
+ break;
+
+ case 4:
+ policyItems = policy.getRowFilterPolicyItems();
+ break;
+
+ case 5:
+ policyItems = policy.getDataMaskPolicyItems();
+ break;
+
+ default:
+ policyItems = policy.getPolicyItems();
+ break;
+ }
+
+ policyItems.get(0).getConditions().add(new RangerPolicyItemCondition("expr", Collections.singletonList(condExpr)));
+
+ svcPolicies.getPolicies().add(policy);
+ assertTrue("policyItem condition refers to user/group attribute: " + condExpr, ServiceDefUtil.addUserStoreEnricherIfNeeded(svcPolicies, RangerAdminUserStoreRetriever.class.getCanonicalName(), "60000"));
+
+ svcPolicies.getServiceDef().getContextEnrichers().clear();
+ svcPolicies.getPolicies().clear();
+ svcPolicies.getPolicyDeltas().add(new RangerPolicyDelta(1L, RangerPolicyDelta.CHANGE_TYPE_POLICY_CREATE, 1L, policy));
+ assertTrue("policy-delta-item condition refers to user/group attribute: " + condExpr, ServiceDefUtil.addUserStoreEnricherIfNeeded(svcPolicies, RangerAdminUserStoreRetriever.class.getCanonicalName(), "60000"));
+
+ svcPolicies.getServiceDef().getContextEnrichers().clear();
+ svcPolicies.getPolicyDeltas().clear();
+ svcPolicies.getSecurityZones().put("zone1", getSecurityZoneInfo("zone1"));
+ svcPolicies.getSecurityZones().get("zone1").getPolicies().add(policy);
+ assertTrue("zone-policy-item condition refers to user/group attribute: " + condExpr, ServiceDefUtil.addUserStoreEnricherIfNeeded(svcPolicies, RangerAdminUserStoreRetriever.class.getCanonicalName(), "60000"));
+
+ svcPolicies.getServiceDef().getContextEnrichers().clear();
+ svcPolicies.getSecurityZones().get("zone1").getPolicies().clear();
+ svcPolicies.getSecurityZones().get("zone1").getPolicyDeltas().add(new RangerPolicyDelta(1L, RangerPolicyDelta.CHANGE_TYPE_POLICY_CREATE, 1L, policy));
+ assertTrue("zone-policy-delta-item condition refers to user/group attribute: " + condExpr, ServiceDefUtil.addUserStoreEnricherIfNeeded(svcPolicies, RangerAdminUserStoreRetriever.class.getCanonicalName(), "60000"));
+
+ svcPolicies.getServiceDef().getContextEnrichers().clear();
+ svcPolicies.getPolicies().clear();
+ svcPolicies.getTagPolicies().getPolicies().add(policy);
+
+ assertTrue("tag-policyItem condition refers to user/group attribute: " + condExpr, ServiceDefUtil.addUserStoreEnricherIfNeeded(svcPolicies, RangerAdminUserStoreRetriever.class.getCanonicalName(), "60000"));
+
+ i++;
+ }
+ }
+
+ @Test
+ public void testPolicyItemRowFilterExprUserGroupRef() {
+ for (String attrExpr : UGA_ATTR_EXPRESSIONS) {
+ String filterExpr = "${{" + attrExpr + "}}";
+ ServicePolicies svcPolicies = getServicePolicies();
+ RangerPolicy policy = getPolicy(svcPolicies);
+
+ policy.getRowFilterPolicyItems().get(0).setRowFilterInfo(new RangerPolicyItemRowFilterInfo("dept in (" + filterExpr + ")"));
+
+ svcPolicies.getPolicies().add(policy);
+ assertTrue("policy row-filter refers to user/group attribute: " + filterExpr, ServiceDefUtil.addUserStoreEnricherIfNeeded(svcPolicies, RangerAdminUserStoreRetriever.class.getCanonicalName(), "60000"));
+
+ svcPolicies.getServiceDef().getContextEnrichers().clear();
+ svcPolicies.getPolicies().clear();
+ svcPolicies.getPolicyDeltas().add(new RangerPolicyDelta(1L, RangerPolicyDelta.CHANGE_TYPE_POLICY_CREATE, 1L, policy));
+ assertTrue("policy-delta row-filter refers to user/group attribute: " + filterExpr, ServiceDefUtil.addUserStoreEnricherIfNeeded(svcPolicies, RangerAdminUserStoreRetriever.class.getCanonicalName(), "60000"));
+
+ svcPolicies.getServiceDef().getContextEnrichers().clear();
+ svcPolicies.getPolicyDeltas().clear();
+ svcPolicies.getSecurityZones().put("zone1", getSecurityZoneInfo("zone1"));
+ svcPolicies.getSecurityZones().get("zone1").getPolicies().add(policy);
+ assertTrue("zone-policy row-filter refers to user/group attribute: " + filterExpr, ServiceDefUtil.addUserStoreEnricherIfNeeded(svcPolicies, RangerAdminUserStoreRetriever.class.getCanonicalName(), "60000"));
+
+ svcPolicies.getServiceDef().getContextEnrichers().clear();
+ svcPolicies.getSecurityZones().get("zone1").getPolicies().clear();
+ svcPolicies.getSecurityZones().get("zone1").getPolicyDeltas().add(new RangerPolicyDelta(1L, RangerPolicyDelta.CHANGE_TYPE_POLICY_CREATE, 1L, policy));
+ assertTrue("zone-policy-delta row-filter refers to user/group attribute: " + filterExpr, ServiceDefUtil.addUserStoreEnricherIfNeeded(svcPolicies, RangerAdminUserStoreRetriever.class.getCanonicalName(), "60000"));
+ }
+ }
+
+
+ private ServicePolicies getServicePolicies() {
+ ServicePolicies ret = new ServicePolicies();
+
+ ret.setServiceName("dev_hive");
+ ret.setServiceId(1L);
+ ret.setPolicyVersion(1L);
+ ret.setServiceDef(getServiceDef("hive"));
+ ret.setPolicies(new ArrayList<>());
+ ret.setPolicyDeltas(new ArrayList<>());
+ ret.setSecurityZones(new HashMap<>());
+
+ ret.setTagPolicies(new ServicePolicies.TagPolicies());
+ ret.getTagPolicies().setServiceDef(getServiceDef("tag"));
+ ret.getTagPolicies().setPolicies(new ArrayList<>());
+
+ return ret;
+ }
+
+ private RangerServiceDef getServiceDef(String serviceType) {
+ RangerServiceDef ret = null;
+
+ try {
+ RangerServiceDef serviceDef = EmbeddedServiceDefsUtil.instance().getEmbeddedServiceDef(serviceType);
+
+ if (serviceDef != null) { // make a copy
+ ret = new RangerServiceDef();
+
+ ret.updateFrom(serviceDef);
+ }
+ } catch (Exception excp) {
+ // ignore
+ }
+
+ return ret;
+ }
+
+ private RangerPolicy getPolicy(ServicePolicies svcPolicies) {
+ RangerPolicy ret = new RangerPolicy();
+
+ ret.setConditions(new ArrayList<>());
+
+ ret.setService(svcPolicies.getServiceName());
+ ret.setServiceType(svcPolicies.getServiceDef().getName());
+ ret.getResources().put("database", new RangerPolicyResource("testdb"));
+ ret.getConditions().add(new RangerPolicyItemCondition("expr", Collections.singletonList("TAG.attr1 == 'value1'")));
+ ret.getPolicyItems().add(getPolicyItem());
+ ret.getAllowExceptions().add(getPolicyItem());
+ ret.getDenyPolicyItems().add(getPolicyItem());
+ ret.getDenyExceptions().add(getPolicyItem());
+ ret.getDataMaskPolicyItems().add(getDataMaskPolicyItem());
+ ret.getRowFilterPolicyItems().add(getRowFilterPolicyItem());
+
+ return ret;
+ }
+
+ private RangerPolicyItem getPolicyItem() {
+ RangerPolicyItem ret = new RangerPolicyItem();
+
+ ret.getUsers().add("testUser");
+ ret.getGroups().add("testGroup");
+ ret.getRoles().add("testRole");
+ ret.getConditions().add(new RangerPolicyItemCondition("expr", Collections.singletonList("TAG.attr1 == 'value1'")));
+
+ return ret;
+ }
+
+ private RangerDataMaskPolicyItem getDataMaskPolicyItem() {
+ RangerDataMaskPolicyItem ret = new RangerDataMaskPolicyItem();
+
+ ret.getUsers().add("testUser");
+ ret.getGroups().add("testGroup");
+ ret.getRoles().add("testRole");
+ ret.getConditions().add(new RangerPolicyItemCondition("expr", Collections.singletonList("TAG.attr1 == 'value1'")));
+ ret.setDataMaskInfo(new RangerPolicyItemDataMaskInfo("MASK_NULL", null, null));
+
+ return ret;
+ }
+
+ private RangerRowFilterPolicyItem getRowFilterPolicyItem() {
+ RangerRowFilterPolicyItem ret = new RangerRowFilterPolicyItem();
+
+ ret.getUsers().add("testUser");
+ ret.getGroups().add("testGroup");
+ ret.getRoles().add("testRole");
+ ret.getConditions().add(new RangerPolicyItemCondition("expr", Collections.singletonList("TAG.attr1 == 'value1'")));
+ ret.setRowFilterInfo(new RangerPolicyItemRowFilterInfo("dept in ('dept1','dept2')"));
+
+ return ret;
+ }
+
+ private SecurityZoneInfo getSecurityZoneInfo(String zoneName) {
+ SecurityZoneInfo ret = new SecurityZoneInfo();
+
+ ret.setZoneName(zoneName);
+ ret.setPolicies(new ArrayList<>());
+ ret.setPolicyDeltas(new ArrayList<>());
+
+ return ret;
+ }
+}
diff --git a/knox-agent/src/main/java/org/apache/ranger/admin/client/RangerAdminJersey2RESTClient.java b/knox-agent/src/main/java/org/apache/ranger/admin/client/RangerAdminJersey2RESTClient.java
index 624228e..c60d647 100644
--- a/knox-agent/src/main/java/org/apache/ranger/admin/client/RangerAdminJersey2RESTClient.java
+++ b/knox-agent/src/main/java/org/apache/ranger/admin/client/RangerAdminJersey2RESTClient.java
@@ -19,6 +19,7 @@
package org.apache.ranger.admin.client;
+import java.io.UnsupportedEncodingException;
import java.lang.reflect.Type;
import java.net.InetAddress;
import java.net.UnknownHostException;
@@ -73,6 +74,7 @@ public class RangerAdminJersey2RESTClient extends AbstractRangerAdminClient {
HostnameVerifier _hv;
String _sslConfigFileName = null;
String _serviceName = null;
+ String _serviceNameUrlParam = null;
String _clusterName = null;
boolean _supportsPolicyDeltas = false;
boolean _supportsTagDeltas = false;
@@ -134,6 +136,13 @@ public class RangerAdminJersey2RESTClient extends AbstractRangerAdminClient {
if(LOG.isDebugEnabled()) {
LOG.debug("<== RangerAdminJersey2RESTClient.init(" + configPropertyPrefix + "): " + _client.toString());
}
+
+ try {
+ this._serviceNameUrlParam = URLEncoderUtil.encodeURIParam(serviceName);
+ } catch (UnsupportedEncodingException e) {
+ LOG.warn("Unsupported encoding, serviceName=" + serviceName);
+ this._serviceNameUrlParam = serviceName;
+ }
}
@Override
@@ -273,6 +282,96 @@ public class RangerAdminJersey2RESTClient extends AbstractRangerAdminClient {
throw new Exception("RangerAdminjersey2RESTClient.getTagTypes() -- *** NOT IMPLEMENTED *** ");
}
+ @Override
+ public RangerUserStore getUserStoreIfUpdated(long lastKnownUserStoreVersion, long lastActivationTimeInMillis) throws Exception {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("==> RangerAdminjersey2RESTClient.getUserStoreIfUpdated(lastKnownUserStoreVersion={}, lastActivationTimeInMillis={})", lastKnownUserStoreVersion, lastActivationTimeInMillis);
+ }
+
+ final RangerUserStore ret;
+ final UserGroupInformation user = MiscUtil.getUGILoginUser();
+ final boolean isSecureMode = user != null && UserGroupInformation.isSecurityEnabled();
+ final Response response;
+
+ Map<String, String> queryParams = new HashMap<String, String>();
+
+ queryParams.put(RangerRESTUtils.REST_PARAM_LAST_KNOWN_USERSTORE_VERSION, Long.toString(lastKnownUserStoreVersion));
+ queryParams.put(RangerRESTUtils.REST_PARAM_LAST_ACTIVATION_TIME, Long.toString(lastActivationTimeInMillis));
+ queryParams.put(RangerRESTUtils.REST_PARAM_PLUGIN_ID, _pluginId);
+ queryParams.put(RangerRESTUtils.REST_PARAM_CLUSTER_NAME, _clusterName);
+ queryParams.put(RangerRESTUtils.REST_PARAM_CAPABILITIES, pluginCapabilities);
+
+ if (isSecureMode) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Checking UserStore updated as user: {}", user);
+ }
+
+ PrivilegedAction<Response> action = () -> {
+ Response resp = null;
+ String relativeURL = RangerRESTUtils.REST_URL_SERVICE_SERCURE_GET_USERSTORE + _serviceNameUrlParam;
+
+ try {
+ resp = get(queryParams, relativeURL);
+ } catch (Exception e) {
+ LOG.error("Failed to get response", e);
+ }
+
+ return resp;
+ };
+
+ response = user.doAs(action);
+ } else {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Checking UserStore updated as user: {}", user);
+ }
+
+ String relativeURL = RangerRESTUtils.REST_URL_SERVICE_GET_USERSTORE + _serviceNameUrlParam;
+
+ response = get(queryParams, relativeURL);
+ }
+
+ if (response == null || response.getStatus() == 304) { // NOT_MODIFIED
+ if (response == null) {
+ LOG.error("Error getting UserStore; Received NULL response!!. secureMode={}, user={}, serviceName={}", isSecureMode, user, _serviceName);
+ } else {
+ String resp = response.hasEntity() ? response.readEntity(String.class) : null;
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("No change in UserStore. secureMode={}, user={}, response={}, serviceName={}, lastKnownUserStoreVersion={}, lastActivationTimeInMillis={}",
+ isSecureMode, user, resp, _serviceName, lastKnownUserStoreVersion, lastActivationTimeInMillis);
+ }
+ }
+
+ ret = null;
+ } else if (response.getStatus() == 200) { // OK
+ ret = response.readEntity(RangerUserStore.class);
+ } else if (response.getStatus() == 404) { // NOT_FOUND
+ ret = null;
+
+ LOG.error("Error getting UserStore; service not found. secureMode={}, user={}, response={}, serviceName={}, lastKnownUserStoreVersion={}, lastActivationTimeInMillis={}",
+ isSecureMode, user, response.getStatus(), _serviceName, lastKnownUserStoreVersion, lastActivationTimeInMillis);
+
+ String exceptionMsg = response.hasEntity() ? response.readEntity(String.class) : null;
+
+ RangerServiceNotFoundException.throwExceptionIfServiceNotFound(_serviceName, exceptionMsg);
+
+ LOG.warn("Received 404 error code with body:[{}], Ignoring", exceptionMsg);
+ } else {
+ String resp = response.hasEntity() ? response.readEntity(String.class) : null;
+
+ LOG.warn("Error getting UserStore. secureMode={}, user={}, response={}, serviceName={}, lastKnownUserStoreVersion={}, lastActivationTimeInMillis={}",
+ isSecureMode, user, resp, _serviceName, lastKnownUserStoreVersion, lastActivationTimeInMillis);
+
+ ret = null;
+ }
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("<== RangerAdminjersey2RESTClient.getUserStoreIfUpdated(lastKnownUserStoreVersion={}, lastActivationTimeInMillis={}): ret={}", lastKnownUserStoreVersion, lastActivationTimeInMillis, ret);
+ }
+
+ return ret;
+ }
+
// We get date from the policy manager as unix long! This deserializer exists to deal with it. Remove this class once we start send date/time per RFC 3339
public static class GsonUnixDateDeserializer implements JsonDeserializer<Date> {
diff --git a/security-admin/src/main/java/org/apache/ranger/rest/XUserREST.java b/security-admin/src/main/java/org/apache/ranger/rest/XUserREST.java
index 4b9085d..6fa50ac 100644
--- a/security-admin/src/main/java/org/apache/ranger/rest/XUserREST.java
+++ b/security-admin/src/main/java/org/apache/ranger/rest/XUserREST.java
@@ -27,6 +27,7 @@ import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.DefaultValue;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
@@ -34,9 +35,9 @@ import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
-import javax.ws.rs.core.Context;
import javax.ws.rs.QueryParam;
-import javax.ws.rs.DefaultValue;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Context;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
@@ -1273,6 +1274,84 @@ public class XUserREST {
}
}
+ @GET
+ @Path("/download/{serviceName}")
+ @Produces({ "application/xml", "application/json" })
+ public RangerUserStore getRangerUserStoreIfUpdated(@PathParam("serviceName") String serviceName,
+ @QueryParam("lastKnownUserStoreVersion") Long lastKnownUserStoreVersion,
+ @DefaultValue("0") @QueryParam("lastActivationTime") Long lastActivationTime,
+ @QueryParam("pluginId") String pluginId,
+ @DefaultValue("") @QueryParam("clusterName") String clusterName,
+ @DefaultValue("") @QueryParam(RangerRESTUtils.REST_PARAM_CAPABILITIES) String pluginCapabilities,
+ @Context HttpServletRequest request) throws Exception {
+ if (logger.isDebugEnabled()) {
+ logger.debug("==> XUserREST.getRangerUserStoreIfUpdated(serviceName={}, lastKnownUserStoreVersion={}, lastActivationTime={})", serviceName, lastKnownUserStoreVersion, lastActivationTime);
+ }
+
+ RangerUserStore ret = null;
+ boolean isValid = false;
+ int httpCode = HttpServletResponse.SC_OK;
+ String logMsg = null;
+
+ try {
+ bizUtil.failUnauthenticatedIfNotAllowed();
+
+ isValid = serviceUtil.isValidService(serviceName, request);
+ } catch (WebApplicationException webException) {
+ httpCode = webException.getResponse().getStatus();
+ logMsg = webException.getResponse().getEntity().toString();
+ } catch (Exception e) {
+ httpCode = HttpServletResponse.SC_BAD_REQUEST;
+ logMsg = e.getMessage();
+ }
+
+ Long downloadedVersion = null;
+
+ if (isValid) {
+ try {
+ XXService xService = rangerDaoManager.getXXService().findByName(serviceName);
+
+ if (xService != null) {
+ if (lastKnownUserStoreVersion == null) {
+ lastKnownUserStoreVersion = Long.valueOf(-1);
+ }
+
+ RangerUserStore rangerUserStore = xUserMgr.getRangerUserStore(lastKnownUserStoreVersion);
+
+ if (rangerUserStore == null) {
+ downloadedVersion = lastKnownUserStoreVersion;
+ httpCode = HttpServletResponse.SC_NOT_MODIFIED;
+ logMsg = "No change since last update";
+ } else {
+ downloadedVersion = rangerUserStore.getUserStoreVersion();
+ ret = rangerUserStore;
+ httpCode = HttpServletResponse.SC_OK;
+ logMsg = "Returning RangerUserStore version " + downloadedVersion;
+ }
+ }
+ } catch (Throwable excp) {
+ logger.error("getRangerUserStoreIfUpdated(serviceName={}, lastKnownUserStoreVersion={}, lastActivationTime={}) failed", serviceName, lastKnownUserStoreVersion, lastActivationTime, excp);
+
+ httpCode = HttpServletResponse.SC_BAD_REQUEST;
+ logMsg = excp.getMessage();
+ }
+ }
+
+ assetMgr.createPluginInfo(serviceName, pluginId, request, RangerPluginInfo.ENTITY_TYPE_USERSTORE, downloadedVersion, lastKnownUserStoreVersion, lastActivationTime, httpCode, clusterName, pluginCapabilities);
+
+ if (httpCode != HttpServletResponse.SC_OK) {
+ boolean logError = httpCode != HttpServletResponse.SC_NOT_MODIFIED;
+
+ throw restErrorUtil.createRESTException(httpCode, logMsg, logError);
+ }
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("<== XUserREST.getRangerUserStoreIfUpdated(serviceName={}, lastKnownUserStoreVersion={}, lastActivationTime={}): {}", serviceName, lastKnownUserStoreVersion, lastActivationTime, ret);
+ }
+
+ return ret;
+ }
+
@GET
@Path("/secure/download/{serviceName}")
@Produces({ "application/xml", "application/json" })
diff --git a/security-admin/src/main/resources/conf.dist/security-applicationContext.xml b/security-admin/src/main/resources/conf.dist/security-applicationContext.xml
index 0e28a97..256c2bf 100644
--- a/security-admin/src/main/resources/conf.dist/security-applicationContext.xml
+++ b/security-admin/src/main/resources/conf.dist/security-applicationContext.xml
@@ -45,6 +45,7 @@ http://www.springframework.org/schema/security/spring-security-oauth2-2.0.xsd">
<security:http pattern="/service/plugins/services/revoke/*" security="none"/>
<security:http pattern="/service/tags/download/*" security="none"/>
<security:http pattern="/service/roles/download/*" security="none"/>
+ <security:http pattern="/service/xusers/download/*" security="none"/>
<security:http pattern="/service/metrics/status" security="none" />
<security:http disable-url-rewriting="true" use-expressions="true" create-session="always" entry-point-ref="authenticationProcessingFilterEntryPoint">
<csrf disabled="true"/>