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

rmani 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 b69227e  RANGER-2512:RangerRolesRESTClient for serving user group 
roles to the plugins for evaluation
b69227e is described below

commit b69227eb2f6b8aacb539a6454c714923257de059
Author: rmani <[email protected]>
AuthorDate: Thu Sep 26 23:27:31 2019 -0700

    RANGER-2512:RangerRolesRESTClient for serving user group roles to the 
plugins for evaluation
    
    Signed-off-by: rmani <[email protected]>
---
 .../admin/client/AbstractRangerAdminClient.java    |   5 +
 .../ranger/admin/client/RangerAdminClient.java     |   3 +
 .../ranger/admin/client/RangerAdminRESTClient.java |  81 +++++
 .../ranger/plugin/model/RangerPluginInfo.java      |  49 +++
 .../ranger/plugin/model/RangerPolicyDelta.java     |   3 +-
 .../plugin/policyengine/RangerPolicyEngine.java    |   7 +-
 .../policyengine/RangerPolicyEngineCache.java      |   4 +-
 .../policyengine/RangerPolicyEngineImpl.java       |  68 +++-
 .../ranger/plugin/service/RangerAuthContext.java   |  14 +-
 .../ranger/plugin/service/RangerBasePlugin.java    |  30 +-
 .../apache/ranger/plugin/util/PolicyRefresher.java |  20 +-
 .../apache/ranger/plugin/util/RangerRESTUtils.java |  20 ++
 .../org/apache/ranger/plugin/util/RangerRoles.java |  78 +++++
 .../ranger/plugin/util/RangerRolesProvider.java    | 352 +++++++++++++++++++++
 .../apache/ranger/plugin/util/RangerRolesUtil.java | 106 +++++++
 .../apache/ranger/plugin/util/ServicePolicies.java |  15 +-
 .../plugin/policyengine/TestPolicyEngine.java      |  48 ++-
 .../admin/client/RangerAdminJersey2RESTClient.java |  87 +++++
 .../optimized/current/ranger_core_db_mysql.sql     |   2 +
 .../043-add-role-version-in-serviceVersionInfo.sql |  34 ++
 .../optimized/current/ranger_core_db_oracle.sql    |   2 +
 .../043-add-role-version-in-serviceVersionInfo.sql |  28 ++
 .../optimized/current/ranger_core_db_postgres.sql  |   2 +
 .../043-add-role-version-in-serviceVersionInfo.sql |  36 +++
 .../current/ranger_core_db_sqlanywhere.sql         |   2 +
 .../043-add-role-version-in-serviceVersionInfo.sql |  25 ++
 .../optimized/current/ranger_core_db_sqlserver.sql |   2 +
 .../042-add-role-version-in-serviceVersionInfo.sql |  29 ++
 .../main/java/org/apache/ranger/biz/AssetMgr.java  | 123 +++++--
 .../java/org/apache/ranger/biz/RoleDBStore.java    |  39 +++
 .../java/org/apache/ranger/biz/ServiceDBStore.java |  69 +---
 .../org/apache/ranger/common/RangerRoleCache.java  | 142 +++++++++
 .../org/apache/ranger/db/XXGlobalStateDao.java     |  47 +++
 .../apache/ranger/entity/XXServiceVersionInfo.java |  22 ++
 .../main/java/org/apache/ranger/rest/RoleREST.java | 189 +++++++++++
 .../java/org/apache/ranger/rest/ServiceREST.java   |   2 -
 .../apache/ranger/service/RangerRoleService.java   |  43 +++
 37 files changed, 1688 insertions(+), 140 deletions(-)

diff --git 
a/agents-common/src/main/java/org/apache/ranger/admin/client/AbstractRangerAdminClient.java
 
b/agents-common/src/main/java/org/apache/ranger/admin/client/AbstractRangerAdminClient.java
index 6367235..2bc7557 100644
--- 
a/agents-common/src/main/java/org/apache/ranger/admin/client/AbstractRangerAdminClient.java
+++ 
b/agents-common/src/main/java/org/apache/ranger/admin/client/AbstractRangerAdminClient.java
@@ -37,6 +37,11 @@ public abstract class AbstractRangerAdminClient implements 
RangerAdminClient {
     }
 
     @Override
+    public RangerRoles getRolesIfUpdated(long lastKnownRoleVersion, long 
lastActivationTimeInMillis) throws Exception {
+        return null;
+    }
+
+    @Override
     public RangerRole createRole(RangerRole request) throws Exception {
         return null;
     }
diff --git 
a/agents-common/src/main/java/org/apache/ranger/admin/client/RangerAdminClient.java
 
b/agents-common/src/main/java/org/apache/ranger/admin/client/RangerAdminClient.java
index b09a9be..9510888 100644
--- 
a/agents-common/src/main/java/org/apache/ranger/admin/client/RangerAdminClient.java
+++ 
b/agents-common/src/main/java/org/apache/ranger/admin/client/RangerAdminClient.java
@@ -23,6 +23,7 @@
 import org.apache.ranger.plugin.model.RangerRole;
 import org.apache.ranger.plugin.util.GrantRevokeRequest;
 import org.apache.ranger.plugin.util.GrantRevokeRoleRequest;
+import org.apache.ranger.plugin.util.RangerRoles;
 import org.apache.ranger.plugin.util.ServicePolicies;
 import org.apache.ranger.plugin.util.ServiceTags;
 
@@ -35,6 +36,8 @@ public interface RangerAdminClient {
 
        ServicePolicies getServicePoliciesIfUpdated(long lastKnownVersion, long 
lastActivationTimeInMillis) throws Exception;
 
+       RangerRoles getRolesIfUpdated(long lastKnownRoleVersion, long 
lastActivationTimeInMills) throws Exception;
+
        RangerRole createRole(RangerRole request) throws Exception;
 
        void dropRole(String execUser, String roleName) throws Exception;
diff --git 
a/agents-common/src/main/java/org/apache/ranger/admin/client/RangerAdminRESTClient.java
 
b/agents-common/src/main/java/org/apache/ranger/admin/client/RangerAdminRESTClient.java
index 5939f38..f564ba5 100644
--- 
a/agents-common/src/main/java/org/apache/ranger/admin/client/RangerAdminRESTClient.java
+++ 
b/agents-common/src/main/java/org/apache/ranger/admin/client/RangerAdminRESTClient.java
@@ -195,6 +195,87 @@ public class RangerAdminRESTClient extends 
AbstractRangerAdminClient {
        }
 
        @Override
+       public RangerRoles getRolesIfUpdated(final long lastKnownRoleVersion, 
final long lastActivationTimeInMillis) throws Exception {
+               if (LOG.isDebugEnabled()) {
+                       LOG.debug("==> 
RangerAdminRESTClient.getRolesIfUpdated(" + lastKnownRoleVersion + ", " + 
lastActivationTimeInMillis + ")");
+               }
+
+               final RangerRoles ret;
+               final UserGroupInformation user = MiscUtil.getUGILoginUser();
+               final boolean isSecureMode = user != null && 
UserGroupInformation.isSecurityEnabled();
+               final ClientResponse response;
+
+               Map<String, String> queryParams = new HashMap<String, String>();
+               
queryParams.put(RangerRESTUtils.REST_PARAM_LAST_KNOWN_ROLE_VERSION, 
Long.toString(lastKnownRoleVersion));
+               
queryParams.put(RangerRESTUtils.REST_PARAM_LAST_ACTIVATION_TIME, 
Long.toString(lastActivationTimeInMillis));
+               queryParams.put(RangerRESTUtils.REST_PARAM_PLUGIN_ID, pluginId);
+               queryParams.put(RangerRESTUtils.REST_PARAM_CLUSTER_NAME, 
clusterName);
+
+               if (isSecureMode) {
+                       if (LOG.isDebugEnabled()) {
+                               LOG.debug("Checking Roles updated as user : " + 
user);
+                       }
+                       PrivilegedAction<ClientResponse> action = new 
PrivilegedAction<ClientResponse>() {
+                               public ClientResponse run() {
+                                       ClientResponse clientRes = null;
+                                       String relativeURL = 
RangerRESTUtils.REST_URL_SERVICE_SERCURE_GET_USER_GROUP_ROLES + 
serviceNameUrlParam;
+                                       try {
+                                               clientRes =  
restClient.get(relativeURL, queryParams);
+                                       } catch (Exception e) {
+                                               LOG.error("Failed to get 
response, Error is : "+e.getMessage());
+                                       }
+                                       return clientRes;
+                               }
+                       };
+                       response = user.doAs(action);
+               } else {
+                       if (LOG.isDebugEnabled()) {
+                               LOG.debug("Checking Roles updated as user : " + 
user);
+                       }
+                       String relativeURL = 
RangerRESTUtils.REST_URL_SERVICE_GET_USER_GROUP_ROLES + serviceNameUrlParam;
+                       response = restClient.get(relativeURL, queryParams);
+               }
+
+               if (response == null || response.getStatus() == 
HttpServletResponse.SC_NOT_MODIFIED) {
+                       if (response == null) {
+                               LOG.error("Error getting Roles; Received NULL 
response!!. secureMode=" + isSecureMode + ", user=" + user + ", serviceName=" + 
serviceName);
+                       } else {
+                               RESTResponse resp = 
RESTResponse.fromClientResponse(response);
+                               if (LOG.isDebugEnabled()) {
+                                       LOG.debug("No change in Roles. 
secureMode=" + isSecureMode + ", user=" + user
+                                                       + ", response=" + resp 
+ ", serviceName=" + serviceName
+                                                       + ", " + 
"lastKnownRoleVersion=" + lastKnownRoleVersion
+                                                       + ", " + 
"lastActivationTimeInMillis=" + lastActivationTimeInMillis);
+                               }
+                       }
+                       ret = null;
+               } else if (response.getStatus() == HttpServletResponse.SC_OK) {
+                       ret = response.getEntity(RangerRoles.class);
+               } else if (response.getStatus() == 
HttpServletResponse.SC_NOT_FOUND) {
+                       ret = null;
+                       LOG.error("Error getting Roles; service not found. 
secureMode=" + isSecureMode + ", user=" + user
+                                       + ", response=" + response.getStatus() 
+ ", serviceName=" + serviceName
+                                       + ", " + "lastKnownRoleVersion=" + 
lastKnownRoleVersion
+                                       + ", " + "lastActivationTimeInMillis=" 
+ lastActivationTimeInMillis);
+                       String exceptionMsg = response.hasEntity() ? 
response.getEntity(String.class) : null;
+
+                       
RangerServiceNotFoundException.throwExceptionIfServiceNotFound(serviceName, 
exceptionMsg);
+
+                       LOG.warn("Received 404 error code with body:[" + 
exceptionMsg + "], Ignoring");
+               } else {
+                       RESTResponse resp = 
RESTResponse.fromClientResponse(response);
+                       LOG.warn("Error getting Roles. secureMode=" + 
isSecureMode + ", user=" + user + ", response=" + resp + ", serviceName=" + 
serviceName);
+                       ret = null;
+               }
+
+               if(LOG.isDebugEnabled()) {
+                       LOG.debug("<== 
RangerAdminRESTClient.getRolesIfUpdated(" + lastKnownRoleVersion + ", " + 
lastActivationTimeInMillis + "): ");
+               }
+
+               return ret;
+       }
+
+       @Override
        public RangerRole createRole(final RangerRole request) throws Exception 
{
                if(LOG.isDebugEnabled()) {
                        LOG.debug("==> RangerAdminRESTClient.createRole(" + 
request + ")");
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 e3f9f15..4bd374e 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
@@ -43,6 +43,7 @@ public class RangerPluginInfo implements Serializable {
 
        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 String PLUGIN_INFO_POLICY_DOWNLOAD_TIME      = 
"policyDownloadTime";
        public static final String PLUGIN_INFO_POLICY_DOWNLOADED_VERSION = 
"policyDownloadedVersion";
@@ -53,6 +54,10 @@ public class RangerPluginInfo implements Serializable {
        public static final String PLUGIN_INFO_TAG_ACTIVATION_TIME       = 
"tagActivationTime";
        public static final String PLUGIN_INFO_TAG_ACTIVE_VERSION        = 
"tagActiveVersion";
 
+       public static final String PLUGIN_INFO_ROLE_DOWNLOAD_TIME         = 
"roleDownloadTime";
+       public static final String PLUGIN_INFO_ROLE_DOWNLOADED_VERSION    = 
"roleDownloadedVersion";
+       public static final String PLUGIN_INFO_ROLE_ACTIVATION_TIME       = 
"roleActivationTime";
+       public static final String PLUGIN_INFO_ROLE_ACTIVE_VERSION        = 
"roleActiveVersion";
 
        public static final String RANGER_ADMIN_LAST_POLICY_UPDATE_TIME  = 
"lastPolicyUpdateTime";
        public static final String RANGER_ADMIN_LATEST_POLICY_VERSION    = 
"latestPolicyVersion";
@@ -271,6 +276,50 @@ public class RangerPluginInfo implements Serializable {
                return StringUtils.isNotBlank(updateTimeString) ? 
Long.valueOf(updateTimeString) : null;
        }
 
+       @JsonIgnore
+       public void setRoleDownloadTime(Long roleDownloadTime) {
+               getInfo().put(PLUGIN_INFO_ROLE_DOWNLOAD_TIME, roleDownloadTime 
== null ? null : Long.toString(roleDownloadTime));
+       }
+
+       @JsonIgnore
+       public Long getRoleDownloadTime() {
+               String downloadTimeString = 
getInfo().get(PLUGIN_INFO_ROLE_DOWNLOAD_TIME);
+               return StringUtils.isNotBlank(downloadTimeString) ? 
Long.valueOf(downloadTimeString) : null;
+       }
+
+       @JsonIgnore
+       public void setRoleDownloadedVersion(Long roleDownloadedVersion) {
+               getInfo().put(PLUGIN_INFO_ROLE_DOWNLOADED_VERSION, 
roleDownloadedVersion == null ? null : Long.toString(roleDownloadedVersion));
+       }
+
+       @JsonIgnore
+       public Long getRoleDownloadedVersion() {
+               String downloadedVersionString = 
getInfo().get(PLUGIN_INFO_ROLE_DOWNLOADED_VERSION);
+               return StringUtils.isNotBlank(downloadedVersionString) ? 
Long.valueOf(downloadedVersionString) : null;
+       }
+
+       @JsonIgnore
+       public void setRoleActivationTime(Long roleActivationTime) {
+               getInfo().put(PLUGIN_INFO_ROLE_ACTIVATION_TIME, 
roleActivationTime == null ? null : Long.toString(roleActivationTime));
+       }
+
+       @JsonIgnore
+       public Long getRoleActivationTime() {
+               String activationTimeString = 
getInfo().get(PLUGIN_INFO_ROLE_ACTIVATION_TIME);
+               return StringUtils.isNotBlank(activationTimeString) ? 
Long.valueOf(activationTimeString) : null;
+       }
+
+       @JsonIgnore
+       public void setRoleActiveVersion(Long roleActiveVersion) {
+               getInfo().put(PLUGIN_INFO_ROLE_ACTIVE_VERSION, 
roleActiveVersion == null ? null : Long.toString(roleActiveVersion));
+       }
+
+       @JsonIgnore
+       public Long getRoleActiveVersion() {
+               String activeVersionString = 
getInfo().get(PLUGIN_INFO_POLICY_ACTIVE_VERSION);
+               return StringUtils.isNotBlank(activeVersionString) ? 
Long.valueOf(activeVersionString) : null;
+       }
+
        @Override
        public String toString() {
                StringBuilder sb = new StringBuilder();
diff --git 
a/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerPolicyDelta.java
 
b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerPolicyDelta.java
index 1b69d8d..1d2b143 100644
--- 
a/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerPolicyDelta.java
+++ 
b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerPolicyDelta.java
@@ -44,8 +44,9 @@ public class RangerPolicyDelta implements 
java.io.Serializable {
     public static final int CHANGE_TYPE_RANGER_ADMIN_START  = 5;
     public static final int CHANGE_TYPE_LOG_ERROR           = 6;
     public static final int CHANGE_TYPE_INVALIDATE_POLICY_DELTAS = 7;
+    public static final int CHANGE_TYPE_ROLE_UPDATE         = 8;
 
-    private static String[] changeTypeNames = { "POLICY_CREATE", 
"POLICY_UPDATE", "POLICY_DELETE", "SERVICE_CHANGE", "SERVICE_DEF_CHANGE", 
"RANGER_ADMIN_START", "LOG_ERROR", "INVALIDATE_POLICY_DELTAS" };
+    private static String[] changeTypeNames = { "POLICY_CREATE", 
"POLICY_UPDATE", "POLICY_DELETE", "SERVICE_CHANGE", "SERVICE_DEF_CHANGE", 
"RANGER_ADMIN_START", "LOG_ERROR", "INVALIDATE_POLICY_DELTAS", "ROLE_UPDATE" };
 
     private Long                id;
     private Integer             changeType;
diff --git 
a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngine.java
 
b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngine.java
index d201aa6..72628ea 100644
--- 
a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngine.java
+++ 
b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngine.java
@@ -29,6 +29,7 @@ import org.apache.ranger.plugin.model.RangerServiceDef;
 import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyResource;
 import org.apache.ranger.plugin.util.GrantRevokeRequest;
 import org.apache.ranger.plugin.util.RangerAccessRequestUtil;
+import org.apache.ranger.plugin.util.RangerRoles;
 import org.apache.ranger.plugin.util.ServicePolicies;
 
 public interface RangerPolicyEngine {
@@ -93,7 +94,11 @@ public interface RangerPolicyEngine {
 
        List<RangerPolicy> getAllowedPolicies(String user, Set<String> 
userGroups, String accessType);
 
-       RangerPolicyEngine cloneWithDelta(ServicePolicies servicePolicies);
+       RangerPolicyEngine cloneWithDelta(ServicePolicies servicePolicies, 
RangerRoles rangerRoles);
+
+       RangerRoles getRangerRoles();
+
+       void setRangerRoles(RangerRoles rangerRoles);
 
        Set<String> getRolesFromUserAndGroups(String user, Set<String> groups);
 
diff --git 
a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngineCache.java
 
b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngineCache.java
index 015ca09..5dae0c1 100644
--- 
a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngineCache.java
+++ 
b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngineCache.java
@@ -92,7 +92,7 @@ public class RangerPolicyEngineCache {
 
 
                if (CollectionUtils.isNotEmpty(policies.getPolicyDeltas())) {
-                       RangerPolicyEngine updatedEngine = 
policyEngine.cloneWithDelta(policies);
+                       RangerPolicyEngine updatedEngine = 
policyEngine.cloneWithDelta(policies, policyEngine.getRangerRoles());
                        if (updatedEngine != null) {
                                
policyEngineCache.put(policies.getServiceName(), updatedEngine);
                                ret = updatedEngine;
@@ -120,8 +120,6 @@ public class RangerPolicyEngineCache {
                        ret.setAuditMode(servicePolicies.getAuditMode());
                        
ret.setPolicyVersion(servicePolicies.getPolicyVersion());
                        
ret.setPolicyUpdateTime(servicePolicies.getPolicyUpdateTime());
-                       ret.setUserRoles(servicePolicies.getUserRoles());
-                       ret.setGroupRoles(servicePolicies.getGroupRoles());
 
                        Map<String, ServicePolicies.SecurityZoneInfo> 
securityZonesInfo = new HashMap<>();
 
diff --git 
a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngineImpl.java
 
b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngineImpl.java
index c23a2d4..77648fd 100644
--- 
a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngineImpl.java
+++ 
b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngineImpl.java
@@ -30,6 +30,7 @@ import 
org.apache.ranger.plugin.contextenricher.RangerContextEnricher;
 import org.apache.ranger.plugin.contextenricher.RangerTagForEval;
 import org.apache.ranger.plugin.model.RangerPolicy;
 import org.apache.ranger.plugin.model.RangerPolicyDelta;
+import org.apache.ranger.plugin.model.RangerRole;
 import org.apache.ranger.plugin.model.RangerServiceDef;
 import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyResource;
 import org.apache.ranger.plugin.model.validation.RangerZoneResourceMatcher;
@@ -43,6 +44,8 @@ import org.apache.ranger.plugin.util.RangerAccessRequestUtil;
 import org.apache.ranger.plugin.util.RangerPerfTracer;
 import org.apache.ranger.plugin.util.RangerResourceTrie;
 import org.apache.ranger.plugin.util.RangerPolicyDeltaUtil;
+import org.apache.ranger.plugin.util.RangerRoles;
+import org.apache.ranger.plugin.util.RangerRolesUtil;
 import org.apache.ranger.plugin.util.ServicePolicies;
 
 import java.util.ArrayList;
@@ -74,6 +77,7 @@ public class RangerPolicyEngineImpl implements 
RangerPolicyEngine {
        private final RangerPolicyRepository tagPolicyRepository;
 
        private List<RangerContextEnricher> allContextEnrichers;
+       private RangerRoles rangerRoles;
 
        private boolean  useForwardedIPAddress;
        private String[] trustedProxyAddresses;
@@ -81,18 +85,27 @@ public class RangerPolicyEngineImpl implements 
RangerPolicyEngine {
        private Map<String, RangerPolicyRepository> policyRepositories = new 
HashMap<>();
 
        private       Map<String, RangerResourceTrie>   trieMap;
+       private Map<String, Set<String>>                userRoleMapping;
+       private Map<String, Set<String>>                groupRoleMapping;
        private       Map<String, String>               zoneTagServiceMap;
-       private final Map<String, Set<String>>          userRoleMapping;
-       private final Map<String, Set<String>>          groupRoleMapping;
        private final RangerPluginContext               pluginContext;
 
        public RangerPolicyEngineImpl(final RangerPolicyEngineImpl other, 
ServicePolicies servicePolicies) {
+               this(other,servicePolicies, null);
+       }
+
+       public RangerPolicyEngineImpl(final RangerPolicyEngineImpl other, 
ServicePolicies servicePolicies, RangerRoles rangerRoles) {
 
                long                    policyVersion = 
servicePolicies.getPolicyVersion();
 
                this.useForwardedIPAddress = other.useForwardedIPAddress;
                this.trustedProxyAddresses = other.trustedProxyAddresses;
 
+               if (rangerRoles != null) {
+                       this.rangerRoles = rangerRoles;
+                       setUserGroupRoleMapping(rangerRoles);
+               }
+
                this.pluginContext = other.pluginContext;
 
                List<RangerPolicyDelta> defaultZoneDeltas = new ArrayList<>();
@@ -206,15 +219,19 @@ public class RangerPolicyEngineImpl implements 
RangerPolicyEngine {
                }
                this.allContextEnrichers = tmpList;
 
-                // Initialize role-related information
-                userRoleMapping = 
MapUtils.isNotEmpty(servicePolicies.getUserRoles()) ? 
servicePolicies.getUserRoles() : null;
-                groupRoleMapping = 
MapUtils.isNotEmpty(servicePolicies.getGroupRoles()) ? 
servicePolicies.getGroupRoles() : null;
-
                reorderPolicyEvaluators();
 
        }
 
+       public RangerPolicyEngineImpl(String appId, ServicePolicies 
servicePolicies, RangerPolicyEngineOptions options) {
+               this(appId, servicePolicies, options, null);
+       }
+
        public RangerPolicyEngineImpl(String appId, ServicePolicies 
servicePolicies, RangerPolicyEngineOptions options, RangerPluginContext 
rangerPluginContext) {
+                       this(appId, servicePolicies, options, 
rangerPluginContext, null);
+       }
+
+       public RangerPolicyEngineImpl(String appId, ServicePolicies 
servicePolicies, RangerPolicyEngineOptions options, RangerPluginContext 
rangerPluginContext, RangerRoles rangerRoles) {
 
                if (LOG.isDebugEnabled()) {
                        LOG.debug("==> RangerPolicyEngineImpl(" + appId + ", " 
+ servicePolicies + ", " + options + ", " + rangerPluginContext + ")");
@@ -235,6 +252,11 @@ public class RangerPolicyEngineImpl implements 
RangerPolicyEngine {
 
                this.pluginContext = (rangerPluginContext != null) ? 
rangerPluginContext : new 
RangerPluginContext(servicePolicies.getServiceDef().getName());
 
+               if (rangerRoles != null) {
+                       this.rangerRoles = rangerRoles;
+                       setUserGroupRoleMapping(rangerRoles);
+               }
+
                RangerAuthContext authContext = new RangerAuthContext(this, 
null, this.pluginContext);
                this.pluginContext.setAuthContext(authContext);
 
@@ -305,10 +327,6 @@ public class RangerPolicyEngineImpl implements 
RangerPolicyEngine {
                        }
                }
 
-                // Initialize role-related information
-                userRoleMapping = 
MapUtils.isNotEmpty(servicePolicies.getUserRoles()) ? 
servicePolicies.getUserRoles() : null;
-                groupRoleMapping = 
MapUtils.isNotEmpty(servicePolicies.getGroupRoles()) ? 
servicePolicies.getGroupRoles() : null;
-
                RangerPerfTracer.log(perf);
 
                if (PERF_POLICYENGINE_INIT_LOG.isDebugEnabled()) {
@@ -323,7 +341,7 @@ public class RangerPolicyEngineImpl implements 
RangerPolicyEngine {
        }
 
        @Override
-       public RangerPolicyEngine cloneWithDelta(ServicePolicies 
servicePolicies) {
+       public RangerPolicyEngine cloneWithDelta(ServicePolicies 
servicePolicies, RangerRoles rangerRoles) {
                if (LOG.isDebugEnabled()) {
                        LOG.debug("==> cloneWithDelta(" + 
Arrays.toString(servicePolicies.getPolicyDeltas().toArray()) + ", " + 
servicePolicies.getPolicyVersion() + ")");
                }
@@ -359,7 +377,7 @@ public class RangerPolicyEngineImpl implements 
RangerPolicyEngine {
                }
 
                if (isValidDeltas) {
-                       ret = new RangerPolicyEngineImpl(this, servicePolicies);
+                       ret = new RangerPolicyEngineImpl(this, servicePolicies, 
rangerRoles);
                } else {
                        ret = null;
                }
@@ -1328,7 +1346,13 @@ public class RangerPolicyEngineImpl implements 
RangerPolicyEngine {
         @Override
         public Set<String> getRolesFromUserAndGroups(String user, Set<String> 
groups) {
                 Set<String> allRoles = new HashSet<>();
-                if (MapUtils.isNotEmpty(userRoleMapping) && 
StringUtils.isNotEmpty(user)) {
+
+                               if (rangerRoles != null ) {
+                                       userRoleMapping  = 
MapUtils.isNotEmpty(this.userRoleMapping)  ? this.userRoleMapping  : null;
+                                       groupRoleMapping = 
MapUtils.isNotEmpty(this.groupRoleMapping) ? this.groupRoleMapping : null;
+                               }
+
+                               if (MapUtils.isNotEmpty(userRoleMapping) && 
StringUtils.isNotEmpty(user)) {
                         Set<String> userRoles = userRoleMapping.get(user);
                         if (CollectionUtils.isNotEmpty(userRoles)) {
                                 allRoles.addAll(userRoles);
@@ -1353,6 +1377,14 @@ public class RangerPolicyEngineImpl implements 
RangerPolicyEngine {
                 return allRoles;
         }
 
+       public RangerRoles getRangerRoles() {
+               return this.rangerRoles;
+       }
+
+       public void setRangerRoles(RangerRoles rangerRoles) {
+               this.rangerRoles = rangerRoles;
+       }
+
        public List<RangerPolicy> getResourcePolicies(String zoneName) {
                RangerPolicyRepository zoneResourceRepository = 
policyRepositories.get(zoneName);
                return zoneResourceRepository == null ? ListUtils.EMPTY_LIST : 
zoneResourceRepository.getPolicies();
@@ -1985,4 +2017,14 @@ public class RangerPolicyEngineImpl implements 
RangerPolicyEngine {
                }
                return other;
        }
+
+       private void setUserGroupRoleMapping(RangerRoles rangerRoles) {
+               Set<RangerRole> rangerRoleSet = rangerRoles.getRangerRoles();
+               if (CollectionUtils.isNotEmpty(rangerRoleSet)) {
+                       RangerRolesUtil rangerRolesUtil = new RangerRolesUtil();
+                       rangerRolesUtil.init(rangerRoleSet);
+                       userRoleMapping  = rangerRolesUtil.getUserRoleMapping();
+                       groupRoleMapping = 
rangerRolesUtil.getGroupRoleMapping();
+               }
+       }
 }
diff --git 
a/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerAuthContext.java
 
b/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerAuthContext.java
index 842c58b..6cd1df6 100644
--- 
a/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerAuthContext.java
+++ 
b/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerAuthContext.java
@@ -39,6 +39,7 @@ import 
org.apache.ranger.plugin.policyengine.RangerResourceACLs;
 import org.apache.ranger.plugin.policyengine.RangerResourceAccessInfo;
 import org.apache.ranger.plugin.util.GrantRevokeRequest;
 import org.apache.ranger.plugin.util.RangerAccessRequestUtil;
+import org.apache.ranger.plugin.util.RangerRoles;
 import org.apache.ranger.plugin.util.ServicePolicies;
 
 import java.util.Collection;
@@ -351,9 +352,9 @@ public class RangerAuthContext implements 
RangerPolicyEngine {
     }
 
     @Override
-    public RangerPolicyEngine cloneWithDelta(ServicePolicies servicePolicies) {
+    public RangerPolicyEngine cloneWithDelta(ServicePolicies servicePolicies, 
RangerRoles rangerRoles) {
         if (policyEngine != null) {
-            return policyEngine.cloneWithDelta(servicePolicies);
+            return policyEngine.cloneWithDelta(servicePolicies, rangerRoles);
         }
         return null;
     }
@@ -366,5 +367,14 @@ public class RangerAuthContext implements 
RangerPolicyEngine {
         return null;
     }
 
+    public RangerRoles getRangerRoles() {
+        return  policyEngine.getRangerRoles();
+    }
 
+    @Override
+    public void setRangerRoles(RangerRoles rangerRoles) {
+        if (policyEngine != null) {
+            policyEngine.setRangerRoles(rangerRoles);
+        }
+    }
 }
diff --git 
a/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBasePlugin.java
 
b/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBasePlugin.java
index cf833b7..1325a40 100644
--- 
a/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBasePlugin.java
+++ 
b/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBasePlugin.java
@@ -77,6 +77,8 @@ public class RangerBasePlugin {
        private Timer                     policyEngineRefreshTimer;
        private RangerAuthContextListener authContextListener;
        private AuditProviderFactory      auditProviderFactory;
+       private RangerRolesProvider               rangerRolesProvider;
+       private RangerRoles               rangerRoles;
 
        private final BlockingQueue<DownloadTrigger> policyDownloadQueue = new 
LinkedBlockingQueue<>();
        private final DownloadTrigger                accessTrigger       = new 
DownloadTrigger();
@@ -151,6 +153,14 @@ public class RangerBasePlugin {
                this.clusterName = clusterName;
        }
 
+       public RangerRoles getRangerRoles() {
+               return this.rangerRoles;
+       }
+
+       public void setRangerRoles(RangerRoles rangerRoles) {
+               this.rangerRoles = rangerRoles;
+       }
+
        public RangerServiceDef getServiceDef() {
                RangerPolicyEngine policyEngine = this.policyEngine;
 
@@ -225,7 +235,9 @@ public class RangerBasePlugin {
 
                RangerAdminClient admin = createAdminClient(serviceName, appId, 
propertyPrefix);
 
-               refresher = new PolicyRefresher(this, serviceType, appId, 
serviceName, admin, policyDownloadQueue, cacheDir);
+               rangerRolesProvider = new RangerRolesProvider(serviceType, 
appId, serviceName, admin,  cacheDir);
+
+               refresher = new PolicyRefresher(this, serviceType, appId, 
serviceName, admin, policyDownloadQueue, cacheDir, rangerRolesProvider);
                refresher.setDaemon(true);
                refresher.startRefresher();
 
@@ -279,6 +291,7 @@ public class RangerBasePlugin {
                        ServicePolicies    servicePolicies = null;
                        boolean            isValid         = true;
                        boolean            usePolicyDeltas = false;
+                       boolean            updateRangerRolesOnly = false;
 
                        if (policies == null) {
                                policies = getDefaultSvcPolicies();
@@ -287,7 +300,7 @@ public class RangerBasePlugin {
                                        isValid = false;
                                }
                        } else {
-                               if ((policies.getPolicies() == null && 
policies.getPolicyDeltas() == null) || (policies.getPolicies() != null && 
policies.getPolicyDeltas() != null)) {
+                               if ((policies.getPolicies() != null && 
policies.getPolicyDeltas() != null)) {
                                        LOG.error("Invalid servicePolicies: 
Both policies and policy-deltas cannot be null OR both of them cannot be 
non-null");
                                        isValid = false;
                                } else if (policies.getPolicies() != null) {
@@ -302,6 +315,9 @@ public class RangerBasePlugin {
                                                isValid = false;
                                                LOG.error("Could not apply 
deltas=" + Arrays.toString(policies.getPolicyDeltas().toArray()));
                                        }
+                               } else if (policies.getPolicies() == null && 
policies.getPolicyDeltas() == null && rangerRoles != null) {
+                                       // When no policies changes and only 
the role changes happens then update the policyengine with Role changes only.
+                                       updateRangerRolesOnly = true;
                                } else {
                                        LOG.error("Should not get here!!");
                                        isValid = false;
@@ -311,11 +327,13 @@ public class RangerBasePlugin {
                        if (isValid) {
                                RangerPolicyEngine newPolicyEngine = null;
 
-                               if (!usePolicyDeltas) {
+                               if(updateRangerRolesOnly) {
+                                       
this.policyEngine.setRangerRoles(rangerRoles);
+                               } else if (!usePolicyDeltas) {
                                        if (LOG.isDebugEnabled()) {
                                                LOG.debug("policies are not 
null. Creating engine from policies");
                                        }
-                                       newPolicyEngine = new 
RangerPolicyEngineImpl(appId, policies, policyEngineOptions, 
rangerPluginContext);
+                                       newPolicyEngine = new 
RangerPolicyEngineImpl(appId, policies, policyEngineOptions, 
rangerPluginContext, rangerRoles);
                                } else {
                                        if (LOG.isDebugEnabled()) {
                                                LOG.debug("policy-deltas are 
not null");
@@ -324,7 +342,7 @@ public class RangerBasePlugin {
                                                if (LOG.isDebugEnabled()) {
                                                        LOG.debug("Non empty 
policy-deltas found. Cloning engine using policy-deltas");
                                                }
-                                               newPolicyEngine = 
oldPolicyEngine.cloneWithDelta(policies);
+                                               newPolicyEngine = 
oldPolicyEngine.cloneWithDelta(policies, rangerRoles);
                                                if (newPolicyEngine != null) {
                                                        if 
(LOG.isDebugEnabled()) {
                                                                
LOG.debug("Applied policyDeltas=" + 
Arrays.toString(policies.getPolicyDeltas().toArray()) + ")");
@@ -334,7 +352,7 @@ public class RangerBasePlugin {
                                                                
LOG.debug("Failed to apply policyDeltas=" + 
Arrays.toString(policies.getPolicyDeltas().toArray()) + "), Creating engine 
from policies");
                                                                
LOG.debug("Creating new engine from servicePolicies:[" + servicePolicies + "]");
                                                        }
-                                                       newPolicyEngine = new 
RangerPolicyEngineImpl(appId, servicePolicies, policyEngineOptions, 
rangerPluginContext);
+                                                       newPolicyEngine = new 
RangerPolicyEngineImpl(appId, servicePolicies, policyEngineOptions, 
rangerPluginContext, rangerRoles);
                                                }
                                        } else {
                                                if (LOG.isDebugEnabled()) {
diff --git 
a/agents-common/src/main/java/org/apache/ranger/plugin/util/PolicyRefresher.java
 
b/agents-common/src/main/java/org/apache/ranger/plugin/util/PolicyRefresher.java
index 0e52c31..d4d7902 100644
--- 
a/agents-common/src/main/java/org/apache/ranger/plugin/util/PolicyRefresher.java
+++ 
b/agents-common/src/main/java/org/apache/ranger/plugin/util/PolicyRefresher.java
@@ -47,6 +47,7 @@ public class PolicyRefresher extends Thread {
        private final String            serviceName;
        private final RangerAdminClient rangerAdmin;
        private final BlockingQueue<DownloadTrigger> policyDownloadQueue;
+       private final RangerRolesProvider rangerRolesProvider;
 
        private final String            cacheFileName;
        private final String            cacheDir;
@@ -58,7 +59,7 @@ public class PolicyRefresher extends Thread {
        private boolean policiesSetInPlugin;
        private boolean serviceDefSetInPlugin;
 
-       public PolicyRefresher(RangerBasePlugin plugIn, String serviceType, 
String appId, String serviceName, RangerAdminClient rangerAdmin, 
BlockingQueue<DownloadTrigger> policyDownloadQueue, String cacheDir) {
+       public PolicyRefresher(RangerBasePlugin plugIn, String serviceType, 
String appId, String serviceName, RangerAdminClient rangerAdmin, 
BlockingQueue<DownloadTrigger> policyDownloadQueue, String cacheDir, 
RangerRolesProvider rangerRolesProvider) {
                if(LOG.isDebugEnabled()) {
                        LOG.debug("==> PolicyRefresher(serviceName=" + 
serviceName + ").PolicyRefresher()");
                }
@@ -68,6 +69,7 @@ public class PolicyRefresher extends Thread {
                this.serviceName       = serviceName;
                this.rangerAdmin       = rangerAdmin;
                this.policyDownloadQueue = policyDownloadQueue;
+               this.rangerRolesProvider = rangerRolesProvider;
 
                if(StringUtils.isEmpty(appId)) {
                        appId = serviceType;
@@ -133,7 +135,7 @@ public class PolicyRefresher extends Thread {
        }
 
        public void startRefresher() {
-
+               loadRoles();
                loadPolicy();
 
                super.start();
@@ -158,6 +160,7 @@ public class PolicyRefresher extends Thread {
                while(true) {
                        try {
                                DownloadTrigger trigger = 
policyDownloadQueue.take();
+                               loadRoles();
                                loadPolicy();
                                trigger.signalCompletion();
                        } catch(InterruptedException excp) {
@@ -428,4 +431,17 @@ public class PolicyRefresher extends Thread {
                        LOG.debug("<== 
PolicyRefresher.disableCache(serviceName=" + serviceName + ")");
                }
        }
+
+       private void loadRoles() {
+               if(LOG.isDebugEnabled()) {
+                       LOG.debug("==> PolicyRefresher(serviceName=" + 
serviceName + ").loadRoles()");
+               }
+
+               //Load the Ranger UserGroup Roles
+               rangerRolesProvider.loadUserGroupRoles(plugIn);
+
+               if(LOG.isDebugEnabled()) {
+                       LOG.debug("<== PolicyRefresher(serviceName=" + 
serviceName + ").loadRoles()");
+               }
+       }
 }
diff --git 
a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRESTUtils.java
 
b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRESTUtils.java
index bdb77e7..d612e7f 100644
--- 
a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRESTUtils.java
+++ 
b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRESTUtils.java
@@ -45,6 +45,9 @@ public class RangerRESTUtils {
        public static final String REST_URL_SECURE_SERVICE_GRANT_ACCESS         
     = "/service/plugins/secure/services/grant/";
        public static final String REST_URL_SECURE_SERVICE_REVOKE_ACCESS        
     = "/service/plugins/secure/services/revoke/";
 
+       public static final String 
REST_URL_ROLE_GET_FOR_SECURE_SERVICE_IF_UPDATED   = 
"/service/roles/secure/download/";
+       public static final String REST_URL_ROLE_GET_FOR_SERVICE_IF_UPDATED     
     = "/service/roles/download/";
+
        public static final String REST_URL_SERVICE_CREATE_ROLE              = 
"/service/public/v2/api/roles/";
        public static final String REST_URL_SERVICE_DROP_ROLE         = 
"/service/public/v2/api/roles/name/";
        public static final String REST_URL_SERVICE_GET_ALL_ROLES         = 
"/service/public/v2/api/roles/names/";
@@ -53,6 +56,9 @@ public class RangerRESTUtils {
        public static final String REST_URL_SERVICE_GRANT_ROLE              = 
"/service/public/v2/api/roles/grant/";
        public static final String REST_URL_SERVICE_REVOKE_ROLE              = 
"/service/public/v2/api/roles/revoke/";
 
+       public static final String 
REST_URL_SERVICE_SERCURE_GET_USER_GROUP_ROLES = 
"/service/roles/secure/download/";
+       public static final String REST_URL_SERVICE_GET_USER_GROUP_ROLES        
 = "/service/roles/download/";
+
        public static final String REST_URL_GET_SERVICE_TAGS_IF_UPDATED = 
"/service/tags/download/";
        public static final String REST_URL_GET_SECURE_SERVICE_TAGS_IF_UPDATED 
= "/service/tags/secure/download/";
        public static final String SERVICE_NAME_PARAM = "serviceName";
@@ -68,6 +74,8 @@ public class RangerRESTUtils {
        public static final String REST_PARAM_LAST_ACTIVATION_TIME = 
"lastActivationTime";
        public static final String REST_PARAM_PLUGIN_ID                 = 
"pluginId";
 
+       public static final String REST_PARAM_LAST_KNOWN_ROLE_VERSION = 
"lastKnownRoleVersion";
+
        private static final int MAX_PLUGIN_ID_LEN = 255;
        
        public static final String REST_PARAM_CLUSTER_NAME   = "clusterName";
@@ -115,11 +123,23 @@ public class RangerRESTUtils {
                return url;
        }
 
+       public String getUrlForRoleUpdate(String baseUrl, String serviceName) {
+               String url = baseUrl + REST_URL_ROLE_GET_FOR_SERVICE_IF_UPDATED 
+ serviceName;
+
+               return url;
+       }
+
+
        public String getSecureUrlForPolicyUpdate(String baseUrl, String 
serviceName) {
                String url = baseUrl + 
REST_URL_POLICY_GET_FOR_SECURE_SERVICE_IF_UPDATED + serviceName;
                return url;
        }
 
+       public String getSecureUrlForRoleUpdate(String baseUrl, String 
serviceName) {
+               String url = baseUrl + 
REST_URL_ROLE_GET_FOR_SECURE_SERVICE_IF_UPDATED + serviceName;
+               return url;
+       }
+
        public String getUrlForTagUpdate(String baseUrl, String serviceName) {
                String url = baseUrl + REST_URL_GET_SERVICE_TAGS_IF_UPDATED + 
serviceName;
 
diff --git 
a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRoles.java 
b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRoles.java
new file mode 100644
index 0000000..354bf44
--- /dev/null
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRoles.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.ranger.plugin.util;
+
+import org.apache.ranger.plugin.model.RangerRole;
+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.Set;
+
+@JsonAutoDetect(fieldVisibility= JsonAutoDetect.Visibility.ANY)
+@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
+@JsonIgnoreProperties(ignoreUnknown=true)
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class RangerRoles implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    private String           serviceName;
+    private Long             roleVersion;
+    private Date             roleUpdateTime;
+    private Set<RangerRole>  rangerRoles;
+
+    public String getServiceName() {
+        return serviceName;
+    }
+
+    public void setServiceName(String serviceName) {
+        this.serviceName = serviceName;
+    }
+
+    public Long getRoleVersion() {
+        return roleVersion;
+    }
+
+    public void setRoleVersion(Long roleVersion) {
+        this.roleVersion = roleVersion;
+    }
+
+    public Date getRoleUpdateTime() {
+        return roleUpdateTime;
+    }
+
+    public void setRoleUpdateTime(Date roleUpdateTime) {
+        this.roleUpdateTime = roleUpdateTime;
+    }
+
+    public Set<RangerRole> getRangerRoles(){
+        return this.rangerRoles;
+    }
+
+    public void setRangerRoles(Set<RangerRole> rangerRoles){
+        this.rangerRoles = rangerRoles;
+    }
+}
diff --git 
a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRolesProvider.java
 
b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRolesProvider.java
new file mode 100644
index 0000000..5ba3cca
--- /dev/null
+++ 
b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRolesProvider.java
@@ -0,0 +1,352 @@
+/*
+ * 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 com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.ranger.admin.client.RangerAdminClient;
+import org.apache.ranger.authorization.hadoop.config.RangerConfiguration;
+import org.apache.ranger.plugin.service.RangerBasePlugin;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.Reader;
+import java.io.Writer;
+
+
+public class RangerRolesProvider {
+       private static final Log LOG = 
LogFactory.getLog(RangerRolesProvider.class);
+
+       private static final Log PERF_POLICYENGINE_INIT_LOG = 
RangerPerfTracer.getPerfLogger("policyengine.init");
+
+       private final String            serviceType;
+       private final String            serviceName;
+       private final RangerAdminClient rangerAdmin;
+
+       private final String            cacheFileName;
+       private final String                    cacheFileNamePrefix;
+       private final String            cacheDir;
+       private final Gson              gson;
+       private final boolean           disableCacheIfServiceNotFound;
+
+       private long    lastActivationTimeInMillis;
+       private long    lastKnownRoleVersion = -1L;
+       private boolean rangerUserGroupRolesSetInPlugin;
+       private boolean serviceDefSetInPlugin;
+
+       public RangerRolesProvider(String serviceType, String appId, String 
serviceName, RangerAdminClient rangerAdmin, String cacheDir) {
+               if (LOG.isDebugEnabled()) {
+                       LOG.debug("==> RangerRolesProvider(serviceName=" + 
serviceName + ").RangerRolesProvider()");
+               }
+
+               this.serviceType = serviceType;
+               this.serviceName = serviceName;
+               this.rangerAdmin = rangerAdmin;
+
+
+               if (StringUtils.isEmpty(appId)) {
+                       appId = serviceType;
+               }
+
+               cacheFileNamePrefix = "roles";
+               String cacheFilename = String.format("%s_%s_%s.json", appId, 
serviceName, cacheFileNamePrefix);
+               cacheFilename = cacheFilename.replace(File.separatorChar, '_');
+               cacheFilename = cacheFilename.replace(File.pathSeparatorChar, 
'_');
+
+               this.cacheFileName = cacheFilename;
+               this.cacheDir = cacheDir;
+
+               Gson gson = null;
+               try {
+                       gson = new 
GsonBuilder().setDateFormat("yyyyMMdd-HH:mm:ss.SSS-Z").create();
+               } catch (Throwable excp) {
+                       LOG.fatal("RangerRolesProvider(): failed to create 
GsonBuilder object", excp);
+               }
+               this.gson = gson;
+
+               String propertyPrefix = "ranger.plugin." + serviceType;
+               disableCacheIfServiceNotFound = 
RangerConfiguration.getInstance().getBoolean(propertyPrefix + 
".disable.cache.if.servicenotfound", true);
+
+               if (LOG.isDebugEnabled()) {
+                       LOG.debug("<== RangerRolesProvider(serviceName=" + 
serviceName + ").RangerRolesProvider()");
+               }
+       }
+
+       public long getLastActivationTimeInMillis() {
+               return lastActivationTimeInMillis;
+       }
+
+       public void setLastActivationTimeInMillis(long 
lastActivationTimeInMillis) {
+               this.lastActivationTimeInMillis = lastActivationTimeInMillis;
+       }
+
+       public void loadUserGroupRoles(RangerBasePlugin plugIn) {
+
+               if(LOG.isDebugEnabled()) {
+                       LOG.debug("==> RangerRolesProvider(serviceName= " + 
serviceName  + " serviceType= " + serviceType +").loadUserGroupRoles()");
+               }
+
+               RangerPerfTracer perf = null;
+
+               
if(RangerPerfTracer.isPerfTraceEnabled(PERF_POLICYENGINE_INIT_LOG)) {
+                       perf = 
RangerPerfTracer.getPerfTracer(PERF_POLICYENGINE_INIT_LOG, 
"RangerRolesProvider.loadUserGroupRoles(serviceName=" + serviceName + ")");
+                       long freeMemory = Runtime.getRuntime().freeMemory();
+                       long totalMemory = Runtime.getRuntime().totalMemory();
+                       PERF_POLICYENGINE_INIT_LOG.debug("In-Use memory: " + 
(totalMemory-freeMemory) + ", Free memory:" + freeMemory);
+               }
+
+               try {
+                       //load userGroupRoles from ranger admin
+                       RangerRoles rangerRoles = loadUserGroupRolesFromAdmin();
+
+                       if (rangerRoles == null) {
+                               //if userGroupRoles fetch from ranger Admin 
Fails, load from cache
+                               if (!rangerUserGroupRolesSetInPlugin) {
+                                       rangerRoles = 
loadUserGroupRolesFromCache();
+                               }
+                       }
+
+                       if (PERF_POLICYENGINE_INIT_LOG.isDebugEnabled()) {
+                               long freeMemory = 
Runtime.getRuntime().freeMemory();
+                               long totalMemory = 
Runtime.getRuntime().totalMemory();
+                               PERF_POLICYENGINE_INIT_LOG.debug("In-Use 
memory: " + (totalMemory - freeMemory) + ", Free memory:" + freeMemory);
+                       }
+
+                       if (rangerRoles != null) {
+                               plugIn.setRangerRoles(rangerRoles);
+                               rangerUserGroupRolesSetInPlugin = true;
+                               
setLastActivationTimeInMillis(System.currentTimeMillis());
+                               lastKnownRoleVersion = 
rangerRoles.getRoleVersion();
+                       } else {
+                               if (!rangerUserGroupRolesSetInPlugin && 
!serviceDefSetInPlugin) {
+                                       plugIn.setRangerRoles(null);
+                                       serviceDefSetInPlugin = true;
+                               }
+                       }
+               } catch (RangerServiceNotFoundException snfe) {
+                       if (disableCacheIfServiceNotFound) {
+                               disableCache();
+                               plugIn.setRangerRoles(null);
+                               
setLastActivationTimeInMillis(System.currentTimeMillis());
+                               lastKnownRoleVersion = -1L;
+                               serviceDefSetInPlugin = true;
+                       }
+               } catch (Exception excp) {
+                       LOG.error("Encountered unexpected exception, 
ignoring..", excp);
+               }
+
+               RangerPerfTracer.log(perf);
+
+               if(LOG.isDebugEnabled()) {
+                       LOG.debug("<== RangerRolesProvider(serviceName=" + 
serviceName + ").loadUserGroupRoles()");
+               }
+       }
+
+       private RangerRoles loadUserGroupRolesFromAdmin() throws 
RangerServiceNotFoundException {
+
+               if(LOG.isDebugEnabled()) {
+                       LOG.debug("==> RangerRolesProvider(serviceName=" + 
serviceName + ").loadUserGroupRolesFromAdmin()");
+               }
+
+               RangerRoles rangerRoles = null;
+
+               RangerPerfTracer perf = null;
+
+               
if(RangerPerfTracer.isPerfTraceEnabled(PERF_POLICYENGINE_INIT_LOG)) {
+                       perf = 
RangerPerfTracer.getPerfTracer(PERF_POLICYENGINE_INIT_LOG, 
"RangerRolesProvider.loadUserGroupRolesFromAdmin(serviceName=" + serviceName + 
")");
+               }
+
+               try {
+                       rangerRoles = 
rangerAdmin.getRolesIfUpdated(lastKnownRoleVersion, lastActivationTimeInMillis);
+
+                       boolean isUpdated = rangerRoles != null;
+
+                       if(isUpdated) {
+                               long newVersion = rangerRoles.getRoleVersion() 
== null ? -1 : rangerRoles.getRoleVersion().longValue();
+                               saveToCache(rangerRoles);
+                               LOG.info("RangerRolesProvider(serviceName=" + 
serviceName + "): found updated version. lastKnownRoleVersion=" + 
lastKnownRoleVersion + "; newVersion=" + newVersion );
+                       } else {
+                               if(LOG.isDebugEnabled()) {
+                                       
LOG.debug("RangerRolesProvider(serviceName=" + serviceName + ").run(): no 
update found. lastKnownRoleVersion=" + lastKnownRoleVersion );
+                               }
+                       }
+               } catch (RangerServiceNotFoundException snfe) {
+                       LOG.error("RangerRolesProvider(serviceName=" + 
serviceName + "): failed to find service. Will clean up local cache of 
rangerRoles (" + lastKnownRoleVersion + ")", snfe);
+                       throw snfe;
+               } catch (Exception excp) {
+                       LOG.error("RangerRolesProvider(serviceName=" + 
serviceName + "): failed to refresh rangerRoles. Will continue to use last 
known version of rangerRoles (" + "lastKnowRoleVersion= " + 
lastKnownRoleVersion, excp);
+                       rangerRoles = null;
+               }
+
+               RangerPerfTracer.log(perf);
+
+               if(LOG.isDebugEnabled()) {
+                       LOG.debug("<== RangerRolesProvider(serviceName=" + 
serviceName + " serviceType= " + serviceType + " 
).loadUserGroupRolesFromAdmin()");
+                }
+
+                return rangerRoles;
+       }
+
+       private RangerRoles loadUserGroupRolesFromCache() {
+
+               RangerRoles rangerRoles = null;
+
+               if (LOG.isDebugEnabled()) {
+                       LOG.debug("==> RangerRolesProvider(serviceName=" + 
serviceName + ").loadUserGroupRolesFromCache()");
+               }
+
+               File cacheFile = cacheDir == null ? null : new File(cacheDir + 
File.separator + cacheFileName);
+
+               if (cacheFile != null && cacheFile.isFile() && 
cacheFile.canRead()) {
+                       Reader reader = null;
+
+                       RangerPerfTracer perf = null;
+
+                       if 
(RangerPerfTracer.isPerfTraceEnabled(PERF_POLICYENGINE_INIT_LOG)) {
+                               perf = 
RangerPerfTracer.getPerfTracer(PERF_POLICYENGINE_INIT_LOG, 
"RangerRolesProvider.loadUserGroupRolesFromCache(serviceName=" + serviceName + 
")");
+                       }
+
+                       try {
+                               reader = new FileReader(cacheFile);
+
+                               rangerRoles = gson.fromJson(reader, 
RangerRoles.class);
+
+                               if (rangerRoles != null) {
+                                       if (!StringUtils.equals(serviceName, 
rangerRoles.getServiceName())) {
+                                               LOG.warn("ignoring unexpected 
serviceName '" + rangerRoles.getServiceName() + "' in cache file '" + 
cacheFile.getAbsolutePath() + "'");
+
+                                               
rangerRoles.setServiceName(serviceName);
+                                       }
+
+                                       lastKnownRoleVersion = 
rangerRoles.getRoleVersion() == null ? -1 : 
rangerRoles.getRoleVersion().longValue();
+                               }
+                       } catch (Exception excp) {
+                               LOG.error("failed to load userGroupRoles from 
cache file " + cacheFile.getAbsolutePath(), excp);
+                       } finally {
+                               RangerPerfTracer.log(perf);
+
+                               if (reader != null) {
+                                       try {
+                                               reader.close();
+                                       } catch (Exception excp) {
+                                               LOG.error("error while closing 
opened cache file " + cacheFile.getAbsolutePath(), excp);
+                                       }
+                               }
+                       }
+               } else {
+                       LOG.warn("cache file does not exist or not readable '" 
+ (cacheFile == null ? null : cacheFile.getAbsolutePath()) + "'");
+               }
+
+               if (LOG.isDebugEnabled()) {
+                       LOG.debug("<== RangerRolesProvider(serviceName=" + 
serviceName + ").RangerRolesProvider()");
+               }
+
+               return rangerRoles;
+       }
+
+       public void saveToCache(RangerRoles rangerRoles) {
+               if(LOG.isDebugEnabled()) {
+                       LOG.debug("==> RangerRolesProvider(serviceName=" + 
serviceName + ").saveToCache()");
+               }
+
+               if(rangerRoles != null) {
+                       File cacheFile = null;
+                       if (cacheDir != null) {
+                               // Create the cacheDir if it doesn't already 
exist
+                               File cacheDirTmp = new File(cacheDir);
+                               if (cacheDirTmp.exists()) {
+                                       cacheFile =  new File(cacheDir + 
File.separator + cacheFileName);
+                               } else {
+                                       try {
+                                               cacheDirTmp.mkdirs();
+                                               cacheFile =  new File(cacheDir 
+ File.separator + cacheFileName);
+                                       } catch (SecurityException ex) {
+                                               LOG.error("Cannot create cache 
directory", ex);
+                                       }
+                               }
+                       }
+
+                       if(cacheFile != null) {
+
+                               RangerPerfTracer perf = null;
+
+                               
if(RangerPerfTracer.isPerfTraceEnabled(PERF_POLICYENGINE_INIT_LOG)) {
+                                       perf = 
RangerPerfTracer.getPerfTracer(PERF_POLICYENGINE_INIT_LOG, 
"RangerRolesProvider.saveToCache(serviceName=" + serviceName + ")");
+                               }
+
+                               Writer writer = null;
+
+                               try {
+                                       writer = new FileWriter(cacheFile);
+
+                               gson.toJson(rangerRoles, writer);
+                       } catch (Exception excp) {
+                                       LOG.error("failed to save rangerRoles 
to cache file '" + cacheFile.getAbsolutePath() + "'", excp);
+                       } finally {
+                                       if(writer != null) {
+                                               try {
+                                                       writer.close();
+                                               } catch(Exception excp) {
+                                                       LOG.error("error while 
closing opened cache file '" + cacheFile.getAbsolutePath() + "'", excp);
+                                               }
+                                       }
+                               }
+
+                               RangerPerfTracer.log(perf);
+                       }
+               } else {
+                       LOG.info("rangerRoles is null. Nothing to save in 
cache");
+               }
+
+               if(LOG.isDebugEnabled()) {
+                       LOG.debug("<== 
RangerRolesProvider.saveToCache(serviceName=" + serviceName + ")");
+               }
+       }
+
+       private void disableCache() {
+               if (LOG.isDebugEnabled()) {
+                       LOG.debug("==> 
RangerRolesProvider.disableCache(serviceName=" + serviceName + ")");
+               }
+
+               File cacheFile = cacheDir == null ? null : new File(cacheDir + 
File.separator + cacheFileName);
+
+               if(cacheFile != null && cacheFile.isFile() && 
cacheFile.canRead()) {
+                       LOG.warn("Cleaning up local RangerRoles cache");
+                       String renamedCacheFile = cacheFile.getAbsolutePath() + 
"_" + System.currentTimeMillis();
+                       if (!cacheFile.renameTo(new File(renamedCacheFile))) {
+                               LOG.error("Failed to move " + 
cacheFile.getAbsolutePath() + " to " + renamedCacheFile);
+                       } else {
+                               LOG.warn("Moved " + cacheFile.getAbsolutePath() 
+ " to " + renamedCacheFile);
+                       }
+               } else {
+                       if (LOG.isDebugEnabled()) {
+                               LOG.debug("No local RangerRoles cache found. No 
need to disable it!");
+                       }
+               }
+
+               if (LOG.isDebugEnabled()) {
+                       LOG.debug("<== 
RangerRolesProvider.disableCache(serviceName=" + serviceName + ")");
+               }
+       }
+}
diff --git 
a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRolesUtil.java
 
b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRolesUtil.java
new file mode 100644
index 0000000..c96d250
--- /dev/null
+++ 
b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRolesUtil.java
@@ -0,0 +1,106 @@
+/*
+ * 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.lang.StringUtils;
+import org.apache.ranger.plugin.model.RangerRole;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class RangerRolesUtil {
+
+    Map<String, Set<String>> userRoleMapping = new HashMap<>();
+    Map<String, Set<String>> groupRoleMapping = new HashMap<>();
+
+    public Map<String, Set<String>> getUserRoleMapping() {
+        return this.userRoleMapping;
+    }
+
+    public Map<String, Set<String>> getGroupRoleMapping() {
+        return this.groupRoleMapping;
+    }
+
+    public RangerRoles init(Set<RangerRole> rangerRoles) {
+        RangerRoles ret = new RangerRoles();
+        if (rangerRoles != null) {
+            if (CollectionUtils.isNotEmpty(rangerRoles)) {
+                for (RangerRole role : rangerRoles) {
+                    Set<RangerRole> containedRoles = 
getAllContainedRoles(rangerRoles, role);
+                    buildMap(userRoleMapping, role, containedRoles, true);
+                    buildMap(groupRoleMapping, role, containedRoles, false);
+                }
+            }
+        }
+        return ret;
+    }
+
+    public Set<RangerRole> getAllContainedRoles(Set<RangerRole> rangerRoles, 
RangerRole role) {
+        Set<RangerRole> allRoles = new HashSet<>();
+        allRoles.add(role);
+        addContainedRoles(allRoles, rangerRoles, role);
+        return allRoles;
+    }
+
+    private void addContainedRoles(Set<RangerRole> allRoles, Set<RangerRole> 
rangerRoles, RangerRole role) {
+        List<RangerRole.RoleMember> roleMembers = role.getRoles();
+        for (RangerRole.RoleMember roleMember : roleMembers) {
+            RangerRole containedRole = getContainedRole(rangerRoles, 
roleMember.getName());
+            if (containedRole!= null && !allRoles.contains(containedRole)) {
+                allRoles.add(containedRole);
+                addContainedRoles(allRoles, rangerRoles, containedRole);
+            }
+        }
+    }
+
+    public void buildMap(Map<String, Set<String>> map, RangerRole role, 
Set<RangerRole> containedRoles, boolean isUser) {
+        buildMap(map, role, role.getName(), isUser);
+        for (RangerRole containedRole : containedRoles) {
+            buildMap(map, containedRole, role.getName(), isUser);
+        }
+    }
+
+    public void buildMap(Map<String, Set<String>> map, RangerRole role, String 
roleName, boolean isUser) {
+        for (RangerRole.RoleMember userOrGroup : isUser ? role.getUsers() : 
role.getGroups()) {
+            if (StringUtils.isNotEmpty(userOrGroup.getName())) {
+                Set<String> roleNames = map.get(userOrGroup.getName());
+                if (roleNames == null) {
+                    roleNames = new HashSet<>();
+                    map.put(userOrGroup.getName(), roleNames);
+                }
+                roleNames.add(roleName);
+            }
+        }
+    }
+
+    public RangerRole getContainedRole(Set<RangerRole> rangerRoles, String 
role) {
+        return (rangerRoles
+                .stream()
+                .filter(containedRole -> role.equals(containedRole.getName()))
+                .findAny()
+                .orElse(null));
+    }
+}
+
+
diff --git 
a/agents-common/src/main/java/org/apache/ranger/plugin/util/ServicePolicies.java
 
b/agents-common/src/main/java/org/apache/ranger/plugin/util/ServicePolicies.java
index 8c63434..f6beac6 100644
--- 
a/agents-common/src/main/java/org/apache/ranger/plugin/util/ServicePolicies.java
+++ 
b/agents-common/src/main/java/org/apache/ranger/plugin/util/ServicePolicies.java
@@ -25,7 +25,6 @@ import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
@@ -60,8 +59,6 @@ public class ServicePolicies implements java.io.Serializable {
        private TagPolicies        tagPolicies;
        private Map<String, SecurityZoneInfo> securityZones;
        private List<RangerPolicyDelta> policyDeltas;
-       private Map<String, Set<String>> userRoles;
-       private Map<String, Set<String>> groupRoles;
 
        /**
         * @return the serviceName
@@ -162,12 +159,6 @@ public class ServicePolicies implements 
java.io.Serializable {
                this.securityZones = securityZones;
        }
 
-       public Map<String, Set<String>> getUserRoles() { return userRoles; }
-       public Map<String, Set<String>> getGroupRoles() { return groupRoles; }
-
-       public void setUserRoles(Map<String, Set<String>> userRoles) { 
this.userRoles = userRoles; }
-       public void setGroupRoles(Map<String, Set<String>> groupRoles) { 
this.groupRoles = groupRoles; }
-
        @Override
        public String toString() {
                return "serviceName=" + serviceName + ", "
@@ -179,9 +170,7 @@ public class ServicePolicies implements 
java.io.Serializable {
                                + "policyDeltas=" + policyDeltas + ", "
                                + "serviceDef=" + serviceDef + ", "
                                + "auditMode=" + auditMode + ", "
-                               + "securityZones=" + securityZones + ", "
-                               + "userRoles=" + userRoles + ", "
-                               + "groupRoles=" + groupRoles + ", "
+                               + "securityZones=" + securityZones
                                ;
        }
        public List<RangerPolicyDelta> getPolicyDeltas() { return 
this.policyDeltas; }
@@ -363,8 +352,6 @@ public class ServicePolicies implements 
java.io.Serializable {
                ret.setServiceDef(source.getServiceDef());
                ret.setPolicyUpdateTime(source.getPolicyUpdateTime());
                ret.setSecurityZones(source.getSecurityZones());
-               ret.setUserRoles(source.getUserRoles());
-               ret.setGroupRoles(source.getGroupRoles());
                ret.setPolicies(Collections.emptyList());
                ret.setPolicyDeltas(null);
                if (source.getTagPolicies() != null) {
diff --git 
a/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyEngine.java
 
b/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyEngine.java
index d0e0cfc..83bbffc 100644
--- 
a/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyEngine.java
+++ 
b/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyEngine.java
@@ -36,6 +36,7 @@ import 
org.apache.ranger.plugin.audit.RangerDefaultAuditHandler;
 import org.apache.ranger.plugin.contextenricher.RangerTagForEval;
 import org.apache.ranger.plugin.model.RangerPolicy;
 import org.apache.ranger.plugin.model.RangerPolicyDelta;
+import org.apache.ranger.plugin.model.RangerRole;
 import org.apache.ranger.plugin.model.RangerServiceDef;
 import org.apache.ranger.plugin.model.RangerValiditySchedule;
 import 
org.apache.ranger.plugin.model.validation.RangerValidityScheduleValidator;
@@ -44,6 +45,7 @@ import 
org.apache.ranger.plugin.policyengine.TestPolicyEngine.PolicyEngineTestCa
 import 
org.apache.ranger.plugin.policyevaluator.RangerValidityScheduleEvaluator;
 import org.apache.ranger.plugin.util.RangerAccessRequestUtil;
 import org.apache.ranger.plugin.util.RangerRequestedResources;
+import org.apache.ranger.plugin.util.RangerRoles;
 import org.apache.ranger.plugin.util.ServicePolicies;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
@@ -57,7 +59,9 @@ import java.io.InputStreamReader;
 import java.io.OutputStreamWriter;
 import java.lang.reflect.Type;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Date;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
@@ -410,8 +414,6 @@ public class TestPolicyEngine {
                servicePolicies.setServiceDef(testCase.serviceDef);
                servicePolicies.setPolicies(testCase.policies);
                servicePolicies.setSecurityZones(testCase.securityZones);
-               servicePolicies.setUserRoles(testCase.userRoles);
-               servicePolicies.setGroupRoles(testCase.groupRoles);
 
                if (StringUtils.isNotBlank(testCase.auditMode)) {
                        servicePolicies.setAuditMode(testCase.auditMode);
@@ -446,7 +448,43 @@ public class TestPolicyEngine {
                RangerPluginContext pluginContext = new 
RangerPluginContext("hive");
                pluginContext.setClusterName("cl1");
                pluginContext.setClusterType("on-prem");
-               RangerPolicyEngine policyEngine = new 
RangerPolicyEngineImpl(testName, servicePolicies, policyEngineOptions,  
pluginContext);
+
+               RangerRoles rangerRoles = new RangerRoles();
+               rangerRoles.setServiceName(testCase.serviceName);
+               rangerRoles.setRoleVersion(-1L);
+               Set<RangerRole> rangerRoleSet = new HashSet<>();
+
+               Map<String, Set<String>> userRoleMapping = testCase.userRoles;
+               Map<String, Set<String>> groupRoleMapping = testCase.groupRoles;
+               if (userRoleMapping != null) {
+                       for (Map.Entry<String, Set<String>> userRole : 
userRoleMapping.entrySet()) {
+                               String user = userRole.getKey();
+                               Set<String> userRoles = userRole.getValue();
+                               RangerRole.RoleMember userRoleMember = new 
RangerRole.RoleMember(user, true);
+                               List<RangerRole.RoleMember> userRoleMembers = 
Arrays.asList(userRoleMember);
+                               for (String usrRole : userRoles) {
+                                       RangerRole rangerUserRole = new 
RangerRole(usrRole, usrRole, null, userRoleMembers, null);
+                                       rangerRoleSet.add(rangerUserRole);
+                               }
+                       }
+               }
+
+               if (groupRoleMapping != null) {
+                       for (Map.Entry<String, Set<String>> groupRole : 
groupRoleMapping.entrySet()) {
+                               String group = groupRole.getKey();
+                               Set<String> groupRoles = groupRole.getValue();
+                               RangerRole.RoleMember groupRoleMember = new 
RangerRole.RoleMember(group, true);
+                               List<RangerRole.RoleMember> groupRoleMembers = 
Arrays.asList(groupRoleMember);
+                               for (String grpRole : groupRoles) {
+                                       RangerRole rangerGroupRole = new 
RangerRole(grpRole, grpRole, null, groupRoleMembers, null);
+                                       rangerRoleSet.add(rangerGroupRole);
+                               }
+                       }
+               }
+
+               rangerRoles.setRangerRoles(rangerRoleSet);
+
+               RangerPolicyEngine policyEngine = new 
RangerPolicyEngineImpl(testName, servicePolicies, policyEngineOptions,  
pluginContext, rangerRoles);
 
                policyEngine.setUseForwardedIPAddress(useForwardedIPAddress);
                policyEngine.setTrustedProxyAddresses(trustedProxyAddresses);
@@ -464,8 +502,8 @@ public class TestPolicyEngine {
                if (testCase.updatedPolicies != null) {
                        
servicePolicies.setPolicyDeltas(testCase.updatedPolicies.policyDeltas);
                        
servicePolicies.setSecurityZones(testCase.updatedPolicies.securityZones);
-                       RangerPolicyEngine updatedPolicyEngine = 
policyEngine.cloneWithDelta(servicePolicies);
-                       RangerPolicyEngine 
updatedPolicyEngineForResourceAccessInfo = 
policyEngineForResourceAccessInfo.cloneWithDelta(servicePolicies);
+                       RangerPolicyEngine updatedPolicyEngine = 
policyEngine.cloneWithDelta(servicePolicies, rangerRoles);
+                       RangerPolicyEngine 
updatedPolicyEngineForResourceAccessInfo = 
policyEngineForResourceAccessInfo.cloneWithDelta(servicePolicies, rangerRoles);
                        runTestCaseTests(updatedPolicyEngine, 
updatedPolicyEngineForResourceAccessInfo, testCase.serviceDef, testName, 
testCase.updatedTests);
                }
        }
diff --git 
a/knox-agent/src/main/java/org/apache/ranger/admin/client/RangerAdminJersey2RESTClient.java
 
b/knox-agent/src/main/java/org/apache/ranger/admin/client/RangerAdminJersey2RESTClient.java
index 5dcce11..53be9c2 100644
--- 
a/knox-agent/src/main/java/org/apache/ranger/admin/client/RangerAdminJersey2RESTClient.java
+++ 
b/knox-agent/src/main/java/org/apache/ranger/admin/client/RangerAdminJersey2RESTClient.java
@@ -206,6 +206,93 @@ public class RangerAdminJersey2RESTClient extends 
AbstractRangerAdminClient {
        }
 
        @Override
+       public RangerRoles getRolesIfUpdated(final long lastKnowRoleVersion, 
final long lastActivationTimeInMillis) throws Exception {
+               if(LOG.isDebugEnabled()) {
+                       LOG.debug("==> 
RangerAdminJersey2RESTClient.getRolesIfUpdated(" + lastKnowRoleVersion + ", " + 
lastActivationTimeInMillis + ")");
+               }
+
+               UserGroupInformation user = MiscUtil.getUGILoginUser();
+               boolean isSecureMode = user != null && 
UserGroupInformation.isSecurityEnabled();
+
+               String      relativeURL = null;
+               RangerRoles ret         = null;
+               Response    response    = null;
+
+               Map<String, String> queryParams = new HashMap<String, String>();
+               
queryParams.put(RangerRESTUtils.REST_PARAM_LAST_KNOWN_ROLE_VERSION, 
Long.toString(lastKnowRoleVersion));
+               
queryParams.put(RangerRESTUtils.REST_PARAM_LAST_ACTIVATION_TIME, 
Long.toString(lastActivationTimeInMillis));
+               queryParams.put(RangerRESTUtils.REST_PARAM_PLUGIN_ID, 
_pluginId);
+               queryParams.put(RangerRESTUtils.REST_PARAM_CLUSTER_NAME, 
_clusterName);
+
+               if (isSecureMode) {
+                       if (LOG.isDebugEnabled()) {
+                               LOG.debug("Checking Roles if updated as user : 
" + user);
+                       }
+
+                       relativeURL = 
_utils.getSecureUrlForRoleUpdate(_baseUrl, _serviceName);
+                       final String secureRelativeUrl = relativeURL;
+                       PrivilegedAction<Response> action = new 
PrivilegedAction<Response>() {
+                               public Response run() {
+                                       return get(queryParams, 
secureRelativeUrl);
+                               }
+                       };
+                       response = user.doAs(action);
+               } else {
+                       if (LOG.isDebugEnabled()) {
+                               LOG.debug("Checking Roles if updated with old 
api call");
+                       }
+
+                       relativeURL = _utils.getUrlForRoleUpdate(_baseUrl, 
_serviceName);
+                       response = get(queryParams, relativeURL);
+               }
+
+               int httpResponseCode = response == null ? -1 : 
response.getStatus();
+               String body = null;
+
+               switch (httpResponseCode) {
+                       case 200:
+                               body = response.readEntity(String.class);
+
+                               if (LOG.isDebugEnabled()) {
+                                       LOG.debug("Response from 200 server: " 
+ body);
+                               }
+
+                               Gson gson = getGson();
+                               ret = gson.fromJson(body, RangerRoles.class);
+
+                               if (LOG.isDebugEnabled()) {
+                                       LOG.debug("Deserialized response to: " 
+ ret);
+                               }
+                               break;
+                       case 304:
+                               LOG.debug("Got response: 304. Ok. Returning 
null");
+                               break;
+                       case -1:
+                               LOG.warn("Unexpected: Null response from policy 
server while trying to get policies! Returning null!");
+                               break;
+                       case 404: {
+                               if (response.hasEntity()) {
+                                       body = 
response.readEntity(String.class);
+                                       if (StringUtils.isNotBlank(body)) {
+                                               
RangerServiceNotFoundException.throwExceptionIfServiceNotFound(_serviceName, 
body);
+                                       }
+                               }
+                               LOG.warn("Received 404 error code with body:[" 
+ body + "], Ignoring");
+                               break;
+                       }
+                       default:
+                               body = response.readEntity(String.class);
+                               LOG.warn(String.format("Unexpected: Received 
status[%d] with body[%s] form url[%s]", httpResponseCode, body, relativeURL));
+                               break;
+               }
+
+               if(LOG.isDebugEnabled()) {
+                       LOG.debug("<== 
RangerAdminJersey2RESTClient.getRolesIfUpdated(" + lastKnowRoleVersion + ", " + 
lastActivationTimeInMillis + "): " + ret);
+               }
+               return ret;
+       }
+
+       @Override
        public void grantAccess(GrantRevokeRequest request) throws Exception {
 
                if(LOG.isDebugEnabled()) {
diff --git a/security-admin/db/mysql/optimized/current/ranger_core_db_mysql.sql 
b/security-admin/db/mysql/optimized/current/ranger_core_db_mysql.sql
index 8e42bd9..1857a77 100644
--- a/security-admin/db/mysql/optimized/current/ranger_core_db_mysql.sql
+++ b/security-admin/db/mysql/optimized/current/ranger_core_db_mysql.sql
@@ -1234,6 +1234,8 @@ CREATE TABLE `x_service_version_info` (
 `policy_update_time` datetime NULL DEFAULT NULL,
 `tag_version` bigint(20) NOT NULL DEFAULT 0,
 `tag_update_time` datetime NULL DEFAULT NULL,
+`role_version` bigint(20) NOT NULL DEFAULT 0,
+`role_update_time` datetime NULL DEFAULT NULL,
 primary key (`id`),
 CONSTRAINT `x_service_version_info_FK_service_id` FOREIGN KEY (`service_id`) 
REFERENCES `x_service` (`id`)
 )ROW_FORMAT=DYNAMIC;
diff --git 
a/security-admin/db/mysql/patches/043-add-role-version-in-serviceVersionInfo.sql
 
b/security-admin/db/mysql/patches/043-add-role-version-in-serviceVersionInfo.sql
new file mode 100644
index 0000000..def5678
--- /dev/null
+++ 
b/security-admin/db/mysql/patches/043-add-role-version-in-serviceVersionInfo.sql
@@ -0,0 +1,34 @@
+-- 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.
+
+drop procedure if exists add-role-version-in-serviceVersionInfo;
+
+delimiter ;;
+create procedure add-role-version-in-serviceVersionInfo() begin
+
+if not exists (select * from information_schema.columns where 
table_schema=database() and table_name = 'x_service_version_info' and 
column_name='role_version') then
+        ALTER TABLE x_service_version_info ADD role_version bigint(20) NOT 
NULL DEFAULT 0;
+end if;
+end;;
+
+if not exists (select * from information_schema.columns where 
table_schema=database() and table_name = 'x_service_version_info' and 
column_name='role_update_time') then
+        ALTER TABLE x_service_version_info ADD role_update_time datetime NULL 
DEFAULT NULL;
+end if;
+end;;
+
+delimiter ;
+call add-role-version-in-serviceVersionInfo();
+
+drop procedure if exists add-role-version-in-serviceVersionInfo;
diff --git 
a/security-admin/db/oracle/optimized/current/ranger_core_db_oracle.sql 
b/security-admin/db/oracle/optimized/current/ranger_core_db_oracle.sql
index 1b158c9..0293abe 100644
--- a/security-admin/db/oracle/optimized/current/ranger_core_db_oracle.sql
+++ b/security-admin/db/oracle/optimized/current/ranger_core_db_oracle.sql
@@ -1310,6 +1310,8 @@ policy_version NUMBER(20) DEFAULT 0 NOT NULL,
 policy_update_time DATE DEFAULT NULL NULL,
 tag_version NUMBER(20) DEFAULT 0 NOT NULL,
 tag_update_time DATE DEFAULT NULL NULL,
+role_version NUMBER(20) DEFAULT 0 NOT NULL,
+role_update_time DATE DEFAULT NULL NULL,
 primary key (id),
 CONSTRAINT x_svc_ver_info_FK_service_id FOREIGN KEY (service_id) REFERENCES 
x_service(id)
 );
diff --git 
a/security-admin/db/oracle/patches/043-add-role-version-in-serviceVersionInfo.sql
 
b/security-admin/db/oracle/patches/043-add-role-version-in-serviceVersionInfo.sql
new file mode 100644
index 0000000..a3fd43d
--- /dev/null
+++ 
b/security-admin/db/oracle/patches/043-add-role-version-in-serviceVersionInfo.sql
@@ -0,0 +1,28 @@
+-- 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.
+
+DECLARE
+        v_count number:=0;
+BEGIN
+        select count(*) into v_count from user_tab_cols where 
table_name='X_SERVICE_VERSION_INFO' and column_name='ROLE_VERSION';
+        if (v_count = 0) then
+                execute immediate 'ALTER TABLE x_service_version_info ADD 
role_version NUMBER(20) DEFAULT 0 NOT NULL';
+        end if;
+
+        select count(*) into v_count from user_tab_cols where 
table_name='X_SERVICE_VERSION_INFO' and column_name='ROLE_UPDATE_TIME';
+        if (v_count = 0) then
+                execute immediate 'ALTER TABLE x_service_version_info ADD 
role_update_time DATE DEFAULT NULL NULL';
+        end if;
+END;/
diff --git 
a/security-admin/db/postgres/optimized/current/ranger_core_db_postgres.sql 
b/security-admin/db/postgres/optimized/current/ranger_core_db_postgres.sql
index 0034759..1d1a31c 100644
--- a/security-admin/db/postgres/optimized/current/ranger_core_db_postgres.sql
+++ b/security-admin/db/postgres/optimized/current/ranger_core_db_postgres.sql
@@ -1165,6 +1165,8 @@ policy_version bigint NOT NULL DEFAULT '0',
 policy_update_time TIMESTAMP DEFAULT NULL,
 tag_version bigint NOT NULL DEFAULT '0',
 tag_update_time TIMESTAMP DEFAULT NULL,
+role_version bigint NOT NULL DEFAULT '0',
+role_update_time TIMESTAMP DEFAULT NULL,
 primary key (id),
 CONSTRAINT x_service_version_info_service_id FOREIGN KEY (service_id) 
REFERENCES x_service (id)
 );
diff --git 
a/security-admin/db/postgres/patches/043-add-role-version-in-serviceVersionInfo.sql
 
b/security-admin/db/postgres/patches/043-add-role-version-in-serviceVersionInfo.sql
new file mode 100644
index 0000000..4801ec3
--- /dev/null
+++ 
b/security-admin/db/postgres/patches/043-add-role-version-in-serviceVersionInfo.sql
@@ -0,0 +1,36 @@
+-- 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.
+
+-- function add-role-version-in-serviceVersionInfo
+select 'delimiter start';
+CREATE OR REPLACE FUNCTION add-role-version-in-serviceVersionInfo()
+RETURNS void AS $$
+DECLARE
+ v_column_exists integer := 0;
+BEGIN
+ select count(*) into v_column_exists from pg_attribute where attrelid 
in(select oid from pg_class where relname='x_service_version_info') and 
attname='role_version';
+ IF v_column_exists = 0 THEN
+  ALTER TABLE x_service_version_info ADD COLUMN role_version bigint NOT NULL 
DEFAULT '0';
+ END IF;
+  select count(*) into v_column_exists from pg_attribute where attrelid 
in(select oid from pg_class where relname='x_service_version_info') and 
attname='role_update_time';
+ IF v_column_exists = 0 THEN
+  ALTER TABLE x_service_version_info ADD COLUMN role_update_time TIMESTAMP 
DEFAULT NULL;
+ END IF;
+END;
+$$ LANGUAGE plpgsql;
+select 'delimiter end';
+
+select add-role-version-in-serviceVersionInfo();
+select 'delimiter end';
diff --git 
a/security-admin/db/sqlanywhere/optimized/current/ranger_core_db_sqlanywhere.sql
 
b/security-admin/db/sqlanywhere/optimized/current/ranger_core_db_sqlanywhere.sql
index 9dc7656..5381398 100644
--- 
a/security-admin/db/sqlanywhere/optimized/current/ranger_core_db_sqlanywhere.sql
+++ 
b/security-admin/db/sqlanywhere/optimized/current/ranger_core_db_sqlanywhere.sql
@@ -1005,6 +1005,8 @@ CREATE TABLE dbo.x_service_version_info(
        policy_update_time datetime DEFAULT NULL NULL,
        tag_version bigint NOT NULL DEFAULT 0,
        tag_update_time datetime DEFAULT NULL NULL,
+       role_version bigint NOT NULL DEFAULT 0,
+       role_update_time datetime DEFAULT NULL NULL,
        CONSTRAINT x_service_version_info_PK_id PRIMARY KEY CLUSTERED(id)
 )
 GO
diff --git 
a/security-admin/db/sqlanywhere/patches/043-add-role-version-in-serviceVersionInfo.sql
 
b/security-admin/db/sqlanywhere/patches/043-add-role-version-in-serviceVersionInfo.sql
new file mode 100644
index 0000000..3862ea3
--- /dev/null
+++ 
b/security-admin/db/sqlanywhere/patches/043-add-role-version-in-serviceVersionInfo.sql
@@ -0,0 +1,25 @@
+-- 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.
+
+IF NOT EXISTS(select * from SYS.SYSCOLUMNS where tname = 
'x_service_version_info' and cname = 'role_version') THEN
+               ALTER TABLE dbo.x_service_version_info ADD role_version bigint 
NOT NULL DEFAULT 0;
+END IF;
+GO
+IF NOT EXISTS(select * from SYS.SYSCOLUMNS where tname = 
'x_service_version_info' and cname = 'role_update_time') THEN
+               ALTER TABLE dbo.x_service_version_info ADD role_update_time 
datetime DEFAULT NULL NULL;
+END IF;
+GO
+
+exit
diff --git 
a/security-admin/db/sqlserver/optimized/current/ranger_core_db_sqlserver.sql 
b/security-admin/db/sqlserver/optimized/current/ranger_core_db_sqlserver.sql
index 9383d1a..d24de68 100644
--- a/security-admin/db/sqlserver/optimized/current/ranger_core_db_sqlserver.sql
+++ b/security-admin/db/sqlserver/optimized/current/ranger_core_db_sqlserver.sql
@@ -2048,6 +2048,8 @@ CREATE TABLE [dbo].[x_service_version_info](
         [policy_update_time] [datetime2] DEFAULT NULL NULL,
         [tag_version] [bigint] NOT NULL DEFAULT 0,
         [tag_update_time] [datetime2] DEFAULT NULL NULL,
+        [policy_version] [bigint] NOT NULL DEFAULT 0,
+        [role_update_time] [datetime2] DEFAULT NULL NULL,
         PRIMARY KEY CLUSTERED
 (
         [id] ASC
diff --git 
a/security-admin/db/sqlserver/patches/042-add-role-version-in-serviceVersionInfo.sql
 
b/security-admin/db/sqlserver/patches/042-add-role-version-in-serviceVersionInfo.sql
new file mode 100644
index 0000000..4f9b379
--- /dev/null
+++ 
b/security-admin/db/sqlserver/patches/042-add-role-version-in-serviceVersionInfo.sql
@@ -0,0 +1,29 @@
+-- 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.
+
+GO
+IF NOT EXISTS(select * from INFORMATION_SCHEMA.columns where table_name = 
'x_service_version_info' and column_name = 'role_version')
+BEGIN
+       ALTER TABLE [dbo].[x_service_version_info] ADD [policy_version] 
[bigint] NOT NULL DEFAULT 0;
+END
+GO
+GO
+IF NOT EXISTS(select * from INFORMATION_SCHEMA.columns where table_name = 
'x_service_version_info' and column_name = 'role_update_time')
+BEGIN
+       ALTER TABLE [dbo].[x_service_version_info] ADD [role_update_time] 
[datetime2] DEFAULT NULL NULL;
+END
+GO
+
+exit
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 63959c9..9d26fb5 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
@@ -684,24 +684,34 @@ public class AssetMgr extends AssetMgrBase {
                pluginSvcVersionInfo.setHostName(hostName);
                pluginSvcVersionInfo.setIpAddress(ipAddress);
 
-               if (entityType == RangerPluginInfo.ENTITY_TYPE_POLICIES) {
-                       
pluginSvcVersionInfo.setPolicyActiveVersion(lastKnownVersion);
-                       
pluginSvcVersionInfo.setPolicyActivationTime(lastActivationTime);
-                       
pluginSvcVersionInfo.setPolicyDownloadedVersion(downloadedVersion);
-                       pluginSvcVersionInfo.setPolicyDownloadTime(new 
Date().getTime());
-               } else {
-                       
pluginSvcVersionInfo.setTagActiveVersion(lastKnownVersion);
-                       
pluginSvcVersionInfo.setTagActivationTime(lastActivationTime);
-                       
pluginSvcVersionInfo.setTagDownloadedVersion(downloadedVersion);
-                       pluginSvcVersionInfo.setTagDownloadTime(new 
Date().getTime());
+               switch (entityType) {
+                       case 0:
+                               
pluginSvcVersionInfo.setPolicyActiveVersion(lastKnownVersion);
+                               
pluginSvcVersionInfo.setPolicyActivationTime(lastActivationTime);
+                               
pluginSvcVersionInfo.setPolicyDownloadedVersion(downloadedVersion);
+                               pluginSvcVersionInfo.setPolicyDownloadTime(new 
Date().getTime());
+                               break;
+                       case 1:
+                               
pluginSvcVersionInfo.setTagActiveVersion(lastKnownVersion);
+                               
pluginSvcVersionInfo.setTagActivationTime(lastActivationTime);
+                               
pluginSvcVersionInfo.setTagDownloadedVersion(downloadedVersion);
+                               pluginSvcVersionInfo.setTagDownloadTime(new 
Date().getTime());
+                               break;
+                       case 2:
+                               
pluginSvcVersionInfo.setRoleActiveVersion(lastKnownVersion);
+                               
pluginSvcVersionInfo.setRoleActivationTime(lastActivationTime);
+                               
pluginSvcVersionInfo.setRoleDownloadedVersion(downloadedVersion);
+                               pluginSvcVersionInfo.setRoleDownloadTime(new 
Date().getTime());
+                               break;
                }
 
-               createOrUpdatePluginInfo(pluginSvcVersionInfo, entityType == 
RangerPluginInfo.ENTITY_TYPE_POLICIES, httpCode, clusterName);
+               createOrUpdatePluginInfo(pluginSvcVersionInfo, entityType , 
httpCode, clusterName);
        }
 
-       private void createOrUpdatePluginInfo(final RangerPluginInfo 
pluginInfo, final boolean isPolicyDownloadRequest, final int httpCode, String 
clusterName) {
+       private void createOrUpdatePluginInfo(final RangerPluginInfo 
pluginInfo, int entityType, final int httpCode, String clusterName) {
+
                if (logger.isDebugEnabled()) {
-                       logger.debug("==> createOrUpdatePluginInfo(pluginInfo = 
" + pluginInfo + ", isPolicyDownloadRequest = " + isPolicyDownloadRequest + ", 
httpCode = " + httpCode + ")");
+                       logger.debug("==> createOrUpdatePluginInfo(pluginInfo = 
" + pluginInfo + ", isPolicyDownloadRequest = " + 
isPolicyDownloadRequest(entityType) + ", httpCode = " + httpCode + ")");
                }
 
                final boolean isTagVersionResetNeeded;
@@ -711,23 +721,33 @@ public class AssetMgr extends AssetMgrBase {
                        // then the TransactionManager will roll-back the 
changes because the HTTP return code is
                        // HttpServletResponse.SC_NOT_MODIFIED
 
-                       if (isPolicyDownloadRequest) {
-                               isTagVersionResetNeeded = 
rangerDaoManager.getXXService().findAssociatedTagService(pluginInfo.getServiceName())
 == null;
-                       } else {
-                               isTagVersionResetNeeded = false;
+                       switch (entityType) {
+                               case 0:
+                                       isTagVersionResetNeeded = 
rangerDaoManager.getXXService().findAssociatedTagService(pluginInfo.getServiceName())
 == null;
+                                       break;
+                               case 1:
+                                       isTagVersionResetNeeded = false;
+                                       break;
+                               case 2:
+                                       isTagVersionResetNeeded = false;
+                                       break;
+                               default:
+                                       isTagVersionResetNeeded = false;
+                                       break;
                        }
 
                        Runnable commitWork = new Runnable() {
                                @Override
                                public void run() {
-                                       
doCreateOrUpdateXXPluginInfo(pluginInfo, isPolicyDownloadRequest, 
isTagVersionResetNeeded, clusterName);
+                                       
doCreateOrUpdateXXPluginInfo(pluginInfo, entityType, isTagVersionResetNeeded, 
clusterName);
                                }
                        };
                        
activityLogger.commitAfterTransactionComplete(commitWork);
                } else if (httpCode == HttpServletResponse.SC_NOT_FOUND) {
                        Runnable commitWork;
-                       if ((isPolicyDownloadRequest && 
(pluginInfo.getPolicyActiveVersion() == null || 
pluginInfo.getPolicyActiveVersion() == -1))
-                               || (!isPolicyDownloadRequest && 
(pluginInfo.getTagActiveVersion() == null || pluginInfo.getTagActiveVersion() 
== -1))) {
+                       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))) {
                                commitWork = new Runnable() {
                                        @Override
                                        public void run() {
@@ -738,7 +758,7 @@ public class AssetMgr extends AssetMgrBase {
                                commitWork = new Runnable() {
                                        @Override
                                        public void run() {
-                                               
doCreateOrUpdateXXPluginInfo(pluginInfo, isPolicyDownloadRequest, false, 
clusterName);
+                                               
doCreateOrUpdateXXPluginInfo(pluginInfo, entityType, false, clusterName);
                                        }
                                };
                        }
@@ -746,15 +766,15 @@ public class AssetMgr extends AssetMgrBase {
 
                } else {
                        isTagVersionResetNeeded = false;
-                       doCreateOrUpdateXXPluginInfo(pluginInfo, 
isPolicyDownloadRequest, isTagVersionResetNeeded, clusterName);
+                       doCreateOrUpdateXXPluginInfo(pluginInfo, entityType, 
isTagVersionResetNeeded, clusterName);
                }
                if (logger.isDebugEnabled()) {
-                       logger.debug("<== createOrUpdatePluginInfo(pluginInfo = 
" + pluginInfo + ", isPolicyDownloadRequest = " + isPolicyDownloadRequest + ", 
httpCode = " + httpCode + ")");
+                       logger.debug("<== createOrUpdatePluginInfo(pluginInfo = 
" + pluginInfo + ", isPolicyDownloadRequest = " + 
isPolicyDownloadRequest(entityType) + ", httpCode = " + httpCode + ")");
                }
 
        }
 
-       private XXPluginInfo doCreateOrUpdateXXPluginInfo(RangerPluginInfo 
pluginInfo, final boolean isPolicyDownloadRequest, final boolean 
isTagVersionResetNeeded, String clusterName) {
+       private XXPluginInfo doCreateOrUpdateXXPluginInfo(RangerPluginInfo 
pluginInfo, int entityType, final boolean isTagVersionResetNeeded, String 
clusterName) {
                XXPluginInfo ret = null;
                Map<String, String> infoMap = null;
 
@@ -770,14 +790,21 @@ public class AssetMgr extends AssetMgrBase {
                                        pluginInfo.setInfo(infoMap);
                                }
                                // ranger-admin is restarted, plugin contains 
latest versions and no earlier record for this plug-in client
-                               if (isPolicyDownloadRequest) {
+                               if (isPolicyDownloadRequest(entityType)) {
                                        if 
(pluginInfo.getPolicyDownloadedVersion() != null && 
pluginInfo.getPolicyDownloadedVersion().equals(pluginInfo.getPolicyActiveVersion()))
 {
                                                // This is our best guess of 
when policies may have been downloaded
                                                
pluginInfo.setPolicyDownloadTime(pluginInfo.getPolicyActivationTime());
                                        }
-                               } else if (pluginInfo.getTagDownloadedVersion() 
!= null && 
pluginInfo.getTagDownloadedVersion().equals(pluginInfo.getTagActiveVersion())) {
-                                       // This is our best guess of when tags 
may have been downloaded
-                                       
pluginInfo.setTagDownloadTime(pluginInfo.getTagActivationTime());
+                               } else if (isTagDownloadRequest(entityType)) {
+                                       if 
(pluginInfo.getTagDownloadedVersion() != null && 
pluginInfo.getTagDownloadedVersion().equals(pluginInfo.getTagActiveVersion())) {
+                                               // This is our best guess of 
when tags may have been downloaded
+                                               
pluginInfo.setTagDownloadTime(pluginInfo.getTagActivationTime());
+                                       }
+                               } else {
+                                       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());
+                                       }
                                }
 
                                xObj = 
pluginInfoService.populateDBObject(pluginInfo);
@@ -802,7 +829,7 @@ public class AssetMgr extends AssetMgrBase {
                                        
dbObj.setIpAddress(pluginInfo.getIpAddress());
                                        needsUpdating = true;
                                }
-                               if (isPolicyDownloadRequest) {
+                               if (isPolicyDownloadRequest(entityType)) {
                                        if (dbObj.getPolicyDownloadedVersion() 
== null || 
!dbObj.getPolicyDownloadedVersion().equals(pluginInfo.getPolicyDownloadedVersion()))
 {
                                                
dbObj.setPolicyDownloadedVersion(pluginInfo.getPolicyDownloadedVersion());
                                                
dbObj.setPolicyDownloadTime(pluginInfo.getPolicyDownloadTime());
@@ -824,7 +851,7 @@ public class AssetMgr extends AssetMgrBase {
                                                
dbObj.setPolicyActivationTime(lastPolicyActivationTime);
                                                needsUpdating = true;
                                        }
-                               } else {
+                               } else if (isTagDownloadRequest(entityType)){
                                        if (dbObj.getTagDownloadedVersion() == 
null || 
!dbObj.getTagDownloadedVersion().equals(pluginInfo.getTagDownloadedVersion())) {
                                                // First download for tags 
after tag-service is associated with resource-service
                                                
dbObj.setTagDownloadedVersion(pluginInfo.getTagDownloadedVersion());
@@ -849,6 +876,30 @@ public class AssetMgr extends AssetMgrBase {
                                                
dbObj.setTagActivationTime(lastTagActivationTime);
                                                needsUpdating = true;
                                        }
+                               } else {
+                                       if (dbObj.getRoleDownloadedVersion() == 
null || 
!dbObj.getRoleDownloadedVersion().equals(pluginInfo.getRoleDownloadedVersion()))
 {
+                                               
dbObj.setRoleDownloadedVersion(pluginInfo.getRoleDownloadedVersion());
+                                               
dbObj.setRoleDownloadTime(pluginInfo.getRoleDownloadTime());
+                                               needsUpdating = true;
+                                       }
+
+                                       Long lastKnownRoleVersion = 
pluginInfo.getRoleActiveVersion();
+                                       Long lastRoleActivationTime = 
pluginInfo.getRoleActivationTime();
+
+                                       if (lastKnownRoleVersion != null && 
lastKnownRoleVersion == -1) {
+                                               
dbObj.setRoleDownloadTime(pluginInfo.getRoleDownloadTime());
+                                               needsUpdating = true;
+                                       }
+
+                                       if (lastKnownRoleVersion != null && 
lastKnownRoleVersion > 0 && (dbObj.getRoleActiveVersion() == null || 
!dbObj.getRoleActiveVersion().equals(lastKnownRoleVersion))) {
+                                               
dbObj.setRoleActiveVersion(lastKnownRoleVersion);
+                                               needsUpdating = true;
+                                       }
+
+                                       if (lastRoleActivationTime != null && 
lastRoleActivationTime > 0 && (dbObj.getRoleActivationTime() == null || 
!dbObj.getRoleActivationTime().equals(lastRoleActivationTime))) {
+                                               
dbObj.setRoleActivationTime(lastRoleActivationTime);
+                                               needsUpdating = true;
+                                       }
                                }
 
                                if (isTagVersionResetNeeded) {
@@ -1178,4 +1229,16 @@ public class AssetMgr extends AssetMgrBase {
                        throw restErrorUtil.createRESTException("Please provide 
a valid syncSource", MessageEnums.INVALID_INPUT_DATA);
                }
        }
+
+       private boolean isPolicyDownloadRequest(int entityType) {
+               return entityType == 0;
+       }
+
+       private boolean isTagDownloadRequest(int entityType) {
+               return entityType == 1;
+       }
+
+       private boolean isRoleDownloadRequest(int entityType) {
+               return entityType == 2;
+       }
 }
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 7a67e9c..9151a72 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
@@ -32,12 +32,14 @@ import org.apache.commons.logging.LogFactory;
 import org.apache.ranger.authorization.hadoop.config.RangerConfiguration;
 import org.apache.ranger.common.MessageEnums;
 import org.apache.ranger.common.RESTErrorUtil;
+import org.apache.ranger.common.RangerRoleCache;
 import org.apache.ranger.db.RangerDaoManager;
 import org.apache.ranger.entity.*;
 import org.apache.ranger.plugin.model.RangerRole;
 import org.apache.ranger.plugin.store.AbstractPredicateUtil;
 import org.apache.ranger.plugin.store.RolePredicateUtil;
 import org.apache.ranger.plugin.store.RoleStore;
+import org.apache.ranger.plugin.util.RangerRoles;
 import org.apache.ranger.plugin.util.SearchFilter;
 import org.apache.ranger.service.RangerRoleService;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -50,6 +52,8 @@ import com.google.gson.GsonBuilder;
 public class RoleDBStore implements RoleStore {
     private static final Log LOG = LogFactory.getLog(RoleDBStore.class);
 
+    private static final String RANGER_ROLE_GLOBAL_STATE_NAME = "RangerRole";
+
     @Autowired
     RangerRoleService roleService;
 
@@ -97,6 +101,8 @@ public class RoleDBStore implements RoleStore {
             throw restErrorUtil.createRESTException("role with name: " + 
role.getName() + " already exists", MessageEnums.ERROR_DUPLICATE_OBJECT);
         }
 
+        
daoMgr.getXXGlobalState().onGlobalAppDataChange(RANGER_ROLE_GLOBAL_STATE_NAME);
+
         RangerRole createdRole = roleService.create(role);
         if (createdRole == null) {
             throw new Exception("Cannot create role:[" + role + "]");
@@ -119,6 +125,8 @@ public class RoleDBStore implements RoleStore {
         Gson gsonBuilder = new 
GsonBuilder().setDateFormat("yyyyMMdd-HH:mm:ss.SSS-Z").create();
         RangerRole oldRole = gsonBuilder.fromJson(xxRole.getRoleText(), 
RangerRole.class);
 
+        
daoMgr.getXXGlobalState().onGlobalAppDataChange(RANGER_ROLE_GLOBAL_STATE_NAME);
+
         RangerRole updatedRole = roleService.update(role);
         if (updatedRole == null) {
             throw new Exception("Cannot update role:[" + role + "]");
@@ -128,6 +136,8 @@ public class RoleDBStore implements RoleStore {
 
         roleService.updatePolicyVersions(updatedRole.getId());
 
+        roleService.updateRoleVersions(updatedRole.getId());
+
         List<XXTrxLog> trxLogList = roleService.getTransactionLog(updatedRole, 
oldRole, "update");
         bizUtil.createTrxLog(trxLogList);
         return role;
@@ -139,6 +149,9 @@ public class RoleDBStore implements RoleStore {
         if (xxRole == null) {
             throw restErrorUtil.createRESTException("Role with name: " + 
roleName + " does not exist");
         }
+
+        
daoMgr.getXXGlobalState().onGlobalAppDataChange(RANGER_ROLE_GLOBAL_STATE_NAME);
+
         RangerRole role = roleService.read(xxRole.getId());
         roleRefUpdater.cleanupRefTables(role);
         roleService.delete(role);
@@ -151,6 +164,8 @@ public class RoleDBStore implements RoleStore {
     public void deleteRole(Long roleId) throws Exception {
         RangerRole role = roleService.read(roleId);
 
+        
daoMgr.getXXGlobalState().onGlobalAppDataChange(RANGER_ROLE_GLOBAL_STATE_NAME);
+
         roleRefUpdater.cleanupRefTables(role);
         roleService.delete(role);
         List<XXTrxLog> trxLogList = roleService.getTransactionLog(role, null, 
"delete");
@@ -262,5 +277,29 @@ public class RoleDBStore implements RoleStore {
         return service == null ? ListUtils.EMPTY_LIST : 
getRoles(service.getId());
     }
 
+    public RangerRoles getRangerRoles(String serviceName, Long 
lastKnownRoleVersion) throws Exception {
+        RangerRoles ret                   = null;
+        Long        rangerRoleVersionInDB = getRoleVersion(serviceName);
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("==> RoleDBStore.getRangerRoles() lastKnownRoleVersion= 
" + lastKnownRoleVersion + " rangerRoleVersionInDB= " + rangerRoleVersionInDB);
+        }
+
+        if (rangerRoleVersionInDB != null) {
+            ret = 
RangerRoleCache.getInstance().getLatestRangerRoleOrCached(serviceName, this, 
lastKnownRoleVersion, rangerRoleVersionInDB);
+        }
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("<= RoleDBStore.getRangerRoles() lastKnownRoleVersion= " 
+ lastKnownRoleVersion + " rangerRoleVersionInDB= " + rangerRoleVersionInDB + " 
RangerRoles= " + ret);
+        }
+
+        return ret;
+    }
+
+    public Long getRoleVersion(String serviceName) {
+        XXServiceVersionInfo xxServiceVersionInfo =  
daoMgr.getXXServiceVersionInfo().findByServiceName(serviceName);
+        return (xxServiceVersionInfo != null) ? 
xxServiceVersionInfo.getRoleVersion():null;
+    }
+
 }
 
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 92436ac..85db577 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
@@ -68,7 +68,6 @@ import org.apache.ranger.common.RangerCommonEnums;
 import org.apache.ranger.common.db.RangerTransactionSynchronizationAdapter;
 import org.apache.ranger.db.XXPolicyDao;
 import org.apache.ranger.entity.XXTagChangeLog;
-import org.apache.ranger.plugin.model.RangerRole;
 import org.apache.ranger.plugin.model.RangerSecurityZone;
 import org.apache.ranger.plugin.util.ServiceTags;
 import org.apache.ranger.plugin.model.validation.RangerServiceDefValidator;
@@ -123,7 +122,6 @@ import org.apache.ranger.entity.XXPolicyRefAccessType;
 import org.apache.ranger.entity.XXPolicyRefCondition;
 import org.apache.ranger.entity.XXPolicyRefResource;
 import org.apache.ranger.entity.XXResourceDef;
-import org.apache.ranger.entity.XXRoleRefRole;
 import org.apache.ranger.entity.XXSecurityZone;
 import org.apache.ranger.entity.XXService;
 import org.apache.ranger.entity.XXServiceConfigDef;
@@ -2812,25 +2810,6 @@ public class ServiceDBStore extends AbstractServiceStore 
{
                        ret.setTagPolicies(tagPolicies);
                }
 
-               if (ret != null) {
-                       // Add role mapping
-                       List<RangerRole> rolesForService = 
roleStore.getRoles(serviceDbObj.getId());
-                       if (CollectionUtils.isNotEmpty(rolesForService)) {
-                               Map<String, Set<String>> userRoleMapping = new 
HashMap<>();
-                               Map<String, Set<String>> groupRoleMapping = new 
HashMap<>();
-                               for (RangerRole role : rolesForService) {
-                                       // Get a closure set of all contained 
roles too
-                                       Set<RangerRole> containedRoles = 
getAllContainedRoles(role);
-
-                                       buildMap(userRoleMapping, role, 
containedRoles, true);
-                                       buildMap(groupRoleMapping, role, 
containedRoles, false);
-                               }
-
-                               ret.setUserRoles(userRoleMapping);
-                               ret.setGroupRoles(groupRoleMapping);
-                       }
-               }
-
                if (LOG.isDebugEnabled()) {
                        LOG.debug("<== ServiceDBStore.getServicePolicies(" + 
serviceName + ", " + lastKnownVersion + "): count=" + ((ret == null || 
ret.getPolicies() == null) ? 0 : ret.getPolicies().size()) + ", delta-count=" + 
((ret == null || ret.getPolicyDeltas() == null) ? 0 : 
ret.getPolicyDeltas().size()));
                }
@@ -2838,45 +2817,6 @@ public class ServiceDBStore extends AbstractServiceStore 
{
                return ret;
        }
 
-       private Set<RangerRole> getAllContainedRoles(RangerRole role) {
-               Set<RangerRole> allRoles = new HashSet<>();
-               allRoles.add(role);
-               addContainedRoles(allRoles, role);
-               return allRoles;
-       }
-
-       private void addContainedRoles(Set<RangerRole> allRoles, RangerRole 
role) {
-               List<XXRoleRefRole> roles = 
daoMgr.getXXRoleRefRole().findByRoleId(role.getId());
-               for (XXRoleRefRole xRefRole : roles) {
-                       RangerRole containedRole = 
roleService.read(xRefRole.getSubRoleId());
-                       if (!allRoles.contains(containedRole)) {
-                               allRoles.add(containedRole);
-                               addContainedRoles(allRoles, containedRole);
-                       }
-               }
-       }
-
-       private void buildMap(Map<String, Set<String>> map, RangerRole role, 
Set<RangerRole> containedRoles, boolean isUser) {
-               buildMap(map, role, role.getName(), isUser);
-
-               for (RangerRole containedRole : containedRoles) {
-                       buildMap(map, containedRole, role.getName(), isUser);
-               }
-       }
-
-       private void buildMap(Map<String, Set<String>> map, RangerRole role, 
String roleName, boolean isUser) {
-               for (RangerRole.RoleMember userOrGroup : isUser ? 
role.getUsers() : role.getGroups()) {
-                       if (StringUtils.isNotEmpty(userOrGroup.getName())) {
-                               Set<String> roleNames = 
map.get(userOrGroup.getName());
-                               if (roleNames == null) {
-                                       roleNames = new HashSet<>();
-                                       map.put(userOrGroup.getName(), 
roleNames);
-                               }
-                               roleNames.add(roleName);
-                       }
-               }
-       }
-
        private static class RangerPolicyDeltaComparator implements 
Comparator<RangerPolicyDelta>, java.io.Serializable {
                @Override
                public int compare(RangerPolicyDelta me, RangerPolicyDelta 
other) {
@@ -3353,7 +3293,7 @@ public class ServiceDBStore extends AbstractServiceStore {
                updatePolicyVersion(service, policyDeltaType, policy);
        }
 
-       public enum VERSION_TYPE { POLICY_VERSION, TAG_VERSION, 
POLICY_AND_TAG_VERSION }
+       public enum VERSION_TYPE { POLICY_VERSION, TAG_VERSION, 
POLICY_AND_TAG_VERSION, ROLE_VERSION }
 
        private void updatePolicyVersion(RangerService service, Integer 
policyDeltaType, RangerPolicy policy) throws Exception {
                if(service == null || service.getId() == null) {
@@ -3419,6 +3359,13 @@ public class ServiceDBStore extends AbstractServiceStore 
{
                                serviceVersionInfoDbObj.setTagUpdateTime(now);
                        }
 
+                       if (versionType == VERSION_TYPE.ROLE_VERSION) {
+                               // get the LatestRoleVersion from the 
GlobalTable and update ServiceInfo for a service
+                               Long currentRoleVersion = 
daoMgr.getXXGlobalState().getRoleVersion("RangerRole");
+                               
serviceVersionInfoDbObj.setRolVersion(currentRoleVersion);
+                               serviceVersionInfoDbObj.setRoleUpdateTime(now);
+                       }
+
                        serviceVersionInfoDao.update(serviceVersionInfoDbObj);
 
                } else {
diff --git 
a/security-admin/src/main/java/org/apache/ranger/common/RangerRoleCache.java 
b/security-admin/src/main/java/org/apache/ranger/common/RangerRoleCache.java
new file mode 100644
index 0000000..b0bd427
--- /dev/null
+++ b/security-admin/src/main/java/org/apache/ranger/common/RangerRoleCache.java
@@ -0,0 +1,142 @@
+/*
+ * 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.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.ranger.authorization.hadoop.config.RangerConfiguration;
+import org.apache.ranger.biz.RoleDBStore;
+import org.apache.ranger.plugin.model.RangerRole;
+
+import org.apache.ranger.plugin.util.RangerRoles;
+import org.apache.ranger.plugin.util.SearchFilter;
+
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.ReentrantLock;
+
+public class RangerRoleCache {
+       private static final Log LOG = LogFactory.getLog(RangerRoleCache.class);
+
+       private static final int MAX_WAIT_TIME_FOR_UPDATE = 10;
+
+       public static volatile RangerRoleCache sInstance = null;
+       private final int waitTimeInSeconds;
+       final ReentrantLock lock = new ReentrantLock();
+
+       RangerRoleCacheWrapper rangerRoleCacheWrapper = null;
+
+       public static RangerRoleCache getInstance() {
+               if (sInstance == null) {
+                       synchronized (RangerRoleCache.class) {
+                               if (sInstance == null) {
+                                       sInstance = new RangerRoleCache();
+                               }
+                       }
+               }
+               return sInstance;
+       }
+
+       private RangerRoleCache() {
+               waitTimeInSeconds = 
RangerConfiguration.getInstance().getInt("ranger.admin.policy.download.cache.max.waittime.for.update",
 MAX_WAIT_TIME_FOR_UPDATE);
+       }
+
+       public RangerRoles getLatestRangerRoleOrCached(String serviceName, 
RoleDBStore roleDBStore, Long lastKnownRoleVersion, Long rangerRoleVersionInDB) 
throws Exception {
+               RangerRoles ret = null;
+
+               if (lastKnownRoleVersion == null || 
!lastKnownRoleVersion.equals(rangerRoleVersionInDB)) {
+                       rangerRoleCacheWrapper = new RangerRoleCacheWrapper();
+                       ret = 
rangerRoleCacheWrapper.getLatestRangerRoles(serviceName, roleDBStore, 
lastKnownRoleVersion, rangerRoleVersionInDB);
+               } else if (lastKnownRoleVersion.equals(rangerRoleVersionInDB)) {
+                       ret = null;
+               } else {
+                       ret = rangerRoleCacheWrapper.getRangerRoles();
+               }
+
+               return ret;
+       }
+
+       private class RangerRoleCacheWrapper {
+               RangerRoles rangerRoles;
+               Long                    rangerRoleVersion;
+
+               RangerRoleCacheWrapper() {
+                       this.rangerRoles = null;
+                       this.rangerRoleVersion = -1L;
+               }
+
+               public RangerRoles getRangerRoles() {
+                       return this.rangerRoles;
+               }
+
+               public Long getRangerRoleVersion() {
+                       return this.rangerRoleVersion;
+               }
+
+               public RangerRoles getLatestRangerRoles(String serviceName, 
RoleDBStore roleDBStore, Long lastKnownRoleVersion, Long rangerRoleVersionInDB) 
throws Exception {
+                       RangerRoles ret  = null;
+                       boolean         lockResult   = false;
+                       if (LOG.isDebugEnabled()) {
+                               LOG.debug("==> 
RangerRoleCache.getLatestRangerRoles(ServiceName= " + serviceName + " 
lastKnownRoleVersion= " + lastKnownRoleVersion + " rangerRoleVersionInDB= " + 
rangerRoleVersionInDB + ")");
+                       }
+
+                       try {
+                               lockResult = lock.tryLock(waitTimeInSeconds, 
TimeUnit.SECONDS);
+
+                               if (lockResult) {
+                                       // We are getting all the Roles to be 
downloaded for now. Should do downloades for each service based on what roles 
are there in the policies.
+                                       SearchFilter searchFilter = null;
+                                       final Set<RangerRole> rangerRoleInDB = 
new HashSet<>(roleDBStore.getRoles(searchFilter));
+
+                                       Date updateTime = new Date();
+
+                                       if (rangerRoleInDB != null) {
+                                               ret = new RangerRoles();
+                                               
ret.setRangerRoles(rangerRoleInDB);
+                                               
ret.setRoleUpdateTime(updateTime);
+                                               
ret.setRoleVersion(rangerRoleVersionInDB);
+                                               rangerRoleVersion = 
rangerRoleVersionInDB;
+                                       } else {
+                                               LOG.error("Could not get Ranger 
Roles from database ...");
+                                       }
+                               } else {
+                                       if (LOG.isDebugEnabled()) {
+                                               LOG.debug("Could not get lock 
in [" + waitTimeInSeconds + "] seconds, returning cached RangerRoles");
+                                       }
+                                       ret = getRangerRoles();
+                               }
+                       } catch (InterruptedException exception) {
+                               
LOG.error("RangerRoleCache.getLatestRangerRoles:lock got interrupted..", 
exception);
+                       } finally {
+                               if (lockResult) {
+                                       lock.unlock();
+                               }
+                       }
+
+                       if (LOG.isDebugEnabled()) {
+                               LOG.debug("<== 
RangerRoleCache.getLatestRangerRoles(ServiceName= " + serviceName + " 
lastKnownRoleVersion= " + lastKnownRoleVersion + " rangerRoleVersionInDB= " + 
rangerRoleVersionInDB + " RangerRoles= " + 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 f6b9e1a..d687e73 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
@@ -17,6 +17,7 @@
 
 package org.apache.ranger.db;
 
+import com.google.gson.Gson;
 import org.apache.commons.lang.StringUtils;
 import org.apache.log4j.Logger;
 import org.apache.ranger.common.DateUtil;
@@ -26,11 +27,15 @@ import org.springframework.stereotype.Service;
 
 import javax.persistence.NoResultException;
 import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
 
 @Service
 public class XXGlobalStateDao extends BaseDao<XXGlobalState> {
     private static final Logger logger = 
Logger.getLogger(RangerDaoManager.class);
 
+    final static String RANGER_ROLE_VERSION_LABEL = "RangerRoleVersion";
+
     public void onGlobalStateChange(String stateName) throws Exception {
 
         if (StringUtils.isBlank(stateName)) {
@@ -58,6 +63,48 @@ public class XXGlobalStateDao extends BaseDao<XXGlobalState> 
{
             }
         }
     }
+
+    public void onGlobalAppDataChange(String stateName) throws Exception {
+
+        if (StringUtils.isBlank(stateName)) {
+            logger.error("Invalid name for state:[" + stateName +"]");
+            throw new Exception("Invalid name for state:[" + stateName +"]");
+        } else {
+            try {
+                XXGlobalState globalState = findByStateName(stateName);
+                if (globalState == null) {
+                    globalState = new XXGlobalState();
+                    globalState.setStateName(stateName);
+                    Map<String,String> roleVersion = new HashMap<>();
+                    roleVersion.put(RANGER_ROLE_VERSION_LABEL,new 
String(Long.toString(1L)));
+                    globalState.setAppData(new Gson().toJson(roleVersion));
+                    create(globalState);
+                } else {
+                    Map<String,String> roleVersionJson = new 
Gson().fromJson(globalState.getAppData(),Map.class);
+                    Long               roleVersion     = 
Long.valueOf(roleVersionJson.get(RANGER_ROLE_VERSION_LABEL)) + 1L;
+                    roleVersionJson.put(RANGER_ROLE_VERSION_LABEL,new 
String(Long.toString(roleVersion)));
+                    globalState.setAppData(new Gson().toJson(roleVersionJson));
+                    update(globalState);
+                }
+            } catch (Exception exception) {
+                logger.error("Cannot create/update GlobalState for state:[" + 
stateName + "]", exception);
+                throw exception;
+            }
+        }
+    }
+
+    public Long getRoleVersion(String stateName) {
+        Long ret = null;
+        try {
+            XXGlobalState       globalState     = findByStateName(stateName);
+            Map<String, String> roleVersionJson = new 
Gson().fromJson(globalState.getAppData(), Map.class);
+            ret                                 = 
Long.valueOf(roleVersionJson.get(RANGER_ROLE_VERSION_LABEL));
+        } catch (Exception exception) {
+            logger.warn("Unable to find the role version in Ranger Database");
+        }
+        return ret;
+    }
+
     /**
      * Default Constructor
      */
diff --git 
a/security-admin/src/main/java/org/apache/ranger/entity/XXServiceVersionInfo.java
 
b/security-admin/src/main/java/org/apache/ranger/entity/XXServiceVersionInfo.java
index cef3863..1d81337 100644
--- 
a/security-admin/src/main/java/org/apache/ranger/entity/XXServiceVersionInfo.java
+++ 
b/security-admin/src/main/java/org/apache/ranger/entity/XXServiceVersionInfo.java
@@ -68,6 +68,13 @@ public class XXServiceVersionInfo implements 
java.io.Serializable {
        @Column(name="tag_update_time"   )
        protected Date tagUpdateTime = DateUtil.getUTCDate();
 
+       @Column(name = "role_version")
+       protected Long roleVersion;
+
+       @Temporal(TemporalType.TIMESTAMP)
+       @Column(name="role_update_time"   )
+       protected Date roleUpdateTime = DateUtil.getUTCDate();
+
        /**
         * Default constructor. This will set all the attributes to default 
value.
         */
@@ -130,6 +137,21 @@ public class XXServiceVersionInfo implements 
java.io.Serializable {
                return this.tagUpdateTime;
        }
 
+       public void setRolVersion(Long roleVersion) {
+               this.roleVersion = roleVersion;
+       }
+
+       public Long getRoleVersion() {
+               return this.roleVersion;
+       }
+
+       public void setRoleUpdateTime( Date updateTime ) {
+               this.roleUpdateTime = updateTime;
+       }
+
+       public Date getRoleUpdateTime( ) {
+               return this.roleUpdateTime;
+       }
 
        /**
         * This return the bean content in string format
diff --git a/security-admin/src/main/java/org/apache/ranger/rest/RoleREST.java 
b/security-admin/src/main/java/org/apache/ranger/rest/RoleREST.java
index 4af768a..d28cf3d 100644
--- a/security-admin/src/main/java/org/apache/ranger/rest/RoleREST.java
+++ b/security-admin/src/main/java/org/apache/ranger/rest/RoleREST.java
@@ -27,6 +27,7 @@ import java.util.List;
 import java.util.Set;
 
 import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 import javax.ws.rs.*;
 import javax.ws.rs.core.Context;
 
@@ -36,6 +37,7 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.ranger.admin.client.datatype.RESTResponse;
 import org.apache.ranger.authorization.utils.StringUtil;
+import org.apache.ranger.biz.AssetMgr;
 import org.apache.ranger.biz.RangerBizUtil;
 import org.apache.ranger.biz.RoleDBStore;
 import org.apache.ranger.biz.ServiceDBStore;
@@ -43,14 +45,21 @@ import org.apache.ranger.biz.XUserMgr;
 import org.apache.ranger.common.RESTErrorUtil;
 import org.apache.ranger.common.RangerSearchUtil;
 import org.apache.ranger.common.RangerValidatorFactory;
+import org.apache.ranger.common.ServiceUtil;
 import org.apache.ranger.common.UserSessionBase;
 import org.apache.ranger.common.RangerConstants;
 import org.apache.ranger.common.PropertiesUtil;
 import org.apache.ranger.common.ContextUtil;
+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.RangerRole;
 import org.apache.ranger.plugin.model.RangerService;
 import org.apache.ranger.plugin.policyengine.RangerPolicyEngine;
+import org.apache.ranger.plugin.store.EmbeddedServiceDefsUtil;
 import org.apache.ranger.plugin.util.GrantRevokeRoleRequest;
+import org.apache.ranger.plugin.util.RangerRoles;
 import org.apache.ranger.plugin.util.SearchFilter;
 import org.apache.ranger.service.RangerRoleService;
 import org.apache.ranger.service.XUserService;
@@ -71,10 +80,18 @@ public class RoleREST {
 
     private static List<String> INVALID_USERS = new ArrayList<>();
 
+    public static final String Allowed_User_List_For_Download = 
"policy.download.auth.users";
+
     @Autowired
     RESTErrorUtil restErrorUtil;
 
     @Autowired
+    AssetMgr assetMgr;
+
+    @Autowired
+    RangerDaoManager daoManager;
+
+    @Autowired
     RoleDBStore roleStore;
 
     @Autowired
@@ -90,6 +107,9 @@ public class RoleREST {
     RangerSearchUtil searchUtil;
 
     @Autowired
+    ServiceUtil serviceUtil;
+
+    @Autowired
     RangerValidatorFactory validatorFactory;
 
     @Autowired
@@ -658,6 +678,175 @@ public class RoleREST {
         return new ArrayList<>(ret);
     }
 
+    @GET
+    @Path("/download/{serviceName}")
+    @Produces({ "application/json", "application/xml" })
+    public RangerRoles getRangerRolesIfUpdated(
+            @PathParam("serviceName") String serviceName,
+            @QueryParam("lastKnownRoleVersion") Long lastKnownRoleVersion,
+            @DefaultValue("0") @QueryParam("lastActivationTime") Long 
lastActivationTime,
+            @QueryParam("pluginId") String pluginId,
+            @DefaultValue("") @QueryParam("clusterName") String clusterName,
+            @Context HttpServletRequest request) throws Exception {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("==> RoleREST.getRangerRolesIfUpdated("
+                    + serviceName + ", " + lastKnownRoleVersion + ", " + 
lastActivationTime + ")");
+        }
+        RangerRoles ret = null;
+
+        boolean isValid           = false;
+        int     httpCode          = HttpServletResponse.SC_OK;
+        Long    downloadedVersion = null;
+        String  logMsg            = null;
+
+        try {
+            isValid = serviceUtil.isValidService(serviceName, request);
+        } catch (WebApplicationException webException) {
+            httpCode = webException.getResponse().getStatus();
+            logMsg = webException.getResponse().getEntity().toString();
+        } catch (Exception e) {
+            httpCode = HttpServletResponse.SC_BAD_REQUEST;
+            logMsg = e.getMessage();
+        }
+        if (isValid) {
+            if (lastKnownRoleVersion == null) {
+                lastKnownRoleVersion = Long.valueOf(-1);
+            }
+            try {
+                RangerRoles rangerRoles = 
roleStore.getRangerRoles(serviceName, lastKnownRoleVersion);
+                if (rangerRoles == null) {
+                    downloadedVersion = lastKnownRoleVersion;
+                    httpCode = HttpServletResponse.SC_NOT_MODIFIED;
+                    logMsg = "No change since last update";
+                } else {
+                    downloadedVersion = rangerRoles.getRoleVersion();
+                    rangerRoles.setServiceName(serviceName);
+                    ret = rangerRoles;
+                    httpCode = HttpServletResponse.SC_OK;
+                    logMsg = "Returning RangerRoles =>" + (ret.toString());
+                }
+
+            } catch (Throwable excp) {
+                LOG.error("getRangerRolesIfUpdated(" + serviceName + ", " + 
lastKnownRoleVersion + ", " + lastActivationTime + ") failed", excp);
+                httpCode = HttpServletResponse.SC_BAD_REQUEST;
+                logMsg = excp.getMessage();
+            }
+        }
+
+        assetMgr.createPluginInfo(serviceName, pluginId, request, 
RangerPluginInfo.ENTITY_TYPE_ROLES, downloadedVersion, lastKnownRoleVersion, 
lastActivationTime, httpCode, clusterName);
+
+        if (httpCode != HttpServletResponse.SC_OK) {
+            boolean logError = httpCode != HttpServletResponse.SC_NOT_MODIFIED;
+            throw restErrorUtil.createRESTException(httpCode, logMsg, 
logError);
+        }
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("<== RoleREST.getRangerRolesIfUpdated(" + serviceName + 
", " + lastKnownRoleVersion + ", " + lastActivationTime + ")" + ret);
+        }
+        return ret;
+    }
+
+    @GET
+    @Path("/secure/download/{serviceName}")
+    @Produces({ "application/json", "application/xml" })
+    public RangerRoles getSecureRangerRolesIfUpdated(
+            @PathParam("serviceName") String serviceName,
+            @QueryParam("lastKnownRoleVersion") Long lastKnownRoleVersion,
+            @DefaultValue("0") @QueryParam("lastActivationTime") Long 
lastActivationTime,
+            @QueryParam("pluginId") String pluginId,
+            @DefaultValue("") @QueryParam("clusterName") String clusterName,
+            @Context HttpServletRequest request) throws Exception {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("==> RoleREST.getSecureRangerRolesIfUpdated("
+                    + serviceName + ", " + lastKnownRoleVersion + ", " + 
lastKnownRoleVersion + ")");
+        }
+        RangerRoles ret  = null;
+        int     httpCode          = HttpServletResponse.SC_OK;
+        String  logMsg            = null;
+        boolean isAllowed         = false;
+        boolean isAdmin           = bizUtil.isAdmin();
+        boolean isKeyAdmin        = bizUtil.isKeyAdmin();
+        Long    downloadedVersion = null;
+
+        request.setAttribute("downloadPolicy", "secure");
+
+        boolean isValid = false;
+        try {
+            isValid = serviceUtil.isValidService(serviceName, request);
+        } catch (WebApplicationException webException) {
+            httpCode = webException.getResponse().getStatus();
+            logMsg = webException.getResponse().getEntity().toString();
+        } catch (Exception e) {
+            httpCode = HttpServletResponse.SC_BAD_REQUEST;
+            logMsg = e.getMessage();
+        }
+        if (isValid) {
+            if (lastKnownRoleVersion == null) {
+                lastKnownRoleVersion = Long.valueOf(-1);
+            }
+            try {
+                XXService xService = 
daoManager.getXXService().findByName(serviceName);
+                if (xService == null) {
+                    LOG.error("Requested Service not found. serviceName=" + 
serviceName);
+                    throw 
restErrorUtil.createRESTException(HttpServletResponse.SC_NOT_FOUND, "Service:" 
+ serviceName + " not found",
+                            false);
+                }
+                XXServiceDef xServiceDef = 
daoManager.getXXServiceDef().getById(xService.getType());
+                RangerService rangerService = 
svcStore.getServiceByName(serviceName);
+
+                if 
(org.apache.commons.lang.StringUtils.equals(xServiceDef.getImplclassname(), 
EmbeddedServiceDefsUtil.KMS_IMPL_CLASS_NAME)) {
+                    if (isKeyAdmin) {
+                        isAllowed = true;
+                    }else {
+                        isAllowed = bizUtil.isUserAllowed(rangerService, 
Allowed_User_List_For_Download);
+                    }
+                }else{
+                    if (isAdmin) {
+                        isAllowed = true;
+                    }else{
+                        isAllowed = bizUtil.isUserAllowed(rangerService, 
Allowed_User_List_For_Download);
+                    }
+                }
+
+                if (isAllowed) {
+                    RangerRoles rangerRoles = 
roleStore.getRangerRoles(serviceName, lastKnownRoleVersion);
+                    if (rangerRoles == null) {
+                        downloadedVersion = lastKnownRoleVersion;
+                        httpCode = HttpServletResponse.SC_NOT_MODIFIED;
+                        logMsg = "No change since last update";
+                    } else {
+                        downloadedVersion = rangerRoles.getRoleVersion();
+                        rangerRoles.setServiceName(serviceName);
+                        ret = rangerRoles;
+                        httpCode = HttpServletResponse.SC_OK;
+                        logMsg = "Returning RangerRoles =>" + (ret.toString());
+                    }
+                } else {
+                    LOG.error("getSecureRangerRolesIfUpdated(" + serviceName + 
", " + lastKnownRoleVersion + ") failed as User doesn't have permission to 
UserGroupRoles");
+                    httpCode = HttpServletResponse.SC_UNAUTHORIZED;
+                    logMsg = "User doesn't have permission to download 
UserGroupRoles";
+                }
+
+            } catch (Throwable excp) {
+                LOG.error("getSecureRangerRolesIfUpdated(" + serviceName + ", 
" + lastKnownRoleVersion + ", " + lastActivationTime + ") failed", excp);
+                httpCode = HttpServletResponse.SC_BAD_REQUEST;
+                logMsg = excp.getMessage();
+            }
+        }
+
+        assetMgr.createPluginInfo(serviceName, pluginId, request, 
RangerPluginInfo.ENTITY_TYPE_ROLES, downloadedVersion, lastKnownRoleVersion, 
lastActivationTime, httpCode, clusterName);
+
+        if (httpCode != HttpServletResponse.SC_OK) {
+            boolean logError = httpCode != HttpServletResponse.SC_NOT_MODIFIED;
+            throw restErrorUtil.createRESTException(httpCode, logMsg, 
logError);
+        }
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("<== RoleREST.getSecureRangerRolesIfUpdated(" + 
serviceName + ", " + lastKnownRoleVersion + ", " + lastActivationTime + ")" + 
ret);
+        }
+        return ret;
+    }
+
     private void ensureAdminAccess(String serviceName, String userName) throws 
Exception {
 
         /* If userName (execUser) is not same as logged in user then check
diff --git 
a/security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java 
b/security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java
index cfeaadd..190c6f5 100644
--- a/security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java
+++ b/security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java
@@ -3811,8 +3811,6 @@ public class ServiceREST {
                                ret.setPolicies(servicePolicies.getPolicies());
                                
ret.setTagPolicies(servicePolicies.getTagPolicies());
                                
ret.setSecurityZones(servicePolicies.getSecurityZones());
-                               
ret.setUserRoles(servicePolicies.getUserRoles());
-                               
ret.setGroupRoles(servicePolicies.getGroupRoles());
 
                                if (containsDisabledResourcePolicies) {
                                        List<RangerPolicy> filteredPolicies = 
new ArrayList<RangerPolicy>();
diff --git 
a/security-admin/src/main/java/org/apache/ranger/service/RangerRoleService.java 
b/security-admin/src/main/java/org/apache/ranger/service/RangerRoleService.java
index 8857afd..e168278 100644
--- 
a/security-admin/src/main/java/org/apache/ranger/service/RangerRoleService.java
+++ 
b/security-admin/src/main/java/org/apache/ranger/service/RangerRoleService.java
@@ -285,6 +285,23 @@ public class RangerRoleService extends 
RangerRoleServiceBase<XXRole, RangerRole>
         return ret;
     }
 
+    public void updateRoleVersions(Long roleId) {
+        if (logger.isDebugEnabled()) {
+            logger.debug("==> updateRoleVersions(roleId=" + roleId + ")");
+        }
+        // Get all roles which include this role because change to this 
affects all these roles
+        Set<Long> containingRoles = getContainingRoles(roleId);
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("All containing Roles for roleId:[" + roleId +"] are 
[" + containingRoles + "]");
+        }
+
+        updateRoleVersions(containingRoles);
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("<== updateRoleVersions(roleId=" + roleId + ")");
+        }
+    }
 
     private void addContainingRoles(Long roleId, Set<Long> allRoles) {
         if (logger.isDebugEnabled()) {
@@ -330,5 +347,31 @@ public class RangerRoleService extends 
RangerRoleServiceBase<XXRole, RangerRole>
         }
     }
 
+    private void updateRoleVersions(Set<Long> roleIds) {
+        if (logger.isDebugEnabled()) {
+            logger.debug("==> updatePolicyVersions(roleIds=" + roleIds + ")");
+        }
+
+        if (CollectionUtils.isNotEmpty(roleIds)) {
+            Set<Long> allAffectedServiceIds = new HashSet<>();
+
+            for (Long roleId : roleIds) {
+                List<Long> affectedServiceIds = 
daoMgr.getXXPolicy().findServiceIdsByRoleId(roleId);
+                allAffectedServiceIds.addAll(affectedServiceIds);
+            }
+
+            if (CollectionUtils.isNotEmpty(allAffectedServiceIds)) {
+                for (final Long serviceId : allAffectedServiceIds) {
+                    Runnable serviceVersionUpdater = new 
ServiceDBStore.ServiceVersionUpdater(daoMgr, serviceId, 
ServiceDBStore.VERSION_TYPE.ROLE_VERSION, null, 
RangerPolicyDelta.CHANGE_TYPE_ROLE_UPDATE, null);
+                    
daoMgr.getRangerTransactionSynchronizationAdapter().executeOnTransactionCommit(serviceVersionUpdater);
+                }
+            }
+        }
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("<== updatePolicyVersions(roleIds=" + roleIds + ")");
+        }
+    }
+
 }
 

Reply via email to