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);
         }
 

Reply via email to