This is an automated email from the ASF dual-hosted git repository.
madhan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ranger.git
The following commit(s) were added to refs/heads/master by this push:
new 84cb3c465 RANGER-4391: updated Ranger plugin to support using
user-groups from Ranger admin
84cb3c465 is described below
commit 84cb3c465c5c6dc71e369a9ccdc1594059b626ae
Author: Madhan Neethiraj <[email protected]>
AuthorDate: Thu Aug 31 18:11:59 2023 -0700
RANGER-4391: updated Ranger plugin to support using user-groups from Ranger
admin
---
.../hadoop/config/RangerPluginConfig.java | 29 +++++++
.../ranger/plugin/service/RangerAuthContext.java | 27 +++++-
.../ranger/plugin/service/RangerBasePlugin.java | 13 ++-
.../service/RangerDefaultRequestProcessor.java | 97 ++++++++++++++++++++--
.../ranger/plugin/util/RangerUserStoreUtil.java | 82 +++++++++++++++++-
.../apache/ranger/plugin/util/ServiceDefUtil.java | 2 +
6 files changed, 231 insertions(+), 19 deletions(-)
diff --git
a/agents-common/src/main/java/org/apache/ranger/authorization/hadoop/config/RangerPluginConfig.java
b/agents-common/src/main/java/org/apache/ranger/authorization/hadoop/config/RangerPluginConfig.java
index ad1ce0986..df6307eb2 100644
---
a/agents-common/src/main/java/org/apache/ranger/authorization/hadoop/config/RangerPluginConfig.java
+++
b/agents-common/src/main/java/org/apache/ranger/authorization/hadoop/config/RangerPluginConfig.java
@@ -48,6 +48,10 @@ public class RangerPluginConfig extends RangerConfiguration {
private final boolean useForwardedIPAddress;
private final String[] trustedProxyAddresses;
private final String propertyPrefix;
+ private final boolean useRangerGroups;
+ private final boolean useOnlyRangerGroups;
+ private final boolean convertEmailToUsername;
+ private final boolean enableImplicitUserStoreEnricher;
private boolean isFallbackSupported;
private Set<String> auditExcludedUsers =
Collections.emptySet();
private Set<String> auditExcludedGroups =
Collections.emptySet();
@@ -116,6 +120,11 @@ public class RangerPluginConfig extends
RangerConfiguration {
this.policyEngineOptions = policyEngineOptions;
+ useRangerGroups = this.getBoolean(propertyPrefix +
".use.rangerGroups", false);
+ useOnlyRangerGroups = this.getBoolean(propertyPrefix +
".use.only.rangerGroups", false);
+ convertEmailToUsername = this.getBoolean(propertyPrefix +
".convert.emailToUser", false);
+ enableImplicitUserStoreEnricher = useRangerGroups ||
convertEmailToUsername || this.getBoolean(propertyPrefix +
".enable.implicit.userstore.enricher", false);
+
LOG.info("" + policyEngineOptions);
}
@@ -135,6 +144,10 @@ public class RangerPluginConfig extends
RangerConfiguration {
this.policyEngineOptions = sourcePluginConfig.getPolicyEngineOptions();
+ this.useRangerGroups =
sourcePluginConfig.useRangerGroups;
+ this.useOnlyRangerGroups =
sourcePluginConfig.useOnlyRangerGroups;
+ this.convertEmailToUsername =
sourcePluginConfig.convertEmailToUsername;
+ this.enableImplicitUserStoreEnricher =
sourcePluginConfig.enableImplicitUserStoreEnricher;
}
public String getServiceType() {
@@ -169,6 +182,22 @@ public class RangerPluginConfig extends
RangerConfiguration {
return propertyPrefix;
}
+ public boolean isUseRangerGroups() {
+ return useRangerGroups;
+ }
+
+ public boolean isUseOnlyRangerGroups() {
+ return useOnlyRangerGroups;
+ }
+
+ public boolean isConvertEmailToUsername() {
+ return convertEmailToUsername;
+ }
+
+ public boolean isEnableImplicitUserStoreEnricher() {
+ return enableImplicitUserStoreEnricher;
+ }
+
public boolean getIsFallbackSupported() {
return isFallbackSupported;
}
diff --git
a/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerAuthContext.java
b/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerAuthContext.java
index 78bd4232e..56e4d782d 100644
---
a/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerAuthContext.java
+++
b/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerAuthContext.java
@@ -26,6 +26,8 @@ import
org.apache.ranger.plugin.contextenricher.RangerContextEnricher;
import org.apache.ranger.plugin.policyengine.RangerPolicyEngine;
import org.apache.ranger.plugin.util.RangerRoles;
import org.apache.ranger.plugin.util.RangerRolesUtil;
+import org.apache.ranger.plugin.util.RangerUserStore;
+import org.apache.ranger.plugin.util.RangerUserStoreUtil;
import java.util.HashSet;
import java.util.Map;
@@ -35,12 +37,17 @@ import java.util.concurrent.ConcurrentHashMap;
public class RangerAuthContext {
private final Map<RangerContextEnricher, Object> requestContextEnrichers;
private RangerRolesUtil rolesUtil;
-
+ private RangerUserStoreUtil userStoreUtil;
public RangerAuthContext(Map<RangerContextEnricher, Object>
requestContextEnrichers, RangerRoles roles) {
+ this(requestContextEnrichers, roles, null);
+ }
+
+ public RangerAuthContext(Map<RangerContextEnricher, Object>
requestContextEnrichers, RangerRoles roles, RangerUserStore userStore) {
this.requestContextEnrichers = requestContextEnrichers != null ?
requestContextEnrichers : new ConcurrentHashMap<>();
setRoles(roles);
+ setUserStore(userStore);
}
public Map<RangerContextEnricher, Object> getRequestContextEnrichers() {
@@ -51,6 +58,10 @@ public class RangerAuthContext {
// concurrentHashMap does not allow null to be inserted into it, so
insert a dummy which is checked
// when enrich() is called
requestContextEnrichers.put(enricher, database != null ? database :
enricher);
+
+ if (database instanceof RangerUserStore) {
+ setUserStore((RangerUserStore) database);
+ }
}
public void cleanupRequestContextEnricher(RangerContextEnricher enricher) {
@@ -58,7 +69,7 @@ public class RangerAuthContext {
}
public void setRoles(RangerRoles roles) {
- this.rolesUtil = roles != null ? new RangerRolesUtil(roles) : new
RangerRolesUtil(null);
+ this.rolesUtil = new RangerRolesUtil(roles);
}
public Set<String> getRolesForUserAndGroups(String user, Set<String>
groups) {
@@ -101,4 +112,16 @@ public class RangerAuthContext {
public RangerRolesUtil getRangerRolesUtil() {
return this.rolesUtil;
}
+
+ public long getUserStoreVersion() {
+ return this.userStoreUtil.getUserStoreVersion();
+ }
+
+ public RangerUserStoreUtil getUserStoreUtil() {
+ return this.userStoreUtil;
+ }
+
+ public void setUserStore(RangerUserStore userStore) {
+ this.userStoreUtil = new RangerUserStoreUtil(userStore);
+ }
}
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 9249b3295..f1eb08e4e 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
@@ -70,7 +70,6 @@ public class RangerBasePlugin {
private RangerAccessResultProcessor resultProcessor;
private RangerRoles roles;
private final List<RangerChainedPlugin> chainedPlugins;
- private final boolean
enableImplicitUserStoreEnricher;
private final boolean dedupStrings;
private boolean
isUserStoreEnricherAddedImplcitly = false;
@@ -101,9 +100,7 @@ public class RangerBasePlugin {
RangerRequestScriptEvaluator.init(pluginConfig);
- this.enableImplicitUserStoreEnricher =
pluginConfig.getBoolean(pluginConfig.getPropertyPrefix() +
".enable.implicit.userstore.enricher", false);
- this.dedupStrings =
pluginConfig.getBoolean(pluginConfig.getPropertyPrefix() + ".dedup.strings",
true);
-
+ this.dedupStrings =
pluginConfig.getBoolean(pluginConfig.getPropertyPrefix() + ".dedup.strings",
true);
this.chainedPlugins = initChainedPlugins();
}
@@ -283,13 +280,15 @@ 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));
+ if (pluginConfig.isEnableImplicitUserStoreEnricher() &&
policies != null && !ServiceDefUtil.isUserStoreEnricherPresent(policies)) {
+ String retrieverClassName =
pluginConfig.get(RangerUserStoreEnricher.USERSTORE_RETRIEVER_CLASSNAME_OPTION,
RangerAdminUserStoreRetriever.class.getCanonicalName());
+ String retrieverPollIntMs =
pluginConfig.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 if (pluginConfig.isUseRangerGroups() ||
pluginConfig.isConvertEmailToUsername()) {
+ isUserStoreEnricherAddedImplcitly =
ServiceDefUtil.addUserStoreEnricher(policies, retrieverClassName,
retrieverPollIntMs);
} else {
isUserStoreEnricherAddedImplcitly =
ServiceDefUtil.addUserStoreEnricherIfNeeded(policies, retrieverClassName,
retrieverPollIntMs);
}
diff --git
a/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerDefaultRequestProcessor.java
b/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerDefaultRequestProcessor.java
index fa06ef634..6fa75d602 100644
---
a/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerDefaultRequestProcessor.java
+++
b/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerDefaultRequestProcessor.java
@@ -21,6 +21,7 @@ package org.apache.ranger.plugin.service;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
+import org.apache.ranger.authorization.hadoop.config.RangerPluginConfig;
import org.apache.ranger.plugin.contextenricher.RangerContextEnricher;
import org.apache.ranger.plugin.policyengine.PolicyEngine;
import org.apache.ranger.plugin.policyengine.RangerAccessRequest;
@@ -28,11 +29,15 @@ import
org.apache.ranger.plugin.policyengine.RangerAccessRequestImpl;
import org.apache.ranger.plugin.policyengine.RangerAccessRequestProcessor;
import org.apache.ranger.plugin.policyengine.RangerAccessResource;
import org.apache.ranger.plugin.policyengine.RangerMutableResource;
+import org.apache.ranger.plugin.policyengine.RangerPluginContext;
import org.apache.ranger.plugin.util.RangerAccessRequestUtil;
import org.apache.ranger.plugin.util.RangerPerfTracer;
+import org.apache.ranger.plugin.util.RangerUserStoreUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -42,9 +47,25 @@ public class RangerDefaultRequestProcessor implements
RangerAccessRequestProcess
private static final Logger LOG =
LoggerFactory.getLogger(RangerDefaultRequestProcessor.class);
protected final PolicyEngine policyEngine;
+ private final boolean useRangerGroups;
+ private final boolean useOnlyRangerGroups;
+ private final boolean convertEmailToUser;
public RangerDefaultRequestProcessor(PolicyEngine policyEngine) {
this.policyEngine = policyEngine;
+
+ RangerPluginContext pluginContext = policyEngine.getPluginContext();
+ RangerPluginConfig pluginConfig = pluginContext != null ?
pluginContext.getConfig() : null;
+
+ if (pluginConfig != null) {
+ useRangerGroups = pluginConfig.isUseRangerGroups();
+ useOnlyRangerGroups = pluginConfig.isUseOnlyRangerGroups();
+ convertEmailToUser = pluginConfig.isConvertEmailToUsername();
+ } else {
+ useRangerGroups = false;
+ useOnlyRangerGroups = false;
+ convertEmailToUser = false;
+ }
}
@Override
@@ -63,7 +84,8 @@ public class RangerDefaultRequestProcessor implements
RangerAccessRequestProcess
setResourceServiceDef(request);
- RangerAccessRequestImpl reqImpl = null;
+ RangerPluginContext pluginContext =
policyEngine.getPluginContext();
+ RangerAccessRequestImpl reqImpl = null;
if (request instanceof RangerAccessRequestImpl) {
reqImpl = (RangerAccessRequestImpl) request;
@@ -72,14 +94,18 @@ public class RangerDefaultRequestProcessor implements
RangerAccessRequestProcess
reqImpl.extractAndSetClientIPAddress(policyEngine.getUseForwardedIPAddress(),
policyEngine.getTrustedProxyAddresses());
}
- if(policyEngine.getPluginContext() != null) {
+ if (pluginContext != null) {
if (reqImpl.getClusterName() == null) {
-
reqImpl.setClusterName(policyEngine.getPluginContext().getClusterName());
+ reqImpl.setClusterName(pluginContext.getClusterName());
}
if (reqImpl.getClusterType() == null) {
-
reqImpl.setClusterType(policyEngine.getPluginContext().getClusterType());
+ reqImpl.setClusterType(pluginContext.getClusterType());
}
+
+ convertEmailToUsername(reqImpl);
+
+ updateUserGroups(reqImpl);
}
}
@@ -92,8 +118,8 @@ public class RangerDefaultRequestProcessor implements
RangerAccessRequestProcess
}
Set<String> roles = request.getUserRoles();
- if (CollectionUtils.isEmpty(roles)) {
- roles =
policyEngine.getPluginContext().getAuthContext().getRolesForUserAndGroups(request.getUser(),
request.getUserGroups());
+ if (pluginContext != null && CollectionUtils.isEmpty(roles)) {
+ roles =
pluginContext.getAuthContext().getRolesForUserAndGroups(request.getUser(),
request.getUserGroups());
if (reqImpl != null && roles != null && !roles.isEmpty()) {
reqImpl.setUserRoles(roles);
@@ -111,7 +137,6 @@ public class RangerDefaultRequestProcessor implements
RangerAccessRequestProcess
if (LOG.isDebugEnabled()) {
LOG.debug("<== preProcess(" + request + ")");
}
-
}
@Override
@@ -148,4 +173,62 @@ public class RangerDefaultRequestProcessor implements
RangerAccessRequestProcess
}
}
+ private void convertEmailToUsername(RangerAccessRequestImpl reqImpl) {
+ if (convertEmailToUser) {
+ RangerPluginContext pluginContext =
policyEngine.getPluginContext();
+ RangerUserStoreUtil userStoreUtil = pluginContext != null ?
pluginContext.getAuthContext().getUserStoreUtil() : null;
+
+ if (userStoreUtil != null) {
+ String userName = reqImpl.getUser();
+ int idxSep = StringUtils.indexOf(userName, '@');
+
+ if (idxSep > 0) {
+ String userNameFromEmail =
userStoreUtil.getUserNameFromEmail(userName);
+
+ if (StringUtils.isBlank(userNameFromEmail)) {
+ userNameFromEmail = userName.substring(0, idxSep);
+ }
+
+ LOG.debug("replacing req.user '{}' with '{}'", userName,
userNameFromEmail);
+
+ reqImpl.setUser(userNameFromEmail);
+ }
+ }
+ }
+ }
+
+ private void updateUserGroups(RangerAccessRequestImpl reqImpl) {
+ if (useRangerGroups) {
+ RangerPluginContext pluginContext =
policyEngine.getPluginContext();
+ RangerUserStoreUtil userStoreUtil = pluginContext != null ?
pluginContext.getAuthContext().getUserStoreUtil() : null;
+ String userName = reqImpl.getUser();
+
+ if (userStoreUtil != null && userName != null) {
+ Set<String> userGroups = reqImpl.getUserGroups();
+ Set<String> rangerUserGroups =
userStoreUtil.getUserGroups(userName);
+
+ if (rangerUserGroups == null) {
+ rangerUserGroups = Collections.emptySet();
+ }
+
+ if (useOnlyRangerGroups) {
+ userGroups = new HashSet<>(rangerUserGroups);
+
+ LOG.debug("replacing req.userGroups '{}' with '{}'",
reqImpl.getUserGroups(), userGroups);
+
+ reqImpl.setUserGroups(userGroups);
+ } else {
+ if (!rangerUserGroups.isEmpty()) {
+ userGroups = userGroups != null ? new
HashSet<>(userGroups) : new HashSet<>();
+
+ userGroups.addAll(rangerUserGroups);
+
+ LOG.debug("replacing req.userGroups '{}' with '{}'",
reqImpl.getUserGroups(), userGroups);
+
+ reqImpl.setUserGroups(userGroups);
+ }
+ }
+ }
+ }
+ }
}
diff --git
a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerUserStoreUtil.java
b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerUserStoreUtil.java
index f66eb1fb0..70f2c6629 100644
---
a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerUserStoreUtil.java
+++
b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerUserStoreUtil.java
@@ -22,11 +22,89 @@ package org.apache.ranger.plugin.util;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.Map;
+import java.util.Set;
public class RangerUserStoreUtil {
public static final String CLOUD_IDENTITY_NAME = "cloud_id";
+ private final RangerUserStore userStore;
+ private final long userStoreVersion;
+ private final Map<String, Set<String>> userGroups;
+ private final Map<String, Map<String, String>> userAttributes;
+ private final Map<String, Map<String, String>> groupAttributes;
+
+ private volatile Map<String, String> userEmailToName = null;
+
+ public RangerUserStoreUtil(RangerUserStore userStore) {
+ this.userStore = userStore;
+
+ if (userStore != null) {
+ this.userStoreVersion = userStore.getUserStoreVersion() != null ?
userStore.getUserStoreVersion() : -1;
+ this.userGroups = userStore.getUserGroupMapping() != null ?
userStore.getUserGroupMapping() : Collections.emptyMap();
+ this.userAttributes = userStore.getUserAttrMapping() != null ?
userStore.getUserAttrMapping() : Collections.emptyMap();
+ this.groupAttributes = userStore.getGroupAttrMapping() != null ?
userStore.getGroupAttrMapping() : Collections.emptyMap();
+ } else {
+ this.userStoreVersion = -1;
+ this.userGroups = Collections.emptyMap();
+ this.userAttributes = Collections.emptyMap();
+ this.groupAttributes = Collections.emptyMap();
+ this.userEmailToName = Collections.emptyMap();
+ }
+ }
+
+ public RangerUserStore getUserStore() { return userStore; }
+
+ public long getUserStoreVersion() { return userStoreVersion; }
+
+ public Set<String> getUserGroups(String userName) { return
userGroups.get(userName); }
+
+ public Map<String, String> getUserAttributes(String userName) { return
userAttributes.get(userName); }
+
+ public Map<String, String> getGroupAttributes(String groupName) { return
groupAttributes.get(groupName); }
+
+ public String getUserNameFromEmail(String emailAddress) {
+ Map<String, String> userEmailToName = this.userEmailToName;
+
+ if (userEmailToName == null) {
+ synchronized (this) {
+ userEmailToName = this.userEmailToName;
+
+ if (userEmailToName == null) {
+ this.userEmailToName = buildUserEmailToNameMap();
+
+ userEmailToName = this.userEmailToName;
+ }
+ }
+ }
+
+ return userEmailToName != null ? userEmailToName.get(emailAddress) :
null;
+ }
+
+ private Map<String, String> buildUserEmailToNameMap() {
+ final Map<String, String> ret;
+
+ if (!userAttributes.isEmpty()) {
+ ret = new HashMap<>();
+
+ for (Map.Entry<String, Map<String, String>> entry :
userAttributes.entrySet()) {
+ String userName = entry.getKey();
+ Map<String, String> userAttrs = entry.getValue();
+ String emailAddr = userAttrs != null ?
userAttrs.get(RangerCommonConstants.SCRIPT_FIELD__EMAIL_ADDRESS) : null;
+
+ if (StringUtils.isNotBlank(emailAddr)) {
+ ret.put(emailAddr, userName);
+ }
+ }
+ } else {
+ ret = Collections.emptyMap();
+ }
+
+ return ret;
+ }
+
public static String getPrintableOptions(Map<String, String>
otherAttributes) {
if (MapUtils.isEmpty(otherAttributes)) return "{}";
StringBuilder ret = new StringBuilder();
@@ -51,9 +129,7 @@ public class RangerUserStoreUtil {
}
public String getCloudId(Map<String, Map<String, String>> attrMap, String
name) {
- String cloudId = null;
- cloudId = getAttrVal(attrMap, name, CLOUD_IDENTITY_NAME);
- return cloudId;
+ return getAttrVal(attrMap, name, CLOUD_IDENTITY_NAME);
}
}
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 01c4a8283..53eb0f81e 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
@@ -535,6 +535,8 @@ public class ServiceDefUtil {
serviceDef.setContextEnrichers(enricherDefs);
+ ret = true;
+
LOG.info("addUserStoreEnricher(serviceName={}): added
userStoreEnricher {}", policies.getServiceName(), userStoreEnricher);
}