This is an automated email from the ASF dual-hosted git repository.

spolavarapu 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 dc63813  RANGER-2697: Usersync and Ranger admin changes to support 
retriving additional user/group attributes from LDAP/AD
dc63813 is described below

commit dc6381372bc49bfdfe8586f24102b7d3c376ca58
Author: Sailaja Polavarapu <[email protected]>
AuthorDate: Thu Feb 13 09:21:35 2020 -0800

    RANGER-2697: Usersync and Ranger admin changes to support retriving 
additional user/group attributes from LDAP/AD
---
 .../org/apache/ranger/plugin/model/GroupInfo.java  |  87 ++++++++++
 .../ranger/plugin/model/RangerPluginInfo.java      |  56 ++++++-
 .../org/apache/ranger/plugin/model/UserInfo.java   |  95 +++++++++++
 .../apache/ranger/plugin/util/RangerUserStore.java | 186 +++++++++++++++++++++
 .../ranger/plugin/util/RangerUserStoreUtil.java    |  60 +++++++
 .../main/java/org/apache/ranger/biz/AssetMgr.java  |  49 +++++-
 .../java/org/apache/ranger/biz/RoleDBStore.java    |   2 +-
 .../java/org/apache/ranger/biz/ServiceDBStore.java |   2 +-
 .../main/java/org/apache/ranger/biz/UserMgr.java   |   3 +
 .../main/java/org/apache/ranger/biz/XUserMgr.java  |  59 +++++--
 .../apache/ranger/common/RangerUserStoreCache.java | 122 ++++++++++++++
 .../org/apache/ranger/db/XXGlobalStateDao.java     |  40 ++---
 .../java/org/apache/ranger/rest/XUserREST.java     | 111 ++++++++++++
 .../apache/ranger/service/XGroupServiceBase.java   |  20 +++
 .../apache/ranger/service/XUserServiceBase.java    |  20 +++
 .../process/LdapDeltaUserGroupBuilder.java         | 127 ++++++++++++--
 .../process/LdapPolicyMgrUserGroupBuilder.java     |  70 ++++----
 .../ldapusersync/process/LdapUserGroupBuilder.java |   4 +-
 .../unixusersync/config/UserGroupSyncConfig.java   |  92 ++++++++++
 .../ranger/unixusersync/model/MUserInfo.java       |  10 +-
 .../ranger/unixusersync/model/XGroupInfo.java      |  11 +-
 .../ranger/unixusersync/model/XUserInfo.java       |  11 +-
 .../process/PolicyMgrUserGroupBuilder.java         |  14 +-
 .../apache/ranger/usergroupsync/UserGroupSink.java |   7 +-
 .../LdapPolicyMgrUserGroupBuilderTest.java         |  10 +-
 .../PolicyMgrUserGroupBuilderTest.java             |   8 +-
 26 files changed, 1172 insertions(+), 104 deletions(-)

diff --git 
a/agents-common/src/main/java/org/apache/ranger/plugin/model/GroupInfo.java 
b/agents-common/src/main/java/org/apache/ranger/plugin/model/GroupInfo.java
new file mode 100644
index 0000000..5925014
--- /dev/null
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/model/GroupInfo.java
@@ -0,0 +1,87 @@
+/*
+ * 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.model;
+
+import org.apache.ranger.plugin.util.RangerUserStoreUtil;
+import org.codehaus.jackson.annotate.JsonAutoDetect;
+import org.codehaus.jackson.annotate.JsonIgnoreProperties;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.HashMap;
+import java.util.Map;
+
+@JsonAutoDetect(fieldVisibility=JsonAutoDetect.Visibility.ANY)
+@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
+@JsonIgnoreProperties(ignoreUnknown=true)
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class GroupInfo extends RangerBaseModelObject implements 
java.io.Serializable {
+
+    private static final long serialVersionUID = 1L;
+    private String                  name;
+    private String                  description;
+    private Map<String, String>     otherAttributes;
+
+    public GroupInfo() {
+        this(null, null, null);
+    }
+
+    public GroupInfo(String name, String description, Map<String, String> 
otherAttributes) {
+        setName(name);
+        setDescription(description);
+        setOtherAttributes(otherAttributes);
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public Map<String, String> getOtherAttributes() {
+        return otherAttributes;
+    }
+
+    public void setOtherAttributes(Map<String, String> otherAttributes) {
+        this.otherAttributes = otherAttributes == null ? new HashMap<>() : 
otherAttributes;
+    }
+
+    @Override
+    public String toString() {
+        return "{name=" + name
+                + ", description=" + description
+                + ", otherAttributes=" + 
RangerUserStoreUtil.getPrintableOptions(otherAttributes)
+                + "}";
+    }
+
+}
\ No newline at end of file
diff --git 
a/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerPluginInfo.java
 
b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerPluginInfo.java
index 5552ce9..5b92566 100644
--- 
a/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerPluginInfo.java
+++ 
b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerPluginInfo.java
@@ -41,9 +41,10 @@ import java.util.Map;
 public class RangerPluginInfo implements Serializable {
        private static final long serialVersionUID = 1L;
 
-       public static final int ENTITY_TYPE_POLICIES = 0;
-       public static final int ENTITY_TYPE_TAGS     = 1;
-       public static final int ENTITY_TYPE_ROLES        = 2;
+       public static final int ENTITY_TYPE_POLICIES    = 0;
+       public static final int ENTITY_TYPE_TAGS        = 1;
+       public static final int ENTITY_TYPE_ROLES               = 2;
+       public static final int ENTITY_TYPE_USERSTORE   = 3;
 
        public static final String PLUGIN_INFO_POLICY_DOWNLOAD_TIME      = 
"policyDownloadTime";
        public static final String PLUGIN_INFO_POLICY_DOWNLOADED_VERSION = 
"policyDownloadedVersion";
@@ -59,6 +60,11 @@ public class RangerPluginInfo implements Serializable {
        public static final String PLUGIN_INFO_ROLE_ACTIVATION_TIME       = 
"roleActivationTime";
        public static final String PLUGIN_INFO_ROLE_ACTIVE_VERSION        = 
"roleActiveVersion";
 
+       public static final String PLUGIN_INFO_USERSTORE_DOWNLOAD_TIME         
= "userstoreDownloadTime";
+       public static final String PLUGIN_INFO_USERSTORE_DOWNLOADED_VERSION    
= "userstoreDownloadedVersion";
+       public static final String PLUGIN_INFO_USERSTORE_ACTIVATION_TIME       
= "userstoreActivationTime";
+       public static final String PLUGIN_INFO_USERSTORE_ACTIVE_VERSION        
= "userstoreActiveVersion";
+
        public static final String RANGER_ADMIN_LAST_POLICY_UPDATE_TIME  = 
"lastPolicyUpdateTime";
        public static final String RANGER_ADMIN_LATEST_POLICY_VERSION    = 
"latestPolicyVersion";
        public static final String RANGER_ADMIN_LAST_TAG_UPDATE_TIME     = 
"lastTagUpdateTime";
@@ -344,6 +350,50 @@ public class RangerPluginInfo implements Serializable {
        }
 
        @JsonIgnore
+       public void setUserStoreDownloadTime(Long userstoreDownloadTime) {
+               getInfo().put(PLUGIN_INFO_USERSTORE_DOWNLOAD_TIME, 
userstoreDownloadTime == null ? null : Long.toString(userstoreDownloadTime));
+       }
+
+       @JsonIgnore
+       public Long getUserStoreDownloadTime() {
+               String downloadTimeString = 
getInfo().get(PLUGIN_INFO_USERSTORE_DOWNLOAD_TIME);
+               return StringUtils.isNotBlank(downloadTimeString) ? 
Long.valueOf(downloadTimeString) : null;
+       }
+
+       @JsonIgnore
+       public void setUserStoreDownloadedVersion(Long 
userstoreDownloadedVersion) {
+               getInfo().put(PLUGIN_INFO_USERSTORE_DOWNLOADED_VERSION, 
userstoreDownloadedVersion == null ? null : 
Long.toString(userstoreDownloadedVersion));
+       }
+
+       @JsonIgnore
+       public Long getUserStoreDownloadedVersion() {
+               String downloadedVersionString = 
getInfo().get(PLUGIN_INFO_USERSTORE_DOWNLOADED_VERSION);
+               return StringUtils.isNotBlank(downloadedVersionString) ? 
Long.valueOf(downloadedVersionString) : null;
+       }
+
+       @JsonIgnore
+       public void setUserStoreActivationTime(Long userstoreActivationTime) {
+               getInfo().put(PLUGIN_INFO_USERSTORE_ACTIVATION_TIME, 
userstoreActivationTime == null ? null : 
Long.toString(userstoreActivationTime));
+       }
+
+       @JsonIgnore
+       public Long getUserStoreActivationTime() {
+               String activationTimeString = 
getInfo().get(PLUGIN_INFO_USERSTORE_ACTIVATION_TIME);
+               return StringUtils.isNotBlank(activationTimeString) ? 
Long.valueOf(activationTimeString) : null;
+       }
+
+       @JsonIgnore
+       public void setUserStoreActiveVersion(Long userstoreActiveVersion) {
+               getInfo().put(PLUGIN_INFO_USERSTORE_ACTIVE_VERSION, 
userstoreActiveVersion == null ? null : Long.toString(userstoreActiveVersion));
+       }
+
+       @JsonIgnore
+       public Long getUserStoreActiveVersion() {
+               String activeVersionString = 
getInfo().get(PLUGIN_INFO_USERSTORE_ACTIVE_VERSION);
+               return StringUtils.isNotBlank(activeVersionString) ? 
Long.valueOf(activeVersionString) : null;
+       }
+
+       @JsonIgnore
        public void setPluginCapabilities(String capabilities) {
                setCapabilities(PLUGIN_INFO_CAPABILITIES, capabilities);
        }
diff --git 
a/agents-common/src/main/java/org/apache/ranger/plugin/model/UserInfo.java 
b/agents-common/src/main/java/org/apache/ranger/plugin/model/UserInfo.java
new file mode 100644
index 0000000..3e933e8
--- /dev/null
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/model/UserInfo.java
@@ -0,0 +1,95 @@
+/*
+ * 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.model;
+
+import org.apache.ranger.plugin.util.RangerUserStoreUtil;
+import org.codehaus.jackson.annotate.JsonAutoDetect;
+import org.codehaus.jackson.annotate.JsonIgnoreProperties;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.*;
+
+@JsonAutoDetect(fieldVisibility=JsonAutoDetect.Visibility.ANY)
+@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
+@JsonIgnoreProperties(ignoreUnknown=true)
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class UserInfo extends RangerBaseModelObject implements 
java.io.Serializable {
+
+    private static final long serialVersionUID = 1L;
+    private String                  name;
+    private String                  description;
+    private Map<String, String>     otherAttributes;
+    private Set<String>             groups;
+
+    public UserInfo() {
+        this(null, null, null);
+    }
+
+    public UserInfo(String name, String description, Map<String, String> 
otherAttributes) {
+        setName(name);
+        setDescription(description);
+        setOtherAttributes(otherAttributes);
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public Map<String, String> getOtherAttributes() {
+        return otherAttributes;
+    }
+
+    public void setOtherAttributes(Map<String, String> otherAttributes) {
+        this.otherAttributes = otherAttributes == null ? new HashMap<>() : 
otherAttributes;
+    }
+
+    public Set<String> getGroups(){
+        return this.groups;
+    }
+
+    public void setGroups(Set<String> groups){
+        this.groups = groups;
+    }
+
+    @Override
+    public String toString() {
+        return "{name=" + name
+                + ", description=" + description
+                + ", otherAttributes=" + 
RangerUserStoreUtil.getPrintableOptions(otherAttributes)
+                + ", groups=" + groups
+                + "}";
+    }
+}
\ No newline at end of file
diff --git 
a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerUserStore.java
 
b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerUserStore.java
new file mode 100644
index 0000000..dfe742f
--- /dev/null
+++ 
b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerUserStore.java
@@ -0,0 +1,186 @@
+/*
+ * 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.commons.collections.CollectionUtils;
+import org.apache.commons.collections.MapUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.ranger.plugin.model.GroupInfo;
+import org.apache.ranger.plugin.model.UserInfo;
+import org.codehaus.jackson.annotate.JsonAutoDetect;
+import org.codehaus.jackson.annotate.JsonIgnoreProperties;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+@JsonAutoDetect(fieldVisibility= JsonAutoDetect.Visibility.ANY)
+@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
+@JsonIgnoreProperties(ignoreUnknown=true)
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class RangerUserStore implements Serializable {
+    private static final long serialVersionUID = 1L;
+    public static final String CLOUD_IDENTITY_NAME = "cloud_id";
+
+    private Long                             userStoreVersion;
+    private Date                             userStoreUpdateTime;
+    private Map<String, Map<String, String>> userAttrMapping;
+    private Map<String, Map<String, String>> groupAttrMapping ;
+    private Map<String, Set<String>>         userGroupMapping;
+    private Map<String, String>              userCloudIdMapping;
+    private Map<String, String>              groupCloudIdMapping;
+
+    public RangerUserStore() {this(-1L, null, null);}
+
+    public RangerUserStore(Long userStoreVersion, Set<UserInfo> users, 
Set<GroupInfo> groups ) {
+        setUserStoreVersion(userStoreVersion);
+        setUserStoreUpdateTime(new Date());
+        buildMap(users, groups);
+    }
+    public Long getUserStoreVersion() {
+        return userStoreVersion;
+    }
+
+    public void setUserStoreVersion(Long userStoreVersion) {
+        this.userStoreVersion = userStoreVersion;
+    }
+
+    public Date getUserStoreUpdateTime() {
+        return userStoreUpdateTime;
+    }
+
+    public void setUserStoreUpdateTime(Date userStoreUpdateTime) {
+        this.userStoreUpdateTime = userStoreUpdateTime;
+    }
+
+    public Map<String, Map<String, String>> getUserAttrMapping() {
+        return userAttrMapping;
+    }
+
+    public void setUserAttrMapping(Map<String, Map<String, String>> 
userAttrMapping) {
+        this.userAttrMapping = userAttrMapping;
+    }
+
+    public Map<String, Map<String, String>> getGroupAttrMapping() {
+        return groupAttrMapping;
+    }
+
+    public void setGroupAttrMapping(Map<String, Map<String, String>> 
groupAttrMapping) {
+        this.groupAttrMapping = groupAttrMapping;
+    }
+
+    public Map<String, Set<String>> getUserGroupMapping() {
+        return userGroupMapping;
+    }
+
+    public void setUserGroupMapping(Map<String, Set<String>> userGroupMapping) 
{
+        this.userGroupMapping = userGroupMapping;
+    }
+
+    public Map<String, String> getUserCloudIdMapping() {
+        return userCloudIdMapping;
+    }
+
+    public void setUserCloudIdMapping(Map<String, String> userCloudIdMapping) {
+        this.userCloudIdMapping = userCloudIdMapping;
+    }
+
+    public Map<String, String> getGroupCloudIdMapping() {
+        return groupCloudIdMapping;
+    }
+
+    public void setGroupCloudIdMapping(Map<String, String> 
groupCloudIdMapping) {
+        this.groupCloudIdMapping = groupCloudIdMapping;
+    }
+
+    @Override
+    public String toString( ) {
+        StringBuilder sb = new StringBuilder();
+
+        toString(sb);
+
+        return sb.toString();
+    }
+
+    public StringBuilder toString(StringBuilder sb) {
+        sb.append("RangerUserStore={")
+                
.append("userStoreVersion=").append(userStoreVersion).append(", ")
+                
.append("userStoreUpdateTime=").append(userStoreUpdateTime).append(", ");
+        sb.append("users={");
+        if(MapUtils.isNotEmpty(userAttrMapping)) {
+            for(String user : userAttrMapping.keySet()) {
+                sb.append(user);
+            }
+        }
+        sb.append("}, ");
+        sb.append("groups={");
+        if(MapUtils.isNotEmpty(groupAttrMapping)) {
+            for(String group : groupAttrMapping.keySet()) {
+                sb.append(group);
+            }
+        }
+        sb.append("}");
+        sb.append("}");
+
+        return sb;
+    }
+
+    private void buildMap(Set<UserInfo> users, Set<GroupInfo> groups) {
+        if (CollectionUtils.isNotEmpty(users)) {
+            userAttrMapping = new HashMap<>();
+            userCloudIdMapping = new HashMap<>();
+            userGroupMapping = new HashMap<>();
+            for (UserInfo user : users) {
+                String username = user.getName();
+                Map<String, String> userAttrs = user.getOtherAttributes();
+                if (MapUtils.isNotEmpty(userAttrs)) {
+                    userAttrMapping.put(username, userAttrs);
+                    String cloudId = userAttrs.get(CLOUD_IDENTITY_NAME);
+                    if (StringUtils.isNotEmpty(cloudId)) {
+                        userCloudIdMapping.put(cloudId, username);
+                    }
+                }
+                userGroupMapping.put(username, user.getGroups());
+            }
+        }
+        if (CollectionUtils.isNotEmpty(groups)) {
+            groupAttrMapping = new HashMap<>();
+            groupCloudIdMapping = new HashMap<>();
+            for (GroupInfo group : groups) {
+                String groupname = group.getName();
+                Map<String, String> groupAttrs = group.getOtherAttributes();
+                if (MapUtils.isNotEmpty(groupAttrs)) {
+                    groupAttrMapping.put(groupname, groupAttrs);
+                    String cloudId = groupAttrs.get(CLOUD_IDENTITY_NAME);
+                    if (StringUtils.isNotEmpty(cloudId)) {
+                        groupCloudIdMapping.put(cloudId, groupname);
+                    }
+                }
+            }
+        }
+    }
+}
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
new file mode 100644
index 0000000..f66eb1f
--- /dev/null
+++ 
b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerUserStoreUtil.java
@@ -0,0 +1,60 @@
+/*
+ * 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.commons.collections.MapUtils;
+import org.apache.commons.lang.StringUtils;
+
+import java.util.Map;
+
+public class RangerUserStoreUtil {
+    public static final String CLOUD_IDENTITY_NAME = "cloud_id";
+
+    public static String getPrintableOptions(Map<String, String> 
otherAttributes) {
+        if (MapUtils.isEmpty(otherAttributes)) return "{}";
+        StringBuilder ret = new StringBuilder();
+        ret.append("{");
+        for (Map.Entry<String, String> entry : otherAttributes.entrySet()) {
+            ret.append(entry.getKey()).append(", 
").append("[").append(entry.getValue()).append("]").append(",");
+        }
+        ret.append("}");
+        return ret.toString();
+    }
+
+    public static String getAttrVal(Map<String, Map<String, String>> attrMap, 
String name, String attrName) {
+        String ret = null;
+
+        if (StringUtils.isNotEmpty(name) && StringUtils.isNotEmpty(attrName)) {
+            Map<String, String> attrs = attrMap.get(name);
+            if (MapUtils.isNotEmpty(attrs)) {
+                ret = attrs.get(attrName);
+            }
+        }
+        return ret;
+    }
+
+    public String getCloudId(Map<String, Map<String, String>> attrMap, String 
name) {
+        String cloudId = null;
+        cloudId = getAttrVal(attrMap, name, CLOUD_IDENTITY_NAME);
+        return cloudId;
+    }
+}
+
+
diff --git a/security-admin/src/main/java/org/apache/ranger/biz/AssetMgr.java 
b/security-admin/src/main/java/org/apache/ranger/biz/AssetMgr.java
index 0f44888..17c105f 100644
--- a/security-admin/src/main/java/org/apache/ranger/biz/AssetMgr.java
+++ b/security-admin/src/main/java/org/apache/ranger/biz/AssetMgr.java
@@ -707,6 +707,12 @@ public class AssetMgr extends AssetMgrBase {
                                
pluginSvcVersionInfo.setRoleDownloadedVersion(downloadedVersion);
                                pluginSvcVersionInfo.setRoleDownloadTime(new 
Date().getTime());
                                break;
+                       case RangerPluginInfo.ENTITY_TYPE_USERSTORE:
+                               
pluginSvcVersionInfo.setUserStoreActiveVersion(lastKnownVersion);
+                               
pluginSvcVersionInfo.setUserStoreActivationTime(lastActivationTime);
+                               
pluginSvcVersionInfo.setUserStoreDownloadedVersion(downloadedVersion);
+                               
pluginSvcVersionInfo.setUserStoreDownloadTime(new Date().getTime());
+                               break;
                }
 
                createOrUpdatePluginInfo(pluginSvcVersionInfo, entityType , 
httpCode, clusterName);
@@ -735,6 +741,9 @@ public class AssetMgr extends AssetMgrBase {
                                case RangerPluginInfo.ENTITY_TYPE_ROLES:
                                        isTagVersionResetNeeded = false;
                                        break;
+                               case RangerPluginInfo.ENTITY_TYPE_USERSTORE:
+                                       isTagVersionResetNeeded = false;
+                                       break;
                                default:
                                        isTagVersionResetNeeded = false;
                                        break;
@@ -751,7 +760,8 @@ public class AssetMgr extends AssetMgrBase {
                        Runnable commitWork;
                        if ((isPolicyDownloadRequest(entityType) && 
(pluginInfo.getPolicyActiveVersion() == null || 
pluginInfo.getPolicyActiveVersion() == -1))
                                        || (isTagDownloadRequest(entityType) && 
(pluginInfo.getTagActiveVersion() == null || pluginInfo.getTagActiveVersion() 
== -1))
-                                       || (isRoleDownloadRequest(entityType) 
&& (pluginInfo.getRoleActiveVersion() == null || 
pluginInfo.getRoleActiveVersion() == -1))) {
+                                       || (isRoleDownloadRequest(entityType) 
&& (pluginInfo.getRoleActiveVersion() == null || 
pluginInfo.getRoleActiveVersion() == -1))
+                                       || 
(isUserStoreDownloadRequest(entityType) && 
(pluginInfo.getUserStoreActiveVersion() == null || 
pluginInfo.getUserStoreActiveVersion() == -1))) {
                                commitWork = new Runnable() {
                                        @Override
                                        public void run() {
@@ -804,11 +814,16 @@ public class AssetMgr extends AssetMgrBase {
                                                // This is our best guess of 
when tags may have been downloaded
                                                
pluginInfo.setTagDownloadTime(pluginInfo.getTagActivationTime());
                                        }
-                               } else {
+                               } else if (isRoleDownloadRequest(entityType)) {
                                        if (pluginInfo.getRoleDownloadTime() != 
null && 
pluginInfo.getRoleDownloadedVersion().equals(pluginInfo.getRoleActiveVersion()))
 {
                                                // This is our best guess of 
when role may have been downloaded
                                                
pluginInfo.setRoleDownloadTime(pluginInfo.getRoleActivationTime());
                                        }
+                               } else {
+                                       if 
(pluginInfo.getUserStoreDownloadTime() != null && 
pluginInfo.getUserStoreDownloadedVersion().equals(pluginInfo.getUserStoreActiveVersion()))
 {
+                                               // This is our best guess of 
when users and groups may have been downloaded
+                                               
pluginInfo.setUserStoreDownloadTime(pluginInfo.getUserStoreActivationTime());
+                                       }
                                }
 
                                
pluginInfo.setAdminCapabilities(adminCapabilities);
@@ -891,7 +906,7 @@ public class AssetMgr extends AssetMgrBase {
                                                
dbObj.setTagActivationTime(lastTagActivationTime);
                                                needsUpdating = true;
                                        }
-                               } else {
+                               } else if (isRoleDownloadRequest(entityType)){
                                        if (dbObj.getRoleDownloadedVersion() == 
null || 
!dbObj.getRoleDownloadedVersion().equals(pluginInfo.getRoleDownloadedVersion()))
 {
                                                
dbObj.setRoleDownloadedVersion(pluginInfo.getRoleDownloadedVersion());
                                                
dbObj.setRoleDownloadTime(pluginInfo.getRoleDownloadTime());
@@ -915,6 +930,30 @@ public class AssetMgr extends AssetMgrBase {
                                                
dbObj.setRoleActivationTime(lastRoleActivationTime);
                                                needsUpdating = true;
                                        }
+                               } else {
+                                       if 
(dbObj.getUserStoreDownloadedVersion() == null || 
!dbObj.getUserStoreDownloadedVersion().equals(pluginInfo.getUserStoreDownloadedVersion()))
 {
+                                               
dbObj.setUserStoreDownloadedVersion(pluginInfo.getUserStoreDownloadedVersion());
+                                               
dbObj.setUserStoreDownloadTime(pluginInfo.getUserStoreDownloadTime());
+                                               needsUpdating = true;
+                                       }
+
+                                       Long lastKnownUserStoreVersion = 
pluginInfo.getUserStoreActiveVersion();
+                                       Long lastUserStoreActivationTime = 
pluginInfo.getUserStoreActivationTime();
+
+                                       if (lastKnownUserStoreVersion != null 
&& lastKnownUserStoreVersion == -1) {
+                                               
dbObj.setUserStoreDownloadTime(pluginInfo.getUserStoreDownloadTime());
+                                               needsUpdating = true;
+                                       }
+
+                                       if (lastKnownUserStoreVersion != null 
&& lastKnownUserStoreVersion > 0 && (dbObj.getUserStoreActiveVersion() == null 
|| !dbObj.getUserStoreActiveVersion().equals(lastKnownUserStoreVersion))) {
+                                               
dbObj.setUserStoreActiveVersion(lastKnownUserStoreVersion);
+                                               needsUpdating = true;
+                                       }
+
+                                       if (lastUserStoreActivationTime != null 
&& lastUserStoreActivationTime > 0 && (dbObj.getUserStoreActivationTime() == 
null || 
!dbObj.getUserStoreActivationTime().equals(lastUserStoreActivationTime))) {
+                                               
dbObj.setUserStoreActivationTime(lastUserStoreActivationTime);
+                                               needsUpdating = true;
+                                       }
                                }
 
                                if (isTagVersionResetNeeded) {
@@ -1256,4 +1295,8 @@ public class AssetMgr extends AssetMgrBase {
        private boolean isRoleDownloadRequest(int entityType) {
                return entityType == RangerPluginInfo.ENTITY_TYPE_ROLES;
        }
+
+       private boolean isUserStoreDownloadRequest(int entityType) {
+               return entityType == RangerPluginInfo.ENTITY_TYPE_USERSTORE;
+       }
 }
diff --git 
a/security-admin/src/main/java/org/apache/ranger/biz/RoleDBStore.java 
b/security-admin/src/main/java/org/apache/ranger/biz/RoleDBStore.java
index 04596dc..5be8d9d 100644
--- a/security-admin/src/main/java/org/apache/ranger/biz/RoleDBStore.java
+++ b/security-admin/src/main/java/org/apache/ranger/biz/RoleDBStore.java
@@ -293,7 +293,7 @@ public class RoleDBStore implements RoleStore {
             XXServiceVersionInfo xxServiceVersionInfo = 
daoMgr.getXXServiceVersionInfo().findByServiceName(serviceName);
             ret = (xxServiceVersionInfo != null) ? 
xxServiceVersionInfo.getRoleVersion() : null;
         } else {
-            ret = 
daoMgr.getXXGlobalState().getRoleVersion(RANGER_ROLE_GLOBAL_STATE_NAME);
+            ret = 
daoMgr.getXXGlobalState().getAppDataVersion(RANGER_ROLE_GLOBAL_STATE_NAME);
         }
 
         return ret;
diff --git 
a/security-admin/src/main/java/org/apache/ranger/biz/ServiceDBStore.java 
b/security-admin/src/main/java/org/apache/ranger/biz/ServiceDBStore.java
index ccda6ab..47250f3 100644
--- a/security-admin/src/main/java/org/apache/ranger/biz/ServiceDBStore.java
+++ b/security-admin/src/main/java/org/apache/ranger/biz/ServiceDBStore.java
@@ -3487,7 +3487,7 @@ public class ServiceDBStore extends AbstractServiceStore {
                                // get the LatestRoleVersion from the 
GlobalTable and update ServiceInfo for a service
                                XXGlobalStateDao xxGlobalStateDao = 
daoMgr.getXXGlobalState();
                                if (xxGlobalStateDao != null) {
-                                       Long roleVersion = 
xxGlobalStateDao.getRoleVersion("RangerRole");
+                                       Long roleVersion = 
xxGlobalStateDao.getAppDataVersion("RangerRole");
                                        if (roleVersion != null) {
                                                
serviceVersionInfoDbObj.setRoleVersion(roleVersion);
                                                
serviceVersionInfoDbObj.setRoleUpdateTime(now);
diff --git a/security-admin/src/main/java/org/apache/ranger/biz/UserMgr.java 
b/security-admin/src/main/java/org/apache/ranger/biz/UserMgr.java
index 3045eaf..2b3cdcb 100644
--- a/security-admin/src/main/java/org/apache/ranger/biz/UserMgr.java
+++ b/security-admin/src/main/java/org/apache/ranger/biz/UserMgr.java
@@ -572,6 +572,7 @@ public class UserMgr {
                gjUser.setPassword(userProfile.getPassword());
                gjUser.setUserSource(userProfile.getUserSource());
                gjUser.setPublicScreenName(userProfile.getPublicScreenName());
+               gjUser.setOtherAttributes(userProfile.getOtherAttributes());
                if (userProfile.getFirstName() != null
                                && userProfile.getLastName() != null
                                && !userProfile.getFirstName().trim().isEmpty()
@@ -1171,6 +1172,7 @@ public class UserMgr {
                                 */
                        }
         }
+
         VXPortalUser userProfileRes = null;
         if (xXPortalUser != null) {
             userProfileRes = 
mapXXPortalUserToVXPortalUserForDefaultAccount(xXPortalUser);
@@ -1246,6 +1248,7 @@ public class UserMgr {
                userProfile.setFirstName(user.getFirstName());
                userProfile.setLastName(user.getLastName());
                userProfile.setPublicScreenName(user.getPublicScreenName());
+               userProfile.setOtherAttributes(user.getOtherAttributes());
 
                List<XXPortalUserRole> gjUserRoleList = daoManager
                                
.getXXPortalUserRole().findByParentId(user.getId());
diff --git a/security-admin/src/main/java/org/apache/ranger/biz/XUserMgr.java 
b/security-admin/src/main/java/org/apache/ranger/biz/XUserMgr.java
index 1c29d82..bfce9a6 100755
--- a/security-admin/src/main/java/org/apache/ranger/biz/XUserMgr.java
+++ b/security-admin/src/main/java/org/apache/ranger/biz/XUserMgr.java
@@ -31,28 +31,21 @@ import java.util.Set;
 
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang.StringUtils;
-import org.apache.ranger.common.ContextUtil;
-import org.apache.ranger.common.GUIDUtil;
-import org.apache.ranger.common.RangerCommonEnums;
+import org.apache.ranger.common.*;
 import org.apache.ranger.entity.XXGroupPermission;
 import org.apache.ranger.entity.XXModuleDef;
 import org.apache.ranger.entity.XXUserPermission;
+import org.apache.ranger.plugin.model.GroupInfo;
 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.RangerRowFilterPolicyItem;
+import org.apache.ranger.plugin.model.UserInfo;
+import org.apache.ranger.plugin.util.RangerUserStore;
 import org.apache.ranger.security.context.RangerAPIMapping;
 import org.apache.ranger.service.*;
 import org.apache.ranger.view.*;
 import org.apache.log4j.Logger;
-import org.apache.ranger.common.AppConstants;
-import org.apache.ranger.common.MessageEnums;
-import org.apache.ranger.common.PropertiesUtil;
-import org.apache.ranger.common.RangerConstants;
-import org.apache.ranger.common.RangerServicePoliciesCache;
-import org.apache.ranger.common.SearchCriteria;
-import org.apache.ranger.common.StringUtil;
-import org.apache.ranger.common.UserSessionBase;
 import org.apache.ranger.db.RangerDaoManager;
 import org.apache.ranger.db.XXAuditMapDao;
 import org.apache.ranger.db.XXAuthSessionDao;
@@ -93,6 +86,8 @@ import org.apache.ranger.entity.XXPortalUserRole;
 @Component
 public class XUserMgr extends XUserMgrBase {
 
+       private static final String RANGER_USER_GROUP_GLOBAL_STATE_NAME = 
"RangerUserStore";
+
        @Autowired
        XUserService xUserService;
 
@@ -584,7 +579,11 @@ public class XUserMgr extends XUserMgrBase {
             assignPermissionToUser(vXPortalUser, true);
         }
                vxUGInfo.setXgroupInfo(vxg);
-
+        try {
+                       
daoManager.getXXGlobalState().onGlobalAppDataChange(RANGER_USER_GROUP_GLOBAL_STATE_NAME);
+               } catch (Exception excp) {
+                       logger.error("createXUserGroupFromMap(" + 
vXUser.getName() + ") failed", excp);
+               }
                return vxUGInfo;
        }
        
@@ -642,6 +641,12 @@ public class XUserMgr extends XUserMgrBase {
 
                vxGUInfo.setXuserInfo(vxu);
 
+               try {
+                       
daoManager.getXXGlobalState().onGlobalAppDataChange(RANGER_USER_GROUP_GLOBAL_STATE_NAME);
+               } catch (Exception excp) {
+                       logger.error("createXGroupUserFromMap(" + 
vXGroup.getName() + ") failed", excp);
+               }
+
                return vxGUInfo;
        }
        
@@ -2544,4 +2549,34 @@ public class XUserMgr extends XUserMgrBase {
                return vxUgsyncAuditInfo;
        }
 
+       public Long getUserStoreVersion() {
+               return 
daoManager.getXXGlobalState().getAppDataVersion(RANGER_USER_GROUP_GLOBAL_STATE_NAME);
+       }
+
+       public Set<UserInfo> getUsers() {
+               return new HashSet<>(xUserService.getUsers());
+       }
+
+       public Set<GroupInfo> getGroups() {
+               return  new HashSet<>(xGroupService.getGroups());
+       }
+
+       public RangerUserStore getRangerUserStore(Long 
lastKnownUserStoreVersion) throws Exception {
+               RangerUserStore ret                   = null;
+               Long        rangerUserStoreVersionInDB = getUserStoreVersion();
+
+               if (logger.isDebugEnabled()) {
+                       logger.debug("==> XUserMgr.getRangerUserStore() 
lastKnownUserStoreVersion= " + lastKnownUserStoreVersion + " 
rangerUserStoreVersionInDB= " + rangerUserStoreVersionInDB);
+               }
+
+               if (rangerUserStoreVersionInDB != null) {
+                       ret = 
RangerUserStoreCache.getInstance().getLatestRangerUserStoreOrCached(this, 
lastKnownUserStoreVersion, rangerUserStoreVersionInDB);
+               }
+
+               if (logger.isDebugEnabled()) {
+                       logger.debug("<= XUserMgr.getRangerUserStore() 
lastKnownUserStoreVersion= " + lastKnownUserStoreVersion + " 
rangerUserStoreVersionInDB= " + rangerUserStoreVersionInDB + " RangerRoles= " + 
ret);
+               }
+
+               return ret;
+       }
 }
diff --git 
a/security-admin/src/main/java/org/apache/ranger/common/RangerUserStoreCache.java
 
b/security-admin/src/main/java/org/apache/ranger/common/RangerUserStoreCache.java
new file mode 100644
index 0000000..8ffc98c
--- /dev/null
+++ 
b/security-admin/src/main/java/org/apache/ranger/common/RangerUserStoreCache.java
@@ -0,0 +1,122 @@
+/*
+ * 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.common;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.ranger.authorization.hadoop.config.RangerAdminConfig;
+import org.apache.ranger.biz.XUserMgr;
+import org.apache.ranger.plugin.model.GroupInfo;
+import org.apache.ranger.plugin.model.UserInfo;
+import org.apache.ranger.plugin.util.RangerUserStore;
+
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.ReentrantLock;
+
+public class RangerUserStoreCache {
+       private static final Log LOG = 
LogFactory.getLog(RangerUserStoreCache.class);
+
+       private static final int MAX_WAIT_TIME_FOR_UPDATE = 10;
+
+       public static volatile RangerUserStoreCache     sInstance = null;
+       private final int                                                       
        waitTimeInSeconds;
+       private final ReentrantLock                                     lock = 
new ReentrantLock();
+       private RangerUserStore                                                 
rangerUserStore;
+
+       public static RangerUserStoreCache getInstance() {
+               if (sInstance == null) {
+                       synchronized (RangerUserStoreCache.class) {
+                               if (sInstance == null) {
+                                       sInstance = new RangerUserStoreCache();
+                               }
+                       }
+               }
+               return sInstance;
+       }
+
+       private RangerUserStoreCache() {
+               RangerAdminConfig config = RangerAdminConfig.getInstance();
+               waitTimeInSeconds = 
config.getInt("ranger.admin.userstore.download.cache.max.waittime.for.update", 
MAX_WAIT_TIME_FOR_UPDATE);
+               this.rangerUserStore = new RangerUserStore();
+       }
+
+       public RangerUserStore getRangerUserStore() {
+               return this.rangerUserStore;
+       }
+
+       public RangerUserStore getLatestRangerUserStoreOrCached(XUserMgr 
xUserMgr, Long lastKnownUserStoreVersion, Long rangerUserStoreVersionInDB) 
throws Exception {
+               RangerUserStore ret = null;
+
+               if (lastKnownUserStoreVersion == null || 
!lastKnownUserStoreVersion.equals(rangerUserStoreVersionInDB)) {
+                       ret = getLatestRangerUserStore(xUserMgr, 
lastKnownUserStoreVersion, rangerUserStoreVersionInDB);
+               } else if 
(lastKnownUserStoreVersion.equals(rangerUserStoreVersionInDB)) {
+                       ret = null;
+               } else {
+                       ret = getRangerUserStore();
+               }
+
+               return ret;
+       }
+
+       public RangerUserStore getLatestRangerUserStore(XUserMgr xUserMgr, Long 
lastKnownUserStoreVersion, Long rangerUserStoreVersionInDB) throws Exception {
+               RangerUserStore ret      = null;
+               boolean         lockResult   = false;
+               if (LOG.isDebugEnabled()) {
+                       LOG.debug("==> 
RangerUserStoreCache.getLatestRangerUserStore(lastKnownUserStoreVersion= " + 
lastKnownUserStoreVersion + " rangerUserStoreVersionInDB= " + 
rangerUserStoreVersionInDB + ")");
+               }
+
+               try {
+                       lockResult = lock.tryLock(waitTimeInSeconds, 
TimeUnit.SECONDS);
+
+                       if (lockResult) {
+                               final Set<UserInfo> rangerUsersInDB = 
xUserMgr.getUsers();
+                               final Set<GroupInfo> rangerGroupsInDB = 
xUserMgr.getGroups();
+                               if 
(CollectionUtils.isNotEmpty(rangerUsersInDB)) {
+                                       for (UserInfo userInfo : 
rangerUsersInDB) {
+                                               //Get user group mapping from 
DB and update userInfo object.
+                                               
userInfo.setGroups(xUserMgr.getGroupsForUser(userInfo.getName()));
+                                       }
+                               }
+
+                               ret = new 
RangerUserStore(rangerUserStoreVersionInDB, rangerUsersInDB, rangerGroupsInDB);
+                               rangerUserStore = ret;
+                       } else {
+                               if (LOG.isDebugEnabled()) {
+                                       LOG.debug("Could not get lock in [" + 
waitTimeInSeconds + "] seconds, returning cached RangerUserStore");
+                               }
+                               ret = getRangerUserStore();
+                       }
+               } catch (InterruptedException exception) {
+                       
LOG.error("RangerUserStoreCache.getLatestRangerUserStore:lock got 
interrupted..", exception);
+               } finally {
+                       if (lockResult) {
+                               lock.unlock();
+                       }
+               }
+
+               if (LOG.isDebugEnabled()) {
+                       LOG.debug("<== 
RangerUserStoreCache.getLatestRangerUserStore(lastKnownUserStoreVersion= " + 
lastKnownUserStoreVersion + " rangerUserStoreVersionInDB= " + 
rangerUserStoreVersionInDB + " RangerUserStore= " + ret + ")");
+               }
+               return ret;
+       }
+}
+
diff --git 
a/security-admin/src/main/java/org/apache/ranger/db/XXGlobalStateDao.java 
b/security-admin/src/main/java/org/apache/ranger/db/XXGlobalStateDao.java
index 2e462bd..b979459 100644
--- a/security-admin/src/main/java/org/apache/ranger/db/XXGlobalStateDao.java
+++ b/security-admin/src/main/java/org/apache/ranger/db/XXGlobalStateDao.java
@@ -35,7 +35,7 @@ import java.util.Map;
 public class XXGlobalStateDao extends BaseDao<XXGlobalState> {
     private static final Logger logger = 
Logger.getLogger(XXGlobalStateDao.class);
 
-    final static String APP_DATA_ENTRY_ROLE_VERSION = "RangerRoleVersion";
+    final static String APP_DATA_ENTRY_VERSION = "Version";
 
     public void onGlobalStateChange(String stateName) throws Exception {
 
@@ -74,9 +74,9 @@ public class XXGlobalStateDao extends BaseDao<XXGlobalState> {
             try {
                 XXGlobalState globalState = findByStateName(stateName);
                 if (globalState == null) {
-                    createGlobalStateForRoleVersion(stateName);
+                    createGlobalStateForAppDataVersion(stateName);
                 } else {
-                    updateGlobalStateForRoleVersion(globalState, stateName);
+                    updateGlobalStateForAppDataVersion(globalState, stateName);
                 }
             } catch (Exception exception) {
                 logger.error("Cannot create/update GlobalState for state:[" + 
stateName + "]", exception);
@@ -85,21 +85,21 @@ public class XXGlobalStateDao extends 
BaseDao<XXGlobalState> {
         }
     }
 
-    public Long getRoleVersion(String stateName) {
+    public Long getAppDataVersion(String stateName) {
         Long ret = null;
         try {
             XXGlobalState       globalState     = findByStateName(stateName);
             if (globalState != null) {
-                Map<String, String> roleVersionJson = new 
Gson().fromJson(globalState.getAppData(), Map.class);
-                if (MapUtils.isNotEmpty(roleVersionJson)) {
-                    ret = 
Long.valueOf(roleVersionJson.get(APP_DATA_ENTRY_ROLE_VERSION));
+                Map<String, String> appDataVersionJson = new 
Gson().fromJson(globalState.getAppData(), Map.class);
+                if (MapUtils.isNotEmpty(appDataVersionJson)) {
+                    ret = 
Long.valueOf(appDataVersionJson.get(APP_DATA_ENTRY_VERSION));
                 } else {
                     ret = 1L;
                 }
             }
         } catch (Exception exception) {
             if (logger.isDebugEnabled()) {
-                logger.debug("Unable to find the role version in Ranger 
Database", exception);
+                logger.debug("Unable to find the version for " + stateName + " 
in Ranger Database", exception);
             }
         }
         return ret;
@@ -140,25 +140,25 @@ public class XXGlobalStateDao extends 
BaseDao<XXGlobalState> {
         }
     }
 
-    private void createGlobalStateForRoleVersion(String stateName) {
+    private void createGlobalStateForAppDataVersion(String stateName) {
         XXGlobalState globalState = new XXGlobalState();
         globalState.setStateName(stateName);
-        Map<String,String> roleVersion = new HashMap<>();
-        roleVersion.put(APP_DATA_ENTRY_ROLE_VERSION,new 
String(Long.toString(1L)));
-        globalState.setAppData(new Gson().toJson(roleVersion));
+        Map<String,String> appDataVersion = new HashMap<>();
+        appDataVersion.put(APP_DATA_ENTRY_VERSION,new 
String(Long.toString(1L)));
+        globalState.setAppData(new Gson().toJson(appDataVersion));
         create(globalState);
     }
 
-    private void updateGlobalStateForRoleVersion(XXGlobalState globalState, 
String stateName) {
-        Map<String,String> roleVersionJson = new 
Gson().fromJson(globalState.getAppData(),Map.class);
-        if (MapUtils.isNotEmpty(roleVersionJson)) {
-            Long roleVersion = 
Long.valueOf(roleVersionJson.get(APP_DATA_ENTRY_ROLE_VERSION)) + 1L;
-            roleVersionJson.put(APP_DATA_ENTRY_ROLE_VERSION, new 
String(Long.toString(roleVersion)));
-            globalState.setAppData(new Gson().toJson(roleVersionJson));
+    private void updateGlobalStateForAppDataVersion(XXGlobalState globalState, 
String stateName) {
+        Map<String,String> appDataVersionJson = new 
Gson().fromJson(globalState.getAppData(),Map.class);
+        if (MapUtils.isNotEmpty(appDataVersionJson)) {
+            Long appDataVersion = 
Long.valueOf(appDataVersionJson.get(APP_DATA_ENTRY_VERSION)) + 1L;
+            appDataVersionJson.put(APP_DATA_ENTRY_VERSION, new 
String(Long.toString(appDataVersion)));
+            globalState.setAppData(new Gson().toJson(appDataVersionJson));
             update(globalState);
         } else {
-            //if not present create Global State for Role Version.
-            createGlobalStateForRoleVersion(stateName);
+            //if not present create Global State for state name Version.
+            createGlobalStateForAppDataVersion(stateName);
         }
     }
 }
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 1e8a093..af80639 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
@@ -24,6 +24,7 @@ import java.util.HashMap;
 import java.util.List;
 
 import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
@@ -32,6 +33,8 @@ 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 org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang.StringUtils;
@@ -39,6 +42,9 @@ import org.apache.log4j.Logger;
 import org.apache.ranger.biz.RangerBizUtil;
 import org.apache.ranger.biz.SessionMgr;
 import org.apache.ranger.biz.XUserMgr;
+import org.apache.ranger.biz.AssetMgr;
+import org.apache.ranger.biz.ServiceDBStore;
+import org.apache.ranger.common.ServiceUtil;
 import org.apache.ranger.common.ContextUtil;
 import org.apache.ranger.common.MessageEnums;
 import org.apache.ranger.common.RESTErrorUtil;
@@ -50,6 +56,13 @@ import org.apache.ranger.common.UserSessionBase;
 import org.apache.ranger.common.annotation.RangerAnnotationClassName;
 import org.apache.ranger.common.annotation.RangerAnnotationJSMgrName;
 import org.apache.ranger.db.RangerDaoManager;
+import org.apache.ranger.entity.XXService;
+import org.apache.ranger.entity.XXServiceDef;
+import org.apache.ranger.plugin.model.RangerPluginInfo;
+import org.apache.ranger.plugin.model.RangerService;
+import org.apache.ranger.plugin.store.EmbeddedServiceDefsUtil;
+import org.apache.ranger.plugin.util.RangerRESTUtils;
+import org.apache.ranger.plugin.util.RangerUserStore;
 import org.apache.ranger.security.context.RangerAPIList;
 import org.apache.ranger.service.AuthSessionService;
 import org.apache.ranger.service.XAuditMapService;
@@ -78,6 +91,8 @@ import 
org.springframework.transaction.annotation.Transactional;
 @Transactional(propagation = Propagation.REQUIRES_NEW)
 public class XUserREST {
 
+       public static final String USERSTORE_DOWNLOAD_USERS = 
"userstore.download.auth.users";
+
        @Autowired
        SearchUtil searchUtil;
 
@@ -131,6 +146,15 @@ public class XUserREST {
        
        @Autowired
        StringUtil stringUtil;
+
+       @Autowired
+       AssetMgr assetMgr;
+
+       @Autowired
+       ServiceUtil serviceUtil;
+
+       @Autowired
+       ServiceDBStore svcStore;
        
        static final Logger logger = Logger.getLogger(XUserMgr.class);
 
@@ -1235,6 +1259,93 @@ public class XUserREST {
                 }
         }
 
+       @GET
+       @Path("/secure/download/{serviceName}")
+       @Produces({ "application/xml", "application/json" })
+       public RangerUserStore 
getSecureRangerUserStoreIfUpdated(@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.getSecureRangerUserStoreIfUpdated("
+                                       + serviceName + ", " + 
lastKnownUserStoreVersion + ", " + lastActivationTime + ")");
+               }
+               RangerUserStore ret = null;
+               int     httpCode          = HttpServletResponse.SC_OK;
+               String  logMsg            = null;
+               boolean isAllowed         = false;
+               boolean isAdmin           = bizUtil.isAdmin();
+               boolean isKeyAdmin        = bizUtil.isKeyAdmin();
+               Long    downloadedVersion = null;
+
+               boolean isValid = false;
+               try {
+                       XXService xService = 
rangerDaoManager.getXXService().findByName(serviceName);
+                       if (xService != null) {
+                               isValid = true;
+                       }
+                       if (isValid) {
+                               if (lastKnownUserStoreVersion == null) {
+                                       lastKnownUserStoreVersion = 
Long.valueOf(-1);
+                               }
+                               XXServiceDef xServiceDef = 
rangerDaoManager.getXXServiceDef().getById(xService.getType());
+                               RangerService rangerService = 
svcStore.getServiceByName(serviceName);
+
+                               if 
(StringUtils.equals(xServiceDef.getImplclassname(), 
EmbeddedServiceDefsUtil.KMS_IMPL_CLASS_NAME)) {
+                                       if (isKeyAdmin) {
+                                               isAllowed = true;
+                                       } else {
+                                               isAllowed = 
bizUtil.isUserAllowed(rangerService, USERSTORE_DOWNLOAD_USERS);
+                                       }
+                               } else {
+                                       if (isAdmin) {
+                                               isAllowed = true;
+                                       } else {
+                                               isAllowed = 
bizUtil.isUserAllowed(rangerService, USERSTORE_DOWNLOAD_USERS);
+                                       }
+                               }
+
+                               if (isAllowed) {
+                                       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 =>" + (ret.toString());
+                                       }
+                               } else {
+                                       
logger.error("getSecureRangerUserStoreIfUpdated(" + serviceName + ", " + 
lastKnownUserStoreVersion + ") failed as User doesn't have permission to 
download UsersAndGroups");
+                                       httpCode = 
HttpServletResponse.SC_UNAUTHORIZED;
+                                       logMsg = "User doesn't have permission 
to download UsersAndGroups";
+                               }
+                       }
+
+               } catch (Throwable excp) {
+                       logger.error("getSecureRangerUserStoreIfUpdated(" + 
serviceName + ", " + lastKnownUserStoreVersion + ", " + lastActivationTime + ") 
failed", 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.getSecureRangerUserStoreIfUpdated(" + serviceName + ", " + 
lastKnownUserStoreVersion + ", " + lastActivationTime + ")" + ret);
+               }
+               return ret;
+       }
+
        @POST
        @Path("/ugsync/auditinfo")
        @Produces({ "application/xml", "application/json" })
diff --git 
a/security-admin/src/main/java/org/apache/ranger/service/XGroupServiceBase.java 
b/security-admin/src/main/java/org/apache/ranger/service/XGroupServiceBase.java
index 1a701bb..cde91dc 100644
--- 
a/security-admin/src/main/java/org/apache/ranger/service/XGroupServiceBase.java
+++ 
b/security-admin/src/main/java/org/apache/ranger/service/XGroupServiceBase.java
@@ -25,15 +25,20 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
+import com.google.gson.Gson;
 
+import com.google.gson.GsonBuilder;
 import org.apache.ranger.common.SearchCriteria;
 import org.apache.ranger.entity.XXGroup;
+import org.apache.ranger.plugin.model.GroupInfo;
 import org.apache.ranger.view.VXGroup;
 import org.apache.ranger.view.VXGroupList;
 
 public abstract class XGroupServiceBase<T extends XXGroup, V extends VXGroup>
                extends AbstractBaseResourceService<T, V> {
        public static final String NAME = "XGroup";
+       private static final Gson gsonBuilder = new GsonBuilder().create();
 
        public XGroupServiceBase() {
 
@@ -84,4 +89,19 @@ public abstract class XGroupServiceBase<T extends XXGroup, V 
extends VXGroup>
                return returnList;
        }
 
+       public List<GroupInfo> getGroups() {
+               List<GroupInfo> returnList = new ArrayList<>();
+
+               @SuppressWarnings("unchecked")
+               List<XXGroup> resultList = daoManager.getXXGroup().getAll();
+
+               // Iterate over the result list and create the return list
+               for (XXGroup gjXGroup : resultList) {
+                       GroupInfo groupInfo = new GroupInfo(gjXGroup.getName(), 
gjXGroup.getDescription(), gsonBuilder.fromJson(gjXGroup.getOtherAttributes(), 
Map.class));
+                       returnList.add(groupInfo);
+               }
+
+               return returnList;
+       }
+
 }
diff --git 
a/security-admin/src/main/java/org/apache/ranger/service/XUserServiceBase.java 
b/security-admin/src/main/java/org/apache/ranger/service/XUserServiceBase.java
index 1004952..9cdc14e 100644
--- 
a/security-admin/src/main/java/org/apache/ranger/service/XUserServiceBase.java
+++ 
b/security-admin/src/main/java/org/apache/ranger/service/XUserServiceBase.java
@@ -25,15 +25,20 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
+import com.google.gson.Gson;
 
+import com.google.gson.GsonBuilder;
 import org.apache.ranger.common.SearchCriteria;
 import org.apache.ranger.entity.XXUser;
+import org.apache.ranger.plugin.model.UserInfo;
 import org.apache.ranger.view.VXUser;
 import org.apache.ranger.view.VXUserList;
 
 public abstract class XUserServiceBase<T extends XXUser, V extends VXUser>
                extends AbstractBaseResourceService<T, V> {
        public static final String NAME = "XUser";
+       private static final Gson gsonBuilder = new GsonBuilder().create();
 
        public XUserServiceBase() {
 
@@ -84,4 +89,19 @@ public abstract class XUserServiceBase<T extends XXUser, V 
extends VXUser>
                return returnList;
        }
 
+       public List<UserInfo> getUsers() {
+               List<UserInfo> returnList = new ArrayList<>();
+
+               @SuppressWarnings("unchecked")
+               List<XXUser> resultList = daoManager.getXXUser().getAll();
+
+               // Iterate over the result list and create the return list
+               for (XXUser gjXUser : resultList) {
+                       UserInfo userInfo = new UserInfo(gjXUser.getName(), 
gjXUser.getDescription(), gsonBuilder.fromJson(gjXUser.getOtherAttributes(), 
Map.class));
+                       returnList.add(userInfo);
+               }
+
+               return returnList;
+       }
+
 }
diff --git 
a/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapDeltaUserGroupBuilder.java
 
b/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapDeltaUserGroupBuilder.java
index ca50f09..bea91c4 100644
--- 
a/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapDeltaUserGroupBuilder.java
+++ 
b/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapDeltaUserGroupBuilder.java
@@ -33,6 +33,7 @@ import java.util.Properties;
 import java.util.Set;
 import java.util.StringTokenizer;
 import java.util.HashMap;
+import java.util.UUID;
 
 import javax.naming.Context;
 import javax.naming.InvalidNameException;
@@ -51,6 +52,7 @@ import javax.naming.ldap.StartTlsResponse;
 
 import org.apache.commons.collections.BidiMap;
 import org.apache.commons.collections.bidimap.DualHashBidiMap;
+import org.apache.commons.lang.StringUtils;
 import org.apache.log4j.Logger;
 import org.apache.ranger.unixusersync.config.UserGroupSyncConfig;
 import org.apache.ranger.unixusersync.model.LdapSyncSourceInfo;
@@ -65,6 +67,7 @@ public class LdapDeltaUserGroupBuilder extends 
AbstractUserGroupSource {
        
        private static final Logger LOG = 
Logger.getLogger(LdapDeltaUserGroupBuilder.class);
        
+       private static final String DATA_TYPE_BYTEARRAY = "byte[]";
        private static final int PAGE_SIZE = 500;
        private static long deltaSyncUserTime = 0; // Used for AD uSNChanged 
        private static long deltaSyncGroupTime = 0; // Used for AD uSNChanged
@@ -80,12 +83,14 @@ public class LdapDeltaUserGroupBuilder extends 
AbstractUserGroupSource {
 
   private String[] userSearchBase;
        private String userNameAttribute;
+       private String userCloudIdAttribute;
   private int    userSearchScope;
   private String userObjectClass;
   private String userSearchFilter;
   private String extendedUserSearchFilter;
   private SearchControls userSearchControls;
   private Set<String> userGroupNameAttributeSet;
+  private Set<String> otherUserAttributes;
 
   private boolean pagedResultsEnabled = true;
   private int pagedResultsSize = PAGE_SIZE;
@@ -102,6 +107,8 @@ public class LdapDeltaUserGroupBuilder extends 
AbstractUserGroupSource {
   private SearchControls groupSearchControls;
   private String groupMemberAttributeName;
   private String groupNameAttribute;
+       private String groupCloudIdAttribute;
+       private Set<String> otherGroupAttributes;
        private int groupHierarchyLevels;
 
        private LdapContext ldapContext;
@@ -126,6 +133,7 @@ public class LdapDeltaUserGroupBuilder extends 
AbstractUserGroupSource {
        int noOfNewGroups;
        int noOfModifiedUsers;
        int noOfModifiedGroups;
+       private Map<String, Map<String, String>> groupInfoMap;
 
        public static void main(String[] args) throws Throwable {
                LdapDeltaUserGroupBuilder  ugBuilder = new 
LdapDeltaUserGroupBuilder();
@@ -188,6 +196,32 @@ public class LdapDeltaUserGroupBuilder extends 
AbstractUserGroupSource {
                        env.put("java.naming.ldap.factory.socket", 
"org.apache.ranger.ldapusersync.process.CustomSSLSocketFactory");
                }
 
+               if (StringUtils.isNotEmpty(userCloudIdAttribute)) {
+                       if 
(config.getUserCloudIdAttributeDataType().equals(DATA_TYPE_BYTEARRAY)) {
+                               env.put("java.naming.ldap.attributes.binary", 
userCloudIdAttribute);
+                       }
+               }
+
+               if (StringUtils.isNotEmpty(groupCloudIdAttribute)) {
+                       if 
(config.getGroupCloudIdAttributeDataType().equals(DATA_TYPE_BYTEARRAY)) {
+                               env.put("java.naming.ldap.attributes.binary", 
groupCloudIdAttribute);
+                       }
+               }
+
+               for (String otherUserAttribute : otherUserAttributes) {
+                       String attrType = 
config.getOtherUserAttributeDataType(otherUserAttribute);
+                       if (attrType.equals(DATA_TYPE_BYTEARRAY)) {
+                               env.put("java.naming.ldap.attributes.binary", 
otherUserAttribute);
+                       }
+               }
+
+               for (String otherGroupAttribute : otherGroupAttributes) {
+                       String attrType = 
config.getOtherGroupAttributeDataType(otherGroupAttribute);
+                       if (attrType.equals(DATA_TYPE_BYTEARRAY)) {
+                               env.put("java.naming.ldap.attributes.binary", 
otherGroupAttribute);
+                       }
+               }
+
                ldapContext = new InitialLdapContext(env, null);
                if (!ldapUrl.startsWith("ldaps")) {
                        if (config.isStartTlsEnabled()) {
@@ -227,9 +261,11 @@ public class LdapDeltaUserGroupBuilder extends 
AbstractUserGroupSource {
                userSearchFilter = config.getUserSearchFilter();
 
                userNameAttribute = config.getUserNameAttribute();
+               userCloudIdAttribute = config.getUserCloudIdAttribute();
 
                Set<String> userSearchAttributes = new HashSet<String>();
                userSearchAttributes.add(userNameAttribute);
+               userSearchAttributes.add(userCloudIdAttribute);
                // For Group based search, user's group name attribute should 
not be added to the user search attributes
                if (!groupSearchFirstEnabled && !groupSearchEnabled) {
                        userGroupNameAttributeSet = 
config.getUserGroupNameAttributeSet();
@@ -237,6 +273,10 @@ public class LdapDeltaUserGroupBuilder extends 
AbstractUserGroupSource {
                                userSearchAttributes.add(useGroupNameAttribute);
                        }
                }
+               otherUserAttributes = config.getOtherUserAttributes();
+               for (String otherUserAttribute : otherUserAttributes) {
+                       userSearchAttributes.add(otherUserAttribute);
+               }
                userSearchAttributes.add("uSNChanged");
                userSearchAttributes.add("modifytimestamp");
                userSearchControls = new SearchControls();
@@ -253,6 +293,7 @@ public class LdapDeltaUserGroupBuilder extends 
AbstractUserGroupSource {
     groupSearchFilter = config.getGroupSearchFilter();
     groupMemberAttributeName =  config.getUserGroupMemberAttributeName();
     groupNameAttribute = config.getGroupNameAttribute();
+    groupCloudIdAttribute = config.getGroupCloudIdAttribute();
                groupHierarchyLevels = config.getGroupHierarchyLevels();
 
     extendedGroupSearchFilter =  "(&"  + extendedGroupSearchFilter + "(|(" + 
groupMemberAttributeName + "={0})(" + groupMemberAttributeName + "={1})))";
@@ -263,9 +304,14 @@ public class LdapDeltaUserGroupBuilder extends 
AbstractUserGroupSource {
 
     Set<String> groupSearchAttributes = new HashSet<String>();
     groupSearchAttributes.add(groupNameAttribute);
+    groupSearchAttributes.add(groupCloudIdAttribute);
     groupSearchAttributes.add(groupMemberAttributeName);
     groupSearchAttributes.add("uSNChanged");
     groupSearchAttributes.add("modifytimestamp");
+    otherGroupAttributes = config.getOtherGroupAttributes();
+    for (String otherGroupAttribute : otherGroupAttributes) {
+               groupSearchAttributes.add(otherGroupAttribute);
+    }
     groupSearchControls.setReturningAttributes(groupSearchAttributes.toArray(
                        new String[groupSearchAttributes.size()]));
 
@@ -284,6 +330,7 @@ public class LdapDeltaUserGroupBuilder extends 
AbstractUserGroupSource {
                                        + ",  userNameAttribute: " + 
userNameAttribute
                                        + ",  userSearchAttributes: " + 
userSearchAttributes
           + ",  userGroupNameAttributeSet: " + userGroupNameAttributeSet
+                       + ",  otherUserAttributes: " + otherUserAttributes
           + ",  pagedResultsEnabled: " + pagedResultsEnabled
           + ",  pagedResultsSize: " + pagedResultsSize
           + ",  groupSearchEnabled: " + groupSearchEnabled
@@ -325,6 +372,7 @@ public class LdapDeltaUserGroupBuilder extends 
AbstractUserGroupSource {
                LOG.info("LdapDeltaUserGroupBuilder updateSink started");
                groupUserTable = HashBasedTable.create();
         groupNameMap = new DualHashBidiMap();
+               groupInfoMap = new HashMap<>();
                noOfNewUsers = 0;
                noOfNewGroups = 0;
                noOfModifiedUsers = 0;
@@ -386,7 +434,7 @@ public class LdapDeltaUserGroupBuilder extends 
AbstractUserGroupSource {
                        String transformGroupName = 
groupNameTransform(groupName);
                        LOG.debug("addOrUpdateGroup(): group = " + groupName + 
" users = " + userList);
                        try {
-                               sink.addOrUpdateGroup(transformGroupName, 
userList);
+                               sink.addOrUpdateGroup(transformGroupName, 
groupInfoMap.get(groupName), userList);
                        } catch (Throwable t) {
                                LOG.error("sink.addOrUpdateGroup failed with 
exception: " + t.getMessage()
                                + ", for group: " + transformGroupName
@@ -519,10 +567,22 @@ public class LdapDeltaUserGroupBuilder extends 
AbstractUserGroupSource {
                                                        }
                                                }
 
+                                               Map<String, String> userAttrMap 
= new HashMap<>();
+                                               Attribute userCloudIdAttr = 
attributes.get(userCloudIdAttribute);
+                                               if (userCloudIdAttr != null) {
+                                                       
addToAttrMap(userAttrMap, "cloud_id", userCloudIdAttr, 
config.getUserCloudIdAttributeDataType());
+                                               }
+                                               for (String otherUserAttribute 
: otherUserAttributes) {
+                                                       if 
(attributes.get(otherUserAttribute) != null) {
+                                                               String attrType 
= config.getOtherUserAttributeDataType(otherUserAttribute);
+                                                               
addToAttrMap(userAttrMap, otherUserAttribute, 
attributes.get(otherUserAttribute), attrType);
+                                                       }
+                                               }
+
                                                if (!groupSearchFirstEnabled) {
                                                        String 
transformUserName = userNameTransform(userName);
                                                        try {
-                                                               
sink.addOrUpdateUser(transformUserName);
+                                                               
sink.addOrUpdateUser(transformUserName, userAttrMap, null);
                                                        } catch (Throwable t) {
                                                                
LOG.error("sink.addOrUpdateUser failed with exception: " + t.getMessage()
                                                                + ", for user: 
" + transformUserName);
@@ -554,7 +614,7 @@ public class LdapDeltaUserGroupBuilder extends 
AbstractUserGroupSource {
 
                                                        List<String> groupList 
= new ArrayList<String>(groups);
                                                        try {
-                                                               
sink.addOrUpdateUser(transformUserName, groupList);
+                                                               
sink.addOrUpdateUser(transformUserName, userAttrMap, groupList);
 
                                                        } catch (Throwable t) {
                                                                
LOG.error("sink.addOrUpdateUserGroups failed with exception: " + t.getMessage()
@@ -569,7 +629,7 @@ public class LdapDeltaUserGroupBuilder extends 
AbstractUserGroupSource {
                                                                if 
(!userNameMap.containsKey(userFullName)) {
                                                                        String 
transformUserName = userNameTransform(userName);
                                                                        try {
-                                                                               
sink.addOrUpdateUser(transformUserName);
+                                                                               
sink.addOrUpdateUser(transformUserName, userAttrMap, null);
                                                                        } catch 
(Throwable t) {
                                                                                
LOG.error("sink.addOrUpdateUser failed with exception: " + t.getMessage()
                                                                                
                + ", for user: " + transformUserName);
@@ -640,7 +700,7 @@ public class LdapDeltaUserGroupBuilder extends 
AbstractUserGroupSource {
                                LOG.info("LdapDeltaUserGroupBuilder.getUsers() 
completed with user count: "
                                                + counter);
                                } catch (Exception t) {
-                                       
LOG.error("LdapDeltaUserGroupBuilder.getUsers() failed with exception: " + t);
+                                       
LOG.error("LdapDeltaUserGroupBuilder.getUsers() failed with exception: ", t);
                                        
LOG.info("LdapDeltaUserGroupBuilder.getUsers() user count: "
                                                        + counter);
                                }
@@ -704,7 +764,8 @@ public class LdapDeltaUserGroupBuilder extends 
AbstractUserGroupSource {
                                                                continue;
                                                        }
                                                        counter++;
-                                                       Attribute groupNameAttr 
= groupEntry.getAttributes().get(groupNameAttribute);
+                                                       Attributes attributes = 
  groupEntry.getAttributes();
+                                                       Attribute groupNameAttr 
= attributes.get(groupNameAttribute);
                                                        if (groupNameAttr == 
null) {
                                                                if 
(LOG.isInfoEnabled())  {
                                                                        
LOG.info(groupNameAttribute + " empty for entry " + 
groupEntry.getNameInNamespace() +
@@ -714,15 +775,27 @@ public class LdapDeltaUserGroupBuilder extends 
AbstractUserGroupSource {
                                                        }
                                                        String gName = (String) 
groupNameAttr.get();
                                                        String 
transformGroupName = groupNameTransform(gName);
+                                                       Map<String, String> 
groupAttrMap = new HashMap<>();
+                                                       Attribute 
groupCloudIdAttr = attributes.get(groupCloudIdAttribute);
+                                                       if (groupCloudIdAttr != 
null) {
+                                                               
addToAttrMap(groupAttrMap, "cloud_id", groupCloudIdAttr, 
config.getGroupCloudIdAttributeDataType());
+                                                       }
+                                                       for (String 
otherGroupAttribute : otherGroupAttributes) {
+                                                               if 
(attributes.get(otherGroupAttribute) != null) {
+                                                                       String 
attrType = config.getOtherGroupAttributeDataType(otherGroupAttribute);
+                                                                       
addToAttrMap(groupAttrMap, otherGroupAttribute, 
attributes.get(otherGroupAttribute), attrType);
+                                                               }
+                                                       }
+                                                       groupInfoMap.put(gName, 
groupAttrMap);
                                                        // If group based 
search is enabled, then
                                                        // update the group 
name to ranger admin
                                                        // check for group 
members and populate userInfo object with user's full name and group mapping
                                                        if 
(groupSearchFirstEnabled) {
                                                                
LOG.debug("Update Ranger admin with " + transformGroupName);
-                                                               
sink.addOrUpdateGroup(transformGroupName);
+                                                               
sink.addOrUpdateGroup(transformGroupName, groupAttrMap);
                                                        }
 
-                                                       Attribute timeStampAttr 
 = groupEntry.getAttributes().get("uSNChanged");
+                                                       Attribute timeStampAttr 
 = attributes.get("uSNChanged");
                                                        if (timeStampAttr != 
null) {
                                                                String 
uSNChangedVal = (String) timeStampAttr.get();
                                                                long 
currentDeltaSyncTime = Long.parseLong(uSNChangedVal);
@@ -730,7 +803,7 @@ public class LdapDeltaUserGroupBuilder extends 
AbstractUserGroupSource {
                                                                        
highestdeltaSyncGroupTime = currentDeltaSyncTime;
                                                                }
                                                        } else {
-                                                               timeStampAttr = 
groupEntry.getAttributes().get("modifytimestamp");
+                                                               timeStampAttr = 
attributes.get("modifytimestamp");
                                                                if 
(timeStampAttr != null) {
                                                                        String 
timeStampVal = (String) timeStampAttr.get();
                                                                        Date 
parseDate = dateFormat.parse(timeStampVal);
@@ -742,7 +815,7 @@ public class LdapDeltaUserGroupBuilder extends 
AbstractUserGroupSource {
                                                                        }
                                                                }
                                                        }
-                                                       Attribute 
groupMemberAttr = groupEntry.getAttributes().get(groupMemberAttributeName);
+                                                       Attribute 
groupMemberAttr = attributes.get(groupMemberAttributeName);
                                                        int userCount = 0;
                                                        if (groupMemberAttr == 
null || groupMemberAttr.size() <= 0) {
                                                                LOG.info("No 
members available for " + gName);
@@ -769,7 +842,8 @@ public class LdapDeltaUserGroupBuilder extends 
AbstractUserGroupSource {
                                                                if 
(groupSearchFirstEnabled && !userSearchEnabled) {
                                                                        String 
transformUserName = userNameTransform(userName);
                                                                        try {
-                                                                               
sink.addOrUpdateUser(transformUserName);
+                                                                               
Map<String, String> userAttrMap = new HashMap<>();
+                                                                               
sink.addOrUpdateUser(transformUserName, userAttrMap, null);
                                                                        } catch 
(Throwable t) {
                                                                                
LOG.error("sink.addOrUpdateUser failed with exception: " + t.getMessage()
                                                                                
+ ", for user: " + transformUserName);
@@ -789,6 +863,8 @@ public class LdapDeltaUserGroupBuilder extends 
AbstractUserGroupSource {
                                                                }
                                 
groupNameMap.put(groupEntry.getNameInNamespace().toLowerCase(), gName);
                                                        }
+
+
                                                        if 
(groupNames.contains(gName)) {
                                                                
noOfModifiedGroups++;
                                                        } else {
@@ -1021,6 +1097,15 @@ public class LdapDeltaUserGroupBuilder extends 
AbstractUserGroupSource {
                                                                continue;
                                                        }
 
+                                                       Map<String, String> 
groupAttrMap = new HashMap<>();
+                                                       for (String 
otherGroupAttribute : otherGroupAttributes) {
+                                                               Attribute 
otherGroupAttr = groupEntry.getAttributes().get(otherGroupAttribute);
+                                                               if 
(otherGroupAttr != null) {
+                                                                       
groupAttrMap.put(otherGroupAttribute, (String) otherGroupAttr.get());
+                                                               }
+                                                       }
+                                                       groupInfoMap.put(gName, 
groupAttrMap);
+
                                                        NamingEnumeration<?> 
userEnum = groupMemberAttr.getAll();
                                                        while 
(userEnum.hasMore()) {
                                                                String 
originalUserFullName = (String) userEnum.next();
@@ -1035,6 +1120,7 @@ public class LdapDeltaUserGroupBuilder extends 
AbstractUserGroupSource {
                                     groupUserTable.put(gName, 
originalUserFullName, originalUserFullName);
                                 }
                                                                
groupNameMap.put(groupEntry.getNameInNamespace().toLowerCase(), gName);
+
                                                        }
                                                        LOG.info("No. of 
members in the group " + gName + " = " + userCount);
                                                }
@@ -1086,5 +1172,22 @@ public class LdapDeltaUserGroupBuilder extends 
AbstractUserGroupSource {
                }
                goUpGroupHierarchyLdap(nextLevelGroups, groupHierarchyLevels-1);
        }
-}
 
+       private void addToAttrMap(Map<String, String> userAttrMap, String 
attrName, Attribute attr, String attrType) throws Throwable{
+               if (attrType.equals(DATA_TYPE_BYTEARRAY)) {
+                       try {
+                               byte[] otherUserAttrBytes = (byte[]) attr.get();
+                               //Convert objectGUID into string and add to 
userAttrMap
+                               String attrVal = 
UUID.nameUUIDFromBytes(otherUserAttrBytes).toString();
+                               userAttrMap.put(attrName, attrVal);
+                       } catch (ClassCastException e) {
+                               LOG.error(attrName + " type is not set properly 
" + e.getMessage());
+                       }
+               } else if (attrType.equals("String")) {
+                       userAttrMap.put(attrName, (String) attr.get());
+               } else {
+                       // This should not be reached.
+                       LOG.warn("Attribute Type " + attrType + " not supported 
for " + attrName);
+               }
+       }
+}
diff --git 
a/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapPolicyMgrUserGroupBuilder.java
 
b/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapPolicyMgrUserGroupBuilder.java
index 8017395..31b4d3d 100644
--- 
a/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapPolicyMgrUserGroupBuilder.java
+++ 
b/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapPolicyMgrUserGroupBuilder.java
@@ -152,25 +152,14 @@ private static final Logger LOG = 
Logger.getLogger(LdapPolicyMgrUserGroupBuilder
 
        @Override
        public void addOrUpdateUser(String userName, List<String> groups) 
throws Throwable {
-               //* Add user to groups mapping in the x_user table. 
-               //* Here the assumption is that the user already exists in 
x_portal_user table.
-               if ( ! isMockRun ) {
-                       // If the rest call to ranger admin fails, 
-                       // propagate the failure to the caller for retry in 
next sync cycle.
-                       if (addUserGroupInfo(userName, groups) == null ) {
-                               String msg = "Failed to add addorUpdate user 
group info";
-                               LOG.error(msg);
-                               throw new Exception(msg);
-                       }
-               }
 
        }
 
        @Override
-       public void addOrUpdateGroup(String groupName) throws Throwable {
+       public void addOrUpdateGroup(String groupName, Map<String, String> 
groupAttrs) throws Throwable {
                //* Build the group info object and do the rest call
                        if ( ! isMockRun ) {
-                               if ( addGroupInfo(groupName) == null) {
+                               if ( addGroupInfo(groupName, groupAttrs) == 
null) {
                                        String msg = "Failed to add addorUpdate 
group info";
                                        LOG.error(msg);
                                        throw new Exception(msg);
@@ -179,13 +168,13 @@ private static final Logger LOG = 
Logger.getLogger(LdapPolicyMgrUserGroupBuilder
 
        }
        
-       private XGroupInfo addGroupInfo(final String groupName){
+       private XGroupInfo addGroupInfo(final String groupName, Map<String, 
String> groupAttrs){
                XGroupInfo ret = null;
                XGroupInfo group = null;
                
                LOG.debug("INFO: addPMXAGroup(" + groupName + ")");
                if (! isMockRun) {
-                       group = addXGroupInfo(groupName);
+                       group = addXGroupInfo(groupName, groupAttrs);
                }
                if (authenticationType != null && 
AUTH_KERBEROS.equalsIgnoreCase(authenticationType) && 
SecureClientLogin.isKerberosCredentialExists(principal,keytab)) {
                        try {
@@ -213,7 +202,7 @@ private static final Logger LOG = 
Logger.getLogger(LdapPolicyMgrUserGroupBuilder
                }       
        }
        
-       private XGroupInfo addXGroupInfo(String aGroupName) {
+       private XGroupInfo addXGroupInfo(String aGroupName, Map<String, String> 
groupAttrs) {
                
                XGroupInfo addGroup = new XGroupInfo();
                
@@ -224,6 +213,8 @@ private static final Logger LOG = 
Logger.getLogger(LdapPolicyMgrUserGroupBuilder
                addGroup.setGroupType("1");
 
                addGroup.setGroupSource(GROUP_SOURCE_EXTERNAL);
+               Gson gson = new Gson();
+               addGroup.setOtherAttributes(gson.toJson(groupAttrs));
                groupuserInfo.setXgroupInfo(addGroup);
 
                return addGroup;
@@ -272,30 +263,33 @@ private static final Logger LOG = 
Logger.getLogger(LdapPolicyMgrUserGroupBuilder
 
        @Override
        public void addOrUpdateUser(String userName) throws Throwable {
+
+       }
+
+       @Override
+       public void addOrUpdateUser(String userName, Map<String, String> 
userAttrs, List<String> groups) throws Throwable {
                // First add to x_portal_user
                LOG.debug("INFO: addPMAccount(" + userName + ")" );
                if (! isMockRun) {
-                       if (addMUser(userName) == null) {
-                       String msg = "Failed to add portal user";
-                       LOG.error(msg);
-                       throw new Exception(msg);
+                       if (addMUser(userName, userAttrs) == null) {
+                               String msg = "Failed to add portal user";
+                               LOG.error(msg);
+                               throw new Exception(msg);
                        }
                }
-               List<String> groups = new ArrayList<String>();
                //* Build the user group info object with empty groups and do 
the rest call
                if ( ! isMockRun ) {
-                       // If the rest call to ranger admin fails, 
+                       // If the rest call to ranger admin fails,
                        // propagate the failure to the caller for retry in 
next sync cycle.
-                       if (addUserGroupInfo(userName, groups) == null ) {
+                       if (addUserGroupInfo(userName, userAttrs, groups) == 
null ) {
                                String msg = "Failed to add addorUpdate user 
group info";
                                LOG.error(msg);
                                throw new Exception(msg);
                        }
                }
-               
        }
-       
-       private UserGroupInfo addUserGroupInfo(String userName, List<String> 
groups){
+
+       private UserGroupInfo addUserGroupInfo(String userName, Map<String, 
String> userAttrs, List<String> groups){
                if(LOG.isDebugEnabled()) {
                        LOG.debug("==> 
LdapPolicyMgrUserGroupBuilder.addUserGroupInfo " + userName + " and groups");
                }
@@ -304,7 +298,7 @@ private static final Logger LOG = 
Logger.getLogger(LdapPolicyMgrUserGroupBuilder
                LOG.debug("INFO: addPMXAUser(" + userName + ")");
                
                if (! isMockRun) {
-                       user = addXUserInfo(userName);
+                       user = addXUserInfo(userName, userAttrs);
                }
                for(String g : groups) {
                                LOG.debug("INFO: addPMXAGroupToUser(" + 
userName + "," + g + ")" );
@@ -337,13 +331,15 @@ private static final Logger LOG = 
Logger.getLogger(LdapPolicyMgrUserGroupBuilder
                }
        }
        
-       private XUserInfo addXUserInfo(String aUserName) {
+       private XUserInfo addXUserInfo(String aUserName, Map<String, String> 
userAttrs) {
                
                XUserInfo xuserInfo = new XUserInfo();
 
                xuserInfo.setName(aUserName);
                
                xuserInfo.setDescription(aUserName + " - add from Unix box");
+               Gson gson = new Gson();
+               xuserInfo.setOtherAttributes(gson.toJson(userAttrs));
         if (userMap.containsKey(aUserName)) {
             List<String> roleList = new ArrayList<String>();
             roleList.add(userMap.get(aUserName));
@@ -359,7 +355,7 @@ private static final Logger LOG = 
Logger.getLogger(LdapPolicyMgrUserGroupBuilder
                List<XGroupInfo> xGroupInfoList = new ArrayList<XGroupInfo>();
                
                for(String groupName : aGroupList) {
-                       XGroupInfo group = addXGroupInfo(groupName);
+                       XGroupInfo group = addXGroupInfo(groupName, null);
                        xGroupInfoList.add(group);
                        addXUserGroupInfo(aUserInfo, group);
                }
@@ -421,6 +417,10 @@ private static final Logger LOG = 
Logger.getLogger(LdapPolicyMgrUserGroupBuilder
 
        @Override
        public void addOrUpdateGroup(String groupName, List<String> users) 
throws Throwable {
+       }
+
+       @Override
+       public void addOrUpdateGroup(String groupName, Map<String, String> 
groupAttrs, List<String> users) throws Throwable {
                // First get the existing group user mappings from Ranger admin.
                // Then compute the delta and send the updated group user 
mappings to ranger admin.
                LOG.debug("addOrUpdateGroup for " + groupName + " with users: " 
+ users);
@@ -484,7 +484,7 @@ private static final Logger LOG = 
Logger.getLogger(LdapPolicyMgrUserGroupBuilder
                if ( ! isMockRun ) {
                        // If the rest call to ranger admin fails, 
                        // propagate the failure to the caller for retry in 
next sync cycle.
-                       if (addGroupUserInfo(groupName, addUsers) == null ) {
+                       if (addGroupUserInfo(groupName, groupAttrs, addUsers) 
== null ) {
                                String msg = "Failed to add addorUpdate group 
user info";
                                LOG.error(msg);
                                throw new Exception(msg);
@@ -654,7 +654,7 @@ private static final Logger LOG = 
Logger.getLogger(LdapPolicyMgrUserGroupBuilder
                }
        }
        
-       private GroupUserInfo addGroupUserInfo(String groupName, List<String> 
users){
+       private GroupUserInfo addGroupUserInfo(String groupName, Map<String, 
String> groupAttrs, List<String> users){
                if(LOG.isDebugEnabled()) {
                        LOG.debug("==> 
LdapPolicyMgrUserGroupBuilder.addGroupUserInfo " + groupName + " and " + users);
                }
@@ -663,7 +663,7 @@ private static final Logger LOG = 
Logger.getLogger(LdapPolicyMgrUserGroupBuilder
                
                LOG.debug("INFO: addPMXAGroup(" + groupName + ")" );
                if (! isMockRun) {
-                       group = addXGroupInfo(groupName);
+                       group = addXGroupInfo(groupName, groupAttrs);
                }
                for(String u : users) {
                                LOG.debug("INFO: addPMXAGroupToUser(" + 
groupName + "," + u + ")" );
@@ -701,7 +701,7 @@ private static final Logger LOG = 
Logger.getLogger(LdapPolicyMgrUserGroupBuilder
                List<XUserInfo> xUserInfoList = new ArrayList<XUserInfo>();
 
                for(String userName : aUserList) {
-                       XUserInfo user = addXUserInfo(userName);
+                       XUserInfo user = addXUserInfo(userName, null);
                        xUserInfoList.add(user);
                        addXUserGroupInfo(user, aGroupInfo);
                }
@@ -772,13 +772,15 @@ private static final Logger LOG = 
Logger.getLogger(LdapPolicyMgrUserGroupBuilder
        }
 
        
-       private MUserInfo addMUser(String aUserName) {
+       private MUserInfo addMUser(String aUserName, Map<String, String> 
userAttrs) {
                MUserInfo ret = null;
                MUserInfo userInfo = new MUserInfo();
 
                userInfo.setLoginId(aUserName);
                userInfo.setFirstName(aUserName);
         userInfo.setLastName(aUserName);
+               Gson gson = new Gson();
+        userInfo.setOtherAttributes(gson.toJson(userAttrs));
         String str[] = new String[1];
         if (userMap.containsKey(aUserName)) {
             str[0] = userMap.get(aUserName);
diff --git 
a/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapUserGroupBuilder.java
 
b/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapUserGroupBuilder.java
index 8efa161..07cba9e 100644
--- 
a/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapUserGroupBuilder.java
+++ 
b/ugsync/src/main/java/org/apache/ranger/ldapusersync/process/LdapUserGroupBuilder.java
@@ -721,10 +721,10 @@ public class LdapUserGroupBuilder extends 
AbstractUserGroupSource {
                                                                        int 
userCount = 0;
                                                                        if 
(groupMemberAttr == null || groupMemberAttr.size() <= 0) {
                                                                                
LOG.info("No members available for " + gName);
-                                                                               
sink.addOrUpdateGroup(gName, null);
+                                                                               
sink.addOrUpdateGroup(gName, new HashMap<String, String>(), null);
                                                                                
continue;
                                                                        }
-                                                                       
sink.addOrUpdateGroup(gName);
+                                                                       
sink.addOrUpdateGroup(gName, new HashMap<String, String>());
                                                                        
NamingEnumeration<?> userEnum = groupMemberAttr.getAll();
                                                                        while 
(userEnum.hasMore()) {
                                                                                
String originalUserFullName = (String) userEnum.next();
diff --git 
a/ugsync/src/main/java/org/apache/ranger/unixusersync/config/UserGroupSyncConfig.java
 
b/ugsync/src/main/java/org/apache/ranger/unixusersync/config/UserGroupSyncConfig.java
index ae4e474..f9f51d9 100644
--- 
a/ugsync/src/main/java/org/apache/ranger/unixusersync/config/UserGroupSyncConfig.java
+++ 
b/ugsync/src/main/java/org/apache/ranger/unixusersync/config/UserGroupSyncConfig.java
@@ -146,6 +146,15 @@ public class UserGroupSyncConfig  {
        private static final String LGSYNC_USER_GROUP_NAME_ATTRIBUTE = 
"ranger.usersync.ldap.user.groupnameattribute";
        private static final String DEFAULT_USER_GROUP_NAME_ATTRIBUTE = 
"memberof,ismemberof";
 
+       private static final String LGSYNC_USER_CLOUDID_ATTRIBUTE = 
"ranger.usersync.ldap.user.cloudid.attribute";
+       private static final String DEFAULT_USER_CLOUDID_ATTRIBUTE = "objectid";
+
+       private static final String LGSYNC_USER_CLOUDID_ATTRIBUTE_DATATYPE = 
"ranger.usersync.ldap.user.cloudid.attribute.datatype";
+       private static final String DEFAULT_USER_CLOUDID_ATTRIBUTE_DATATYPE = 
"byte[]";
+
+       private static final String LGSYNC_OTHER_USER_ATTRIBUTES = 
"ranger.usersync.ldap.user.otherattributes";
+       private static final String DEFAULT_OTHER_USER_ATTRIBUTES = 
"userurincipaluame,";
+
        public static final String UGSYNC_NONE_CASE_CONVERSION_VALUE = "none";
        public static final String UGSYNC_LOWER_CASE_CONVERSION_VALUE = "lower";
        public static final String UGSYNC_UPPER_CASE_CONVERSION_VALUE = "upper";
@@ -195,6 +204,15 @@ public class UserGroupSyncConfig  {
        private static final String LGSYNC_GROUP_MEMBER_ATTRIBUTE_NAME = 
"ranger.usersync.group.memberattributename";
        private static final String DEFAULT_LGSYNC_GROUP_MEMBER_ATTRIBUTE_NAME 
= "member";
 
+       private static final String LGSYNC_GROUP_CLOUDID_ATTRIBUTE = 
"ranger.usersync.ldap.group.cloudid.attribute";
+       private static final String DEFAULT_GROUP_CLOUDID_ATTRIBUTE = 
"objectid";
+
+       private static final String LGSYNC_GROUP_CLOUDID_ATTRIBUTE_DATATYPE = 
"ranger.usersync.ldap.group.cloudid.attribute.datatype";
+       private static final String DEFAULT_GROUP_CLOUDID_ATTRIBUTE_DATATYPE = 
"byte[]";
+
+       private static final String LGSYNC_OTHER_GROUP_ATTRIBUTES = 
"ranger.usersync.ldap.group.otherattributes";
+       private static final String DEFAULT_OTHER_GROUP_ATTRIBUTES = 
"displayname,";
+
        private static final String LGSYNC_GROUP_HIERARCHY_LEVELS = 
"ranger.usersync.ldap.grouphierarchylevels";
        private static final int DEFAULT_LGSYNC_GROUP_HIERARCHY_LEVELS = 0;
 
@@ -648,6 +666,43 @@ public class UserGroupSyncConfig  {
                return userGroupNameAttributeSet;
        }
 
+       public Set<String> getOtherUserAttributes() {
+               String otherAttributes =  
prop.getProperty(LGSYNC_OTHER_USER_ATTRIBUTES);
+               if(otherAttributes == null || otherAttributes.trim().isEmpty()) 
{
+                       otherAttributes = DEFAULT_OTHER_USER_ATTRIBUTES;
+               }
+               StringTokenizer st = new StringTokenizer(otherAttributes, ",");
+               Set<String> otherUserAttributes = new HashSet<String>();
+               while (st.hasMoreTokens()) {
+                       otherUserAttributes.add(st.nextToken().trim());
+               }
+               return otherUserAttributes;
+       }
+
+       public String getUserCloudIdAttribute() {
+               String val =  prop.getProperty(LGSYNC_USER_CLOUDID_ATTRIBUTE);
+               if (val == null || val.trim().isEmpty()) {
+                       return DEFAULT_USER_CLOUDID_ATTRIBUTE;
+               }
+               return val;
+       }
+
+       public String getUserCloudIdAttributeDataType() {
+               String val =  
prop.getProperty(LGSYNC_USER_CLOUDID_ATTRIBUTE_DATATYPE);
+               if (val == null || val.trim().isEmpty()) {
+                       return DEFAULT_USER_CLOUDID_ATTRIBUTE_DATATYPE;
+               }
+               return val;
+       }
+
+       public String getOtherUserAttributeDataType(String attrName) {
+               String attrType =  
prop.getProperty(LGSYNC_OTHER_USER_ATTRIBUTES + "." + attrName + "datatype");
+               if (attrType == null || attrType.isEmpty()) {
+                       attrType = "String";
+               }
+               return attrType.trim();
+       }
+
        public String getUserNameCaseConversion() {
                String ret = 
prop.getProperty(UGSYNC_USERNAME_CASE_CONVERSION_PARAM, 
DEFAULT_UGSYNC_USERNAME_CASE_CONVERSION_VALUE);
                return ret.trim().toLowerCase();
@@ -789,6 +844,43 @@ public class UserGroupSyncConfig  {
                return val;
        }
 
+       public String getGroupCloudIdAttribute() {
+               String val =  prop.getProperty(LGSYNC_GROUP_CLOUDID_ATTRIBUTE);
+               if (val == null || val.trim().isEmpty()) {
+                       return DEFAULT_GROUP_CLOUDID_ATTRIBUTE;
+               }
+               return val;
+       }
+
+       public String getGroupCloudIdAttributeDataType() {
+               String val =  
prop.getProperty(LGSYNC_GROUP_CLOUDID_ATTRIBUTE_DATATYPE);
+               if (val == null || val.trim().isEmpty()) {
+                       return DEFAULT_GROUP_CLOUDID_ATTRIBUTE_DATATYPE;
+               }
+               return val;
+       }
+
+       public Set<String> getOtherGroupAttributes() {
+               String otherAttributes =  
prop.getProperty(LGSYNC_OTHER_GROUP_ATTRIBUTES);
+               if(otherAttributes == null || otherAttributes.trim().isEmpty()) 
{
+                       otherAttributes = DEFAULT_OTHER_GROUP_ATTRIBUTES;
+               }
+               StringTokenizer st = new StringTokenizer(otherAttributes, ",");
+               Set<String> otherGroupAttributes = new HashSet<String>();
+               while (st.hasMoreTokens()) {
+                       otherGroupAttributes.add(st.nextToken().trim());
+               }
+               return otherGroupAttributes;
+       }
+
+       public String getOtherGroupAttributeDataType(String attrName) {
+                String attrType =  
prop.getProperty(LGSYNC_OTHER_GROUP_ATTRIBUTES + "." + attrName + "datatype");
+                if (attrType == null || attrType.isEmpty()) {
+                        attrType = "String";
+                }
+                return attrType.trim();
+        }
+
        public int getGroupHierarchyLevels() {
                int groupHierarchyLevels;
                String val = prop.getProperty(LGSYNC_GROUP_HIERARCHY_LEVELS);
diff --git 
a/ugsync/src/main/java/org/apache/ranger/unixusersync/model/MUserInfo.java 
b/ugsync/src/main/java/org/apache/ranger/unixusersync/model/MUserInfo.java
index 841bac6..4f865af 100644
--- a/ugsync/src/main/java/org/apache/ranger/unixusersync/model/MUserInfo.java
+++ b/ugsync/src/main/java/org/apache/ranger/unixusersync/model/MUserInfo.java
@@ -26,6 +26,7 @@ public class MUserInfo {
        private String lastName;
        private String emailAddress;
        private String[] userRoleList = { "ROLE_USER" };
+       private String otherAttributes;
        
        
        public String getLoginId() {
@@ -58,5 +59,12 @@ public class MUserInfo {
        public void setUserRoleList(String[] userRoleList) {
                this.userRoleList = userRoleList;
        }
-       
+
+       public String getOtherAttributes() {
+               return otherAttributes;
+       }
+
+       public void setOtherAttributes(String otherAttributes) {
+               this.otherAttributes = otherAttributes;
+       }
 }
diff --git 
a/ugsync/src/main/java/org/apache/ranger/unixusersync/model/XGroupInfo.java 
b/ugsync/src/main/java/org/apache/ranger/unixusersync/model/XGroupInfo.java
index cbe0eb0..b61f39c 100644
--- a/ugsync/src/main/java/org/apache/ranger/unixusersync/model/XGroupInfo.java
+++ b/ugsync/src/main/java/org/apache/ranger/unixusersync/model/XGroupInfo.java
@@ -26,6 +26,7 @@ public class XGroupInfo {
        private String description;
        private String groupType;
        private String groupSource;
+       private String otherAttributes;
        public String getId() {
                return id;
        }
@@ -57,7 +58,15 @@ public class XGroupInfo {
        public void setGroupSource(String groupSource) {
                this.groupSource = groupSource;
        }
-       
+
+       public String getOtherAttributes() {
+               return otherAttributes;
+       }
+
+       public void setOtherAttributes(String otherAttributes) {
+               this.otherAttributes = otherAttributes;
+       }
+
        @Override
        public boolean equals(Object o) {
                if (this == o) return true;
diff --git 
a/ugsync/src/main/java/org/apache/ranger/unixusersync/model/XUserInfo.java 
b/ugsync/src/main/java/org/apache/ranger/unixusersync/model/XUserInfo.java
index e2f36b2..bee6323 100644
--- a/ugsync/src/main/java/org/apache/ranger/unixusersync/model/XUserInfo.java
+++ b/ugsync/src/main/java/org/apache/ranger/unixusersync/model/XUserInfo.java
@@ -26,6 +26,7 @@ public class XUserInfo {
        private String id;
        private String name;
        private String  description;
+       private String otherAttributes;
     private List<String> groupNameList = new ArrayList<String>();
     private List<String> userRoleList = new ArrayList<String>();
        
@@ -74,7 +75,15 @@ public class XUserInfo {
         this.userRoleList = userRoleList;
     }
 
-    @Override
+       public String getOtherAttributes() {
+               return otherAttributes;
+       }
+
+       public void setOtherAttributes(String otherAttributes) {
+               this.otherAttributes = otherAttributes;
+       }
+
+       @Override
     public String toString() {
         return "XUserInfo [id=" + id + ", name=" + name + ", description="
                 + description + ", groupNameList=" + groupNameList
diff --git 
a/ugsync/src/main/java/org/apache/ranger/unixusersync/process/PolicyMgrUserGroupBuilder.java
 
b/ugsync/src/main/java/org/apache/ranger/unixusersync/process/PolicyMgrUserGroupBuilder.java
index f08c511..7402b69 100644
--- 
a/ugsync/src/main/java/org/apache/ranger/unixusersync/process/PolicyMgrUserGroupBuilder.java
+++ 
b/ugsync/src/main/java/org/apache/ranger/unixusersync/process/PolicyMgrUserGroupBuilder.java
@@ -1374,7 +1374,7 @@ public class PolicyMgrUserGroupBuilder implements 
UserGroupSink {
        }
 
        @Override
-       public void addOrUpdateGroup(String groupName) throws Throwable{
+       public void addOrUpdateGroup(String groupName, Map<String, String> 
groupAttrs) throws Throwable{
                XGroupInfo group = groupName2XGroupInfoMap.get(groupName);
 
                if (group == null) {    // Does not exists
@@ -1478,7 +1478,7 @@ public class PolicyMgrUserGroupBuilder implements 
UserGroupSink {
                                newGroupList.add(groupName);
                        }
                }
-               addOrUpdateGroup(groupName);
+               addOrUpdateGroup(groupName, new HashMap<String, String>());
 
        }
 
@@ -1657,4 +1657,14 @@ public class PolicyMgrUserGroupBuilder implements 
UserGroupSink {
             }
         }
     }
+
+       @Override
+       public void addOrUpdateUser(String user, Map<String, String> userAttrs, 
List<String> groups) throws Throwable {
+
+       }
+
+       @Override
+       public void addOrUpdateGroup(String group, Map<String, String> 
groupAttrs, List<String> users) throws Throwable {
+
+       }
 }
diff --git 
a/ugsync/src/main/java/org/apache/ranger/usergroupsync/UserGroupSink.java 
b/ugsync/src/main/java/org/apache/ranger/usergroupsync/UserGroupSink.java
index 77bd016..368c4f8 100644
--- a/ugsync/src/main/java/org/apache/ranger/usergroupsync/UserGroupSink.java
+++ b/ugsync/src/main/java/org/apache/ranger/usergroupsync/UserGroupSink.java
@@ -22,6 +22,7 @@
 import org.apache.ranger.unixusersync.model.UgsyncAuditInfo;
 
 import java.util.List;
+import java.util.Map;
 
 public interface UserGroupSink {
        void init() throws Throwable;
@@ -30,9 +31,13 @@ public interface UserGroupSink {
        
        void addOrUpdateUser(String user) throws Throwable;
        
-       void addOrUpdateGroup(String group) throws Throwable;
+       void addOrUpdateGroup(String group, Map<String, String> groupAttrs) 
throws Throwable;
        
        void addOrUpdateGroup(String group, List<String> users) throws 
Throwable;
 
        void postUserGroupAuditInfo(UgsyncAuditInfo ugsyncAuditInfo) throws 
Throwable;
+
+       void addOrUpdateUser(String user, Map<String, String> userAttrs, 
List<String> groups) throws Throwable;
+
+       void addOrUpdateGroup(String group, Map<String, String> groupAttrs, 
List<String> users) throws Throwable;
 }
diff --git 
a/ugsync/src/test/java/org/apache/ranger/usergroupsync/LdapPolicyMgrUserGroupBuilderTest.java
 
b/ugsync/src/test/java/org/apache/ranger/usergroupsync/LdapPolicyMgrUserGroupBuilderTest.java
index 99bc2b4..e10f632 100644
--- 
a/ugsync/src/test/java/org/apache/ranger/usergroupsync/LdapPolicyMgrUserGroupBuilderTest.java
+++ 
b/ugsync/src/test/java/org/apache/ranger/usergroupsync/LdapPolicyMgrUserGroupBuilderTest.java
@@ -21,6 +21,7 @@ package org.apache.ranger.usergroupsync;
 
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 import org.apache.ranger.ldapusersync.process.LdapPolicyMgrUserGroupBuilder;
@@ -36,14 +37,13 @@ public class LdapPolicyMgrUserGroupBuilderTest extends 
LdapPolicyMgrUserGroupBui
         }
 
         @Override
-        public void addOrUpdateUser(String user, List<String> groups) {
-                allGroups.addAll(groups);
-                //allUsers.add(user);
+        public void addOrUpdateUser(String user, Map<String, String> 
userAttrs, List<String> groups) {
+                allUsers.add(user);
                 //System.out.println("Username: " + user + " and associated 
groups: " + groups);
         }
 
         @Override
-        public void addOrUpdateGroup(String group) {
+        public void addOrUpdateGroup(String group, Map<String, String> 
groupAttrs) {
                 allGroups.add(group);
                 //System.out.println("Groupname: " + group);
         }
@@ -55,7 +55,7 @@ public class LdapPolicyMgrUserGroupBuilderTest extends 
LdapPolicyMgrUserGroupBui
         }
 
         @Override
-        public void addOrUpdateGroup(String group, List<String> users) {
+        public void addOrUpdateGroup(String group, Map<String, String> 
groupAttrs, List<String> users) {
                boolean addGroup = false;
                        for (String user : users) {
                                if (allUsers.contains(user)) {
diff --git 
a/ugsync/src/test/java/org/apache/ranger/usergroupsync/PolicyMgrUserGroupBuilderTest.java
 
b/ugsync/src/test/java/org/apache/ranger/usergroupsync/PolicyMgrUserGroupBuilderTest.java
index 2bc3951..b0ce872 100644
--- 
a/ugsync/src/test/java/org/apache/ranger/usergroupsync/PolicyMgrUserGroupBuilderTest.java
+++ 
b/ugsync/src/test/java/org/apache/ranger/usergroupsync/PolicyMgrUserGroupBuilderTest.java
@@ -19,9 +19,7 @@
 
 package org.apache.ranger.usergroupsync;
 
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
+import java.util.*;
 
 import org.apache.ranger.unixusersync.process.PolicyMgrUserGroupBuilder;
 
@@ -43,13 +41,13 @@ public class PolicyMgrUserGroupBuilderTest extends 
PolicyMgrUserGroupBuilder {
         }
 
         @Override
-        public void addOrUpdateGroup(String group) {
+        public void addOrUpdateGroup(String group, Map<String, String> 
groupAttrs ) {
                 allGroups.add(group);
         }
 
         @Override
         public void addOrUpdateGroup(String group, List<String> users) {
-                addOrUpdateGroup(group);
+                addOrUpdateGroup(group, new HashMap<String, String>());
         }
 
         public int getTotalUsers() {

Reply via email to