You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ranger.apache.org by ab...@apache.org on 2019/05/30 20:09:57 UTC

[ranger] branch master updated: RANGER-2414: Enhancements to support roles in Ranger policies

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

abhay 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 e9b1493  RANGER-2414: Enhancements to support roles in Ranger policies
e9b1493 is described below

commit e9b149324d1856eef88cd28ef8096e48e9842927
Author: Abhay Kulkarni <ab...@apache.org>
AuthorDate: Thu May 30 12:39:03 2019 -0700

    RANGER-2414: Enhancements to support roles in Ranger policies
---
 .../ranger/plugin/errors/ValidationErrorCode.java  |   2 +-
 .../apache/ranger/plugin/model/RangerPolicy.java   |  59 ++-
 .../org/apache/ranger/plugin/model/RangerRole.java | 188 ++++++++
 .../model/validation/RangerPolicyValidator.java    |   4 +-
 .../plugin/policyengine/RangerPolicyEngine.java    |   4 +
 .../policyengine/RangerPolicyEngineCache.java      |   2 +
 .../policyengine/RangerPolicyEngineImpl.java       |  86 +++-
 .../plugin/policyengine/RangerResourceACLs.java    |  40 ++
 .../RangerDefaultPolicyEvaluator.java              |  50 +--
 .../RangerDefaultPolicyItemEvaluator.java          |  16 +-
 .../RangerOptimizedPolicyEvaluator.java            |  24 +-
 .../policyevaluator/RangerPolicyEvaluator.java     |  60 ++-
 .../policyevaluator/RangerPolicyItemEvaluator.java |   2 +-
 .../ranger/plugin/service/RangerAuthContext.java   |  20 +-
 .../org/apache/ranger/plugin/store/RoleStore.java  |  47 ++
 .../plugin/util/RangerAccessRequestUtil.java       |  10 +
 .../apache/ranger/plugin/util/SearchFilter.java    |   3 +
 .../apache/ranger/plugin/util/ServicePolicies.java |  16 +-
 .../validation/TestRangerPolicyValidator.java      |   2 +-
 .../ranger/plugin/policyengine/TestPolicyACLs.java |  41 +-
 .../plugin/policyengine/TestPolicyEngine.java      |  11 +
 .../policyengine/test_aclprovider_default.json     |  24 ++
 .../policyengine/test_policyengine_with_roles.json | 213 +++++++++
 .../optimized/current/ranger_core_db_mysql.sql     |  90 ++++
 .../db/mysql/patches/041-create-role-schema.sql    | 105 +++++
 .../optimized/current/ranger_core_db_oracle.sql    | 112 +++++
 .../db/oracle/patches/041-create-role-schema.sql   | 147 +++++++
 .../optimized/current/ranger_core_db_postgres.sql  | 110 +++++
 .../db/postgres/patches/041-create-role-schema.sql | 120 ++++++
 .../current/ranger_core_db_sqlanywhere.sql         | 123 ++++++
 .../sqlanywhere/patches/041-create-role-schema.sql | 155 +++++++
 .../optimized/current/ranger_core_db_sqlserver.sql | 176 +++++++-
 .../sqlserver/patches/041-create-role-schema.sql   | 187 ++++++++
 .../org/apache/ranger/biz/PolicyRefUpdater.java    |  30 ++
 .../apache/ranger/biz/RangerPolicyRetriever.java   |  13 +
 .../java/org/apache/ranger/biz/RoleDBStore.java    | 234 ++++++++++
 .../java/org/apache/ranger/biz/RoleRefUpdater.java | 175 ++++++++
 .../java/org/apache/ranger/biz/ServiceDBStore.java |  33 ++
 .../org/apache/ranger/common/AppConstants.java     |   6 +-
 .../org/apache/ranger/db/RangerDaoManagerBase.java |  10 +
 .../java/org/apache/ranger/db/XXPolicyDao.java     |  13 +
 .../org/apache/ranger/db/XXPolicyRefRoleDao.java   | 100 +++++
 .../main/java/org/apache/ranger/db/XXRoleDao.java  |  78 ++++
 .../org/apache/ranger/db/XXRoleRefGroupDao.java    |  75 ++++
 .../org/apache/ranger/db/XXRoleRefRoleDao.java     |  75 ++++
 .../org/apache/ranger/db/XXRoleRefUserDao.java     |  75 ++++
 .../org/apache/ranger/entity/XXPolicyRefRole.java  | 206 +++++++++
 .../main/java/org/apache/ranger/entity/XXRole.java |  76 ++++
 .../java/org/apache/ranger/entity/XXRoleBase.java  | 101 +++++
 .../org/apache/ranger/entity/XXRoleRefGroup.java   | 234 ++++++++++
 .../org/apache/ranger/entity/XXRoleRefRole.java    | 233 ++++++++++
 .../org/apache/ranger/entity/XXRoleRefUser.java    | 234 ++++++++++
 .../java/org/apache/ranger/rest/PublicAPIsv2.java  |  84 ++++
 .../main/java/org/apache/ranger/rest/RoleREST.java | 477 +++++++++++++++++++++
 .../java/org/apache/ranger/rest/ServiceREST.java   |   8 +-
 .../ranger/service/RangerPolicyServiceBase.java    |   3 +
 .../apache/ranger/service/RangerRoleService.java   | 258 +++++++++++
 .../ranger/service/RangerRoleServiceBase.java      |  67 +++
 .../org/apache/ranger/view/RangerRoleList.java     |  74 ++++
 .../main/resources/META-INF/jpa_named_queries.xml  |  82 ++++
 .../scripts/collection_bases/VXRoleListBase.js     |  99 +++++
 .../main/webapp/scripts/collections/VXRoleList.js  |  34 ++
 .../main/webapp/scripts/controllers/Controller.js  |  31 ++
 .../main/webapp/scripts/model_bases/VXRoleBase.js  |  62 +++
 .../src/main/webapp/scripts/models/VXRole.js       |  92 ++++
 .../src/main/webapp/scripts/modules/XALinks.js     |  23 +-
 .../webapp/scripts/modules/globalize/message/en.js |  23 +-
 .../src/main/webapp/scripts/routers/Router.js      |   3 +
 .../src/main/webapp/scripts/utils/XAEnums.js       |   3 +-
 .../src/main/webapp/scripts/utils/XAUtils.js       | 105 ++++-
 .../scripts/views/policies/PermissionList.js       |  46 +-
 .../scripts/views/policies/RangerPolicyCreate.js   |  31 +-
 .../scripts/views/policies/RangerPolicyForm.js     |  32 +-
 .../scripts/views/policies/RangerPolicyRO.js       |   1 +
 .../views/policies/RangerPolicyTableLayout.js      |  26 +-
 .../webapp/scripts/views/reports/AuditLayout.js    |   7 +-
 .../scripts/views/reports/OperationDiffDetail.js   |  10 +
 .../scripts/views/users/AddUsersOrGroupsList.js    | 154 +++++++
 .../main/webapp/scripts/views/users/RoleCreate.js  | 154 +++++++
 .../main/webapp/scripts/views/users/RoleForm.js    | 114 +++++
 .../webapp/scripts/views/users/UserTableLayout.js  | 204 ++++++++-
 security-admin/src/main/webapp/styles/xa.css       |  80 +++-
 .../main/webapp/templates/common/TopNav_tmpl.html  |   2 +-
 .../webapp/templates/policies/PermissionItem.html  |  11 +-
 .../webapp/templates/policies/PermissionList.html  |   4 +-
 .../templates/policies/RangerPolicyRO_tmpl.html    |   9 +
 .../templates/reports/RoleOperationDiff_tmpl.html  |  79 ++++
 .../reports/RoleUpdateOperationDiff_tmpl.html      |  74 ++++
 .../AddUserOrGroupsItem_tmpl.html}                 |  40 +-
 .../templates/users/AddUserOrGroupsList_tmpl.html  |  39 ++
 .../RoleCreate_tmpl.html}                          |  39 +-
 .../RoleForm_tmpl.html}                            |  49 +--
 .../templates/users/UserTableLayout_tmpl.html      |   8 +-
 .../org/apache/ranger/biz/TestServiceDBStore.java  |   3 +-
 94 files changed, 6763 insertions(+), 231 deletions(-)

diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/errors/ValidationErrorCode.java b/agents-common/src/main/java/org/apache/ranger/plugin/errors/ValidationErrorCode.java
index 800b3c4..aa87c81 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/errors/ValidationErrorCode.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/errors/ValidationErrorCode.java
@@ -85,7 +85,7 @@ public enum ValidationErrorCode {
     POLICY_VALIDATION_ERR_RECURSIVE_NOT_SUPPORTED(3017, "Recursive option not supported: resource-name=[{0}]."),
     POLICY_VALIDATION_ERR_INVALID_RESOURCE_VALUE_REGEX(3018, "Invalid resource specified. A value of [{0}] is not valid for resource [{1}]"),
     POLICY_VALIDATION_ERR_NULL_POLICY_ITEM(3019, "policy items object was null"),
-    POLICY_VALIDATION_ERR_MISSING_USER_AND_GROUPS(3020, "both users and user-groups collections on the policy item were null/empty"),
+    POLICY_VALIDATION_ERR_MISSING_USER_AND_GROUPS(3020, "All of users,  user-groups and roles collections on the policy item were null/empty"),
     POLICY_VALIDATION_ERR_NULL_POLICY_ITEM_ACCESS(3021, "policy items access object was null"),
     POLICY_VALIDATION_ERR_POLICY_ITEM_ACCESS_TYPE_INVALID(3022, "Invalid access type: access type=[{0}], valid access types=[{1}]"),
     POLICY_VALIDATION_ERR_POLICY_ITEM_ACCESS_TYPE_DENY(3023, "Currently deny access types are not supported. Access type is set to deny."),
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerPolicy.java b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerPolicy.java
index 3cf509d..c228da5 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerPolicy.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerPolicy.java
@@ -834,17 +834,19 @@ public class RangerPolicy extends RangerBaseModelObject implements java.io.Seria
 		private List<RangerPolicyItemAccess>    accesses;
 		private List<String>                    users;
 		private List<String>                    groups;
+		private List<String>                    roles;
 		private List<RangerPolicyItemCondition> conditions;
 		private Boolean                         delegateAdmin;
 
 		public RangerPolicyItem() {
-			this(null, null, null, null, null);
+			this(null, null, null, null, null, null);
 		}
 
-		public RangerPolicyItem(List<RangerPolicyItemAccess> accessTypes, List<String> users, List<String> groups, List<RangerPolicyItemCondition> conditions, Boolean delegateAdmin) {
+		public RangerPolicyItem(List<RangerPolicyItemAccess> accessTypes, List<String> users, List<String> groups, List<String> roles, List<RangerPolicyItemCondition> conditions, Boolean delegateAdmin) {
 			setAccesses(accessTypes);
 			setUsers(users);
 			setGroups(groups);
+			setRoles(roles);
 			setConditions(conditions);
 			setDelegateAdmin(delegateAdmin);
 		}
@@ -922,6 +924,30 @@ public class RangerPolicy extends RangerBaseModelObject implements java.io.Seria
 			}
 		}
 		/**
+		 * @return the roles
+		 */
+		public List<String> getRoles() {
+			return roles;
+		}
+		/**
+		 * @param roles the roles to set
+		 */
+		public void setRoles(List<String> roles) {
+			if(this.roles == null) {
+				this.roles = new ArrayList<>();
+			}
+
+			if(this.roles == roles) {
+				return;
+			}
+
+			this.roles.clear();
+
+			if(roles != null) {
+				this.roles.addAll(roles);
+			}
+		}
+		/**
 		 * @return the conditions
 		 */
 		public List<RangerPolicyItemCondition> getConditions() {
@@ -1002,6 +1028,16 @@ public class RangerPolicy extends RangerBaseModelObject implements java.io.Seria
 			}
 			sb.append("} ");
 
+			sb.append("roles={");
+			if(roles != null) {
+				for(String role : roles) {
+					if(role != null) {
+						sb.append(role).append(" ");
+					}
+				}
+			}
+			sb.append("} ");
+
 			sb.append("conditions={");
 			if(conditions != null) {
 				for(RangerPolicyItemCondition condition : conditions) {
@@ -1029,6 +1065,8 @@ public class RangerPolicy extends RangerBaseModelObject implements java.io.Seria
 			result = prime * result
 					+ ((delegateAdmin == null) ? 0 : delegateAdmin.hashCode());
 			result = prime * result
+					+ ((roles == null) ? 0 : roles.hashCode());
+			result = prime * result
 					+ ((groups == null) ? 0 : groups.hashCode());
 			result = prime * result + ((users == null) ? 0 : users.hashCode());
 			return result;
@@ -1058,6 +1096,11 @@ public class RangerPolicy extends RangerBaseModelObject implements java.io.Seria
 					return false;
 			} else if (!delegateAdmin.equals(other.delegateAdmin))
 				return false;
+			if (roles == null) {
+				if (other.roles != null)
+					return false;
+			} else if (!roles.equals(other.roles))
+				return false;
 			if (groups == null) {
 				if (other.groups != null)
 					return false;
@@ -1084,11 +1127,11 @@ public class RangerPolicy extends RangerBaseModelObject implements java.io.Seria
 		private RangerPolicyItemDataMaskInfo dataMaskInfo;
 
 		public RangerDataMaskPolicyItem() {
-			this(null, null, null, null, null, null);
+			this(null, null, null, null, null, null, null);
 		}
 
-		public RangerDataMaskPolicyItem(List<RangerPolicyItemAccess> accesses, RangerPolicyItemDataMaskInfo dataMaskDetail, List<String> users, List<String> groups, List<RangerPolicyItemCondition> conditions, Boolean delegateAdmin) {
-			super(accesses, users, groups, conditions, delegateAdmin);
+		public RangerDataMaskPolicyItem(List<RangerPolicyItemAccess> accesses, RangerPolicyItemDataMaskInfo dataMaskDetail, List<String> users, List<String> groups, List<String> roles, List<RangerPolicyItemCondition> conditions, Boolean delegateAdmin) {
+			super(accesses, users, groups, roles, conditions, delegateAdmin);
 
 			setDataMaskInfo(dataMaskDetail);
 		}
@@ -1171,11 +1214,11 @@ public class RangerPolicy extends RangerBaseModelObject implements java.io.Seria
 		private RangerPolicyItemRowFilterInfo rowFilterInfo;
 
 		public RangerRowFilterPolicyItem() {
-			this(null, null, null, null, null, null);
+			this(null, null, null, null, null, null, null);
 		}
 
-		public RangerRowFilterPolicyItem(RangerPolicyItemRowFilterInfo rowFilterInfo, List<RangerPolicyItemAccess> accesses, List<String> users, List<String> groups, List<RangerPolicyItemCondition> conditions, Boolean delegateAdmin) {
-			super(accesses, users, groups, conditions, delegateAdmin);
+		public RangerRowFilterPolicyItem(RangerPolicyItemRowFilterInfo rowFilterInfo, List<RangerPolicyItemAccess> accesses, List<String> users, List<String> groups, List<String> roles, List<RangerPolicyItemCondition> conditions, Boolean delegateAdmin) {
+			super(accesses, users, groups, roles, conditions, delegateAdmin);
 
 			setRowFilterInfo(rowFilterInfo);
 		}
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerRole.java b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerRole.java
new file mode 100644
index 0000000..88567e0
--- /dev/null
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/model/RangerRole.java
@@ -0,0 +1,188 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.ranger.plugin.model;
+
+import org.apache.commons.collections.MapUtils;
+import org.codehaus.jackson.annotate.JsonAutoDetect;
+import org.codehaus.jackson.annotate.JsonIgnoreProperties;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+@JsonAutoDetect(fieldVisibility=JsonAutoDetect.Visibility.ANY)
+@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
+@JsonIgnoreProperties(ignoreUnknown=true)
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class RangerRole extends RangerBaseModelObject implements java.io.Serializable {
+    public static final String KEY_USER = "user";
+    public static final String KEY_GROUP = "group";
+
+    private static final long serialVersionUID = 1L;
+    private String                  name;
+    private String                  description;
+    private Map<String, Object>     options;
+    private List<RoleMember>        users;
+    private List<RoleMember>        groups;
+    private List<RoleMember>        roles;
+
+    public RangerRole() {
+        this(null, null, null, null, null, null);
+    }
+
+    public RangerRole(String name, String description, Map<String, Object> options, List<RoleMember> users, List<RoleMember> groups) {
+        this(name, description, options, users, groups, null);
+    }
+
+    public RangerRole(String name, String description, Map<String, Object> options, List<RoleMember> users, List<RoleMember> groups, List<RoleMember> roles) {
+        setName(name);
+        setDescription(description);
+        setOptions(options);
+        setUsers(users);
+        setGroups(groups);
+        setRoles(roles);
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public Map<String, Object> getOptions() {
+        return options;
+    }
+
+    public void setOptions(Map<String, Object> options) {
+        this.options = options == null ? new HashMap<>() : options;
+    }
+
+    public List<RoleMember> getUsers() {
+        return users;
+    }
+
+    public void setUsers(List<RoleMember> users) {
+        this.users = users == null ? new ArrayList<>() : users;
+    }
+
+    public List<RoleMember> getGroups() {
+        return groups;
+    }
+
+    public void setGroups(List<RoleMember> groups) {
+        this.groups = groups == null ? new ArrayList<>() : groups;
+    }
+
+    public List<RoleMember> getRoles() {
+        return roles;
+    }
+
+    public void setRoles(List<RoleMember> roles) {
+        this.roles = roles == null ? new ArrayList<>() : roles;
+    }
+
+    @Override
+    public String toString() {
+        return "{name=" + name
+                + ", description=" + description
+                + ", options=" + getPrintableOptions(options)
+                + ", users=" + users
+                + ", groups=" + groups
+                + ", roles=" + roles
+                + "}";
+    }
+
+    @JsonAutoDetect(fieldVisibility=JsonAutoDetect.Visibility.ANY)
+    @JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
+    @JsonIgnoreProperties(ignoreUnknown=true)
+    @XmlRootElement
+    @XmlAccessorType(XmlAccessType.FIELD)
+    public static class RoleMember implements java.io.Serializable {
+        private static final long serialVersionUID = 1L;
+
+        private String  name;
+        private boolean isAdmin;
+
+        public RoleMember() {
+            this(null, false);
+        }
+        public RoleMember(String name, boolean isAdmin) {
+            setName(name);
+            setIsAdmin(isAdmin);
+        }
+        public void setName(String name) {
+            this.name = name;
+        }
+        public void setIsAdmin(boolean isAdmin) {
+            this.isAdmin = isAdmin;
+        }
+        public String getName() { return name; }
+        public boolean getIsAdmin() { return isAdmin; }
+
+        @Override
+        public String toString() {
+            return "{" + name + ", " + isAdmin + "}";
+        }
+        @Override
+        public int hashCode() {
+            return Objects.hash(name, isAdmin);
+        }
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+            if (obj == null)
+                return false;
+            if (getClass() != obj.getClass())
+                return false;
+            RoleMember other = (RoleMember) obj;
+            return Objects.equals(name, other.name) && isAdmin == other.isAdmin;
+        }
+    }
+
+    private String getPrintableOptions(Map<String, Object> options) {
+        if (MapUtils.isEmpty(options)) return "{}";
+        StringBuilder ret = new StringBuilder();
+        ret.append("{");
+        for (Map.Entry<String, Object> entry : options.entrySet()) {
+            ret.append(entry.getKey()).append(", ").append("[").append(entry.getValue()).append("]").append(",");
+        }
+        ret.append("}");
+        return ret.toString();
+    }
+
+}
\ No newline at end of file
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerPolicyValidator.java b/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerPolicyValidator.java
index 5316bae..412d9e1 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerPolicyValidator.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/model/validation/RangerPolicyValidator.java
@@ -910,10 +910,10 @@ public class RangerPolicyValidator extends RangerValidator {
 				valid = isValidItemAccesses(policyItem.getAccesses(), failures, serviceDef) && valid;
 			}
 			// both users and user-groups collections can't be empty
-			if (CollectionUtils.isEmpty(policyItem.getUsers()) && CollectionUtils.isEmpty(policyItem.getGroups())) {
+			if (CollectionUtils.isEmpty(policyItem.getUsers()) && CollectionUtils.isEmpty(policyItem.getGroups()) && CollectionUtils.isEmpty(policyItem.getRoles())) {
 				ValidationErrorCode error = ValidationErrorCode.POLICY_VALIDATION_ERR_MISSING_USER_AND_GROUPS;
 				failures.add(new ValidationFailureDetailsBuilder()
-					.field("policy item users/user-groups")
+					.field("policy item users/user-groups/roles")
 					.isMissing()
 					.becauseOf(error.getMessage())
 					.errorCode(error.getErrorCode())
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 9ed500c..d201aa6 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
@@ -79,6 +79,8 @@ public interface RangerPolicyEngine {
 
 	boolean isAccessAllowed(RangerPolicy policy, String user, Set<String> userGroups, String accessType);
 
+	boolean isAccessAllowed(RangerPolicy policy, String user, Set<String> userGroups, Set<String> roles, String accessType);
+
 	List<RangerPolicy> getExactMatchPolicies(RangerAccessResource resource, Map<String, Object> evalContext);
 
 	List<RangerPolicy> getExactMatchPolicies(RangerPolicy policy, Map<String, Object> evalContext);
@@ -93,4 +95,6 @@ public interface RangerPolicyEngine {
 
 	RangerPolicyEngine cloneWithDelta(ServicePolicies servicePolicies);
 
+	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 99b2ab3..4a41e62 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
@@ -115,6 +115,8 @@ 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 db5dde7..73fd0c2 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
@@ -84,6 +84,8 @@ public class RangerPolicyEngineImpl implements RangerPolicyEngine {
 
 	private Map<String, RangerResourceTrie>   trieMap;
 	private Map<String, String>               zoneTagServiceMap;
+	private final Map<String, Set<String>>         userRoleMapping;
+	private final Map<String, Set<String>>         groupRoleMapping;
 
 	public RangerPolicyEngineImpl(final RangerPolicyEngineImpl other, ServicePolicies servicePolicies) {
 
@@ -208,6 +210,10 @@ 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();
 
 	}
@@ -298,6 +304,10 @@ 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()) {
@@ -405,6 +415,12 @@ public class RangerPolicyEngineImpl implements RangerPolicyEngine {
 
 		RangerAccessRequestUtil.setCurrentUserInContext(request.getContext(), request.getUser());
 
+		Set<String> roles = getRolesFromUserAndGroups(request.getUser(), request.getUserGroups());
+
+		if (CollectionUtils.isNotEmpty(roles)) {
+			RangerAccessRequestUtil.setCurrentUserRolesInContext(request.getContext(), roles);
+		}
+
 		List<RangerContextEnricher> enrichers = allContextEnrichers;
 
 		if(!CollectionUtils.isEmpty(enrichers)) {
@@ -656,6 +672,23 @@ public class RangerPolicyEngineImpl implements RangerPolicyEngine {
 							ret.setGroupAccessInfo(groupName, accessInfo.getKey(), accessResult, policy);
 						}
 					}
+
+					for (Map.Entry<String, Map<String, PolicyACLSummary.AccessResult>> roleAccessInfo : aclSummary.getRolesAccessInfo().entrySet()) {
+						final String roleName = roleAccessInfo.getKey();
+
+						for (Map.Entry<String, PolicyACLSummary.AccessResult> accessInfo : roleAccessInfo.getValue().entrySet()) {
+							if (isConditional) {
+								accessResult = ACCESS_CONDITIONAL;
+							} else {
+								accessResult = accessInfo.getValue().getResult();
+								if (accessResult.equals(RangerPolicyEvaluator.ACCESS_UNDETERMINED)) {
+									accessResult = RangerPolicyEvaluator.ACCESS_DENIED;
+								}
+							}
+							RangerPolicy policy = evaluator.getPolicy();
+							ret.setRoleAccessInfo(roleName, accessInfo.getKey(), accessResult, policy);
+						}
+					}
 				}
 			}
 			ret.finalizeAcls();
@@ -804,9 +837,11 @@ public class RangerPolicyEngineImpl implements RangerPolicyEngine {
 			matchedRepositories.add(this.policyRepository);
 		}
 
+		Set<String> roles = getRolesFromUserAndGroups(user, userGroups);
+
 		for (RangerPolicyRepository policyRepository : matchedRepositories) {
 			for (RangerPolicyEvaluator evaluator : policyRepository.getLikelyMatchPolicyEvaluators(resource, RangerPolicy.POLICY_TYPE_ACCESS)) {
-				ret = evaluator.isAccessAllowed(resource, user, userGroups, accessType);
+				ret = evaluator.isAccessAllowed(resource, user, userGroups, roles, accessType);
 
 				if (ret) {
 					break;
@@ -836,12 +871,27 @@ public class RangerPolicyEngineImpl implements RangerPolicyEngine {
 			LOG.debug("==> RangerPolicyEngineImpl.isAccessAllowed(" + policy.getId() + ", " + user + ", " + userGroups + ", " + accessType + ")");
 		}
 
+		boolean ret = isAccessAllowed(policy, user, userGroups, null, accessType);
+
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("<== RangerPolicyEngineImpl.isAccessAllowed(" + policy.getId() + ", " + user + ", " + userGroups + ", " + accessType + ") : " + ret);
+		}
+
+		return ret;
+	}
+
+	@Override
+	public boolean isAccessAllowed(RangerPolicy policy, String user, Set<String> userGroups, Set<String> roles, String accessType) {
+		if (LOG.isDebugEnabled()) {
+			LOG.debug("==> RangerPolicyEngineImpl.isAccessAllowed(" + policy.getId() + ", " + user + ", " + userGroups + ", " + roles + ", " + accessType + ")");
+		}
+
 		boolean ret = false;
 
 		RangerPerfTracer perf = null;
 
 		if(RangerPerfTracer.isPerfTraceEnabled(PERF_POLICYENGINE_REQUEST_LOG)) {
-			perf = RangerPerfTracer.getPerfTracer(PERF_POLICYENGINE_REQUEST_LOG, "RangerPolicyEngine.isAccessAllowed(user=" + user + "," + userGroups + ",accessType=" + accessType + ")");
+			perf = RangerPerfTracer.getPerfTracer(PERF_POLICYENGINE_REQUEST_LOG, "RangerPolicyEngine.isAccessAllowed(user=" + user + "," + userGroups + ", roles=" + roles + ",accessType=" + accessType + ")");
 		}
 
 		String zoneName = trieMap == null ? null : policy.getZoneName();
@@ -867,7 +917,7 @@ public class RangerPolicyEngineImpl implements RangerPolicyEngine {
 
 		for (RangerPolicyRepository policyRepository : matchedRepositories) {
 			for (RangerPolicyEvaluator evaluator : policyRepository.getPolicyEvaluators()) {
-				ret = evaluator.isAccessAllowed(policy, user, userGroups, accessType);
+				ret = evaluator.isAccessAllowed(policy, user, userGroups, roles, accessType);
 
 				if (ret) {
 					break;
@@ -881,7 +931,7 @@ public class RangerPolicyEngineImpl implements RangerPolicyEngine {
 		RangerPerfTracer.log(perf);
 
 		if (LOG.isDebugEnabled()) {
-			LOG.debug("<== RangerPolicyEngineImpl.isAccessAllowed(" + policy.getId() + ", " + user + ", " + userGroups + ", " + accessType + "): " + ret);
+			LOG.debug("<== RangerPolicyEngineImpl.isAccessAllowed(" + policy.getId() + ", " + user + ", " + userGroups + ", " + roles + ", " + accessType + "): " + ret);
 		}
 
 		return ret;
@@ -1217,6 +1267,34 @@ public class RangerPolicyEngineImpl implements RangerPolicyEngine {
 		return ret;
 	}
 
+	@Override
+	public Set<String> getRolesFromUserAndGroups(String user, Set<String> groups) {
+		Set<String> allRoles = new HashSet<>();
+		if (MapUtils.isNotEmpty(userRoleMapping) && StringUtils.isNotEmpty(user)) {
+			Set<String> userRoles = userRoleMapping.get(user);
+			if (CollectionUtils.isNotEmpty(userRoles)) {
+				allRoles.addAll(userRoles);
+			}
+		}
+
+		if (MapUtils.isNotEmpty(groupRoleMapping)) {
+			if (CollectionUtils.isNotEmpty(groups)) {
+				for (String group : groups) {
+					Set<String> groupRoles = groupRoleMapping.get(group);
+					if (CollectionUtils.isNotEmpty(groupRoles)) {
+						allRoles.addAll(groupRoles);
+					}
+				}
+			}
+			Set<String> publicGroupRoles = groupRoleMapping.get(RangerPolicyEngine.GROUP_PUBLIC);
+			if (CollectionUtils.isNotEmpty(publicGroupRoles)) {
+				allRoles.addAll(publicGroupRoles);
+			}
+		}
+
+		return allRoles;
+	}
+
 	public List<RangerPolicy> getResourcePolicies(String zoneName) {
 		RangerPolicyRepository zoneResourceRepository = policyRepositories.get(zoneName);
 		return zoneResourceRepository == null ? ListUtils.EMPTY_LIST : zoneResourceRepository.getPolicies();
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerResourceACLs.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerResourceACLs.java
index eafbde2..a0def54 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerResourceACLs.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerResourceACLs.java
@@ -40,6 +40,7 @@ import static org.apache.ranger.plugin.policyevaluator.RangerPolicyEvaluator.ACC
 public class RangerResourceACLs {
 	final private Map<String, Map<String, AccessResult>> userACLs  = new HashMap<>();
 	final private Map<String, Map<String, AccessResult>> groupACLs = new HashMap<>();
+	final private Map<String, Map<String, AccessResult>> roleACLs  = new HashMap<>();
 	public RangerResourceACLs() {
 	}
 
@@ -51,6 +52,8 @@ public class RangerResourceACLs {
 		return groupACLs;
 	}
 
+	public Map<String, Map<String, AccessResult>> getRoleACLs() { return roleACLs; }
+
 	public void finalizeAcls() {
 		Map<String, AccessResult>  publicGroupAccessInfo = groupACLs.get(RangerPolicyEngine.GROUP_PUBLIC);
 		if (publicGroupAccessInfo != null) {
@@ -83,6 +86,7 @@ public class RangerResourceACLs {
 		}
 		finalizeAcls(userACLs);
 		finalizeAcls(groupACLs);
+		finalizeAcls(roleACLs);
 	}
 
 	public void setUserAccessInfo(String userName, String accessType, Integer access, RangerPolicy policy) {
@@ -127,11 +131,33 @@ public class RangerResourceACLs {
 		}
 	}
 
+	public void setRoleAccessInfo(String roleName, String accessType, Integer access, RangerPolicy policy) {
+		Map<String, AccessResult> roleAccessInfo = roleACLs.get(roleName);
+
+		if (roleAccessInfo == null) {
+			roleAccessInfo = new HashMap<>();
+
+			roleACLs.put(roleName, roleAccessInfo);
+		}
+
+		AccessResult accessResult = roleAccessInfo.get(accessType);
+
+		if (accessResult == null) {
+			accessResult = new AccessResult(access, policy);
+
+			roleAccessInfo.put(accessType, accessResult);
+		} else {
+			accessResult.setResult(access);
+			accessResult.setPolicy(policy);
+		}
+	}
+
 	@Override
 	public String toString() {
 		StringBuffer sb = new StringBuffer();
 
 		sb.append("{");
+
 		sb.append("UserACLs={");
 		for (Map.Entry<String, Map<String, AccessResult>> entry : userACLs.entrySet()) {
 			sb.append("user=").append(entry.getKey()).append(":");
@@ -143,6 +169,7 @@ public class RangerResourceACLs {
 			sb.append("},");
 		}
 		sb.append("}");
+
 		sb.append(", GroupACLs={");
 		for (Map.Entry<String, Map<String, AccessResult>> entry : groupACLs.entrySet()) {
 			sb.append("group=").append(entry.getKey()).append(":");
@@ -154,6 +181,19 @@ public class RangerResourceACLs {
 			sb.append("},");
 		}
 		sb.append("}");
+
+		sb.append(", RoleACLs={");
+		for (Map.Entry<String, Map<String, AccessResult>> entry : roleACLs.entrySet()) {
+			sb.append("role=").append(entry.getKey()).append(":");
+			sb.append("permissions={");
+			for (Map.Entry<String, AccessResult> permission : entry.getValue().entrySet()) {
+				sb.append("{Permission=").append(permission.getKey()).append(", value=").append(permission.getValue()).append("}, ");
+				sb.append("{RangerPolicy ID=").append(permission.getValue().getPolicy().getId()).append("},");
+			}
+			sb.append("},");
+		}
+		sb.append("}");
+
 		sb.append("}");
 
 		return sb.toString();
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultPolicyEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultPolicyEvaluator.java
index a57b398..fc38a08 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultPolicyEvaluator.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultPolicyEvaluator.java
@@ -335,18 +335,18 @@ public class RangerDefaultPolicyEvaluator extends RangerAbstractPolicyEvaluator
 	}
 
 	@Override
-	public boolean isAccessAllowed(RangerAccessResource resource, String user, Set<String> userGroups, String accessType) {
+	public boolean isAccessAllowed(RangerAccessResource resource, String user, Set<String> userGroups, Set<String> roles, String accessType) {
 		if(LOG.isDebugEnabled()) {
-			LOG.debug("==> RangerDefaultPolicyEvaluator.isAccessAllowed(" + resource + ", " + user + ", " + userGroups + ", " + accessType + ")");
+			LOG.debug("==> RangerDefaultPolicyEvaluator.isAccessAllowed(" + resource + ", " + user + ", " + userGroups + ", " + roles + ", " + accessType + ")");
 		}
 
 		Map<String, Object> evalContext = new HashMap<>();
 		RangerAccessRequestUtil.setCurrentUserInContext(evalContext, user);
 
-		boolean ret = isAccessAllowed(user, userGroups, accessType) && isMatch(resource, evalContext);
+		boolean ret = isAccessAllowed(user, userGroups, roles, accessType) && isMatch(resource, evalContext);
 		
 		if(LOG.isDebugEnabled()) {
-			LOG.debug("<== RangerDefaultPolicyEvaluator.isAccessAllowed(" + resource + ", " + user + ", " + userGroups + ", " + accessType + "): " + ret);
+			LOG.debug("<== RangerDefaultPolicyEvaluator.isAccessAllowed(" + resource + ", " + user + ", " + userGroups + ", " + roles + ", " + accessType + "): " + ret);
 		}
 
 		return ret;
@@ -365,7 +365,7 @@ public class RangerDefaultPolicyEvaluator extends RangerAbstractPolicyEvaluator
 		Map<String, Object> evalContext = new HashMap<>();
 		RangerAccessRequestUtil.setCurrentUserInContext(evalContext, user);
 
-		boolean ret = isAccessAllowed(user, userGroups, accessType) && isMatch(resources, evalContext);
+		boolean ret = isAccessAllowed(user, userGroups, null, accessType) && isMatch(resources, evalContext);
 
 		if(LOG.isDebugEnabled()) {
 			LOG.debug("<== RangerDefaultPolicyEvaluator.isAccessAllowed(" + resources + ", " + user + ", " + userGroups + ", " + accessType + "): " + ret);
@@ -375,18 +375,18 @@ public class RangerDefaultPolicyEvaluator extends RangerAbstractPolicyEvaluator
 	}
 
 	@Override
-	public boolean isAccessAllowed(RangerPolicy policy, String user, Set<String> userGroups, String accessType) {
+	public boolean isAccessAllowed(RangerPolicy policy, String user, Set<String> userGroups, Set<String> roles,  String accessType) {
 		if(LOG.isDebugEnabled()) {
-			LOG.debug("==> RangerDefaultPolicyEvaluator.isAccessAllowed(" + policy.getId() + ", " + user + ", " + userGroups + ", " + accessType + ")");
+			LOG.debug("==> RangerDefaultPolicyEvaluator.isAccessAllowed(" + policy.getId() + ", " + user + ", " + userGroups + ", " + roles + ", " + accessType + ")");
 		}
 
 		Map<String, Object> evalContext = new HashMap<>();
 		RangerAccessRequestUtil.setCurrentUserInContext(evalContext, user);
 
-		boolean ret = isAccessAllowed(user, userGroups, accessType) && isMatch(policy, evalContext);
+		boolean ret = isAccessAllowed(user, userGroups, roles, accessType) && isMatch(policy, evalContext);
 		
 		if(LOG.isDebugEnabled()) {
-			LOG.debug("<== RangerDefaultPolicyEvaluator.isAccessAllowed(" + policy.getId() + ", " + user + ", " + userGroups + ", " + accessType + "): " + ret);
+			LOG.debug("<== RangerDefaultPolicyEvaluator.isAccessAllowed(" + policy.getId() + ", " + user + ", " + userGroups + ", " + roles + ", " + accessType + "): " + ret);
 		}
 
 		return ret;
@@ -520,11 +520,13 @@ public class RangerDefaultPolicyEvaluator extends RangerAbstractPolicyEvaluator
 		final boolean hasPublicGroupInAllowAndUsersInAllowExceptions = hasPublicGroupAndUserInException(getPolicy().getPolicyItems(), getPolicy().getAllowExceptions());
 		final boolean hasPublicGroupInDenyAndUsersInDenyExceptions   = hasPublicGroupAndUserInException(getPolicy().getDenyPolicyItems(), getPolicy().getDenyExceptions());
 		final boolean hasContextSensitiveSpecification               = hasContextSensitiveSpecification();
+		final boolean hasRoles										 = hasRoles();
 		final boolean isUsableForEvaluation                          =    !hasNonPublicGroupOrConditionsInAllowExceptions
 		                                                               && !hasNonPublicGroupOrConditionsInDenyExceptions
 		                                                               && !hasPublicGroupInAllowAndUsersInAllowExceptions
 		                                                               && !hasPublicGroupInDenyAndUsersInDenyExceptions
-		                                                               && !hasContextSensitiveSpecification;
+		                                                               && !hasContextSensitiveSpecification
+		                                                               && !hasRoles;
 
 		if (isUsableForEvaluation || isCreationForced) {
 			ret = new PolicyACLSummary();
@@ -703,9 +705,9 @@ public class RangerDefaultPolicyEvaluator extends RangerAbstractPolicyEvaluator
 		return ret;
 	}
 
-	protected RangerPolicyItemEvaluator getDeterminingPolicyItem(String user, Set<String> userGroups, String accessType) {
+	protected RangerPolicyItemEvaluator getDeterminingPolicyItem(String user, Set<String> userGroups, Set<String> roles, String accessType) {
 		if(LOG.isDebugEnabled()) {
-			LOG.debug("==> RangerDefaultPolicyEvaluator.getDeterminingPolicyItem(" + user + ", " + userGroups + ", " + accessType + ")");
+			LOG.debug("==> RangerDefaultPolicyEvaluator.getDeterminingPolicyItem(" + user + ", " + userGroups + ", " + roles + ", " + accessType + ")");
 		}
 
 		RangerPolicyItemEvaluator ret = null;
@@ -714,14 +716,14 @@ public class RangerDefaultPolicyEvaluator extends RangerAbstractPolicyEvaluator
 		 *  1. if a deny matches without hitting any deny-exception, return that
 		 *  2. if an allow matches without hitting any allow-exception, return that
 		 */
-		ret = getMatchingPolicyItem(user, userGroups, accessType, denyEvaluators, denyExceptionEvaluators);
+		ret = getMatchingPolicyItem(user, userGroups, roles, accessType, denyEvaluators, denyExceptionEvaluators);
 
 		if(ret == null) {
-			ret = getMatchingPolicyItem(user, userGroups, accessType, allowEvaluators, allowExceptionEvaluators);
+			ret = getMatchingPolicyItem(user, userGroups, roles, accessType, allowEvaluators, allowExceptionEvaluators);
 		}
 
 		if(LOG.isDebugEnabled()) {
-			LOG.debug("<== RangerDefaultPolicyEvaluator.getDeterminingPolicyItem(" + user + ", " + userGroups + ", " + accessType + "): " + ret);
+			LOG.debug("<== RangerDefaultPolicyEvaluator.getDeterminingPolicyItem(" + user + ", " + userGroups + ", " + roles + ", " + accessType + "): " + ret);
 		}
 
 		return ret;
@@ -779,9 +781,9 @@ public class RangerDefaultPolicyEvaluator extends RangerAbstractPolicyEvaluator
 		return ret;
 	}
 
-	protected boolean isAccessAllowed(String user, Set<String> userGroups, String accessType) {
+	protected boolean isAccessAllowed(String user, Set<String> userGroups, Set<String> roles, String accessType) {
 		if(LOG.isDebugEnabled()) {
-			LOG.debug("==> RangerDefaultPolicyEvaluator.isAccessAllowed(" + user + ", " + userGroups + ", " + accessType + ")");
+			LOG.debug("==> RangerDefaultPolicyEvaluator.isAccessAllowed(" + user + ", " + userGroups + ", " + roles + ", " + accessType + ")");
 		}
 
 		boolean ret = false;
@@ -806,7 +808,7 @@ public class RangerDefaultPolicyEvaluator extends RangerAbstractPolicyEvaluator
 				LOG.debug("Using policyItemEvaluators for checking if access is allowed. PolicyId=[" + getId() +"]");
 			}
 
-			RangerPolicyItemEvaluator item = this.getDeterminingPolicyItem(user, userGroups, accessType);
+			RangerPolicyItemEvaluator item = this.getDeterminingPolicyItem(user, userGroups, roles, accessType);
 
 			if (item != null && item.getPolicyItemType() == RangerPolicyItemEvaluator.POLICY_ITEM_TYPE_ALLOW) {
 				ret = true;
@@ -816,7 +818,7 @@ public class RangerDefaultPolicyEvaluator extends RangerAbstractPolicyEvaluator
 		RangerPerfTracer.log(perf);
 
 		if(LOG.isDebugEnabled()) {
-			LOG.debug("<== RangerDefaultPolicyEvaluator.isAccessAllowed(" + user + ", " + userGroups + ", " + accessType + "): " + ret);
+			LOG.debug("<== RangerDefaultPolicyEvaluator.isAccessAllowed(" + user + ", " + userGroups + ", " + roles + ", " + accessType + "): " + ret);
 		}
 
 		return ret;
@@ -1145,16 +1147,16 @@ public class RangerDefaultPolicyEvaluator extends RangerAbstractPolicyEvaluator
         return ret;
     }
 
-	private <T extends RangerPolicyItemEvaluator> T getMatchingPolicyItem(String user, Set<String> userGroups, String accessType, List<T> evaluators, List<T> exceptionEvaluators) {
+	private <T extends RangerPolicyItemEvaluator> T getMatchingPolicyItem(String user, Set<String> userGroups, Set<String> roles, String accessType, List<T> evaluators, List<T> exceptionEvaluators) {
         if(LOG.isDebugEnabled()) {
-            LOG.debug("==> RangerDefaultPolicyEvaluator.getMatchingPolicyItem(" + user + ", " + userGroups + ", " + accessType + ")");
+            LOG.debug("==> RangerDefaultPolicyEvaluator.getMatchingPolicyItem(" + user + ", " + userGroups + ", " + roles + ", " + accessType + ")");
         }
 
         T ret = null;
 
         if(CollectionUtils.isNotEmpty(evaluators)) {
             for (T evaluator : evaluators) {
-                if(evaluator.matchUserGroup(user, userGroups) && evaluator.matchAccessType(accessType)) {
+                if(evaluator.matchUserGroup(user, userGroups, roles) && evaluator.matchAccessType(accessType)) {
                     ret = evaluator;
 
                     break;
@@ -1164,7 +1166,7 @@ public class RangerDefaultPolicyEvaluator extends RangerAbstractPolicyEvaluator
 
         if(ret != null && CollectionUtils.isNotEmpty(exceptionEvaluators)) {
             for (T exceptionEvaluator : exceptionEvaluators) {
-                if(exceptionEvaluator.matchUserGroup(user, userGroups) && exceptionEvaluator.matchAccessType(accessType)) {
+                if(exceptionEvaluator.matchUserGroup(user, userGroups, roles) && exceptionEvaluator.matchAccessType(accessType)) {
                     if(LOG.isDebugEnabled()) {
                         LOG.debug("RangerDefaultPolicyEvaluator.getMatchingPolicyItem(" + user + ", " + userGroups + ", " + accessType + "): found exception policyItem(" + exceptionEvaluator.getPolicyItem() + "); ignoring the matchedPolicyItem(" + ret.getPolicyItem() + ")");
                     }
@@ -1177,7 +1179,7 @@ public class RangerDefaultPolicyEvaluator extends RangerAbstractPolicyEvaluator
         }
 
         if(LOG.isDebugEnabled()) {
-            LOG.debug("<== RangerDefaultPolicyEvaluator.getMatchingPolicyItem(" + user + ", " + userGroups + ", " + accessType + "): " + ret);
+            LOG.debug("<== RangerDefaultPolicyEvaluator.getMatchingPolicyItem(" + user + ", " + userGroups + ", " + roles + ", " + accessType + "): " + ret);
         }
         return ret;
     }
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultPolicyItemEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultPolicyItemEvaluator.java
index 45231e7..5bbbece 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultPolicyItemEvaluator.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultPolicyItemEvaluator.java
@@ -40,6 +40,7 @@ import org.apache.ranger.plugin.policyengine.RangerAccessResult;
 import org.apache.ranger.plugin.policyengine.RangerPolicyEngine;
 import org.apache.ranger.plugin.policyengine.RangerPolicyEngineOptions;
 import org.apache.ranger.plugin.policyresourcematcher.RangerPolicyResourceMatcher;
+import org.apache.ranger.plugin.util.RangerAccessRequestUtil;
 import org.apache.ranger.plugin.util.RangerPerfTracer;
 
 
@@ -159,9 +160,9 @@ public class RangerDefaultPolicyItemEvaluator extends RangerAbstractPolicyItemEv
 	}
 
 	@Override
-	public boolean matchUserGroup(String user, Set<String> userGroups) {
+	public boolean matchUserGroup(String user, Set<String> userGroups, Set<String> roles) {
 		if(LOG.isDebugEnabled()) {
-			LOG.debug("==> RangerDefaultPolicyItemEvaluator.matchUserGroup(" + policyItem + ", " + user + ", " + userGroups + ")");
+			LOG.debug("==> RangerDefaultPolicyItemEvaluator.matchUserGroup(" + policyItem + ", " + user + ", " + userGroups + ", " + roles + ")");
 		}
 
 		boolean ret = false;
@@ -175,10 +176,13 @@ public class RangerDefaultPolicyItemEvaluator extends RangerAbstractPolicyItemEv
 				ret = policyItem.getGroups().contains(RangerPolicyEngine.GROUP_PUBLIC) ||
 						!Collections.disjoint(policyItem.getGroups(), userGroups);
 			}
+			if (!ret && CollectionUtils.isNotEmpty(roles) && CollectionUtils.isNotEmpty(policyItem.getRoles())) {
+				ret = !Collections.disjoint(policyItem.getRoles(), roles);
+			}
 		}
 
 		if(LOG.isDebugEnabled()) {
-			LOG.debug("<== RangerDefaultPolicyItemEvaluator.matchUserGroup(" + policyItem + ", " + user + ", " + userGroups + "): " + ret);
+			LOG.debug("<== RangerDefaultPolicyItemEvaluator.matchUserGroup(" + policyItem + ", " + user + ", " + userGroups + ", " + roles + "): " + ret);
 		}
 
 		return ret;
@@ -203,7 +207,11 @@ public class RangerDefaultPolicyItemEvaluator extends RangerAbstractPolicyItemEv
 			}
 		}
 		if (!ret) {
-			ret = matchUserGroup(user, userGroups);
+			Set<String> roles = null;
+			if (CollectionUtils.isNotEmpty(policyItem.getRoles())) {
+				roles = RangerAccessRequestUtil.getCurrentUserRolesFromContext(request.getContext());
+			}
+			ret = matchUserGroup(user, userGroups, roles);
 		}
 
 		if(LOG.isDebugEnabled()) {
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerOptimizedPolicyEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerOptimizedPolicyEvaluator.java
index 47b4921..7eb15d8 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerOptimizedPolicyEvaluator.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerOptimizedPolicyEvaluator.java
@@ -29,12 +29,14 @@ import org.apache.ranger.plugin.policyengine.RangerAccessRequest;
 import org.apache.ranger.plugin.policyengine.RangerAccessResource;
 import org.apache.ranger.plugin.policyengine.RangerPolicyEngine;
 import org.apache.ranger.plugin.policyengine.RangerPolicyEngineOptions;
+import org.apache.ranger.plugin.util.RangerAccessRequestUtil;
 
 import java.util.*;
 
 public class RangerOptimizedPolicyEvaluator extends RangerDefaultPolicyEvaluator {
     private static final Log LOG = LogFactory.getLog(RangerOptimizedPolicyEvaluator.class);
 
+    private Set<String> roles          = new HashSet<>();
     private Set<String> groups         = new HashSet<>();
     private Set<String> users          = new HashSet<>();
     private Set<String> accessPerms    = new HashSet<>();
@@ -228,15 +230,15 @@ public class RangerOptimizedPolicyEvaluator extends RangerDefaultPolicyEvaluator
     }
 
     @Override
-    protected boolean isAccessAllowed(String user, Set<String> userGroups, String accessType) {
+    protected boolean isAccessAllowed(String user, Set<String> userGroups, Set<String> roles, String accessType) {
         if(LOG.isDebugEnabled()) {
-            LOG.debug("==> RangerOptimizedPolicyEvaluator.isAccessAllowed(" + user + ", " + userGroups + ", " + accessType + ")");
+            LOG.debug("==> RangerOptimizedPolicyEvaluator.isAccessAllowed(" + user + ", " + userGroups + ", " + roles + ", " + accessType + ")");
         }
 
-        boolean ret = hasMatchablePolicyItem(user, userGroups, accessType) && super.isAccessAllowed(user, userGroups, accessType);
+        boolean ret = hasMatchablePolicyItem(user, userGroups, roles, accessType) && super.isAccessAllowed(user, userGroups, roles, accessType);
 
         if(LOG.isDebugEnabled()) {
-            LOG.debug("<== RangerOptimizedPolicyEvaluator.isAccessAllowed(" + user + ", " + userGroups + ", " + accessType + "): " + ret);
+            LOG.debug("<== RangerOptimizedPolicyEvaluator.isAccessAllowed(" + user + ", " + userGroups + ", " + roles + ", " + accessType + "): " + ret);
         }
 
         return ret;
@@ -246,7 +248,7 @@ public class RangerOptimizedPolicyEvaluator extends RangerDefaultPolicyEvaluator
     protected boolean hasMatchablePolicyItem(RangerAccessRequest request) {
         boolean ret = false;
 
-        if (hasPublicGroup || hasCurrentUser || isOwnerMatch(request) || users.contains(request.getUser()) || CollectionUtils.containsAny(groups, request.getUserGroups())) {
+        if (hasPublicGroup || hasCurrentUser || isOwnerMatch(request) || users.contains(request.getUser()) || CollectionUtils.containsAny(groups, request.getUserGroups()) || (CollectionUtils.isNotEmpty(roles) && CollectionUtils.containsAny(roles, RangerAccessRequestUtil.getCurrentUserRolesFromContext(request.getContext())))) {
             if(request.isAccessTypeDelegatedAdmin()) {
                 ret = delegateAdmin;
             } else if(hasAllPerms) {
@@ -275,10 +277,17 @@ public class RangerOptimizedPolicyEvaluator extends RangerDefaultPolicyEvaluator
         return ret;
     }
 
-    private boolean hasMatchablePolicyItem(String user, Set<String> userGroups, String accessType) {
+    private boolean hasMatchablePolicyItem(String user, Set<String> userGroups, Set<String> rolesFromContext, String accessType) {
         boolean ret = false;
 
-        if (hasPublicGroup || hasCurrentUser || users.contains(user) || CollectionUtils.containsAny(groups, userGroups)) {
+        boolean hasRole = false;
+        if (CollectionUtils.isNotEmpty(roles)) {
+            if (CollectionUtils.isNotEmpty(rolesFromContext)) {
+                hasRole = CollectionUtils.containsAny(roles, rolesFromContext);
+            }
+        }
+
+        if (hasPublicGroup || hasCurrentUser || users.contains(user) || CollectionUtils.containsAny(groups, userGroups) || hasRole) {
             boolean isAdminAccess = StringUtils.equals(accessType, RangerPolicyEngine.ADMIN_ACCESS);
 
             if(isAdminAccess) {
@@ -309,6 +318,7 @@ public class RangerOptimizedPolicyEvaluator extends RangerDefaultPolicyEvaluator
 	                }
 	            }
 
+	            roles.addAll(item.getRoles());
 	            groups.addAll(item.getGroups());
 	            users.addAll(item.getUsers());
 
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerPolicyEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerPolicyEvaluator.java
index 5400f71..5174f4e 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerPolicyEvaluator.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerPolicyEvaluator.java
@@ -102,11 +102,11 @@ public interface RangerPolicyEvaluator extends RangerPolicyResourceEvaluator {
 
 	boolean isCompleteMatch(Map<String, RangerPolicyResource> resources, Map<String, Object> evalContext);
 
-	boolean isAccessAllowed(RangerAccessResource resource, String user, Set<String> userGroups, String accessType);
+	boolean isAccessAllowed(RangerAccessResource resource, String user, Set<String> userGroups, Set<String> roles, String accessType);
 
 	boolean isAccessAllowed(Map<String, RangerPolicyResource> resources, String user, Set<String> userGroups, String accessType);
 
-	boolean isAccessAllowed(RangerPolicy policy, String user, Set<String> userGroups, String accessType);
+	boolean isAccessAllowed(RangerPolicy policy, String user, Set<String> userGroups, Set<String> roles, String accessType);
 
 	void updateAccessResult(RangerAccessResult result, RangerPolicyResourceMatcher.MatchType matchType, boolean isAllowed, String reason);
 
@@ -140,10 +140,50 @@ public interface RangerPolicyEvaluator extends RangerPolicyResourceEvaluator {
 		return false;
 	}
 
+	default boolean hasRoles() {
+		RangerPolicy policy = getPolicy();
+
+		for (RangerPolicyItem policyItem : policy.getPolicyItems()) {
+			if (hasRoles(policyItem)) {
+				return true;
+			}
+		}
+		for (RangerPolicyItem policyItem : policy.getDenyPolicyItems()) {
+			if (hasRoles(policyItem)) {
+				return true;
+			}
+		}
+		for (RangerPolicyItem policyItem : policy.getAllowExceptions()) {
+			if (hasRoles(policyItem)) {
+				return true;
+			}
+		}
+		for (RangerPolicyItem policyItem : policy.getDenyExceptions()) {
+			if (hasRoles(policyItem)) {
+				return true;
+			}
+		}
+		for (RangerPolicy.RangerDataMaskPolicyItem policyItem : policy.getDataMaskPolicyItems()) {
+			if (hasRoles(policyItem)) {
+				return true;
+			}
+		}
+		for (RangerPolicy.RangerRowFilterPolicyItem policyItem : policy.getRowFilterPolicyItems()) {
+			if (hasRoles(policyItem)) {
+				return true;
+			}
+		}
+		return false;
+	}
+
 	static boolean hasContextSensitiveSpecification(RangerPolicyItem policyItem) {
 		return  CollectionUtils.isNotEmpty(policyItem.getConditions()) || policyItem.getUsers().contains(RangerPolicyEngine.RESOURCE_OWNER); /* || policyItem.getGroups().contains(RangerPolicyEngine.RESOURCE_GROUP_OWNER) */
 	}
 
+	static boolean hasRoles(RangerPolicyItem policyItem) {
+		return  CollectionUtils.isNotEmpty(policyItem.getRoles());
+	}
+
 	class PolicyEvalOrderComparator implements Comparator<RangerPolicyEvaluator>, Serializable {
 		@Override
 		public int compare(RangerPolicyEvaluator me, RangerPolicyEvaluator other) {
@@ -197,8 +237,9 @@ public interface RangerPolicyEvaluator extends RangerPolicyResourceEvaluator {
 	class PolicyACLSummary {
 		private final Map<String, Map<String, AccessResult>> usersAccessInfo = new HashMap<>();
 		private final Map<String, Map<String, AccessResult>> groupsAccessInfo = new HashMap<>();
+		private final Map<String, Map<String, AccessResult>> rolesAccessInfo  = new HashMap<>();
 
-		private enum AccessorType { USER, GROUP }
+		private enum AccessorType { USER, GROUP, ROLE }
 
 		public static class AccessResult {
 			private int result;
@@ -247,6 +288,10 @@ public interface RangerPolicyEvaluator extends RangerPolicyResourceEvaluator {
 			return groupsAccessInfo;
 		}
 
+		public Map<String, Map<String, AccessResult>> getRolesAccessInfo() {
+			return rolesAccessInfo;
+		}
+
 		void processPolicyItem(RangerPolicyItem policyItem, int policyItemType, boolean isConditional) {
 			final Integer result;
 			final boolean hasContextSensitiveSpecification = RangerPolicyEvaluator.hasContextSensitiveSpecification(policyItem);
@@ -287,6 +332,7 @@ public interface RangerPolicyEvaluator extends RangerPolicyResourceEvaluator {
 
 				final List<String> groups         = policyItem.getGroups();
 				final List<String> users          = policyItem.getUsers();
+				final List<String> roles          = policyItem.getRoles();
 				boolean            hasPublicGroup = false;
 
 				for (RangerPolicyItemAccess access : accesses) {
@@ -313,6 +359,10 @@ public interface RangerPolicyEvaluator extends RangerPolicyResourceEvaluator {
 					if (hasPublicGroup) {
 						addAccess(RangerPolicyEngine.GROUP_PUBLIC, AccessorType.GROUP, access.getType(), result, policyItemType);
 					}
+
+					for (String role : roles) {
+						addAccess(role, AccessorType.ROLE, access.getType(), result, policyItemType);
+					}
 				}
 			}
 		}
@@ -394,6 +444,10 @@ public interface RangerPolicyEvaluator extends RangerPolicyResourceEvaluator {
 					accessorsAccessInfo = groupsAccessInfo;
 					break;
 
+				case ROLE:
+					accessorsAccessInfo = rolesAccessInfo;
+					break;
+
 				default:
 					return;
 			}
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerPolicyItemEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerPolicyItemEvaluator.java
index a6e24c6..ec3950f 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerPolicyItemEvaluator.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerPolicyItemEvaluator.java
@@ -53,7 +53,7 @@ public interface RangerPolicyItemEvaluator {
 
 	boolean isMatch(RangerAccessRequest request);
 
-	boolean matchUserGroup(String user, Set<String> userGroups);
+	boolean matchUserGroup(String user, Set<String> userGroups, Set<String> roles);
 
 	boolean matchAccessType(String accessType);
 
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 5a18226..e854e05 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
@@ -155,6 +155,13 @@ public class RangerAuthContext implements RangerPolicyEngine {
 	    }
 
 	    RangerAccessRequestUtil.setCurrentUserInContext(request.getContext(), request.getUser());
+
+        Set<String> roles = getRolesFromUserAndGroups(request.getUser(), request.getUserGroups());
+
+        if (CollectionUtils.isNotEmpty(roles)) {
+            RangerAccessRequestUtil.setCurrentUserRolesInContext(request.getContext(), roles);
+        }
+
 	    if (MapUtils.isNotEmpty(requestContextEnrichers)) {
             for (Map.Entry<RangerContextEnricher, Object> entry : requestContextEnrichers.entrySet()) {
                 if (entry.getValue() instanceof RangerContextEnricher && entry.getKey().equals(entry.getValue())) {
@@ -237,7 +244,12 @@ public class RangerAuthContext implements RangerPolicyEngine {
     }
 
     @Override
-	public boolean isAccessAllowed(RangerPolicy policy, String user, Set<String> userGroups, String accessType) {
+    public boolean isAccessAllowed(RangerPolicy policy, String user, Set<String> userGroups, String accessType) {
+        return false;
+    }
+
+    @Override
+	public boolean isAccessAllowed(RangerPolicy policy, String user, Set<String> userGroups, Set<String> roles, String accessType) {
     	return false;
     }
 
@@ -266,4 +278,10 @@ public class RangerAuthContext implements RangerPolicyEngine {
         return policyEngine.cloneWithDelta(servicePolicies);
     }
 
+    @Override
+    public Set<String> getRolesFromUserAndGroups(String user, Set<String> groups) {
+        return policyEngine.getRolesFromUserAndGroups(user, groups);
+    }
+
+
 }
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/store/RoleStore.java b/agents-common/src/main/java/org/apache/ranger/plugin/store/RoleStore.java
new file mode 100644
index 0000000..2fec9a0
--- /dev/null
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/store/RoleStore.java
@@ -0,0 +1,47 @@
+/*
+ * 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.store;
+
+import java.util.List;
+
+import org.apache.ranger.plugin.model.RangerRole;
+import org.apache.ranger.plugin.util.SearchFilter;
+
+public interface RoleStore {
+
+    void             init() throws Exception;
+
+    RangerRole       createRole(RangerRole role) throws Exception;
+
+    RangerRole       updateRole(RangerRole role) throws Exception;
+
+    void             deleteRole(String roleName) throws Exception;
+
+    void             deleteRole(Long roleId) throws Exception;
+
+    RangerRole       getRole(Long id) throws Exception;
+
+    RangerRole       getRole(String name) throws Exception;
+
+    List<RangerRole> getRoles(SearchFilter filter) throws Exception;
+
+    List<String>     getRoleNames(SearchFilter filter) throws Exception;
+}
+
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerAccessRequestUtil.java b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerAccessRequestUtil.java
index c20ccde..c8276f1 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerAccessRequestUtil.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerAccessRequestUtil.java
@@ -19,6 +19,7 @@
 
 package org.apache.ranger.plugin.util;
 
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
@@ -39,6 +40,7 @@ public class RangerAccessRequestUtil {
 	public static final String KEY_CONTEXT_REQUESTED_RESOURCES = "REQUESTED_RESOURCES";
 	public static final String KEY_TOKEN_NAMESPACE = "token:";
 	public static final String KEY_USER = "USER";
+	public static final String KEY_ROLES = "ROLES";
 
 	public static void setRequestTagsInContext(Map<String, Object> context, Set<RangerTagForEval> tags) {
 		if(CollectionUtils.isEmpty(tags)) {
@@ -145,4 +147,12 @@ public class RangerAccessRequestUtil {
 		String tokenNameWithNamespace = KEY_TOKEN_NAMESPACE + tokenName;
 		return MapUtils.isNotEmpty(context) ? context.get(tokenNameWithNamespace) : null;
 	}
+
+	public static void setCurrentUserRolesInContext(Map<String, Object> context, Set<String> roles) {
+		setTokenInContext(context, KEY_ROLES, roles);
+	}
+	public static Set<String> getCurrentUserRolesFromContext(Map<String, Object> context) {
+		Object ret = getTokenFromContext(context, KEY_ROLES);
+		return ret != null ? (Set<String>) ret : Collections.EMPTY_SET;
+	}
 }
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/util/SearchFilter.java b/agents-common/src/main/java/org/apache/ranger/plugin/util/SearchFilter.java
index e22249a..4b9848d 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/util/SearchFilter.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/util/SearchFilter.java
@@ -40,6 +40,7 @@ public class SearchFilter {
 	public static final String TAG_SERVICE_ID  = "tagServiceId";  // search
 	public static final String USER            = "user";          // search
 	public static final String GROUP           = "group";         // search
+	public static final String ROLE            = "role";         // search
 	public static final String RESOURCE_PREFIX = "resource:";     // search
 	public static final String RESOURCE_MATCH_SCOPE = "resourceMatchScope"; // search - valid values: "self", "ancestor", "self_or_ancestor"
 	public static final String POL_RESOURCE    = "polResource";   // search
@@ -58,6 +59,8 @@ public class SearchFilter {
     public static final String POLICY_LABEL_ID       = "policyLabelId";      // search, sort
     public static final String ZONE_ID               = "zoneId";      // search, sort
     public static final String ZONE_NAME             = "zoneName";      // search, sort
+	public static final String ROLE_ID               = "roleId";      // search, sort
+	public static final String ROLE_NAME             = "roleName";      // search, sort
 
 	public static final String TAG_DEF_ID                = "tagDefId";            // search
 	public static final String TAG_DEF_GUID              = "tagDefGuid";          // search
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 cbd2cb0..8c63434 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,6 +25,7 @@ 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;
@@ -59,6 +60,8 @@ 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
@@ -159,6 +162,12 @@ 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 + ", "
@@ -170,7 +179,9 @@ public class ServicePolicies implements java.io.Serializable {
 			 	+ "policyDeltas=" + policyDeltas + ", "
 			 	+ "serviceDef=" + serviceDef + ", "
 			 	+ "auditMode=" + auditMode + ", "
-			 	+ "securityZones=" + securityZones
+			 	+ "securityZones=" + securityZones + ", "
+				+ "userRoles=" + userRoles + ", "
+				+ "groupRoles=" + groupRoles + ", "
 				;
 	}
 	public List<RangerPolicyDelta> getPolicyDeltas() { return this.policyDeltas; }
@@ -341,6 +352,7 @@ public class ServicePolicies implements java.io.Serializable {
 					;
 		}
 	}
+
 	static public ServicePolicies copyHeader(ServicePolicies source) {
 		ServicePolicies ret = new ServicePolicies();
 
@@ -351,6 +363,8 @@ 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/model/validation/TestRangerPolicyValidator.java b/agents-common/src/test/java/org/apache/ranger/plugin/model/validation/TestRangerPolicyValidator.java
index e6d90a4..f0e2d07 100644
--- a/agents-common/src/test/java/org/apache/ranger/plugin/model/validation/TestRangerPolicyValidator.java
+++ b/agents-common/src/test/java/org/apache/ranger/plugin/model/validation/TestRangerPolicyValidator.java
@@ -564,7 +564,7 @@ public class TestRangerPolicyValidator {
 		when(policyItem.getUsers()).thenReturn(null);
 		when(policyItem.getGroups()).thenReturn(new ArrayList<String>());
 		_failures.clear(); Assert.assertFalse(_validator.isValidPolicyItem(policyItem, _failures, _serviceDef));
-		_utils.checkFailureForMissingValue(_failures, "policy item users/user-groups");
+		_utils.checkFailureForMissingValue(_failures, "policy item users/user-groups/roles");
 	}
 	
 	@Test
diff --git a/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyACLs.java b/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyACLs.java
index e92a2e6..1abd209 100644
--- a/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyACLs.java
+++ b/agents-common/src/test/java/org/apache/ranger/plugin/policyengine/TestPolicyACLs.java
@@ -101,7 +101,7 @@ public class TestPolicyACLs {
 				policyEngine.preProcess(request);
 				RangerResourceACLs acls = policyEngine.getResourceACLs(request);
 
-				boolean userACLsMatched = true, groupACLsMatched = true;
+				boolean userACLsMatched = true, groupACLsMatched = true, roleACLsMatched = true;
 
 				if (MapUtils.isNotEmpty(acls.getUserACLs()) && MapUtils.isNotEmpty(oneTest.userPermissions)) {
 
@@ -178,7 +178,43 @@ public class TestPolicyACLs {
 					groupACLsMatched = false;
 				}
 
-				assertTrue("getResourceACLs() failed! " + testCase.name + ":" + oneTest.name, userACLsMatched && groupACLsMatched);
+				if (MapUtils.isNotEmpty(acls.getRoleACLs()) && MapUtils.isNotEmpty(oneTest.rolePermissions)) {
+					for (Map.Entry<String, Map<String, RangerResourceACLs.AccessResult>> entry :
+							acls.getRoleACLs().entrySet()) {
+						String roleName = entry.getKey();
+						Map<String, RangerResourceACLs.AccessResult> expected = oneTest.rolePermissions.get(roleName);
+						if (MapUtils.isNotEmpty(entry.getValue()) && MapUtils.isNotEmpty(expected)) {
+							// Compare
+							for (Map.Entry<String, RangerResourceACLs.AccessResult> privilege : entry.getValue().entrySet()) {
+								if (StringUtils.equals(RangerPolicyEngine.ADMIN_ACCESS, privilege.getKey())) {
+									continue;
+								}
+								RangerResourceACLs.AccessResult expectedResult = expected.get(privilege.getKey());
+								if (expectedResult == null) {
+									roleACLsMatched = false;
+									break;
+								} else if (!expectedResult.equals(privilege.getValue())) {
+									roleACLsMatched = false;
+									break;
+								}
+							}
+						} else if (!(MapUtils.isEmpty(entry.getValue()) && MapUtils.isEmpty(expected))){
+							Set<String> privileges = entry.getValue().keySet();
+							if (privileges.size() == 1 && privileges.contains(RangerPolicyEngine.ADMIN_ACCESS)) {
+								roleACLsMatched = true;
+							} else {
+								roleACLsMatched = false;
+							}
+							break;
+						}
+						if (!roleACLsMatched) {
+							break;
+						}
+					}
+				} else if (!(MapUtils.isEmpty(acls.getRoleACLs()) && MapUtils.isEmpty(oneTest.rolePermissions))) {
+					roleACLsMatched = false;
+				}
+				assertTrue("getResourceACLs() failed! " + testCase.name + ":" + oneTest.name, userACLsMatched && groupACLsMatched && roleACLsMatched);
 			}
 		}
 	}
@@ -196,6 +232,7 @@ public class TestPolicyACLs {
 				RangerAccessResource   resource;
 				Map<String, Map<String, RangerResourceACLs.AccessResult>> userPermissions;
 				Map<String, Map<String, RangerResourceACLs.AccessResult>> groupPermissions;
+				Map<String, Map<String, RangerResourceACLs.AccessResult>> rolePermissions;
 			}
 		}
 	}
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 5a47ba4..c3b31bb 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
@@ -376,6 +376,13 @@ public class TestPolicyEngine {
 		runTestsFromResourceFiles(conditionsTestResourceFiles);
 	}
 
+	@Test
+	public void testPolicyEngine_with_roles() {
+		String[] conditionsTestResourceFiles = { "/policyengine/test_policyengine_with_roles.json" };
+
+		runTestsFromResourceFiles(conditionsTestResourceFiles);
+	}
+
 	private void runTestsFromResourceFiles(String[] resourceNames) {
 		for(String resourceName : resourceNames) {
 			InputStream inStream = this.getClass().getResourceAsStream(resourceName);
@@ -395,6 +402,8 @@ 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);
@@ -581,6 +590,8 @@ public class TestPolicyEngine {
 		public List<RangerPolicy> policies;
 		public TagPolicyInfo	  tagPolicyInfo;
 		public Map<String, ServicePolicies.SecurityZoneInfo> securityZones;
+		public Map<String, Set<String>> userRoles;
+		public Map<String, Set<String>> groupRoles;
 		public String             auditMode;
 		public List<TestData>     tests;
 
diff --git a/agents-common/src/test/resources/policyengine/test_aclprovider_default.json b/agents-common/src/test/resources/policyengine/test_aclprovider_default.json
index b4c4def..7c7004a 100644
--- a/agents-common/src/test/resources/policyengine/test_aclprovider_default.json
+++ b/agents-common/src/test/resources/policyengine/test_aclprovider_default.json
@@ -357,6 +357,24 @@
                 "conditions":[{"type":"ip-range","values":["10.*.10.*"]}]
               }
             ]
+          },
+          {
+            "id": 15, "name": "db=db3; table=tbl3; column=col3", "isEnabled": true, "isAuditEnabled": true,
+            "resources": {
+              "database": { "values": [ "db3" ] },
+              "table": { "values": [ "tbl3" ] },
+              "column": { "values": [ "col3" ] }
+            },
+            "policyItems": [
+              { "accesses": [ { "type": "select", "isAllowed": true }, { "type": "update", "isAllowed": true } ],
+                "users": [ "john", "jane" ], "roles": ["tarzan"]
+              }
+            ],
+            "denyPolicyItems": [
+              { "accesses": [ { "type": "drop", "isAllowed": true } ],
+                "users": ["adam", "eve"], "roles": ["eden"]
+              }
+            ]
           }
         ],
         "tagPolicies": {
@@ -579,6 +597,12 @@
           "resource": {"elements":{"database":"db2", "table":"tbl2", "column": "col2" }},
           "userPermissions": {"john":{"select":{"result":1, "isFinal":true}, "update":{"result":-1, "isFinal":true}}, "jane":{"select":{"result":1, "isFinal":true},"update":{"result":1, "isFinal":true}}, "adam":{"drop":{"result":2, "isFinal":true}}, "eve":{"drop":{"result":2, "isFinal":true}}},
           "groupPermissions": {}
+        },
+        {
+          "name": "roles-test",
+          "resource": {"elements":{"database":"db3", "table":"tbl3", "column": "col3" }},
+          "userPermissions": {"john":{"select":{"result":1, "isFinal":true}, "update":{"result":1, "isFinal":true}}, "jane":{"select":{"result":1, "isFinal":true},"update":{"result":1, "isFinal":true}}, "adam":{"drop":{"result":-1, "isFinal":true}}, "eve":{"drop":{"result":-1, "isFinal":true}}},
+          "rolePermissions": {"tarzan":{"select":{"result":1, "isFinal":true}, "update":{"result":1, "isFinal":true}}, "eden":{"drop":{"result":-1, "isFinal":true}}}
         }
       ]
     }
diff --git a/agents-common/src/test/resources/policyengine/test_policyengine_with_roles.json b/agents-common/src/test/resources/policyengine/test_policyengine_with_roles.json
new file mode 100644
index 0000000..c8352cc
--- /dev/null
+++ b/agents-common/src/test/resources/policyengine/test_policyengine_with_roles.json
@@ -0,0 +1,213 @@
+{
+  "serviceName": "hivedev",
+  "serviceDef": {
+    "name": "hive",
+    "id": 3,
+    "resources": [
+      {
+        "name": "database",
+        "level": 1,
+        "mandatory": true,
+        "lookupSupported": true,
+        "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher",
+        "matcherOptions": {
+          "wildCard": true,
+          "ignoreCase": true
+        },
+        "isValidLeaf": true,
+        "label": "Hive Database",
+        "description": "Hive Database"
+      },
+      {
+        "name": "table",
+        "level": 2,
+        "parent": "database",
+        "mandatory": true,
+        "lookupSupported": true,
+        "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher",
+        "matcherOptions": {
+          "wildCard": true,
+          "ignoreCase": true
+        },
+        "isValidLeaf": true,
+        "label": "Hive Table",
+        "description": "Hive Table"
+      },
+      {
+        "name": "column",
+        "level": 3,
+        "parent": "table",
+        "mandatory": true,
+        "lookupSupported": true,
+        "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher",
+        "matcherOptions": {
+          "wildCard": true,
+          "ignoreCase": true
+        },
+        "label": "Hive Column",
+        "description": "Hive Column"
+      }
+    ],
+    "accessTypes": [
+      {
+        "name": "select",
+        "label": "Select"
+      },
+      {
+        "name": "update",
+        "label": "Update"
+      },
+      {
+        "name": "create",
+        "label": "Create"
+      },
+      {
+        "name": "drop",
+        "label": "Drop"
+      },
+      {
+        "name": "alter",
+        "label": "Alter"
+      },
+      {
+        "name": "index",
+        "label": "Index"
+      },
+      {
+        "name": "lock",
+        "label": "Lock"
+      },
+      {
+        "name": "all",
+        "label": "All",
+        "impliedGrants": [
+          "select",
+          "update",
+          "create",
+          "drop",
+          "alter",
+          "index",
+          "lock"
+        ]
+      }
+    ]
+  },
+  "policies": [
+    {
+      "id": 1,
+      "name": "db=default: audit-all-access",
+      "isEnabled": true,
+      "isAuditEnabled": true,
+      "resources": {
+        "database": {
+          "values": [
+            "default"
+          ]
+        },
+        "table": {
+          "values": [
+            "*"
+          ]
+        },
+        "column": {
+          "values": [
+            "*"
+          ]
+        }
+      },
+      "policyItems": [
+        {
+          "accesses": [],
+          "users": [],
+          "groups": [
+            "public"
+          ],
+          "delegateAdmin": false
+        }
+      ]
+    },
+    {
+      "id": 2,
+      "name": "db=default",
+      "isEnabled": true,
+      "isAuditEnabled": true,
+      "resources": {
+        "database": {
+          "values": [
+            "default"
+          ]
+        }
+      },
+      "policyItems": [
+        {
+          "accesses": [
+            {
+              "type": "create",
+              "isAllowed": true
+            },
+            {
+              "type": "drop",
+              "isAllowed": true
+            },
+            {
+              "type": "select",
+              "isAllowed": true
+            }
+          ],
+          "users": [
+            "user1"
+          ],
+          "groups": [ "role-group1"],
+          "roles": ["fin-admin", "fin-group"],
+          "delegateAdmin": false
+        }
+      ]
+    }
+  ],
+  "userRoles": {"role-user1": ["fin-admin", "hr-admin"]},
+  "groupRoles":  {"role-group1": ["fin-group", "hr-group"]},
+  "tests": [
+    {"name":"ALLOW 'create database default default ;' for user='role-user1'",
+      "request":{
+        "resource":{"elements":{"database":"default"}},
+        "accessType":"create","user":"role-user1","userGroups":[],"requestData":"create database default ; for role-user1"
+      },
+      "result":{"isAudited":true,"isAllowed":true,"policyId":2}
+    },
+    {"name":"DENY 'create database default default ;' for user='role-user2'",
+      "request":{
+        "resource":{"elements":{"database":"default"}},
+        "accessType":"create","user":"role-user2","userGroups":[],"requestData":"create database default ; for role-user2"
+      },
+      "result":{"isAudited":true,"isAllowed":false,"policyId":-1}
+    },
+    {"name":"ALLOW 'create database default default ;' for group='role-group1'",
+      "request":{
+        "resource":{"elements":{"database":"default"}},
+        "accessType":"create","user":"","userGroups":["role-group1"],"requestData":"create database default ; for role-group1"
+      },
+      "result":{"isAudited":true,"isAllowed":true,"policyId":2}
+    },
+    {"name":"DENY 'create database default default ;' for group='role-group2'",
+      "request":{
+        "resource":{"elements":{"database":"default"}},
+        "accessType":"create","user":"","userGroups":["role-group2"],"requestData":"create database default ; for role-group2"
+      },
+      "result":{"isAudited":true,"isAllowed":false,"policyId":-1}
+    },
+    {"name":"ALLOW 'create database default default ;' for user1",
+      "request":{
+        "resource":{"elements":{"database":"default"}},
+        "accessType":"create","user":"user1","userGroups":[],"requestData":"create database default ; for user1"
+      },
+      "result":{"isAudited":true,"isAllowed":true,"policyId":2}
+    },
+    {"name":"DENY 'create database default ;' for user2",
+      "request":{
+        "resource":{"elements":{"database":"default"}},
+        "accessType":"create","user":"user2","userGroups":[],"requestData":"create database default ; for user2"
+      },
+      "result":{"isAudited":true,"isAllowed":false,"policyId":-1}
+    }
+  ]
+}
\ No newline at end of file
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 769afb5..7aa9b3f 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
@@ -76,6 +76,11 @@ DROP TABLE IF EXISTS `x_group_users`;
 DROP TABLE IF EXISTS `x_user`;
 DROP TABLE IF EXISTS `x_group_groups`;
 DROP TABLE IF EXISTS `x_group`;
+DROP TABLE IF EXISTS `x_role_ref_role`;
+DROP TABLE IF EXISTS `x_policy_ref_role`;
+DROP TABLE IF EXISTS `x_role_ref_group`;
+DROP TABLE IF EXISTS `x_role_ref_user`;
+DROP TABLE IF EXISTS `x_role`;
 DROP TABLE IF EXISTS `x_db_base`;
 DROP TABLE IF EXISTS `x_cred_store`;
 DROP TABLE IF EXISTS `x_auth_sess`;
@@ -1450,6 +1455,90 @@ CREATE TABLE IF NOT EXISTS `x_policy_change_log` (
 primary key (`id`)
 ) ROW_FORMAT=DYNAMIC;
 
+CREATE TABLE IF NOT EXISTS `x_role`(
+`id` bigint(20) NOT NULL AUTO_INCREMENT,
+`create_time` datetime NULL DEFAULT NULL,
+`update_time` datetime NULL DEFAULT NULL,
+`added_by_id` bigint(20) NULL DEFAULT NULL,
+`upd_by_id` bigint(20) NULL DEFAULT NULL,
+`version` bigint(20) NULL DEFAULT NULL,
+`name` varchar(255) NOT NULL,
+`description` varchar(1024) NULL DEFAULT NULL,
+`role_options` varchar(4000) NULL DEFAULT NULL,
+`role_text` MEDIUMTEXT NULL DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `x_role_UK_name`(`name`(190)),
+ CONSTRAINT `x_role_FK_added_by_id` FOREIGN KEY (`added_by_id`) REFERENCES `x_portal_user` (`id`),
+ CONSTRAINT `x_role_FK_upd_by_id` FOREIGN KEY (`upd_by_id`) REFERENCES `x_portal_user` (`id`)
+)ROW_FORMAT=DYNAMIC;
+
+CREATE TABLE IF NOT EXISTS `x_role_ref_user`(
+`id` bigint(20) NOT NULL AUTO_INCREMENT,
+`create_time` datetime NULL DEFAULT NULL,
+`update_time` datetime NULL DEFAULT NULL,
+`added_by_id` bigint(20) NULL DEFAULT NULL,
+`upd_by_id` bigint(20) NULL DEFAULT NULL,
+`role_id` bigint(20) NOT NULL,
+`user_id` bigint(20) NULL DEFAULT NULL,
+`user_name` varchar(767) NULL DEFAULT NULL,
+`priv_type` int(10) NULL DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ CONSTRAINT `x_role_ref_user_FK_added_by_id` FOREIGN KEY (`added_by_id`) REFERENCES `x_portal_user` (`id`),
+ CONSTRAINT `x_role_ref_user_FK_upd_by_id` FOREIGN KEY (`upd_by_id`) REFERENCES `x_portal_user` (`id`),
+ CONSTRAINT `x_role_ref_user_FK_role_id` FOREIGN KEY (`role_id`) REFERENCES `x_role` (`id`),
+ CONSTRAINT `x_role_ref_user_FK_user_id` FOREIGN KEY (`user_id`) REFERENCES `x_user` (`id`)
+)ROW_FORMAT=DYNAMIC;
+
+CREATE TABLE IF NOT EXISTS `x_role_ref_group`(
+`id` bigint(20) NOT NULL AUTO_INCREMENT,
+`create_time` datetime NULL DEFAULT NULL,
+`update_time` datetime NULL DEFAULT NULL,
+`added_by_id` bigint(20) NULL DEFAULT NULL,
+`upd_by_id` bigint(20) NULL DEFAULT NULL,
+`role_id` bigint(20) NOT NULL,
+`group_id` bigint(20) NULL DEFAULT NULL,
+`group_name` varchar(767) NULL DEFAULT NULL,
+`priv_type` int(10) NULL DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ CONSTRAINT `x_role_ref_group_FK_added_by_id` FOREIGN KEY (`added_by_id`) REFERENCES `x_portal_user` (`id`),
+ CONSTRAINT `x_role_ref_group_FK_upd_by_id` FOREIGN KEY (`upd_by_id`) REFERENCES `x_portal_user` (`id`),
+ CONSTRAINT `x_role_ref_group_FK_role_id` FOREIGN KEY (`role_id`) REFERENCES `x_role` (`id`),
+ CONSTRAINT `x_role_ref_group_FK_group_id` FOREIGN KEY (`group_id`) REFERENCES `x_group` (`id`)
+)ROW_FORMAT=DYNAMIC;
+
+CREATE TABLE IF NOT EXISTS `x_policy_ref_role`(
+`id` bigint(20) NOT NULL AUTO_INCREMENT,
+`create_time` datetime NULL DEFAULT NULL,
+`update_time` datetime NULL DEFAULT NULL,
+`added_by_id` bigint(20) NULL DEFAULT NULL,
+`upd_by_id` bigint(20) NULL DEFAULT NULL,
+`policy_id` bigint(20) NOT NULL,
+`role_id` bigint(20) NOT NULL,
+`role_name` varchar(255) NULL DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `x_policy_ref_role_UK_polId_roleId`(`policy_id`, `role_id`),
+ CONSTRAINT `x_policy_ref_role_FK_added_by_id` FOREIGN KEY (`added_by_id`) REFERENCES `x_portal_user` (`id`),
+ CONSTRAINT `x_policy_ref_role_FK_upd_by_id` FOREIGN KEY (`upd_by_id`) REFERENCES `x_portal_user` (`id`),
+ CONSTRAINT `x_policy_ref_role_FK_policy_id` FOREIGN KEY (`policy_id`) REFERENCES `x_policy` (`id`),
+ CONSTRAINT `x_policy_ref_role_FK_role_id` FOREIGN KEY (`role_id`) REFERENCES `x_role` (`id`)
+)ROW_FORMAT=DYNAMIC;
+
+CREATE TABLE IF NOT EXISTS `x_role_ref_role`(
+`id` bigint(20) NOT NULL AUTO_INCREMENT,
+`create_time` datetime NULL DEFAULT NULL,
+`update_time` datetime NULL DEFAULT NULL,
+`added_by_id` bigint(20) NULL DEFAULT NULL,
+`upd_by_id` bigint(20) NULL DEFAULT NULL,
+`role_ref_id` bigint(20) NULL DEFAULT NULL,
+`role_id` bigint(20) NOT NULL,
+`role_name` varchar(255) NULL DEFAULT NULL,
+`priv_type` int(10) NULL DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ CONSTRAINT `x_role_ref_role_FK_added_by_id` FOREIGN KEY (`added_by_id`) REFERENCES `x_portal_user` (`id`),
+ CONSTRAINT `x_role_ref_role_FK_upd_by_id` FOREIGN KEY (`upd_by_id`) REFERENCES `x_portal_user` (`id`),
+ CONSTRAINT `x_role_ref_role_FK_role_ref_id` FOREIGN KEY (`role_ref_id`) REFERENCES `x_role` (`id`)
+)ROW_FORMAT=DYNAMIC;
+
 CREATE INDEX x_policy_change_log_IDX_service_id ON x_policy_change_log(service_id);
 CREATE INDEX x_policy_change_log_IDX_policy_version ON x_policy_change_log(policy_version);
 CREATE INDEX x_service_config_def_IDX_def_id ON x_service_config_def(def_id);
@@ -1558,6 +1647,7 @@ INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active
 INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('038',UTC_TIMESTAMP(),'Ranger 1.0.0',UTC_TIMESTAMP(),'localhost','Y');
 INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('039',UTC_TIMESTAMP(),'Ranger 1.0.0',UTC_TIMESTAMP(),'localhost','Y');
 INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('040',UTC_TIMESTAMP(),'Ranger 1.0.0',UTC_TIMESTAMP(),'localhost','Y');
+INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('041',UTC_TIMESTAMP(),'Ranger 1.0.0',UTC_TIMESTAMP(),'localhost','Y');
 INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('DB_PATCHES',UTC_TIMESTAMP(),'Ranger 1.0.0',UTC_TIMESTAMP(),'localhost','Y');
 
 INSERT INTO x_user_module_perm (user_id,module_id,create_time,update_time,added_by_id,upd_by_id,is_allowed)
diff --git a/security-admin/db/mysql/patches/041-create-role-schema.sql b/security-admin/db/mysql/patches/041-create-role-schema.sql
new file mode 100644
index 0000000..2f0d5e9
--- /dev/null
+++ b/security-admin/db/mysql/patches/041-create-role-schema.sql
@@ -0,0 +1,105 @@
+-- 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 TABLE IF EXISTS `x_role_ref_role`;
+DROP TABLE IF EXISTS `x_policy_ref_role`;
+DROP TABLE IF EXISTS `x_role_ref_group`;
+DROP TABLE IF EXISTS `x_role_ref_user`;
+DROP TABLE IF EXISTS `x_role`;
+
+CREATE TABLE IF NOT EXISTS `x_role`(
+`id` bigint(20) NOT NULL AUTO_INCREMENT,
+`create_time` datetime NULL DEFAULT NULL,
+`update_time` datetime NULL DEFAULT NULL,
+`added_by_id` bigint(20) NULL DEFAULT NULL,
+`upd_by_id` bigint(20) NULL DEFAULT NULL,
+`version` bigint(20) NULL DEFAULT NULL,
+`name` varchar(255) NOT NULL,
+`description` varchar(1024) NULL DEFAULT NULL,
+`role_options` varchar(4000) NULL DEFAULT NULL,
+`role_text` MEDIUMTEXT NULL DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `x_role_UK_name`(`name`(190)),
+ CONSTRAINT `x_role_FK_added_by_id` FOREIGN KEY (`added_by_id`) REFERENCES `x_portal_user` (`id`),
+ CONSTRAINT `x_role_FK_upd_by_id` FOREIGN KEY (`upd_by_id`) REFERENCES `x_portal_user` (`id`)
+)ROW_FORMAT=DYNAMIC;
+
+CREATE TABLE IF NOT EXISTS `x_role_ref_user`(
+`id` bigint(20) NOT NULL AUTO_INCREMENT,
+`create_time` datetime NULL DEFAULT NULL,
+`update_time` datetime NULL DEFAULT NULL,
+`added_by_id` bigint(20) NULL DEFAULT NULL,
+`upd_by_id` bigint(20) NULL DEFAULT NULL,
+`role_id` bigint(20) NOT NULL,
+`user_id` bigint(20) NULL DEFAULT NULL,
+`user_name` varchar(767) NULL DEFAULT NULL,
+`priv_type` int(10) NULL DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ CONSTRAINT `x_role_ref_user_FK_added_by_id` FOREIGN KEY (`added_by_id`) REFERENCES `x_portal_user` (`id`),
+ CONSTRAINT `x_role_ref_user_FK_upd_by_id` FOREIGN KEY (`upd_by_id`) REFERENCES `x_portal_user` (`id`),
+ CONSTRAINT `x_role_ref_user_FK_role_id` FOREIGN KEY (`role_id`) REFERENCES `x_role` (`id`),
+ CONSTRAINT `x_role_ref_user_FK_user_id` FOREIGN KEY (`user_id`) REFERENCES `x_user` (`id`)
+)ROW_FORMAT=DYNAMIC;
+
+CREATE TABLE IF NOT EXISTS `x_role_ref_group`(
+`id` bigint(20) NOT NULL AUTO_INCREMENT,
+`create_time` datetime NULL DEFAULT NULL,
+`update_time` datetime NULL DEFAULT NULL,
+`added_by_id` bigint(20) NULL DEFAULT NULL,
+`upd_by_id` bigint(20) NULL DEFAULT NULL,
+`role_id` bigint(20) NOT NULL,
+`group_id` bigint(20) NULL DEFAULT NULL,
+`group_name` varchar(767) NULL DEFAULT NULL,
+`priv_type` int(10) NULL DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ CONSTRAINT `x_role_ref_group_FK_added_by_id` FOREIGN KEY (`added_by_id`) REFERENCES `x_portal_user` (`id`),
+ CONSTRAINT `x_role_ref_group_FK_upd_by_id` FOREIGN KEY (`upd_by_id`) REFERENCES `x_portal_user` (`id`),
+ CONSTRAINT `x_role_ref_group_FK_role_id` FOREIGN KEY (`role_id`) REFERENCES `x_role` (`id`),
+ CONSTRAINT `x_role_ref_group_FK_group_id` FOREIGN KEY (`group_id`) REFERENCES `x_group` (`id`)
+)ROW_FORMAT=DYNAMIC;
+
+CREATE TABLE IF NOT EXISTS `x_policy_ref_role`(
+`id` bigint(20) NOT NULL AUTO_INCREMENT,
+`create_time` datetime NULL DEFAULT NULL,
+`update_time` datetime NULL DEFAULT NULL,
+`added_by_id` bigint(20) NULL DEFAULT NULL,
+`upd_by_id` bigint(20) NULL DEFAULT NULL,
+`policy_id` bigint(20) NOT NULL,
+`role_id` bigint(20) NOT NULL,
+`role_name` varchar(255) NULL DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `x_policy_ref_role_UK_polId_roleId`(`policy_id`, `role_id`),
+ CONSTRAINT `x_policy_ref_role_FK_added_by_id` FOREIGN KEY (`added_by_id`) REFERENCES `x_portal_user` (`id`),
+ CONSTRAINT `x_policy_ref_role_FK_upd_by_id` FOREIGN KEY (`upd_by_id`) REFERENCES `x_portal_user` (`id`),
+ CONSTRAINT `x_policy_ref_role_FK_policy_id` FOREIGN KEY (`policy_id`) REFERENCES `x_policy` (`id`),
+ CONSTRAINT `x_policy_ref_role_FK_role_id` FOREIGN KEY (`role_id`) REFERENCES `x_role` (`id`)
+)ROW_FORMAT=DYNAMIC;
+
+CREATE TABLE IF NOT EXISTS `x_role_ref_role`(
+`id` bigint(20) NOT NULL AUTO_INCREMENT,
+`create_time` datetime NULL DEFAULT NULL,
+`update_time` datetime NULL DEFAULT NULL,
+`added_by_id` bigint(20) NULL DEFAULT NULL,
+`upd_by_id` bigint(20) NULL DEFAULT NULL,
+`role_ref_id` bigint(20) NULL DEFAULT NULL,
+`role_id` bigint(20) NOT NULL,
+`role_name` varchar(255) NULL DEFAULT NULL,
+`priv_type` int(10) NULL DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ CONSTRAINT `x_role_ref_role_FK_added_by_id` FOREIGN KEY (`added_by_id`) REFERENCES `x_portal_user` (`id`),
+ CONSTRAINT `x_role_ref_role_FK_upd_by_id` FOREIGN KEY (`upd_by_id`) REFERENCES `x_portal_user` (`id`),
+ CONSTRAINT `x_role_ref_role_FK_role_ref_id` FOREIGN KEY (`role_ref_id`) REFERENCES `x_role` (`id`)
+)ROW_FORMAT=DYNAMIC;
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 9a9e36b..100ee9e 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
@@ -31,6 +31,13 @@ call spdropsequence('X_AUDIT_MAP_SEQ');
 call spdropsequence('X_AUTH_SESS_SEQ');
 call spdropsequence('X_CRED_STORE_SEQ');
 call spdropsequence('X_DB_BASE_SEQ');
+
+call spdropsequence('X_ROLE_REF_ROLE_SEQ');
+call spdropsequence('X_POLICY_REF_ROLE_SEQ');
+call spdropsequence('X_ROLE_REF_GROUP_SEQ');
+call spdropsequence('X_ROLE_REF_USER_SEQ');
+call spdropsequence('X_ROLE_SEQ');
+
 call spdropsequence('X_GROUP_SEQ');
 call spdropsequence('X_GROUP_USERS_SEQ');
 call spdropsequence('X_GROUP_GROUPS_SEQ');
@@ -92,6 +99,7 @@ call spdropsequence('X_SEC_ZONE_REF_TAG_SRVC_SEQ');
 call spdropsequence('X_RANGER_GLOBAL_STATE_SEQ');
 call spdropsequence('X_SECURITY_ZONE_SEQ');
 call spdropsequence('X_POLICY_CHANGE_LOG_SEQ');
+
 CREATE SEQUENCE SEQ_GEN_IDENTITY START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE;
 CREATE SEQUENCE X_ACCESS_AUDIT_SEQ START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE;
 CREATE SEQUENCE X_ASSET_SEQ START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE;
@@ -162,6 +170,12 @@ CREATE SEQUENCE X_SEC_ZONE_REF_GROUP_SEQ START WITH 1 INCREMENT BY 1 NOCACHE NOC
 CREATE SEQUENCE X_POLICY_CHANGE_LOG_SEQ START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE;
 call spdropsequence('X_DB_VERSION_H_SEQ');
 CREATE SEQUENCE X_DB_VERSION_H_SEQ START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE;
+
+CREATE SEQUENCE X_ROLE_SEQ START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE;
+CREATE SEQUENCE X_ROLE_REF_USER_SEQ START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE;
+CREATE SEQUENCE X_ROLE_REF_GROUP_SEQ START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE;
+CREATE SEQUENCE X_POLICY_REF_ROLE_SEQ START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE;
+CREATE SEQUENCE X_ROLE_REF_ROLE_SEQ START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE;
 commit;
 
 CREATE OR REPLACE PROCEDURE spdroptable(ObjName IN varchar2)
@@ -247,6 +261,13 @@ call spdroptable('x_trx_log');
 call spdroptable('x_resource');
 call spdroptable('x_policy_export_audit');
 call spdroptable('x_group_users');
+
+call spdroptable('x_role_ref_role');
+call spdroptable('x_policy_ref_role');
+call spdroptable('x_role_ref_group');
+call spdroptable('x_role_ref_user');
+call spdroptable('x_role');
+
 call spdroptable('x_user');
 call spdroptable('x_group_groups');
 call spdroptable('x_group');
@@ -1478,6 +1499,96 @@ CREATE INDEX x_plcy_chng_log_IDX_service_id ON x_policy_change_log(service_id);
 CREATE INDEX x_plcy_chng_log_IDX_policy_ver ON x_policy_change_log(policy_version);
 COMMIT;
 
+CREATE TABLE x_role(
+id NUMBER(20) NOT NULL,
+create_time DATE DEFAULT NULL NULL,
+update_time DATE DEFAULT NULL NULL,
+added_by_id NUMBER(20) DEFAULT NULL NULL,
+upd_by_id NUMBER(20) DEFAULT NULL NULL,
+version NUMBER(20) DEFAULT NULL NULL,
+name varchar(255) NOT NULL,
+description varchar(1024) DEFAULT NULL NULL,
+role_options varchar(4000) DEFAULT NULL NULL,
+role_text CLOB DEFAULT NULL NULL,
+ PRIMARY KEY (id),
+ CONSTRAINT x_role_UK_name UNIQUE(name),
+ CONSTRAINT x_role_FK_added_by_id FOREIGN KEY (added_by_id) REFERENCES x_portal_user (id),
+ CONSTRAINT x_role_FK_upd_by_id FOREIGN KEY (upd_by_id) REFERENCES x_portal_user (id)
+);
+commit;
+
+CREATE TABLE x_role_ref_user(
+id NUMBER(20) NOT NULL,
+create_time DATE DEFAULT NULL NULL,
+update_time DATE DEFAULT NULL NULL,
+added_by_id NUMBER(20) DEFAULT NULL NULL,
+upd_by_id NUMBER(20) DEFAULT NULL NULL,
+role_id NUMBER(20) NOT NULL,
+user_id NUMBER(20) DEFAULT NULL NULL,
+user_name varchar(767) DEFAULT NULL NULL,
+priv_type NUMBER(10)  DEFAULT NULL NULL,
+ PRIMARY KEY (id),
+ CONSTRAINT x_role_ref_user_FK_added_by_id FOREIGN KEY (added_by_id) REFERENCES x_portal_user (id),
+ CONSTRAINT x_role_ref_user_FK_upd_by_id FOREIGN KEY (upd_by_id) REFERENCES x_portal_user (id),
+ CONSTRAINT x_role_ref_user_FK_role_id FOREIGN KEY (role_id) REFERENCES x_role (id),
+ CONSTRAINT x_role_ref_user_FK_user_id FOREIGN KEY (user_id) REFERENCES x_user (id)
+);
+commit;
+
+CREATE TABLE x_role_ref_group(
+id NUMBER(20) NOT NULL,
+create_time DATE DEFAULT NULL NULL,
+update_time DATE DEFAULT NULL NULL,
+added_by_id NUMBER(20) DEFAULT NULL NULL,
+upd_by_id NUMBER(20) DEFAULT NULL NULL,
+role_id NUMBER(20) NOT NULL,
+group_id NUMBER(20) DEFAULT NULL NULL,
+group_name varchar(767) DEFAULT NULL NULL,
+priv_type NUMBER(10)  DEFAULT NULL NULL,
+ PRIMARY KEY (id),
+ CONSTRAINT x_role_ref_grp_FK_added_by_id FOREIGN KEY (added_by_id) REFERENCES x_portal_user (id),
+ CONSTRAINT x_role_ref_grp_FK_upd_by_id FOREIGN KEY (upd_by_id) REFERENCES x_portal_user (id),
+ CONSTRAINT x_role_ref_grp_FK_role_id FOREIGN KEY (role_id) REFERENCES x_role (id),
+ CONSTRAINT x_role_ref_grp_FK_group_id FOREIGN KEY (group_id) REFERENCES x_group (id)
+);
+commit;
+
+
+CREATE TABLE x_policy_ref_role(
+id NUMBER(20) NOT NULL,
+create_time DATE DEFAULT NULL NULL,
+update_time DATE DEFAULT NULL NULL,
+added_by_id NUMBER(20) DEFAULT NULL NULL,
+upd_by_id NUMBER(20) DEFAULT NULL NULL,
+policy_id NUMBER(20) NOT NULL,
+role_id NUMBER(20) NOT NULL,
+role_name varchar(255) DEFAULT NULL NULL,
+ PRIMARY KEY (id),
+ CONSTRAINT x_pol_ref_role_UK_polId_roleId UNIQUE(policy_id,role_id),
+ CONSTRAINT x_pol_ref_role_FK_added_by_id FOREIGN KEY (added_by_id) REFERENCES x_portal_user (id),
+ CONSTRAINT x_pol_ref_role_FK_upd_by_id FOREIGN KEY (upd_by_id) REFERENCES x_portal_user (id),
+ CONSTRAINT x_pol_ref_role_FK_policy_id FOREIGN KEY (policy_id) REFERENCES x_policy (id),
+ CONSTRAINT x_pol_ref_role_FK_role_id FOREIGN KEY (role_id) REFERENCES x_role (id)
+);
+commit;
+
+CREATE TABLE x_role_ref_role(
+id NUMBER(20) NOT NULL,
+create_time DATE DEFAULT NULL NULL,
+update_time DATE DEFAULT NULL NULL,
+added_by_id NUMBER(20) DEFAULT NULL NULL,
+upd_by_id NUMBER(20) DEFAULT NULL NULL,
+role_ref_id NUMBER(20) DEFAULT NULL NULL,
+role_id NUMBER(20) NOT NULL,
+role_name varchar(255) DEFAULT NULL NULL,
+priv_type NUMBER(10)  DEFAULT NULL NULL,
+ PRIMARY KEY (id),
+ CONSTRAINT x_role_ref_role_FK_added_by_id FOREIGN KEY (added_by_id) REFERENCES x_portal_user (id),
+ CONSTRAINT x_role_ref_role_FK_upd_by_id FOREIGN KEY (upd_by_id) REFERENCES x_portal_user (id),
+ CONSTRAINT x_role_ref_role_FK_role_ref_id FOREIGN KEY (role_ref_id) REFERENCES x_role (id)
+);
+commit;
+
 CREATE TABLE x_security_zone_ref_resource (
 id NUMBER(20) NOT NULL,
 create_time DATE DEFAULT NULL NULL,
@@ -1729,6 +1840,7 @@ INSERT INTO x_db_version_h (id,version,inst_at,inst_by,updated_at,updated_by,act
 INSERT INTO x_db_version_h (id,version,inst_at,inst_by,updated_at,updated_by,active) VALUES (X_DB_VERSION_H_SEQ.nextval, '038',sys_extract_utc(systimestamp),'Ranger 1.0.0',sys_extract_utc(systimestamp),'localhost','Y');
 INSERT INTO x_db_version_h (id,version,inst_at,inst_by,updated_at,updated_by,active) VALUES (X_DB_VERSION_H_SEQ.nextval, '039',sys_extract_utc(systimestamp),'Ranger 1.0.0',sys_extract_utc(systimestamp),'localhost','Y');
 INSERT INTO x_db_version_h (id,version,inst_at,inst_by,updated_at,updated_by,active) VALUES (X_DB_VERSION_H_SEQ.nextval, '040',sys_extract_utc(systimestamp),'Ranger 1.0.0',sys_extract_utc(systimestamp),'localhost','Y');
+INSERT INTO x_db_version_h (id,version,inst_at,inst_by,updated_at,updated_by,active) VALUES (X_DB_VERSION_H_SEQ.nextval, '041',sys_extract_utc(systimestamp),'Ranger 1.0.0',sys_extract_utc(systimestamp),'localhost','Y');
 INSERT INTO x_db_version_h (id,version,inst_at,inst_by,updated_at,updated_by,active) VALUES (X_DB_VERSION_H_SEQ.nextval, 'DB_PATCHES',sys_extract_utc(systimestamp),'Ranger 1.0.0',sys_extract_utc(systimestamp),'localhost','Y');
 INSERT INTO x_user_module_perm (id,user_id,module_id,create_time,update_time,added_by_id,upd_by_id,is_allowed) VALUES (X_USER_MODULE_PERM_SEQ.nextval,getXportalUIdByLoginId('admin'),getModulesIdByName('Reports'),sys_extract_utc(systimestamp),sys_extract_utc(systimestamp),getXportalUIdByLoginId('admin'),getXportalUIdByLoginId('admin'),1);
 INSERT INTO x_user_module_perm (id,user_id,module_id,create_time,update_time,added_by_id,upd_by_id,is_allowed) VALUES (X_USER_MODULE_PERM_SEQ.nextval,getXportalUIdByLoginId('admin'),getModulesIdByName('Resource Based Policies'),sys_extract_utc(systimestamp),sys_extract_utc(systimestamp),getXportalUIdByLoginId('admin'),getXportalUIdByLoginId('admin'),1);
diff --git a/security-admin/db/oracle/patches/041-create-role-schema.sql b/security-admin/db/oracle/patches/041-create-role-schema.sql
new file mode 100644
index 0000000..65969a4
--- /dev/null
+++ b/security-admin/db/oracle/patches/041-create-role-schema.sql
@@ -0,0 +1,147 @@
+-- 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.
+
+
+CREATE OR REPLACE PROCEDURE spdropsequence(ObjName IN varchar2)
+IS
+v_counter integer;
+BEGIN
+    select count(*) into v_counter from user_sequences where sequence_name = upper(ObjName);
+      if (v_counter > 0) then
+        execute immediate 'DROP SEQUENCE ' || ObjName;
+      end if;
+END;/
+/
+
+CREATE OR REPLACE PROCEDURE spdroptable(ObjName IN varchar2)
+IS
+v_counter integer;
+BEGIN
+    select count(*) into v_counter from user_tables where table_name = upper(ObjName);
+     if (v_counter > 0) then
+     execute immediate 'drop table ' || ObjName || ' cascade constraints';
+     end if;
+END;/
+/
+
+
+call spdropsequence('X_ROLE_REF_ROLE_SEQ');
+call spdropsequence('X_POLICY_REF_ROLE_SEQ');
+call spdropsequence('X_ROLE_REF_GROUP_SEQ');
+call spdropsequence('X_ROLE_REF_USER_SEQ');
+call spdropsequence('X_ROLE_SEQ');
+
+CREATE SEQUENCE X_ROLE_SEQ START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE;
+CREATE SEQUENCE X_ROLE_REF_USER_SEQ START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE;
+CREATE SEQUENCE X_ROLE_REF_GROUP_SEQ START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE;
+CREATE SEQUENCE X_POLICY_REF_ROLE_SEQ START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE;
+CREATE SEQUENCE X_ROLE_REF_ROLE_SEQ START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE;
+
+call spdroptable('x_role_ref_role');
+call spdroptable('x_policy_ref_role');
+call spdroptable('x_role_ref_group');
+call spdroptable('x_role_ref_user');
+call spdroptable('x_role');
+commit;
+
+CREATE TABLE x_role(
+id NUMBER(20) NOT NULL,
+create_time DATE DEFAULT NULL NULL,
+update_time DATE DEFAULT NULL NULL,
+added_by_id NUMBER(20) DEFAULT NULL NULL,
+upd_by_id NUMBER(20) DEFAULT NULL NULL,
+version NUMBER(20) DEFAULT NULL NULL,
+name varchar(255) NOT NULL,
+description varchar(1024) DEFAULT NULL NULL,
+role_options varchar(4000) DEFAULT NULL NULL,
+role_text CLOB DEFAULT NULL NULL,
+ PRIMARY KEY (id),
+ CONSTRAINT x_role_UK_name UNIQUE(name),
+ CONSTRAINT x_role_FK_added_by_id FOREIGN KEY (added_by_id) REFERENCES x_portal_user (id),
+ CONSTRAINT x_role_FK_upd_by_id FOREIGN KEY (upd_by_id) REFERENCES x_portal_user (id)
+);
+commit;
+
+CREATE TABLE x_role_ref_user(
+id NUMBER(20) NOT NULL,
+create_time DATE DEFAULT NULL NULL,
+update_time DATE DEFAULT NULL NULL,
+added_by_id NUMBER(20) DEFAULT NULL NULL,
+upd_by_id NUMBER(20) DEFAULT NULL NULL,
+role_id NUMBER(20) NOT NULL,
+user_id NUMBER(20) DEFAULT NULL NULL,
+user_name varchar(767) DEFAULT NULL NULL,
+priv_type NUMBER(10)  DEFAULT NULL NULL,
+ PRIMARY KEY (id),
+ CONSTRAINT x_role_ref_user_FK_added_by_id FOREIGN KEY (added_by_id) REFERENCES x_portal_user (id),
+ CONSTRAINT x_role_ref_user_FK_upd_by_id FOREIGN KEY (upd_by_id) REFERENCES x_portal_user (id),
+ CONSTRAINT x_role_ref_user_FK_role_id FOREIGN KEY (role_id) REFERENCES x_role (id),
+ CONSTRAINT x_role_ref_user_FK_user_id FOREIGN KEY (user_id) REFERENCES x_user (id)
+);
+commit;
+
+CREATE TABLE x_role_ref_group(
+id NUMBER(20) NOT NULL,
+create_time DATE DEFAULT NULL NULL,
+update_time DATE DEFAULT NULL NULL,
+added_by_id NUMBER(20) DEFAULT NULL NULL,
+upd_by_id NUMBER(20) DEFAULT NULL NULL,
+role_id NUMBER(20) NOT NULL,
+group_id NUMBER(20) DEFAULT NULL NULL,
+group_name varchar(767) DEFAULT NULL NULL,
+priv_type NUMBER(10)  DEFAULT NULL NULL,
+ PRIMARY KEY (id),
+ CONSTRAINT x_role_ref_grp_FK_added_by_id FOREIGN KEY (added_by_id) REFERENCES x_portal_user (id),
+ CONSTRAINT x_role_ref_grp_FK_upd_by_id FOREIGN KEY (upd_by_id) REFERENCES x_portal_user (id),
+ CONSTRAINT x_role_ref_grp_FK_role_id FOREIGN KEY (role_id) REFERENCES x_role (id),
+ CONSTRAINT x_role_ref_grp_FK_group_id FOREIGN KEY (group_id) REFERENCES x_group (id)
+);
+commit;
+
+
+CREATE TABLE x_policy_ref_role(
+id NUMBER(20) NOT NULL,
+create_time DATE DEFAULT NULL NULL,
+update_time DATE DEFAULT NULL NULL,
+added_by_id NUMBER(20) DEFAULT NULL NULL,
+upd_by_id NUMBER(20) DEFAULT NULL NULL,
+policy_id NUMBER(20) NOT NULL,
+role_id NUMBER(20) NOT NULL,
+role_name varchar(255) DEFAULT NULL NULL,
+ PRIMARY KEY (id),
+ CONSTRAINT x_pol_ref_role_UK_polId_roleId UNIQUE(policy_id,role_id),
+ CONSTRAINT x_pol_ref_role_FK_added_by_id FOREIGN KEY (added_by_id) REFERENCES x_portal_user (id),
+ CONSTRAINT x_pol_ref_role_FK_upd_by_id FOREIGN KEY (upd_by_id) REFERENCES x_portal_user (id),
+ CONSTRAINT x_pol_ref_role_FK_policy_id FOREIGN KEY (policy_id) REFERENCES x_policy (id),
+ CONSTRAINT x_pol_ref_role_FK_role_id FOREIGN KEY (role_id) REFERENCES x_role (id)
+);
+commit;
+
+CREATE TABLE x_role_ref_role(
+id NUMBER(20) NOT NULL,
+create_time DATE DEFAULT NULL NULL,
+update_time DATE DEFAULT NULL NULL,
+added_by_id NUMBER(20) DEFAULT NULL NULL,
+upd_by_id NUMBER(20) DEFAULT NULL NULL,
+role_ref_id NUMBER(20) DEFAULT NULL NULL,
+role_id NUMBER(20) NOT NULL,
+role_name varchar(255) DEFAULT NULL NULL,
+priv_type NUMBER(10)  DEFAULT NULL NULL,
+ PRIMARY KEY (id),
+ CONSTRAINT x_role_ref_role_FK_added_by_id FOREIGN KEY (added_by_id) REFERENCES x_portal_user (id),
+ CONSTRAINT x_role_ref_role_FK_upd_by_id FOREIGN KEY (upd_by_id) REFERENCES x_portal_user (id),
+ CONSTRAINT x_role_ref_role_FK_role_ref_id FOREIGN KEY (role_ref_id) REFERENCES x_role (id)
+);
+commit;
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 df4201d..eac6a75 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
@@ -71,6 +71,13 @@ DROP TABLE IF EXISTS x_perm_map CASCADE;
 DROP TABLE IF EXISTS x_trx_log CASCADE;
 DROP TABLE IF EXISTS x_resource CASCADE;
 DROP TABLE IF EXISTS x_policy_export_audit CASCADE;
+
+DROP TABLE IF EXISTS x_role_ref_role CASCADE;
+DROP TABLE IF EXISTS x_policy_ref_role CASCADE;
+DROP TABLE IF EXISTS x_role_ref_group CASCADE;
+DROP TABLE IF EXISTS x_role_ref_user CASCADE;
+DROP TABLE IF EXISTS x_role CASCADE;
+
 DROP TABLE IF EXISTS x_group_users CASCADE;
 DROP TABLE IF EXISTS x_user CASCADE;
 DROP TABLE IF EXISTS x_group_groups;
@@ -138,6 +145,13 @@ DROP SEQUENCE IF EXISTS x_trx_log_seq;
 DROP SEQUENCE IF EXISTS x_resource_seq;
 DROP SEQUENCE IF EXISTS x_policy_export_seq;
 DROP SEQUENCE IF EXISTS x_group_users_seq;
+
+DROP SEQUENCE IF EXISTS x_role_ref_role_SEQ;
+DROP SEQUENCE IF EXISTS x_policy_ref_role_SEQ;
+DROP SEQUENCE IF EXISTS x_role_ref_group_SEQ;
+DROP SEQUENCE IF EXISTS x_role_ref_user_SEQ;
+DROP SEQUENCE IF EXISTS x_role_SEQ;
+
 DROP SEQUENCE IF EXISTS x_user_seq;
 DROP SEQUENCE IF EXISTS x_group_groups_seq;
 DROP SEQUENCE IF EXISTS x_group_seq;
@@ -1444,6 +1458,101 @@ policy_id bigint DEFAULT NULL NULL,
 primary key (id)
 );
 commit;
+
+CREATE SEQUENCE x_role_SEQ;
+CREATE TABLE x_role(
+id BIGINT DEFAULT nextval('x_role_SEQ'::regclass),
+create_time TIMESTAMP DEFAULT NULL NULL,
+update_time TIMESTAMP DEFAULT NULL NULL,
+added_by_id BIGINT DEFAULT NULL NULL,
+upd_by_id BIGINT DEFAULT NULL NULL,
+version BIGINT DEFAULT '0' NOT NULL,
+name varchar(255) NOT NULL,
+description varchar(1024) DEFAULT NULL NULL,
+role_options varchar(4000) DEFAULT NULL NULL,
+role_text text DEFAULT NULL NULL,
+ PRIMARY KEY (id),
+ CONSTRAINT x_role_UK_name UNIQUE(name),
+ CONSTRAINT x_role_FK_added_by_id FOREIGN KEY (added_by_id) REFERENCES x_portal_user (id),
+ CONSTRAINT x_role_FK_upd_by_id FOREIGN KEY (upd_by_id) REFERENCES x_portal_user (id)
+);
+commit;
+
+CREATE SEQUENCE x_role_ref_user_SEQ;
+CREATE TABLE x_role_ref_user(
+id BIGINT DEFAULT nextval('x_role_ref_user_SEQ'::regclass),
+create_time TIMESTAMP DEFAULT NULL NULL,
+update_time TIMESTAMP DEFAULT NULL NULL,
+added_by_id BIGINT DEFAULT NULL NULL,
+upd_by_id BIGINT DEFAULT NULL NULL,
+role_id BIGINT NOT NULL,
+user_id BIGINT DEFAULT NULL NULL,
+user_name varchar(767) DEFAULT NULL NULL,
+priv_type INT DEFAULT NULL NULL,
+ PRIMARY KEY (id),
+ CONSTRAINT x_role_ref_user_FK_added_by_id FOREIGN KEY (added_by_id) REFERENCES x_portal_user (id),
+ CONSTRAINT x_role_ref_user_FK_upd_by_id FOREIGN KEY (upd_by_id) REFERENCES x_portal_user (id),
+ CONSTRAINT x_role_ref_user_FK_role_id FOREIGN KEY (role_id) REFERENCES x_role (id),
+ CONSTRAINT x_role_ref_user_FK_user_id FOREIGN KEY (user_id) REFERENCES x_user (id)
+);
+commit;
+
+CREATE SEQUENCE x_role_ref_group_SEQ;
+CREATE TABLE x_role_ref_group(
+id BIGINT DEFAULT nextval('x_role_ref_group_SEQ'::regclass),
+create_time TIMESTAMP DEFAULT NULL NULL,
+update_time TIMESTAMP DEFAULT NULL NULL,
+added_by_id BIGINT DEFAULT NULL NULL,
+upd_by_id BIGINT DEFAULT NULL NULL,
+role_id BIGINT NOT NULL,
+group_id BIGINT DEFAULT NULL NULL,
+group_name varchar(767) DEFAULT NULL NULL,
+priv_type INT DEFAULT NULL NULL,
+ PRIMARY KEY (id),
+ CONSTRAINT x_role_ref_grp_FK_added_by_id FOREIGN KEY (added_by_id) REFERENCES x_portal_user (id),
+ CONSTRAINT x_role_ref_grp_FK_upd_by_id FOREIGN KEY (upd_by_id) REFERENCES x_portal_user (id),
+ CONSTRAINT x_role_ref_grp_FK_role_id FOREIGN KEY (role_id) REFERENCES x_role (id),
+ CONSTRAINT x_role_ref_grp_FK_group_id FOREIGN KEY (group_id) REFERENCES x_group (id)
+);
+commit;
+
+CREATE SEQUENCE x_policy_ref_role_SEQ;
+CREATE TABLE x_policy_ref_role(
+id BIGINT DEFAULT nextval('x_policy_ref_role_SEQ'::regclass),
+create_time TIMESTAMP DEFAULT NULL NULL,
+update_time TIMESTAMP DEFAULT NULL NULL,
+added_by_id BIGINT DEFAULT NULL NULL,
+upd_by_id BIGINT DEFAULT NULL NULL,
+policy_id BIGINT NOT NULL,
+role_id BIGINT NOT NULL,
+role_name varchar(255) DEFAULT NULL,
+ PRIMARY KEY (id),
+ CONSTRAINT x_pol_ref_role_UK_polId_roleId UNIQUE(policy_id,role_id),
+ CONSTRAINT x_pol_ref_role_FK_added_by_id FOREIGN KEY (added_by_id) REFERENCES x_portal_user (id),
+ CONSTRAINT x_pol_ref_role_FK_upd_by_id FOREIGN KEY (upd_by_id) REFERENCES x_portal_user (id),
+ CONSTRAINT x_pol_ref_role_FK_policy_id FOREIGN KEY (policy_id) REFERENCES x_policy (id),
+ CONSTRAINT x_pol_ref_role_FK_role_id FOREIGN KEY (role_id) REFERENCES x_role (id)
+);
+commit;
+
+CREATE SEQUENCE x_role_ref_role_SEQ;
+CREATE TABLE x_role_ref_role(
+id BIGINT DEFAULT nextval('x_role_ref_role_SEQ'::regclass),
+create_time TIMESTAMP DEFAULT NULL NULL,
+update_time TIMESTAMP DEFAULT NULL NULL,
+added_by_id BIGINT DEFAULT NULL NULL,
+upd_by_id BIGINT DEFAULT NULL NULL,
+role_ref_id BIGINT DEFAULT NULL NULL,
+role_id BIGINT NOT NULL,
+role_name varchar(255) DEFAULT NULL NULL,
+priv_type INT DEFAULT NULL NULL,
+ PRIMARY KEY (id),
+ CONSTRAINT x_role_ref_role_FK_added_by_id FOREIGN KEY (added_by_id) REFERENCES x_portal_user (id),
+ CONSTRAINT x_role_ref_role_FK_upd_by_id FOREIGN KEY (upd_by_id) REFERENCES x_portal_user (id),
+ CONSTRAINT x_role_ref_role_FK_role_ref_id FOREIGN KEY (role_ref_id) REFERENCES x_role (id)
+);
+commit;
+
 CREATE INDEX x_policy_change_log_IDX_service_id ON x_policy_change_log(service_id);
 CREATE INDEX x_policy_change_log_IDX_policy_version ON x_policy_change_log(policy_version);
 commit;
@@ -1655,6 +1764,7 @@ INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active
 INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('038',current_timestamp,'Ranger 1.0.0',current_timestamp,'localhost','Y');
 INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('039',current_timestamp,'Ranger 1.0.0',current_timestamp,'localhost','Y');
 INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('040',current_timestamp,'Ranger 1.0.0',current_timestamp,'localhost','Y');
+INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('041',current_timestamp,'Ranger 1.0.0',current_timestamp,'localhost','Y');
 INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('DB_PATCHES',current_timestamp,'Ranger 1.0.0',current_timestamp,'localhost','Y');
 
 INSERT INTO x_user_module_perm (user_id,module_id,create_time,update_time,added_by_id,upd_by_id,is_allowed) VALUES
diff --git a/security-admin/db/postgres/patches/041-create-role-schema.sql b/security-admin/db/postgres/patches/041-create-role-schema.sql
new file mode 100644
index 0000000..2d7f52f
--- /dev/null
+++ b/security-admin/db/postgres/patches/041-create-role-schema.sql
@@ -0,0 +1,120 @@
+-- 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 TABLE IF EXISTS x_role_ref_role CASCADE;
+DROP SEQUENCE IF EXISTS x_role_ref_role_SEQ;
+DROP TABLE IF EXISTS x_policy_ref_role CASCADE;
+DROP SEQUENCE IF EXISTS x_policy_ref_role_SEQ;
+DROP TABLE IF EXISTS x_role_ref_group CASCADE;
+DROP SEQUENCE IF EXISTS x_role_ref_group_SEQ;
+DROP TABLE IF EXISTS x_role_ref_user CASCADE;
+DROP SEQUENCE IF EXISTS x_role_ref_user_SEQ;
+DROP TABLE IF EXISTS x_role CASCADE;
+DROP SEQUENCE IF EXISTS x_role_SEQ;
+
+CREATE SEQUENCE x_role_SEQ;
+CREATE TABLE x_role(
+id BIGINT DEFAULT nextval('x_role_SEQ'::regclass),
+create_time TIMESTAMP DEFAULT NULL NULL,
+update_time TIMESTAMP DEFAULT NULL NULL,
+added_by_id BIGINT DEFAULT NULL NULL,
+upd_by_id BIGINT DEFAULT NULL NULL,
+version BIGINT DEFAULT '0' NOT NULL,
+name varchar(255) NOT NULL,
+description varchar(1024) DEFAULT NULL NULL,
+role_options varchar(4000) DEFAULT NULL NULL,
+role_text text DEFAULT NULL NULL,
+ PRIMARY KEY (id),
+ CONSTRAINT x_role_UK_name UNIQUE(name),
+ CONSTRAINT x_role_FK_added_by_id FOREIGN KEY (added_by_id) REFERENCES x_portal_user (id),
+ CONSTRAINT x_role_FK_upd_by_id FOREIGN KEY (upd_by_id) REFERENCES x_portal_user (id)
+);
+commit;
+
+CREATE SEQUENCE x_role_ref_user_SEQ;
+CREATE TABLE x_role_ref_user(
+id BIGINT DEFAULT nextval('x_role_ref_user_SEQ'::regclass),
+create_time TIMESTAMP DEFAULT NULL NULL,
+update_time TIMESTAMP DEFAULT NULL NULL,
+added_by_id BIGINT DEFAULT NULL NULL,
+upd_by_id BIGINT DEFAULT NULL NULL,
+role_id BIGINT NOT NULL,
+user_id BIGINT DEFAULT NULL NULL,
+user_name varchar(767) DEFAULT NULL NULL,
+priv_type INT DEFAULT NULL NULL,
+ PRIMARY KEY (id),
+ CONSTRAINT x_role_ref_user_FK_added_by_id FOREIGN KEY (added_by_id) REFERENCES x_portal_user (id),
+ CONSTRAINT x_role_ref_user_FK_upd_by_id FOREIGN KEY (upd_by_id) REFERENCES x_portal_user (id),
+ CONSTRAINT x_role_ref_user_FK_role_id FOREIGN KEY (role_id) REFERENCES x_role (id),
+ CONSTRAINT x_role_ref_user_FK_user_id FOREIGN KEY (user_id) REFERENCES x_user (id)
+);
+commit;
+
+CREATE SEQUENCE x_role_ref_group_SEQ;
+CREATE TABLE x_role_ref_group(
+id BIGINT DEFAULT nextval('x_role_ref_group_SEQ'::regclass),
+create_time TIMESTAMP DEFAULT NULL NULL,
+update_time TIMESTAMP DEFAULT NULL NULL,
+added_by_id BIGINT DEFAULT NULL NULL,
+upd_by_id BIGINT DEFAULT NULL NULL,
+role_id BIGINT NOT NULL,
+group_id BIGINT DEFAULT NULL NULL,
+group_name varchar(767) DEFAULT NULL NULL,
+priv_type INT DEFAULT NULL NULL,
+ PRIMARY KEY (id),
+ CONSTRAINT x_role_ref_grp_FK_added_by_id FOREIGN KEY (added_by_id) REFERENCES x_portal_user (id),
+ CONSTRAINT x_role_ref_grp_FK_upd_by_id FOREIGN KEY (upd_by_id) REFERENCES x_portal_user (id),
+ CONSTRAINT x_role_ref_grp_FK_role_id FOREIGN KEY (role_id) REFERENCES x_role (id),
+ CONSTRAINT x_role_ref_grp_FK_group_id FOREIGN KEY (group_id) REFERENCES x_group (id)
+);
+commit;
+
+CREATE SEQUENCE x_policy_ref_role_SEQ;
+CREATE TABLE x_policy_ref_role(
+id BIGINT DEFAULT nextval('x_policy_ref_role_SEQ'::regclass),
+create_time TIMESTAMP DEFAULT NULL NULL,
+update_time TIMESTAMP DEFAULT NULL NULL,
+added_by_id BIGINT DEFAULT NULL NULL,
+upd_by_id BIGINT DEFAULT NULL NULL,
+policy_id BIGINT NOT NULL,
+role_id BIGINT NOT NULL,
+role_name varchar(255) DEFAULT NULL,
+ PRIMARY KEY (id),
+ CONSTRAINT x_pol_ref_role_UK_polId_roleId UNIQUE(policy_id,role_id),
+ CONSTRAINT x_pol_ref_role_FK_added_by_id FOREIGN KEY (added_by_id) REFERENCES x_portal_user (id),
+ CONSTRAINT x_pol_ref_role_FK_upd_by_id FOREIGN KEY (upd_by_id) REFERENCES x_portal_user (id),
+ CONSTRAINT x_pol_ref_role_FK_policy_id FOREIGN KEY (policy_id) REFERENCES x_policy (id),
+ CONSTRAINT x_pol_ref_role_FK_role_id FOREIGN KEY (role_id) REFERENCES x_role (id)
+);
+commit;
+
+CREATE SEQUENCE x_role_ref_role_SEQ;
+CREATE TABLE x_role_ref_role(
+id BIGINT DEFAULT nextval('x_role_ref_role_SEQ'::regclass),
+create_time TIMESTAMP DEFAULT NULL NULL,
+update_time TIMESTAMP DEFAULT NULL NULL,
+added_by_id BIGINT DEFAULT NULL NULL,
+upd_by_id BIGINT DEFAULT NULL NULL,
+role_ref_id BIGINT DEFAULT NULL NULL,
+role_id BIGINT NOT NULL,
+role_name varchar(255) DEFAULT NULL NULL,
+priv_type INT DEFAULT NULL NULL,
+ PRIMARY KEY (id),
+ CONSTRAINT x_role_ref_role_FK_added_by_id FOREIGN KEY (added_by_id) REFERENCES x_portal_user (id),
+ CONSTRAINT x_role_ref_role_FK_upd_by_id FOREIGN KEY (upd_by_id) REFERENCES x_portal_user (id),
+ CONSTRAINT x_role_ref_role_FK_role_ref_id FOREIGN KEY (role_ref_id) REFERENCES x_role (id)
+);
+commit;
+
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 a2d4137..b836ff1 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
@@ -155,6 +155,18 @@ call dbo.removeForeignKeysAndTable('x_policy_export_audit')
 GO
 call dbo.removeForeignKeysAndTable('x_group_users')
 GO
+
+call dbo.removeForeignKeysAndTable('x_role_ref_role')
+GO
+call dbo.removeForeignKeysAndTable('x_policy_ref_role')
+GO
+call dbo.removeForeignKeysAndTable('x_role_ref_group')
+GO
+call dbo.removeForeignKeysAndTable('x_role_ref_user')
+GO
+call dbo.removeForeignKeysAndTable('x_role')
+
+GO
 call dbo.removeForeignKeysAndTable('x_user')
 GO
 call dbo.removeForeignKeysAndTable('x_group_groups')
@@ -177,6 +189,7 @@ call dbo.removeForeignKeysAndTable('x_portal_user')
 GO
 call dbo.removeForeignKeysAndTable('x_db_version_h')
 GO
+
 create table dbo.x_db_version_h(
 id bigint identity not null primary key,
 version varchar(64) not null,
@@ -1208,6 +1221,78 @@ CREATE TABLE dbo.x_policy_change_log(
 )
 GO
 
+CREATE TABLE dbo.x_role(
+id bigint IDENTITY NOT NULL,
+create_time datetime DEFAULT NULL NULL,
+update_time datetime DEFAULT NULL NULL,
+added_by_id bigint DEFAULT NULL NULL,
+upd_by_id bigint  DEFAULT NULL NULL,
+version bigint  DEFAULT 0 NOT NULL,
+name varchar(255) NOT NULL,
+description varchar(1024) DEFAULT NULL NULL,
+role_options varchar(4000) DEFAULT NULL NULL,
+role_text text DEFAULT NULL NULL,
+CONSTRAINT x_role_PK_id PRIMARY KEY CLUSTERED(id),
+CONSTRAINT x_role_UK_name UNIQUE NONCLUSTERED (name)
+)
+GO
+
+CREATE TABLE dbo.x_role_ref_user(
+id bigint IDENTITY NOT NULL,
+create_time datetime DEFAULT NULL NULL,
+update_time datetime DEFAULT NULL NULL,
+added_by_id bigint  DEFAULT NULL NULL,
+upd_by_id bigint DEFAULT NULL NULL,
+role_id bigint NOT NULL,
+user_id bigint DEFAULT NULL NULL,
+user_name varchar(767) DEFAULT NULL NULL,
+priv_type int DEFAULT NULL,
+CONSTRAINT x_role_ref_user_PK_id PRIMARY KEY CLUSTERED(id)
+)
+GO
+
+CREATE TABLE dbo.x_role_ref_group(
+id bigint IDENTITY NOT NULL,
+create_time datetime DEFAULT NULL NULL,
+update_time datetime DEFAULT NULL NULL,
+added_by_id bigint DEFAULT NULL NULL,
+upd_by_id bigint DEFAULT NULL NULL,
+role_id bigint NOT NULL,
+group_id bigint DEFAULT NULL NULL,
+group_name varchar(767) DEFAULT NULL NULL,
+priv_type int DEFAULT NULL,
+ CONSTRAINT x_role_ref_grp_PK_id PRIMARY KEY CLUSTERED(id)
+)
+GO
+
+CREATE TABLE dbo.x_policy_ref_role(
+id bigint IDENTITY NOT NULL,
+create_time datetime DEFAULT NULL NULL,
+update_time datetime DEFAULT NULL NULL,
+added_by_id bigint DEFAULT NULL NULL,
+upd_by_id bigint DEFAULT NULL NULL,
+policy_id bigint NOT NULL,
+role_id bigint NOT NULL,
+role_name varchar(255) DEFAULT NULL NULL,
+ CONSTRAINT x_pol_ref_role_PK_id PRIMARY KEY CLUSTERED(id),
+ CONSTRAINT x_pol_ref_role_UK_polId_roleId UNIQUE NONCLUSTERED (policy_id, role_id)
+ )
+GO
+
+CREATE TABLE dbo.x_role_ref_role(
+id bigint IDENTITY NOT NULL,
+create_time datetime DEFAULT NULL NULL,
+update_time datetime DEFAULT NULL NULL,
+added_by_id bigint DEFAULT NULL NULL,
+upd_by_id bigint DEFAULT NULL NULL,
+role_ref_id bigint DEFAULT NULL NULL,
+role_id bigint NOT NULL,
+role_name varchar(255) DEFAULT NULL NULL,
+priv_type int DEFAULT NULL,
+ CONSTRAINT x_role_ref_role_PK_id PRIMARY KEY CLUSTERED(id)
+ )
+GO
+
 ALTER TABLE dbo.x_asset ADD CONSTRAINT x_asset_FK_added_by_id FOREIGN KEY(added_by_id) REFERENCES dbo.x_portal_user(id)
 GO
 ALTER TABLE dbo.x_asset ADD CONSTRAINT x_asset_FK_upd_by_id FOREIGN KEY(upd_by_id) REFERENCES dbo.x_portal_user (id)
@@ -1594,6 +1679,42 @@ ALTER TABLE dbo.x_security_zone_ref_group ADD CONSTRAINT x_sz_ref_grp_FK_zone_id
 GO
 ALTER TABLE dbo.x_security_zone_ref_group ADD CONSTRAINT x_sz_ref_grp_FK_group_id FOREIGN KEY(group_id) REFERENCES dbo.x_group (id)
 GO
+
+ALTER TABLE dbo.x_role_ref_role ADD CONSTRAINT x_role_ref_role_FK_added_by_id FOREIGN KEY (added_by_id) REFERENCES dbo.x_portal_user (id)
+GO
+ALTER TABLE dbo.x_role_ref_role ADD CONSTRAINT x_role_ref_role_FK_upd_by_id FOREIGN KEY (upd_by_id) REFERENCES dbo.x_portal_user (id)
+GO
+ALTER TABLE dbo.x_role_ref_role ADD CONSTRAINT x_role_ref_role_FK_role_ref_id FOREIGN KEY (role_ref_id) REFERENCES dbo.x_role (id)
+GO
+ALTER TABLE dbo.x_policy_ref_role ADD CONSTRAINT x_pol_ref_role_FK_added_by_id FOREIGN KEY (added_by_id) REFERENCES dbo.x_portal_user (id)
+GO
+ALTER TABLE dbo.x_policy_ref_role ADD CONSTRAINT x_pol_ref_role_FK_upd_by_id FOREIGN KEY (upd_by_id) REFERENCES dbo.x_portal_user (id)
+GO
+ALTER TABLE dbo.x_policy_ref_role ADD CONSTRAINT x_pol_ref_role_FK_policy_id FOREIGN KEY (policy_id) REFERENCES dbo.x_policy (id)
+GO
+ALTER TABLE dbo.x_policy_ref_role ADD CONSTRAINT x_pol_ref_role_FK_role_id FOREIGN KEY (role_id) REFERENCES dbo.x_role (id)
+GO
+ALTER TABLE dbo.x_role_ref_group ADD CONSTRAINT x_role_ref_grp_FK_added_by_id FOREIGN KEY (added_by_id) REFERENCES dbo.x_portal_user (id)
+GO
+ALTER TABLE dbo.x_role_ref_group ADD CONSTRAINT x_role_ref_grp_FK_upd_by_id FOREIGN KEY (upd_by_id) REFERENCES dbo.x_portal_user (id)
+GO
+ALTER TABLE dbo.x_role_ref_group ADD CONSTRAINT x_role_ref_grp_FK_role_id FOREIGN KEY (role_id) REFERENCES dbo.x_role (id)
+GO
+ALTER TABLE dbo.x_role_ref_group ADD CONSTRAINT x_role_ref_grp_FK_group_id FOREIGN KEY (group_id) REFERENCES dbo.x_group (id)
+GO
+ALTER TABLE dbo.x_role_ref_user ADD CONSTRAINT x_role_ref_user_FK_added_by_id FOREIGN KEY (added_by_id) REFERENCES dbo.x_portal_user (id)
+GO
+ALTER TABLE dbo.x_role_ref_user ADD CONSTRAINT x_role_ref_user_FK_upd_by_id FOREIGN KEY (upd_by_id) REFERENCES dbo.x_portal_user (id)
+GO
+ALTER TABLE dbo.x_role_ref_user ADD CONSTRAINT x_role_ref_user_FK_role_id FOREIGN KEY (role_id) REFERENCES dbo.x_role (id)
+GO
+ALTER TABLE dbo.x_role_ref_user ADD CONSTRAINT x_role_ref_user_FK_user_id FOREIGN KEY (user_id) REFERENCES dbo.x_user (id)
+GO
+ALTER TABLE dbo.x_role ADD CONSTRAINT x_role_FK_added_by_id FOREIGN KEY (added_by_id) REFERENCES dbo.x_portal_user (id)
+GO
+ALTER TABLE dbo.x_role ADD CONSTRAINT x_role_FK_upd_by_id FOREIGN KEY (upd_by_id) REFERENCES dbo.x_portal_user (id)
+
+GO
 CREATE NONCLUSTERED INDEX x_asset_cr_time ON dbo.x_asset(create_time ASC)
 GO
 CREATE NONCLUSTERED INDEX x_asset_FK_added_by_id ON dbo.x_asset(added_by_id ASC)
@@ -2001,6 +2122,8 @@ INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active
 GO
 INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('040',CURRENT_TIMESTAMP,'Ranger 1.0.0',CURRENT_TIMESTAMP,'localhost','Y');
 GO
+INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('041',CURRENT_TIMESTAMP,'Ranger 1.0.0',CURRENT_TIMESTAMP,'localhost','Y');
+GO
 INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('DB_PATCHES',CURRENT_TIMESTAMP,'Ranger 1.0.0',CURRENT_TIMESTAMP,'localhost','Y');
 GO
 INSERT INTO x_user_module_perm (user_id,module_id,create_time,update_time,added_by_id,upd_by_id,is_allowed) VALUES (dbo.getXportalUIdByLoginId('admin'),dbo.getModulesIdByName('Reports'),CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,dbo.getXportalUIdByLoginId('admin'),dbo.getXportalUIdByLoginId('admin'),1);
diff --git a/security-admin/db/sqlanywhere/patches/041-create-role-schema.sql b/security-admin/db/sqlanywhere/patches/041-create-role-schema.sql
new file mode 100644
index 0000000..9ad6ebd
--- /dev/null
+++ b/security-admin/db/sqlanywhere/patches/041-create-role-schema.sql
@@ -0,0 +1,155 @@
+-- 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.
+
+
+CREATE OR REPLACE PROCEDURE dbo.removeForeignKeysAndTable (IN table_name varchar(100))
+AS
+BEGIN
+	DECLARE @stmt VARCHAR(300)
+	DECLARE @tblname VARCHAR(300)
+	DECLARE @drpstmt VARCHAR(1000)
+	DECLARE cur CURSOR FOR select 'alter table dbo.' + table_name + ' drop constraint ' + role from SYS.SYSFOREIGNKEYS where foreign_creator ='dbo' and foreign_tname = table_name
+	OPEN cur WITH HOLD
+		fetch cur into @stmt
+		WHILE (@@sqlstatus = 0)
+		BEGIN
+			execute(@stmt)
+			fetch cur into @stmt
+		END
+	close cur
+	DEALLOCATE CURSOR cur
+	SET @tblname ='dbo.' + table_name;
+	SET @drpstmt = 'DROP TABLE IF EXISTS ' + @tblname;
+	execute(@drpstmt)
+END
+GO
+
+call dbo.removeForeignKeysAndTable('x_role_ref_role')
+GO
+call dbo.removeForeignKeysAndTable('x_policy_ref_role')
+GO
+call dbo.removeForeignKeysAndTable('x_role_ref_group')
+GO
+call dbo.removeForeignKeysAndTable('x_role_ref_user')
+GO
+call dbo.removeForeignKeysAndTable('x_role')
+GO
+
+CREATE TABLE dbo.x_role(
+id bigint IDENTITY NOT NULL,
+create_time datetime DEFAULT NULL NULL,
+update_time datetime DEFAULT NULL NULL,
+added_by_id bigint DEFAULT NULL NULL,
+upd_by_id bigint  DEFAULT NULL NULL,
+version bigint  DEFAULT 0 NOT NULL,
+name varchar(255) NOT NULL,
+description varchar(1024) DEFAULT NULL NULL,
+role_options varchar(4000) DEFAULT NULL NULL,
+role_text text DEFAULT NULL NULL,
+CONSTRAINT x_role_PK_id PRIMARY KEY CLUSTERED(id),
+CONSTRAINT x_role_UK_name UNIQUE NONCLUSTERED (name)
+)
+GO
+ALTER TABLE dbo.x_role ADD CONSTRAINT x_role_FK_added_by_id FOREIGN KEY (added_by_id) REFERENCES dbo.x_portal_user (id)
+GO
+ALTER TABLE dbo.x_role ADD CONSTRAINT x_role_FK_upd_by_id FOREIGN KEY (upd_by_id) REFERENCES dbo.x_portal_user (id)
+GO
+
+CREATE TABLE dbo.x_role_ref_user(
+id bigint IDENTITY NOT NULL,
+create_time datetime DEFAULT NULL NULL,
+update_time datetime DEFAULT NULL NULL,
+added_by_id bigint  DEFAULT NULL NULL,
+upd_by_id bigint DEFAULT NULL NULL,
+role_id bigint NOT NULL,
+user_id bigint DEFAULT NULL NULL,
+user_name varchar(767) DEFAULT NULL NULL,
+priv_type int DEFAULT NULL NULL,
+CONSTRAINT x_role_ref_user_PK_id PRIMARY KEY CLUSTERED(id)
+)
+GO
+ALTER TABLE dbo.x_role_ref_user ADD CONSTRAINT x_role_ref_user_FK_added_by_id FOREIGN KEY (added_by_id) REFERENCES dbo.x_portal_user (id)
+GO
+ALTER TABLE dbo.x_role_ref_user ADD CONSTRAINT x_role_ref_user_FK_upd_by_id FOREIGN KEY (upd_by_id) REFERENCES dbo.x_portal_user (id)
+GO
+ALTER TABLE dbo.x_role_ref_user ADD CONSTRAINT x_role_ref_user_FK_role_id FOREIGN KEY (role_id) REFERENCES dbo.x_role (id)
+GO
+ALTER TABLE dbo.x_role_ref_user ADD CONSTRAINT x_role_ref_user_FK_user_id FOREIGN KEY (user_id) REFERENCES dbo.x_user (id)
+GO
+
+CREATE TABLE dbo.x_role_ref_group(
+id bigint IDENTITY NOT NULL,
+create_time datetime DEFAULT NULL NULL,
+update_time datetime DEFAULT NULL NULL,
+added_by_id bigint DEFAULT NULL NULL,
+upd_by_id bigint DEFAULT NULL NULL,
+role_id bigint NOT NULL,
+group_id bigint DEFAULT NULL NULL,
+group_name varchar(767) DEFAULT NULL NULL,
+priv_type int DEFAULT NULL,
+ CONSTRAINT x_role_ref_grp_PK_id PRIMARY KEY CLUSTERED(id)
+)
+GO
+ALTER TABLE dbo.x_role_ref_group ADD CONSTRAINT x_role_ref_grp_FK_added_by_id FOREIGN KEY (added_by_id) REFERENCES dbo.x_portal_user (id)
+GO
+ALTER TABLE dbo.x_role_ref_group ADD CONSTRAINT x_role_ref_grp_FK_upd_by_id FOREIGN KEY (upd_by_id) REFERENCES dbo.x_portal_user (id)
+GO
+ALTER TABLE dbo.x_role_ref_group ADD CONSTRAINT x_role_ref_grp_FK_role_id FOREIGN KEY (role_id) REFERENCES dbo.x_role (id)
+GO
+ALTER TABLE dbo.x_role_ref_group ADD CONSTRAINT x_role_ref_grp_FK_group_id FOREIGN KEY (group_id) REFERENCES dbo.x_group (id)
+GO
+
+CREATE TABLE dbo.x_policy_ref_role(
+id bigint IDENTITY NOT NULL,
+create_time datetime DEFAULT NULL NULL,
+update_time datetime DEFAULT NULL NULL,
+added_by_id bigint DEFAULT NULL NULL,
+upd_by_id bigint DEFAULT NULL NULL,
+policy_id bigint NOT NULL,
+role_id bigint NOT NULL,
+role_name varchar(255) DEFAULT NULL NULL,
+ CONSTRAINT x_pol_ref_role_PK_id PRIMARY KEY CLUSTERED(id),
+ CONSTRAINT x_pol_ref_role_UK_polId_roleId UNIQUE NONCLUSTERED (policy_id, role_id)
+ )
+GO
+ALTER TABLE dbo.x_policy_ref_role ADD CONSTRAINT x_pol_ref_role_FK_added_by_id FOREIGN KEY (added_by_id) REFERENCES dbo.x_portal_user (id)
+GO
+ALTER TABLE dbo.x_policy_ref_role ADD CONSTRAINT x_pol_ref_role_FK_upd_by_id FOREIGN KEY (upd_by_id) REFERENCES dbo.x_portal_user (id)
+GO
+ALTER TABLE dbo.x_policy_ref_role ADD CONSTRAINT x_pol_ref_role_FK_policy_id FOREIGN KEY (policy_id) REFERENCES dbo.x_policy (id)
+GO
+ALTER TABLE dbo.x_policy_ref_role ADD CONSTRAINT x_pol_ref_role_FK_role_id FOREIGN KEY (role_id) REFERENCES dbo.x_role (id)
+GO
+
+CREATE TABLE dbo.x_role_ref_role(
+id bigint IDENTITY NOT NULL,
+create_time datetime DEFAULT NULL NULL,
+update_time datetime DEFAULT NULL NULL,
+added_by_id bigint DEFAULT NULL NULL,
+upd_by_id bigint DEFAULT NULL NULL,
+role_ref_id bigint DEFAULT NULL NULL,
+role_id bigint NOT NULL,
+role_name varchar(255) DEFAULT NULL NULL,
+priv_type int DEFAULT NULL,
+ CONSTRAINT x_role_ref_role_PK_id PRIMARY KEY CLUSTERED(id)
+ )
+GO
+ALTER TABLE dbo.x_role_ref_role ADD CONSTRAINT x_role_ref_role_FK_added_by_id FOREIGN KEY (added_by_id) REFERENCES dbo.x_portal_user (id)
+GO
+ALTER TABLE dbo.x_role_ref_role ADD CONSTRAINT x_role_ref_role_FK_upd_by_id FOREIGN KEY (upd_by_id) REFERENCES dbo.x_portal_user (id)
+GO
+ALTER TABLE dbo.x_role_ref_role ADD CONSTRAINT x_role_ref_role_FK_role_ref_id FOREIGN KEY (role_ref_id) REFERENCES dbo.x_role (id)
+GO
+exit
\ No newline at end of file
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 1f3ccbf..cca959a 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
@@ -865,6 +865,32 @@ IF (OBJECT_ID('x_group_users') IS NOT NULL)
 BEGIN
     DROP TABLE [dbo].[x_group_users]
 END
+
+IF (OBJECT_ID('x_role_ref_role') IS NOT NULL)
+BEGIN
+    DROP TABLE [dbo].[x_role_ref_role]
+END
+
+IF (OBJECT_ID('x_policy_ref_role') IS NOT NULL)
+BEGIN
+    DROP TABLE [dbo].[x_policy_ref_role]
+END
+
+IF (OBJECT_ID('x_role_ref_group') IS NOT NULL)
+BEGIN
+    DROP TABLE [dbo].[x_role_ref_group]
+END
+
+IF (OBJECT_ID('x_role_ref_user') IS NOT NULL)
+BEGIN
+    DROP TABLE [dbo].[x_role_ref_user]
+END
+
+IF (OBJECT_ID('x_role') IS NOT NULL)
+BEGIN
+    DROP TABLE [dbo].[x_role]
+END
+
 IF (OBJECT_ID('x_user') IS NOT NULL)
 BEGIN
     DROP TABLE [dbo].[x_user]
@@ -909,6 +935,8 @@ IF (OBJECT_ID('x_db_version_h') IS NOT NULL)
 BEGIN
     DROP TABLE [dbo].[x_db_version_h]
 END
+
+
 SET ANSI_NULLS ON
 SET QUOTED_IDENTIFIER ON
 SET ANSI_PADDING ON
@@ -1187,7 +1215,7 @@ CREATE TABLE [dbo].[x_policy_export_audit](
         [http_ret_code] [int] DEFAULT 0 NOT NULL,
         [cluster_name] [varchar](255) DEFAULT NULL NULL,
         [zone_name] [varchar](255) DEFAULT NULL NULL,
-        [policy_version] [bigint] DEFAULT NULL NULL,
+        [policy_version] [bigint] DEFAULT NULL NULL
 PRIMARY KEY CLUSTERED
 (
         [id] ASC
@@ -2397,6 +2425,151 @@ CREATE NONCLUSTERED INDEX [x_policy_change_log_IDX_policy_version] ON [x_policy_
    [policy_version] ASC
 )
 WITH (SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF) ON [PRIMARY]
+
+GO
+SET ANSI_NULLS ON
+SET QUOTED_IDENTIFIER ON
+SET ANSI_PADDING ON
+CREATE TABLE [dbo].[x_role](
+ [id] [bigint] IDENTITY(1,1) NOT NULL,
+[create_time] [datetime2] DEFAULT NULL NULL,
+[update_time] [datetime2] DEFAULT NULL NULL,
+[added_by_id] [bigint] DEFAULT NULL NULL,
+[upd_by_id] [bigint] DEFAULT NULL NULL,
+[version] [bigint] DEFAULT NULL NULL,
+[name] [varchar](255) NOT NULL,
+[description] [varchar](1024) DEFAULT NULL NULL,
+[role_options] [varchar](4000) DEFAULT NULL NULL,
+[role_text] [int] DEFAULT NULL NULL,
+  PRIMARY KEY CLUSTERED
+(
+        [id] ASC
+)WITH (PAD_INDEX = OFF,STATISTICS_NORECOMPUTE = OFF,IGNORE_DUP_KEY = OFF,ALLOW_ROW_LOCKS = ON,ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
+
+ CONSTRAINT [x_role$x_role_UK_name] UNIQUE NONCLUSTERED
+(
+        [name] ASC
+)WITH (PAD_INDEX = OFF,STATISTICS_NORECOMPUTE = OFF,IGNORE_DUP_KEY = OFF,ALLOW_ROW_LOCKS = ON,ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
+) ON [PRIMARY]
+GO
+ALTER TABLE [dbo].[x_role] WITH CHECK ADD CONSTRAINT [x_role_FK_added_by_id] FOREIGN KEY([added_by_id]) REFERENCES [dbo].[x_portal_user] ([id])
+GO
+ALTER TABLE [dbo].[x_role] WITH CHECK ADD CONSTRAINT [x_role_FK_upd_by_id] FOREIGN KEY([upd_by_id]) REFERENCES [dbo].[x_portal_user] ([id])
+GO
+
+SET ANSI_NULLS ON
+SET QUOTED_IDENTIFIER ON
+SET ANSI_PADDING ON
+CREATE TABLE [dbo].[x_role_ref_user](
+[id] [bigint] IDENTITY(1,1) NOT NULL,
+[create_time] [datetime2] DEFAULT NULL NULL,
+[update_time] [datetime2] DEFAULT NULL NULL,
+[added_by_id] [bigint] DEFAULT NULL NULL,
+[upd_by_id] [bigint] DEFAULT NULL NULL,
+[role_id] [bigint] NOT NULL,
+[user_id] [bigint] DEFAULT NULL NULL,
+[user_name] [varchar](767) DEFAULT NULL NULL,
+[priv_type] [int] DEFAULT NULL NULL,
+  PRIMARY KEY CLUSTERED
+(
+        [id] ASC
+)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
+) ON [PRIMARY]
+GO
+ALTER TABLE [dbo].[x_role_ref_user] WITH CHECK ADD CONSTRAINT [x_role_ref_user_FK_added_by_id] FOREIGN KEY([added_by_id]) REFERENCES [dbo].[x_portal_user] ([id])
+GO
+ALTER TABLE [dbo].[x_role_ref_user] WITH CHECK ADD CONSTRAINT [x_role_ref_user_FK_upd_by_id] FOREIGN KEY([upd_by_id]) REFERENCES [dbo].[x_portal_user] ([id])
+GO
+ALTER TABLE [dbo].[x_role_ref_user] WITH CHECK ADD CONSTRAINT [x_role_ref_user_FK_role_id] FOREIGN KEY([role_id]) REFERENCES [dbo].[x_role] ([id])
+GO
+ALTER TABLE [dbo].[x_role_ref_user] WITH CHECK ADD CONSTRAINT [x_role_ref_user_FK_user_id] FOREIGN KEY([user_id]) REFERENCES [dbo].[x_user] ([id])
+GO
+
+SET ANSI_NULLS ON
+SET QUOTED_IDENTIFIER ON
+SET ANSI_PADDING ON
+CREATE TABLE [dbo].[x_role_ref_group](
+[id] [bigint] IDENTITY(1,1) NOT NULL,
+[create_time] [datetime2] DEFAULT NULL NULL,
+[update_time] [datetime2] DEFAULT NULL NULL,
+[added_by_id] [bigint] DEFAULT NULL NULL,
+[upd_by_id] [bigint] DEFAULT NULL NULL,
+[role_id] [bigint] NOT NULL,
+[group_id] [bigint] DEFAULT NULL NULL,
+[group_name] [varchar](767) DEFAULT NULL NULL,
+[priv_type] [int] DEFAULT NULL NULL,
+ PRIMARY KEY CLUSTERED
+(
+        [id] ASC
+)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
+) ON [PRIMARY]
+GO
+ALTER TABLE [dbo].[x_role_ref_group] WITH CHECK ADD CONSTRAINT [x_role_ref_group_FK_added_by_id] FOREIGN KEY([added_by_id]) REFERENCES [dbo].[x_portal_user] ([id])
+GO
+ALTER TABLE [dbo].[x_role_ref_group] WITH CHECK ADD CONSTRAINT [x_role_ref_group_FK_upd_by_id] FOREIGN KEY([upd_by_id]) REFERENCES [dbo].[x_portal_user] ([id])
+GO
+ALTER TABLE [dbo].[x_role_ref_group] WITH CHECK ADD CONSTRAINT [x_role_ref_group_FK_role_id] FOREIGN KEY([role_id]) REFERENCES [dbo].[x_role] ([id])
+GO
+ALTER TABLE [dbo].[x_role_ref_group] WITH CHECK ADD CONSTRAINT [x_role_ref_group_FK_group_id] FOREIGN KEY([group_id]) REFERENCES [dbo].[x_group] ([id])
+GO
+
+SET ANSI_NULLS ON
+SET QUOTED_IDENTIFIER ON
+SET ANSI_PADDING ON
+CREATE TABLE [dbo].[x_policy_ref_role](
+[id] [bigint] IDENTITY(1,1) NOT NULL,
+[create_time] [datetime2] DEFAULT NULL NULL,
+[update_time] [datetime2] DEFAULT NULL NULL,
+[added_by_id] [bigint] DEFAULT NULL NULL,
+[upd_by_id] [bigint] DEFAULT NULL NULL,
+[policy_id] [bigint] NOT NULL,
+[role_id] [bigint] NOT NULL,
+[role_name] [varchar](255) DEFAULT NULL NULL,
+ PRIMARY KEY CLUSTERED
+  (
+  [id] ASC
+  ) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
+    CONSTRAINT [x_policy_ref_role$x_policy_ref_role_UK_polId_roleId] UNIQUE NONCLUSTERED
+(
+        [policy_id] ASC, [role_id] ASC
+)WITH (PAD_INDEX = OFF,STATISTICS_NORECOMPUTE = OFF,IGNORE_DUP_KEY = OFF,ALLOW_ROW_LOCKS = ON,ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
+) ON [PRIMARY]
+GO
+ALTER TABLE [dbo].[x_policy_ref_role] WITH CHECK ADD CONSTRAINT [x_policy_ref_role_FK_added_by_id] FOREIGN KEY([added_by_id]) REFERENCES [dbo].[x_portal_user] ([id])
+GO
+ALTER TABLE [dbo].[x_policy_ref_role] WITH CHECK ADD CONSTRAINT [x_policy_ref_role_FK_upd_by_id] FOREIGN KEY([upd_by_id]) REFERENCES [dbo].[x_portal_user] ([id])
+GO
+ALTER TABLE [dbo].[x_policy_ref_role] WITH CHECK ADD CONSTRAINT [x_policy_ref_role_FK_policy_id] FOREIGN KEY([policy_id]) REFERENCES [dbo].[x_policy] ([id])
+GO
+ALTER TABLE [dbo].[x_policy_ref_role] WITH CHECK ADD CONSTRAINT [x_policy_ref_role_FK_role_id] FOREIGN KEY([role_id]) REFERENCES [dbo].[x_role] ([id])
+GO
+
+SET ANSI_NULLS ON
+SET QUOTED_IDENTIFIER ON
+SET ANSI_PADDING ON
+CREATE TABLE [dbo].[x_role_ref_role](
+[id] [bigint] IDENTITY(1,1) NOT NULL,
+[create_time] [datetime2] DEFAULT NULL NULL,
+[update_time] [datetime2] DEFAULT NULL NULL,
+[added_by_id] [bigint] DEFAULT NULL NULL,
+[upd_by_id] [bigint] DEFAULT NULL NULL,
+[role_ref_id] [bigint] DEFAULT NULL NULL,
+[role_id] [bigint] NOT NULL,
+[role_name] [varchar](255) DEFAULT NULL NULL,
+[priv_type] [int] DEFAULT NULL NULL,
+  PRIMARY KEY CLUSTERED
+  (
+  [id] ASC
+  ) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
+)ON [PRIMARY]
+GO
+ALTER TABLE [dbo].[x_role_ref_role] WITH CHECK ADD CONSTRAINT [x_role_ref_role_FK_added_by_id] FOREIGN KEY([added_by_id]) REFERENCES [dbo].[x_portal_user] ([id])
+GO
+ALTER TABLE [dbo].[x_role_ref_role] WITH CHECK ADD CONSTRAINT [x_role_ref_role_FK_upd_by_id] FOREIGN KEY([upd_by_id]) REFERENCES [dbo].[x_portal_user] ([id])
+GO
+ALTER TABLE [dbo].[x_role_ref_role] WITH CHECK ADD CONSTRAINT [x_role_ref_role_FK_role_ref_id] FOREIGN KEY([role_ref_id]) REFERENCES [dbo].[x_role] ([id])
+GO
+
 SET ANSI_NULLS ON
 SET QUOTED_IDENTIFIER ON
 SET ANSI_PADDING ON
@@ -3682,6 +3855,7 @@ INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active
 INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('038',CURRENT_TIMESTAMP,'Ranger 1.0.0',CURRENT_TIMESTAMP,'localhost','Y');
 INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('039',CURRENT_TIMESTAMP,'Ranger 1.0.0',CURRENT_TIMESTAMP,'localhost','Y');
 INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('040',CURRENT_TIMESTAMP,'Ranger 1.0.0',CURRENT_TIMESTAMP,'localhost','Y');
+INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('041',CURRENT_TIMESTAMP,'Ranger 1.0.0',CURRENT_TIMESTAMP,'localhost','Y');
 INSERT INTO x_db_version_h (version,inst_at,inst_by,updated_at,updated_by,active) VALUES ('DB_PATCHES',CURRENT_TIMESTAMP,'Ranger 1.0.0',CURRENT_TIMESTAMP,'localhost','Y');
 INSERT INTO x_user_module_perm (user_id,module_id,create_time,update_time,added_by_id,upd_by_id,is_allowed) VALUES (dbo.getXportalUIdByLoginId('admin'),dbo.getModulesIdByName('Reports'),CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,dbo.getXportalUIdByLoginId('admin'),dbo.getXportalUIdByLoginId('admin'),1);
 INSERT INTO x_user_module_perm (user_id,module_id,create_time,update_time,added_by_id,upd_by_id,is_allowed) VALUES (dbo.getXportalUIdByLoginId('admin'),dbo.getModulesIdByName('Resource Based Policies'),CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,dbo.getXportalUIdByLoginId('admin'),dbo.getXportalUIdByLoginId('admin'),1);
diff --git a/security-admin/db/sqlserver/patches/041-create-role-schema.sql b/security-admin/db/sqlserver/patches/041-create-role-schema.sql
new file mode 100644
index 0000000..a404281
--- /dev/null
+++ b/security-admin/db/sqlserver/patches/041-create-role-schema.sql
@@ -0,0 +1,187 @@
+-- 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 (OBJECT_ID('x_role_ref_role') IS NOT NULL)
+BEGIN
+    DROP TABLE [dbo].[x_role_ref_role]
+END
+
+IF (OBJECT_ID('x_policy_ref_role') IS NOT NULL)
+BEGIN
+    DROP TABLE [dbo].[x_policy_ref_role]
+END
+
+IF (OBJECT_ID('x_role_ref_group') IS NOT NULL)
+BEGIN
+    DROP TABLE [dbo].[x_role_ref_group]
+END
+
+IF (OBJECT_ID('x_role_ref_user') IS NOT NULL)
+BEGIN
+    DROP TABLE [dbo].[x_role_ref_user]
+END
+
+IF (OBJECT_ID('x_role') IS NOT NULL)
+BEGIN
+    DROP TABLE [dbo].[x_role]
+END
+
+
+GO
+SET ANSI_NULLS ON
+SET QUOTED_IDENTIFIER ON
+SET ANSI_PADDING ON
+CREATE TABLE [dbo].[x_role](
+ [id] [bigint] IDENTITY(1,1) NOT NULL,
+[create_time] [datetime2] DEFAULT NULL NULL,
+[update_time] [datetime2] DEFAULT NULL NULL,
+[added_by_id] [bigint] DEFAULT NULL NULL,
+[upd_by_id] [bigint] DEFAULT NULL NULL,
+[version] [bigint] DEFAULT NULL NULL,
+[name] [varchar](255) NOT NULL,
+[description] [varchar](1024) DEFAULT NULL NULL,
+[role_options] [varchar](4000) DEFAULT NULL NULL,
+[role_text] [int] DEFAULT NULL NULL,
+  PRIMARY KEY CLUSTERED
+(
+        [id] ASC
+)WITH (PAD_INDEX = OFF,STATISTICS_NORECOMPUTE = OFF,IGNORE_DUP_KEY = OFF,ALLOW_ROW_LOCKS = ON,ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
+
+ CONSTRAINT [x_role$x_role_UK_name] UNIQUE NONCLUSTERED
+(
+        [name] ASC
+)WITH (PAD_INDEX = OFF,STATISTICS_NORECOMPUTE = OFF,IGNORE_DUP_KEY = OFF,ALLOW_ROW_LOCKS = ON,ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
+) ON [PRIMARY]
+GO
+ALTER TABLE [dbo].[x_role] WITH CHECK ADD CONSTRAINT [x_role_FK_added_by_id] FOREIGN KEY([added_by_id]) REFERENCES [dbo].[x_portal_user] ([id])
+GO
+ALTER TABLE [dbo].[x_role] WITH CHECK ADD CONSTRAINT [x_role_FK_upd_by_id] FOREIGN KEY([upd_by_id]) REFERENCES [dbo].[x_portal_user] ([id])
+GO
+
+SET ANSI_NULLS ON
+SET QUOTED_IDENTIFIER ON
+SET ANSI_PADDING ON
+CREATE TABLE [dbo].[x_role_ref_user](
+[id] [bigint] IDENTITY(1,1) NOT NULL,
+[create_time] [datetime2] DEFAULT NULL NULL,
+[update_time] [datetime2] DEFAULT NULL NULL,
+[added_by_id] [bigint] DEFAULT NULL NULL,
+[upd_by_id] [bigint] DEFAULT NULL NULL,
+[role_id] [bigint] NOT NULL,
+[user_id] [bigint] DEFAULT NULL NULL,
+[user_name] [varchar](767) DEFAULT NULL NULL,
+[priv_type] [int] DEFAULT NULL NULL,
+  PRIMARY KEY CLUSTERED
+(
+        [id] ASC
+)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
+) ON [PRIMARY]
+GO
+ALTER TABLE [dbo].[x_role_ref_user] WITH CHECK ADD CONSTRAINT [x_role_ref_user_FK_added_by_id] FOREIGN KEY([added_by_id]) REFERENCES [dbo].[x_portal_user] ([id])
+GO
+ALTER TABLE [dbo].[x_role_ref_user] WITH CHECK ADD CONSTRAINT [x_role_ref_user_FK_upd_by_id] FOREIGN KEY([upd_by_id]) REFERENCES [dbo].[x_portal_user] ([id])
+GO
+ALTER TABLE [dbo].[x_role_ref_user] WITH CHECK ADD CONSTRAINT [x_role_ref_user_FK_role_id] FOREIGN KEY([role_id]) REFERENCES [dbo].[x_role] ([id])
+GO
+ALTER TABLE [dbo].[x_role_ref_user] WITH CHECK ADD CONSTRAINT [x_role_ref_user_FK_user_id] FOREIGN KEY([user_id]) REFERENCES [dbo].[x_user] ([id])
+GO
+
+
+SET ANSI_NULLS ON
+SET QUOTED_IDENTIFIER ON
+SET ANSI_PADDING ON
+CREATE TABLE [dbo].[x_role_ref_group](
+[id] [bigint] IDENTITY(1,1) NOT NULL,
+[create_time] [datetime2] DEFAULT NULL NULL,
+[update_time] [datetime2] DEFAULT NULL NULL,
+[added_by_id] [bigint] DEFAULT NULL NULL,
+[upd_by_id] [bigint] DEFAULT NULL NULL,
+[role_id] [bigint] NOT NULL,
+[group_id] [bigint] DEFAULT NULL NULL,
+[group_name] [varchar](767) DEFAULT NULL NULL,
+[priv_type] [int] DEFAULT NULL NULL,
+ PRIMARY KEY CLUSTERED
+(
+        [id] ASC
+)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
+) ON [PRIMARY]
+GO
+ALTER TABLE [dbo].[x_role_ref_group] WITH CHECK ADD CONSTRAINT [x_role_ref_group_FK_added_by_id] FOREIGN KEY([added_by_id]) REFERENCES [dbo].[x_portal_user] ([id])
+GO
+ALTER TABLE [dbo].[x_role_ref_group] WITH CHECK ADD CONSTRAINT [x_role_ref_group_FK_upd_by_id] FOREIGN KEY([upd_by_id]) REFERENCES [dbo].[x_portal_user] ([id])
+GO
+ALTER TABLE [dbo].[x_role_ref_group] WITH CHECK ADD CONSTRAINT [x_role_ref_group_FK_role_id] FOREIGN KEY([role_id]) REFERENCES [dbo].[x_role] ([id])
+GO
+ALTER TABLE [dbo].[x_role_ref_group] WITH CHECK ADD CONSTRAINT [x_role_ref_group_FK_group_id] FOREIGN KEY([group_id]) REFERENCES [dbo].[x_group] ([id])
+GO
+
+SET ANSI_NULLS ON
+SET QUOTED_IDENTIFIER ON
+SET ANSI_PADDING ON
+CREATE TABLE [dbo].[x_policy_ref_role](
+[id] [bigint] IDENTITY(1,1) NOT NULL,
+[create_time] [datetime2] DEFAULT NULL NULL,
+[update_time] [datetime2] DEFAULT NULL NULL,
+[added_by_id] [bigint] DEFAULT NULL NULL,
+[upd_by_id] [bigint] DEFAULT NULL NULL,
+[policy_id] [bigint] NOT NULL,
+[role_id] [bigint] NOT NULL,
+[role_name] [varchar](255) DEFAULT NULL NULL,
+ PRIMARY KEY CLUSTERED
+  (
+  [id] ASC
+  ) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
+    CONSTRAINT [x_policy_ref_role$x_policy_ref_role_UK_polId_roleId] UNIQUE NONCLUSTERED
+(
+        [policy_id] ASC, [role_id] ASC
+)WITH (PAD_INDEX = OFF,STATISTICS_NORECOMPUTE = OFF,IGNORE_DUP_KEY = OFF,ALLOW_ROW_LOCKS = ON,ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
+) ON [PRIMARY]
+GO
+ALTER TABLE [dbo].[x_policy_ref_role] WITH CHECK ADD CONSTRAINT [x_policy_ref_role_FK_added_by_id] FOREIGN KEY([added_by_id]) REFERENCES [dbo].[x_portal_user] ([id])
+GO
+ALTER TABLE [dbo].[x_policy_ref_role] WITH CHECK ADD CONSTRAINT [x_policy_ref_role_FK_upd_by_id] FOREIGN KEY([upd_by_id]) REFERENCES [dbo].[x_portal_user] ([id])
+GO
+ALTER TABLE [dbo].[x_policy_ref_role] WITH CHECK ADD CONSTRAINT [x_policy_ref_role_FK_policy_id] FOREIGN KEY([policy_id]) REFERENCES [dbo].[x_policy] ([id])
+GO
+ALTER TABLE [dbo].[x_policy_ref_role] WITH CHECK ADD CONSTRAINT [x_policy_ref_role_FK_role_id] FOREIGN KEY([role_id]) REFERENCES [dbo].[x_role] ([id])
+GO
+
+SET ANSI_NULLS ON
+SET QUOTED_IDENTIFIER ON
+SET ANSI_PADDING ON
+CREATE TABLE [dbo].[x_role_ref_role](
+[id] [bigint] IDENTITY(1,1) NOT NULL,
+[create_time] [datetime2] DEFAULT NULL NULL,
+[update_time] [datetime2] DEFAULT NULL NULL,
+[added_by_id] [bigint] DEFAULT NULL NULL,
+[upd_by_id] [bigint] DEFAULT NULL NULL,
+[role_ref_id] [bigint] DEFAULT NULL NULL,
+[role_id] [bigint] NOT NULL,
+[role_name] [varchar](255) DEFAULT NULL NULL,
+[priv_type] [int] DEFAULT NULL NULL,
+  PRIMARY KEY CLUSTERED
+  (
+  [id] ASC
+  ) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
+)ON [PRIMARY]
+GO
+ALTER TABLE [dbo].[x_role_ref_role] WITH CHECK ADD CONSTRAINT [x_role_ref_role_FK_added_by_id] FOREIGN KEY([added_by_id]) REFERENCES [dbo].[x_portal_user] ([id])
+GO
+ALTER TABLE [dbo].[x_role_ref_role] WITH CHECK ADD CONSTRAINT [x_role_ref_role_FK_upd_by_id] FOREIGN KEY([upd_by_id]) REFERENCES [dbo].[x_portal_user] ([id])
+GO
+ALTER TABLE [dbo].[x_role_ref_role] WITH CHECK ADD CONSTRAINT [x_role_ref_role_FK_role_ref_id] FOREIGN KEY([role_ref_id]) REFERENCES [dbo].[x_role] ([id])
+GO
+exit
\ No newline at end of file
diff --git a/security-admin/src/main/java/org/apache/ranger/biz/PolicyRefUpdater.java b/security-admin/src/main/java/org/apache/ranger/biz/PolicyRefUpdater.java
index 921dc37..055cd38 100644
--- a/security-admin/src/main/java/org/apache/ranger/biz/PolicyRefUpdater.java
+++ b/security-admin/src/main/java/org/apache/ranger/biz/PolicyRefUpdater.java
@@ -31,6 +31,7 @@ import org.apache.ranger.db.XXPolicyRefConditionDao;
 import org.apache.ranger.db.XXPolicyRefDataMaskTypeDao;
 import org.apache.ranger.db.XXPolicyRefGroupDao;
 import org.apache.ranger.db.XXPolicyRefResourceDao;
+import org.apache.ranger.db.XXPolicyRefRoleDao;
 import org.apache.ranger.db.XXPolicyRefUserDao;
 import org.apache.ranger.entity.XXAccessTypeDef;
 import org.apache.ranger.entity.XXDataMaskTypeDef;
@@ -42,8 +43,10 @@ import org.apache.ranger.entity.XXPolicyRefCondition;
 import org.apache.ranger.entity.XXPolicyRefDataMaskType;
 import org.apache.ranger.entity.XXPolicyRefGroup;
 import org.apache.ranger.entity.XXPolicyRefResource;
+import org.apache.ranger.entity.XXPolicyRefRole;
 import org.apache.ranger.entity.XXPolicyRefUser;
 import org.apache.ranger.entity.XXResourceDef;
+import org.apache.ranger.entity.XXRole;
 import org.apache.ranger.entity.XXServiceDef;
 import org.apache.ranger.entity.XXUser;
 import org.apache.ranger.plugin.model.RangerPolicy;
@@ -73,6 +76,7 @@ public class PolicyRefUpdater {
 		cleanupRefTables(policy);
 
 		final Set<String> resourceNames   = policy.getResources().keySet();
+		final Set<String> roleNames       = new HashSet<>();
 		final Set<String> groupNames      = new HashSet<>();
 		final Set<String> userNames       = new HashSet<>();
 		final Set<String> accessTypes     = new HashSet<>();
@@ -92,6 +96,7 @@ public class PolicyRefUpdater {
 			}
 
 			for (RangerPolicyItem policyItem : policyItems) {
+				roleNames.addAll(policyItem.getRoles());
 				groupNames.addAll(policyItem.getGroups());
 				userNames.addAll(policyItem.getUsers());
 
@@ -131,6 +136,26 @@ public class PolicyRefUpdater {
 			daoMgr.getXXPolicyRefResource().create(xPolRes);
 		}
 
+		for (String role : roleNames) {
+			if (StringUtils.isBlank(role)) {
+				continue;
+			}
+
+			XXRole xRole = daoMgr.getXXRole().findByRoleName(role);
+
+			if (xRole == null) {
+				throw new Exception(role + ": role does not exist. policy='"+  policy.getName() + "' service='"+ policy.getService() + "' role='" + role + "'");
+			}
+
+			XXPolicyRefRole xPolRole = rangerAuditFields.populateAuditFields(new XXPolicyRefRole(), xPolicy);
+
+			xPolRole.setPolicyId(policy.getId());
+			xPolRole.setRoleId(xRole.getId());
+			xPolRole.setRoleName(role);
+
+			daoMgr.getXXPolicyRefRole().create(xPolRole);
+		}
+
 		for (String group : groupNames) {
 			if (StringUtils.isBlank(group)) {
 				continue;
@@ -228,6 +253,7 @@ public class PolicyRefUpdater {
 		}
 
 		XXPolicyRefResourceDao     xPolResDao      = daoMgr.getXXPolicyRefResource();
+		XXPolicyRefRoleDao         xPolRoleDao     = daoMgr.getXXPolicyRefRole();
 		XXPolicyRefGroupDao        xPolGroupDao    = daoMgr.getXXPolicyRefGroup();
 		XXPolicyRefUserDao         xPolUserDao     = daoMgr.getXXPolicyRefUser();
 		XXPolicyRefAccessTypeDao   xPolAccessDao   = daoMgr.getXXPolicyRefAccessType();
@@ -238,6 +264,10 @@ public class PolicyRefUpdater {
 			xPolResDao.remove(resource);
 		}
 
+		for(XXPolicyRefRole role : xPolRoleDao.findByPolicyId(policyId)) {
+			xPolRoleDao.remove(role);
+		}
+
 		for(XXPolicyRefGroup group : xPolGroupDao.findByPolicyId(policyId)) {
 			xPolGroupDao.remove(group);
 		}
diff --git a/security-admin/src/main/java/org/apache/ranger/biz/RangerPolicyRetriever.java b/security-admin/src/main/java/org/apache/ranger/biz/RangerPolicyRetriever.java
index f48a803..4815f5b 100644
--- a/security-admin/src/main/java/org/apache/ranger/biz/RangerPolicyRetriever.java
+++ b/security-admin/src/main/java/org/apache/ranger/biz/RangerPolicyRetriever.java
@@ -306,6 +306,7 @@ public class RangerPolicyRetriever {
 	class LookupCache {
 		final Map<Long, String>              userScreenNames            = new HashMap<Long, String>();
 		final Map<Long, String>              zoneNames                  = new HashMap<Long, String>();
+		final Map<Long, Map<String, String>> roleMappingsPerPolicy      = new HashMap<>();
 		final Map<Long, Map<String, String>> groupMappingsPerPolicy     = new HashMap<>();
 		final Map<Long, Map<String, String>> userMappingsPerPolicy      = new HashMap<>();
 		final Map<Long, Map<String, String>> accessMappingsPerPolicy    = new HashMap<>();
@@ -416,6 +417,9 @@ public class RangerPolicyRetriever {
 			return policyNameMap != null ? policyNameMap.get(nameToMap) : null;
 		}
 
+		void setRoleNameMapping(List<PolicyTextNameMap> roleNameMapping) {
+			setNameMapping(roleMappingsPerPolicy, roleNameMapping);
+		}
 		void setGroupNameMapping(List<PolicyTextNameMap> groupNameMapping) {
 			setNameMapping(groupMappingsPerPolicy, groupNameMapping);
 		}
@@ -473,6 +477,7 @@ public class RangerPolicyRetriever {
 			if (xService != null) {
 				Long serviceId = xService.getId();
 
+				lookupCache.setRoleNameMapping(daoMgr.getXXPolicyRefRole().findUpdatedRoleNamesByService(serviceId));
 				lookupCache.setGroupNameMapping(daoMgr.getXXPolicyRefGroup().findUpdatedGroupNamesByService(serviceId));
 				lookupCache.setUserNameMapping(daoMgr.getXXPolicyRefUser().findUpdatedUserNamesByService(serviceId));
 				lookupCache.setAccessNameMapping(daoMgr.getXXPolicyRefAccessType().findUpdatedAccessNamesByService(serviceId));
@@ -493,6 +498,7 @@ public class RangerPolicyRetriever {
 		RetrieverContext(XXPolicy xPolicy, XXService xService) {
 			Long policyId = xPolicy.getId();
 
+			lookupCache.setRoleNameMapping(daoMgr.getXXPolicyRefRole().findUpdatedRoleNamesByPolicy(policyId));
 			lookupCache.setGroupNameMapping(daoMgr.getXXPolicyRefGroup().findUpdatedGroupNamesByPolicy(policyId));
 			lookupCache.setUserNameMapping(daoMgr.getXXPolicyRefUser().findUpdatedUserNamesByPolicy(policyId));
 			lookupCache.setAccessNameMapping(daoMgr.getXXPolicyRefAccessType().findUpdatedAccessNamesByPolicy(policyId));
@@ -585,6 +591,13 @@ public class RangerPolicyRetriever {
 				}
 
 				for (RangerPolicyItem policyItem : policyItems) {
+					if (lookupCache.roleMappingsPerPolicy.containsKey(policyId)) {
+						List<String> updatedRoles = getUpdatedNames(lookupCache.roleMappingsPerPolicy, policyId, policyItem.getRoles());
+
+						if (updatedRoles != null) {
+							policyItem.setRoles(updatedRoles);
+						}
+					}
 					if (lookupCache.groupMappingsPerPolicy.containsKey(policyId)) {
 						List<String> updatedGroups = getUpdatedNames(lookupCache.groupMappingsPerPolicy, policyId, policyItem.getGroups());
 
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
new file mode 100644
index 0000000..3de2548
--- /dev/null
+++ b/security-admin/src/main/java/org/apache/ranger/biz/RoleDBStore.java
@@ -0,0 +1,234 @@
+/*
+ * 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.biz;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.PostConstruct;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.collections.ListUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.ranger.common.MessageEnums;
+import org.apache.ranger.common.RESTErrorUtil;
+import org.apache.ranger.db.RangerDaoManager;
+import org.apache.ranger.entity.XXRole;
+import org.apache.ranger.entity.XXService;
+import org.apache.ranger.entity.XXTrxLog;
+import org.apache.ranger.plugin.model.RangerRole;
+import org.apache.ranger.plugin.store.AbstractPredicateUtil;
+import org.apache.ranger.plugin.store.RoleStore;
+import org.apache.ranger.plugin.util.SearchFilter;
+import org.apache.ranger.service.RangerRoleService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+@Component
+public class RoleDBStore implements RoleStore {
+    private static final Log LOG = LogFactory.getLog(RoleDBStore.class);
+
+    @Autowired
+    RangerRoleService roleService;
+
+    @Autowired
+    RangerDaoManager daoMgr;
+
+    @Autowired
+    RESTErrorUtil restErrorUtil;
+
+    @Autowired
+	RoleRefUpdater roleRefUpdater;
+
+    @Autowired
+    RangerBizUtil bizUtil;
+
+    AbstractPredicateUtil predicateUtil = null;
+
+    public void init() throws Exception {}
+
+    @PostConstruct
+    public void initStore() {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("==> RoleDBStore.initStore()");
+        }
+
+        //predicateUtil = new RolePredicateUtil();
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("<== RoleDBStore.initStore()");
+        }
+    }
+
+    @Override
+    public RangerRole createRole(RangerRole role) throws Exception {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("==> RoleDBStore.createRole()");
+        }
+
+        XXRole xxRole = daoMgr.getXXRole().findByRoleName(role.getName());
+
+        if (xxRole != null) {
+            throw restErrorUtil.createRESTException("role with name: " + role.getName() + " already exists", MessageEnums.ERROR_DUPLICATE_OBJECT);
+        }
+
+        RangerRole createdRole = roleService.create(role);
+        if (createdRole == null) {
+            throw new Exception("Cannot create role:[" + role + "]");
+        }
+
+        roleRefUpdater.createNewRoleMappingForRefTable(createdRole);
+
+        List<XXTrxLog> trxLogList = roleService.getTransactionLog(createdRole, null, "create");
+        bizUtil.createTrxLog(trxLogList);
+        return createdRole;
+    }
+
+    @Override
+    public RangerRole updateRole(RangerRole role) throws Exception {
+        XXRole xxRole = daoMgr.getXXRole().findByRoleId(role.getId());
+        if (xxRole == null) {
+            throw restErrorUtil.createRESTException("role with id: " + role.getId() + " does not exist");
+        }
+
+        Gson gsonBuilder = new GsonBuilder().setDateFormat("yyyyMMdd-HH:mm:ss.SSS-Z").create();
+        RangerRole oldRole = gsonBuilder.fromJson(xxRole.getRoleText(), RangerRole.class);
+
+        RangerRole updatedRole = roleService.update(role);
+        if (updatedRole == null) {
+            throw new Exception("Cannot update role:[" + role + "]");
+        }
+
+        roleRefUpdater.createNewRoleMappingForRefTable(updatedRole);
+
+        roleService.updatePolicyVersions(updatedRole.getId());
+
+        List<XXTrxLog> trxLogList = roleService.getTransactionLog(updatedRole, oldRole, "update");
+        bizUtil.createTrxLog(trxLogList);
+        return role;
+    }
+
+    @Override
+    public void deleteRole(String roleName) throws Exception {
+        XXRole xxRole = daoMgr.getXXRole().findByRoleName(roleName);
+        if (xxRole == null) {
+            throw restErrorUtil.createRESTException("Role with name: " + roleName + " does not exist");
+        }
+        RangerRole role = roleService.read(xxRole.getId());
+        roleRefUpdater.cleanupRefTables(role);
+        roleService.delete(role);
+
+        List<XXTrxLog> trxLogList = roleService.getTransactionLog(role, null, "delete");
+        bizUtil.createTrxLog(trxLogList);
+    }
+
+    @Override
+    public void deleteRole(Long roleId) throws Exception {
+        RangerRole role = roleService.read(roleId);
+
+        roleRefUpdater.cleanupRefTables(role);
+        roleService.delete(role);
+        List<XXTrxLog> trxLogList = roleService.getTransactionLog(role, null, "delete");
+        bizUtil.createTrxLog(trxLogList);
+    }
+
+    @Override
+    public RangerRole getRole(Long id) throws Exception {
+        return roleService.read(id);
+    }
+
+    @Override
+    public RangerRole getRole(String name) throws Exception {
+        XXRole xxRole = daoMgr.getXXRole().findByRoleName(name);
+        if (xxRole == null) {
+            throw restErrorUtil.createRESTException("Role with name: " + name + " does not exist");
+        }
+        return roleService.read(xxRole.getId());
+    }
+
+    @Override
+    public List<RangerRole> getRoles(SearchFilter filter) throws Exception {
+        List<RangerRole> ret = new ArrayList<>();
+
+        List<XXRole> xxRoles = daoMgr.getXXRole().getAll();
+
+        if (CollectionUtils.isNotEmpty(xxRoles)) {
+            for (XXRole xxRole : xxRoles) {
+                ret.add(roleService.read(xxRole.getId()));
+            }
+
+            if (predicateUtil != null && filter != null && !filter.isEmpty()) {
+                List<RangerRole> copy = new ArrayList<>(ret);
+
+                predicateUtil.applyFilter(copy, filter);
+                ret = copy;
+            }
+        }
+
+        return ret;
+    }
+
+    @Override
+    public List<String> getRoleNames(SearchFilter filter) throws Exception {
+        List<String> ret = new ArrayList<>();
+
+        List<RangerRole> roles = getRoles(filter);
+
+        if (CollectionUtils.isNotEmpty(roles)) {
+            for (RangerRole role : roles) {
+                ret.add(role.getName());
+            }
+        }
+
+        return ret;
+    }
+
+    public List<RangerRole> getRoles(String serviceName) {
+        List<RangerRole> ret = ListUtils.EMPTY_LIST;
+        if (StringUtils.isNotEmpty(serviceName)) {
+            XXService xxService = daoMgr.getXXService().findByName(serviceName);
+            ret = getRoles(xxService);
+        }
+        return ret;
+    }
+
+    public List<RangerRole> getRoles(Long serviceId) {
+        List<RangerRole> ret = ListUtils.EMPTY_LIST;
+        if (serviceId != null) {
+            List<XXRole> rolesFromDb = daoMgr.getXXRole().findByServiceId(serviceId);
+            if (CollectionUtils.isNotEmpty(rolesFromDb)) {
+                ret = new ArrayList<>();
+                for (XXRole xxRole : rolesFromDb) {
+                    ret.add(roleService.read(xxRole.getId()));
+                }
+            }
+        }
+        return ret;
+    }
+
+    public List<RangerRole> getRoles(XXService service) {
+        return service == null ? ListUtils.EMPTY_LIST : getRoles(service.getId());
+    }
+
+}
+
diff --git a/security-admin/src/main/java/org/apache/ranger/biz/RoleRefUpdater.java b/security-admin/src/main/java/org/apache/ranger/biz/RoleRefUpdater.java
new file mode 100644
index 0000000..3742bd6
--- /dev/null
+++ b/security-admin/src/main/java/org/apache/ranger/biz/RoleRefUpdater.java
@@ -0,0 +1,175 @@
+/*
+ * 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.biz;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.ranger.common.MessageEnums;
+import org.apache.ranger.common.RESTErrorUtil;
+import org.apache.ranger.db.RangerDaoManager;
+import org.apache.ranger.db.XXRoleRefGroupDao;
+import org.apache.ranger.db.XXRoleRefRoleDao;
+import org.apache.ranger.db.XXRoleRefUserDao;
+import org.apache.ranger.entity.XXGroup;
+import org.apache.ranger.entity.XXRole;
+import org.apache.ranger.entity.XXRoleRefGroup;
+import org.apache.ranger.entity.XXRoleRefRole;
+import org.apache.ranger.entity.XXRoleRefUser;
+import org.apache.ranger.entity.XXUser;
+import org.apache.ranger.plugin.model.RangerRole;
+import org.apache.ranger.service.RangerAuditFields;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class RoleRefUpdater {
+	@Autowired
+	RangerDaoManager daoMgr;
+
+	@Autowired
+	RangerAuditFields<?> rangerAuditFields;
+
+	@Autowired
+	RESTErrorUtil restErrorUtil;
+
+	public void createNewRoleMappingForRefTable(RangerRole rangerRole) throws Exception {
+		if (rangerRole == null) {
+			return;
+		}
+
+		cleanupRefTables(rangerRole);
+		final Long roleId = rangerRole.getId();
+
+		final Set<String> roleUsers = new HashSet<>();
+		final Set<String> roleGroups = new HashSet<>();
+		final Set<String> roleRoles = new HashSet<>();
+
+		for (RangerRole.RoleMember user : rangerRole.getUsers()) {
+			roleUsers.add(user.getName());
+		}
+		for (RangerRole.RoleMember group : rangerRole.getGroups()) {
+			roleGroups.add(group.getName());
+		}
+		for (RangerRole.RoleMember role : rangerRole.getRoles()) {
+			roleRoles.add(role.getName());
+		}
+
+		if (CollectionUtils.isNotEmpty(roleUsers)) {
+			for (String roleUser : roleUsers) {
+
+				if (StringUtils.isBlank(roleUser)) {
+					continue;
+				}
+
+				XXUser xUser = daoMgr.getXXUser().findByUserName(roleUser);
+
+				if (xUser == null) {
+					throw restErrorUtil.createRESTException("user with name: " + roleUser + " does not exist ",
+							MessageEnums.INVALID_INPUT_DATA);
+				}
+
+				XXRoleRefUser xRoleRefUser = rangerAuditFields.populateAuditFieldsForCreate(new XXRoleRefUser());
+
+				xRoleRefUser.setRoleId(roleId);
+				xRoleRefUser.setUserId(xUser.getId());
+				xRoleRefUser.setUserName(roleUser);
+				xRoleRefUser.setUserType(0);
+				daoMgr.getXXRoleRefUser().create(xRoleRefUser);
+			}
+		}
+
+		if (CollectionUtils.isNotEmpty(roleGroups)) {
+			for (String roleGroup : roleGroups) {
+
+				if (StringUtils.isBlank(roleGroup)) {
+					continue;
+				}
+
+				XXGroup xGroup = daoMgr.getXXGroup().findByGroupName(roleGroup);
+
+				if (xGroup == null) {
+					throw restErrorUtil.createRESTException("group with name: " + roleGroup + " does not exist ",
+							MessageEnums.INVALID_INPUT_DATA);
+				}
+
+				XXRoleRefGroup xRoleRefGroup = rangerAuditFields.populateAuditFieldsForCreate(new XXRoleRefGroup());
+
+				xRoleRefGroup.setRoleId(roleId);
+				xRoleRefGroup.setGroupId(xGroup.getId());
+				xRoleRefGroup.setGroupName(roleGroup);
+				xRoleRefGroup.setGroupType(0);
+				daoMgr.getXXRoleRefGroup().create(xRoleRefGroup);
+			}
+		}
+
+		if (CollectionUtils.isNotEmpty(roleRoles)) {
+			for (String roleRole : roleRoles) {
+
+				if (StringUtils.isBlank(roleRole)) {
+					continue;
+				}
+
+				XXRole xRole = daoMgr.getXXRole().findByRoleName(roleRole);
+
+				if (xRole == null) {
+					throw restErrorUtil.createRESTException("Role with name: " + roleRole + " does not exist ",
+							MessageEnums.INVALID_INPUT_DATA);
+				}
+
+				XXRoleRefRole xRoleRefRole = rangerAuditFields.populateAuditFieldsForCreate(new XXRoleRefRole());
+
+				xRoleRefRole.setRoleId(roleId);
+				xRoleRefRole.setSubRoleId(xRole.getId());
+				xRoleRefRole.setSubRoleName(roleRole);
+				xRoleRefRole.setSubRoleType(0);
+				daoMgr.getXXRoleRefRole().create(xRoleRefRole);
+			}
+		}
+
+	}
+
+	public Boolean cleanupRefTables(RangerRole rangerRole) {
+		final Long roleId = rangerRole.getId();
+
+		if (roleId == null) {
+			return false;
+		}
+
+		XXRoleRefUserDao xRoleUserDao = daoMgr.getXXRoleRefUser();
+		XXRoleRefGroupDao xRoleGroupDao = daoMgr.getXXRoleRefGroup();
+		XXRoleRefRoleDao xRoleRoleDao = daoMgr.getXXRoleRefRole();
+
+		for (XXRoleRefUser xxRoleRefUser : xRoleUserDao.findByRoleId(roleId)) {
+			xRoleUserDao.remove(xxRoleRefUser);
+		}
+
+		for (XXRoleRefGroup xxRoleRefGroup : xRoleGroupDao.findByRoleId(roleId)) {
+			xRoleGroupDao.remove(xxRoleRefGroup);
+		}
+
+		for (XXRoleRefRole xxRoleRefRole : xRoleRoleDao.findByRoleId(roleId)) {
+			xRoleRoleDao.remove(xxRoleRefRole);
+		}
+		return true;
+	}
+}
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 eef29b0..2933392 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
@@ -66,6 +66,7 @@ import org.apache.ranger.common.RangerCommonEnums;
 import org.apache.ranger.common.db.RangerTransactionSynchronizationAdapter;
 import org.apache.ranger.db.XXPolicyDao;
 import org.apache.ranger.entity.*;
+import org.apache.ranger.plugin.model.RangerRole;
 import org.apache.ranger.plugin.model.RangerSecurityZone;
 import org.apache.ranger.plugin.model.validation.RangerServiceDefValidator;
 import org.apache.ranger.plugin.model.validation.RangerValidator;
@@ -286,6 +287,9 @@ public class ServiceDBStore extends AbstractServiceStore {
 	@Autowired
     RangerSecurityZoneServiceService securityZoneService;
 
+	@Autowired
+	RoleDBStore roleStore;
+
 	private static volatile boolean legacyServiceDefsInitDone = false;
 	private Boolean populateExistingBaseFields = false;
 	
@@ -2651,6 +2655,23 @@ 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) {
+					buildMap(userRoleMapping, role.getUsers(), role.getName());
+					buildMap(groupRoleMapping, role.getGroups(), role.getName());
+					// TBD - roles within roles
+				}
+
+				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()));
 		}
@@ -2658,6 +2679,18 @@ public class ServiceDBStore extends AbstractServiceStore {
 		return ret;
 	}
 
+	private void buildMap(Map<String, Set<String>> map, List<RangerRole.RoleMember> usersOrGroups, String roleName) {
+		for(RangerRole.RoleMember userOrGroup : usersOrGroups) {
+			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) {
diff --git a/security-admin/src/main/java/org/apache/ranger/common/AppConstants.java b/security-admin/src/main/java/org/apache/ranger/common/AppConstants.java
index 039e4e8..e190bbc 100644
--- a/security-admin/src/main/java/org/apache/ranger/common/AppConstants.java
+++ b/security-admin/src/main/java/org/apache/ranger/common/AppConstants.java
@@ -609,6 +609,7 @@ public class AppConstants extends RangerCommonEnums {
 	public static final int CLASS_TYPE_UGYNC_AUDIT_INFO = 1055;
 
 	public static final int CLASS_TYPE_RANGER_SECURITY_ZONE = 1056;
+	public static final int CLASS_TYPE_RANGER_ROLE = 1057;
 	/**
 	 * Class type of RangerSecurityZone
 	 */
@@ -616,7 +617,7 @@ public class AppConstants extends RangerCommonEnums {
 	/**
 	 * Max value for enum ClassTypes_MAX
 	 */
-	public static final int ClassTypes_MAX = 1057;
+	public static final int ClassTypes_MAX = 1058;
 
 	
 	/***************************************************************
@@ -1006,6 +1007,9 @@ public class AppConstants extends RangerCommonEnums {
 		if( elementValue == 1056 ) {
 			return "Ranger Security Zone"; //CLASS_TYPE_RANGER_SECURITY_ZONE
 		}
+		if( elementValue == 1057 ) {
+			return "Ranger Role"; //CLASS_TYPE_RANGER_ROLE
+		}
 		return null;
 	}
 
diff --git a/security-admin/src/main/java/org/apache/ranger/db/RangerDaoManagerBase.java b/security-admin/src/main/java/org/apache/ranger/db/RangerDaoManagerBase.java
index 979fd65..e4e335f 100644
--- a/security-admin/src/main/java/org/apache/ranger/db/RangerDaoManagerBase.java
+++ b/security-admin/src/main/java/org/apache/ranger/db/RangerDaoManagerBase.java
@@ -305,5 +305,15 @@ public abstract class RangerDaoManagerBase {
 
 	public XXPolicyChangeLogDao getXXPolicyChangeLog() { return new XXPolicyChangeLogDao(this); }
 
+	public XXRoleDao getXXRole() { return new XXRoleDao(this); }
+
+	public XXPolicyRefRoleDao getXXPolicyRefRole() { return new XXPolicyRefRoleDao(this); }
+
+	public XXRoleRefUserDao getXXRoleRefUser() { return new XXRoleRefUserDao(this); }
+
+	public XXRoleRefGroupDao getXXRoleRefGroup() { return new XXRoleRefGroupDao(this); }
+
+	public XXRoleRefRoleDao getXXRoleRefRole() { return new XXRoleRefRoleDao(this); }
+
 }
 
diff --git a/security-admin/src/main/java/org/apache/ranger/db/XXPolicyDao.java b/security-admin/src/main/java/org/apache/ranger/db/XXPolicyDao.java
index 5d513bd..baf6b6e 100644
--- a/security-admin/src/main/java/org/apache/ranger/db/XXPolicyDao.java
+++ b/security-admin/src/main/java/org/apache/ranger/db/XXPolicyDao.java
@@ -22,6 +22,7 @@ import java.util.List;
 
 import javax.persistence.NoResultException;
 
+import org.apache.commons.collections.ListUtils;
 import org.apache.ranger.common.db.BaseDao;
 import org.apache.ranger.entity.XXPolicy;
 import org.apache.ranger.plugin.model.RangerSecurityZone;
@@ -187,5 +188,17 @@ public class XXPolicyDao extends BaseDao<XXPolicy> {
 			return new ArrayList<XXPolicy>();
 		}
 	}
+	public List<XXPolicy> findByRoleId(Long roleId) {
+		List<XXPolicy> ret = ListUtils.EMPTY_LIST;
+		if (roleId != null) {
+			try {
+				ret = getEntityManager().createNamedQuery("XXPolicy.findByRoleId", tClass)
+						.setParameter("roleId", roleId)
+						.getResultList();
+			} catch (NoResultException excp) {
+			}
+		}
+		return ret;
+	}
 
 }
\ No newline at end of file
diff --git a/security-admin/src/main/java/org/apache/ranger/db/XXPolicyRefRoleDao.java b/security-admin/src/main/java/org/apache/ranger/db/XXPolicyRefRoleDao.java
new file mode 100644
index 0000000..b92f806
--- /dev/null
+++ b/security-admin/src/main/java/org/apache/ranger/db/XXPolicyRefRoleDao.java
@@ -0,0 +1,100 @@
+/*
+ * 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.db;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.persistence.NoResultException;
+
+import org.apache.ranger.biz.RangerPolicyRetriever;
+import org.apache.ranger.common.db.BaseDao;
+import org.apache.ranger.entity.XXPolicyRefRole;
+import org.springframework.stereotype.Service;
+
+@Service
+public class XXPolicyRefRoleDao extends BaseDao<XXPolicyRefRole>{
+
+
+    public XXPolicyRefRoleDao(RangerDaoManagerBase daoManager)  {
+        super(daoManager);
+    }
+
+    public List<XXPolicyRefRole> findByPolicyId(Long policyId) {
+        if(policyId == null) {
+            return Collections.EMPTY_LIST;
+        }
+        try {
+            return getEntityManager()
+                    .createNamedQuery("XXPolicyRefRole.findByPolicyId", tClass)
+                    .setParameter("policyId", policyId).getResultList();
+        } catch (NoResultException e) {
+            return Collections.EMPTY_LIST;
+        }
+    }
+    public List<XXPolicyRefRole> findByRoleName(String roleName) {
+        if (roleName == null) {
+            return Collections.EMPTY_LIST;
+        }
+        try {
+            return getEntityManager().createNamedQuery("XXPolicyRefRole.findByRoleName", tClass)
+                    .setParameter("roleName", roleName).getResultList();
+        } catch (NoResultException e) {
+            return Collections.EMPTY_LIST;
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public List<RangerPolicyRetriever.PolicyTextNameMap> findUpdatedRoleNamesByPolicy(Long policyId) {
+        List<RangerPolicyRetriever.PolicyTextNameMap> ret = new ArrayList<>();
+        if (policyId != null) {
+            List<Object[]> rows = (List<Object[]>) getEntityManager()
+                    .createNamedQuery("XXPolicyRefRole.findUpdatedRoleNamesByPolicy")
+                    .setParameter("policy", policyId)
+                    .getResultList();
+            if (rows != null) {
+                for (Object[] row : rows) {
+                    ret.add(new RangerPolicyRetriever.PolicyTextNameMap((Long)row[0], (String)row[1], (String)row[2]));
+                }
+            }
+        }
+        return ret;
+    }
+
+    @SuppressWarnings("unchecked")
+    public List<RangerPolicyRetriever.PolicyTextNameMap> findUpdatedRoleNamesByService(Long serviceId) {
+        List<RangerPolicyRetriever.PolicyTextNameMap> ret = new ArrayList<>();
+        if (serviceId != null) {
+            List<Object[]> rows = (List<Object[]>) getEntityManager()
+                    .createNamedQuery("XXPolicyRefRole.findUpdatedRoleNamesByService")
+                    .setParameter("service", serviceId)
+                    .getResultList();
+            if (rows != null) {
+                for (Object[] row : rows) {
+                    ret.add(new RangerPolicyRetriever.PolicyTextNameMap((Long)row[0], (String)row[1], (String)row[2]));
+                }
+            }
+        }
+        return ret;
+    }
+
+}
+
diff --git a/security-admin/src/main/java/org/apache/ranger/db/XXRoleDao.java b/security-admin/src/main/java/org/apache/ranger/db/XXRoleDao.java
new file mode 100644
index 0000000..5b6028f
--- /dev/null
+++ b/security-admin/src/main/java/org/apache/ranger/db/XXRoleDao.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.db;
+
+import org.apache.commons.collections.ListUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.ranger.common.db.BaseDao;
+import org.apache.ranger.entity.XXRole;
+import org.springframework.stereotype.Service;
+
+import javax.persistence.NoResultException;
+import java.util.List;
+
+@Service
+public class XXRoleDao extends BaseDao<XXRole> {
+    /**
+     * Default Constructor
+     */
+    public XXRoleDao(RangerDaoManagerBase daoManager) {
+        super(daoManager);
+    }
+    public XXRole findByRoleId(Long roleId) {
+        if (roleId == null) {
+            return null;
+        }
+        try {
+            XXRole xxRole = getEntityManager()
+                    .createNamedQuery("XXRole.findByRoleId", tClass)
+                    .setParameter("roleId", roleId)
+                    .getSingleResult();
+            return xxRole;
+        } catch (NoResultException e) {
+            return null;
+        }
+    }
+    public XXRole findByRoleName(String roleName) {
+        if (StringUtils.isBlank(roleName)) {
+            return null;
+        }
+        try {
+            XXRole xxRole = getEntityManager()
+                    .createNamedQuery("XXRole.findByRoleName", tClass)
+                    .setParameter("roleName", roleName)
+                    .getSingleResult();
+            return xxRole;
+        } catch (NoResultException e) {
+            return null;
+        }
+    }
+    public List<XXRole> findByServiceId(Long serviceId) {
+        List<XXRole> ret;
+        try {
+            ret = getEntityManager()
+                    .createNamedQuery("XXRole.findByServiceId", tClass)
+                    .setParameter("serviceId", serviceId)
+                    .getResultList();
+        } catch (NoResultException e) {
+            ret = ListUtils.EMPTY_LIST;
+        }
+        return ret;
+    }
+}
+
diff --git a/security-admin/src/main/java/org/apache/ranger/db/XXRoleRefGroupDao.java b/security-admin/src/main/java/org/apache/ranger/db/XXRoleRefGroupDao.java
new file mode 100644
index 0000000..eb470f2
--- /dev/null
+++ b/security-admin/src/main/java/org/apache/ranger/db/XXRoleRefGroupDao.java
@@ -0,0 +1,75 @@
+/*
+ * 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.db;
+
+import java.util.Collections;
+import java.util.List;
+
+import javax.persistence.NoResultException;
+
+import org.apache.ranger.common.db.BaseDao;
+import org.apache.ranger.entity.XXRoleRefGroup;
+import org.springframework.stereotype.Service;
+
+@Service
+public class XXRoleRefGroupDao extends BaseDao<XXRoleRefGroup>{
+
+    public XXRoleRefGroupDao(RangerDaoManagerBase daoManager)  {
+        super(daoManager);
+    }
+
+    public List<XXRoleRefGroup> findByRoleId(Long roleId) {
+        if(roleId == null) {
+            return Collections.EMPTY_LIST;
+        }
+        try {
+            return getEntityManager()
+                    .createNamedQuery("XXRoleRefGroup.findByRoleId", tClass)
+                    .setParameter("roleId", roleId).getResultList();
+        } catch (NoResultException e) {
+            return Collections.EMPTY_LIST;
+        }
+    }
+
+    public List<XXRoleRefGroup> findByGroupId(Long groupId) {
+        if(groupId == null) {
+            return Collections.EMPTY_LIST;
+        }
+        try {
+            return getEntityManager()
+                    .createNamedQuery("XXRoleRefGroup.findByGroupId", tClass)
+                    .setParameter("groupId", groupId).getResultList();
+        } catch (NoResultException e) {
+            return Collections.EMPTY_LIST;
+        }
+    }
+
+    public List<XXRoleRefGroup> findByGroupName(String groupName) {
+        if (groupName == null) {
+            return Collections.EMPTY_LIST;
+        }
+        try {
+            return getEntityManager().createNamedQuery("XXRoleRefGroup.findByGroupName", tClass)
+                    .setParameter("groupName", groupName).getResultList();
+        } catch (NoResultException e) {
+            return Collections.EMPTY_LIST;
+        }
+    }
+}
\ No newline at end of file
diff --git a/security-admin/src/main/java/org/apache/ranger/db/XXRoleRefRoleDao.java b/security-admin/src/main/java/org/apache/ranger/db/XXRoleRefRoleDao.java
new file mode 100644
index 0000000..80e0854
--- /dev/null
+++ b/security-admin/src/main/java/org/apache/ranger/db/XXRoleRefRoleDao.java
@@ -0,0 +1,75 @@
+/*
+ * 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.db;
+
+import java.util.Collections;
+import java.util.List;
+
+import javax.persistence.NoResultException;
+
+import org.apache.ranger.common.db.BaseDao;
+import org.apache.ranger.entity.XXRoleRefRole;
+import org.springframework.stereotype.Service;
+
+@Service
+public class XXRoleRefRoleDao extends BaseDao<XXRoleRefRole>{
+
+    public XXRoleRefRoleDao(RangerDaoManagerBase daoManager)  {
+        super(daoManager);
+    }
+
+    public List<XXRoleRefRole> findByRoleId(Long roleId) {
+        if(roleId == null) {
+            return Collections.EMPTY_LIST;
+        }
+        try {
+            return getEntityManager()
+                    .createNamedQuery("XXRoleRefRole.findByRoleId", tClass)
+                    .setParameter("roleId", roleId).getResultList();
+        } catch (NoResultException e) {
+            return Collections.EMPTY_LIST;
+        }
+    }
+
+    public List<XXRoleRefRole> findBySubRoleId(Long subRoleId) {
+        if(subRoleId == null) {
+            return Collections.EMPTY_LIST;
+        }
+        try {
+            return getEntityManager()
+                    .createNamedQuery("XXRoleRefRole.findBySubRoleId", tClass)
+                    .setParameter("subRoleId", subRoleId).getResultList();
+        } catch (NoResultException e) {
+            return Collections.EMPTY_LIST;
+        }
+    }
+
+    public List<XXRoleRefRole> findBySubRoleName(String subRoleName) {
+        if (subRoleName == null) {
+            return Collections.EMPTY_LIST;
+        }
+        try {
+            return getEntityManager().createNamedQuery("XXRoleRefRole.findBySubRoleName", tClass)
+                    .setParameter("subRoleName", subRoleName).getResultList();
+        } catch (NoResultException e) {
+            return Collections.EMPTY_LIST;
+        }
+    }
+}
\ No newline at end of file
diff --git a/security-admin/src/main/java/org/apache/ranger/db/XXRoleRefUserDao.java b/security-admin/src/main/java/org/apache/ranger/db/XXRoleRefUserDao.java
new file mode 100644
index 0000000..ba9fb49
--- /dev/null
+++ b/security-admin/src/main/java/org/apache/ranger/db/XXRoleRefUserDao.java
@@ -0,0 +1,75 @@
+/*
+ * 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.db;
+
+import java.util.Collections;
+import java.util.List;
+
+import javax.persistence.NoResultException;
+
+import org.apache.ranger.common.db.BaseDao;
+import org.apache.ranger.entity.XXRoleRefUser;
+import org.springframework.stereotype.Service;
+
+@Service
+public class XXRoleRefUserDao extends BaseDao<XXRoleRefUser>{
+
+    public XXRoleRefUserDao(RangerDaoManagerBase daoManager)  {
+        super(daoManager);
+    }
+
+    public List<XXRoleRefUser> findByRoleId(Long roleId) {
+        if(roleId == null) {
+            return Collections.EMPTY_LIST;
+        }
+        try {
+            return getEntityManager()
+                    .createNamedQuery("XXRoleRefUser.findByRoleId", tClass)
+                    .setParameter("roleId", roleId).getResultList();
+        } catch (NoResultException e) {
+            return Collections.EMPTY_LIST;
+        }
+    }
+
+    public List<XXRoleRefUser> findByUserId(Long userId) {
+        if(userId == null) {
+            return Collections.EMPTY_LIST;
+        }
+        try {
+            return getEntityManager()
+                    .createNamedQuery("XXRoleRefUser.findByUserId", tClass)
+                    .setParameter("userId", userId).getResultList();
+        } catch (NoResultException e) {
+            return Collections.EMPTY_LIST;
+        }
+    }
+
+    public List<XXRoleRefUser> findByUserName(String userName) {
+        if (userName == null) {
+            return Collections.EMPTY_LIST;
+        }
+        try {
+            return getEntityManager().createNamedQuery("XXRoleRefUser.findByUserName", tClass)
+                    .setParameter("userName", userName).getResultList();
+        } catch (NoResultException e) {
+            return Collections.EMPTY_LIST;
+        }
+    }
+}
\ No newline at end of file
diff --git a/security-admin/src/main/java/org/apache/ranger/entity/XXPolicyRefRole.java b/security-admin/src/main/java/org/apache/ranger/entity/XXPolicyRefRole.java
new file mode 100644
index 0000000..7aee502
--- /dev/null
+++ b/security-admin/src/main/java/org/apache/ranger/entity/XXPolicyRefRole.java
@@ -0,0 +1,206 @@
+/*
+ * 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.entity;
+
+import java.io.Serializable;
+import java.util.Objects;
+
+import javax.persistence.Cacheable;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.Table;
+import javax.xml.bind.annotation.XmlRootElement;
+
+
+/**
+ * The persistent class for the x_policy_ref_role database table.
+ *
+ */
+@Entity
+@Cacheable
+@XmlRootElement
+@Table(name="x_policy_ref_role")
+public class XXPolicyRefRole extends XXDBBase implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+    /**
+     * id of the XXPolicyRefRole
+     * <ul>
+     * </ul>
+     *
+     */
+    @Id
+    @SequenceGenerator(name = "x_policy_ref_role_SEQ", sequenceName = "x_policy_ref_role_SEQ", allocationSize = 1)
+    @GeneratedValue(strategy = GenerationType.AUTO, generator = "x_policy_ref_role_SEQ")
+    @Column(name = "id")
+    protected Long id;
+
+    /**
+     * policyId of the XXPolicyRefRole
+     * <ul>
+     * </ul>
+     *
+     */
+    @Column(name = "policy_id")
+    protected Long policyId;
+
+    /**
+     * roleId of the XXPolicyRefRole
+     * <ul>
+     * </ul>
+     *
+     */
+    @Column(name = "role_id")
+    protected Long roleId;
+
+    /**
+     * roleName of the XXPolicyRefRole
+     * <ul>
+     * </ul>
+     *
+     */
+    @Column(name = "role_name")
+    protected String roleName;
+
+    /**
+     * This method sets the value to the member attribute <b> id</b> . You
+     * cannot set null to the attribute.
+     *
+     * @param id
+     *            Value to set member attribute <b> id</b>
+     */
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    /**
+     * Returns the value for the member attribute <b>id</b>
+     *
+     * @return Date - value of member attribute <b>id</b> .
+     */
+    public Long getId() {
+        return this.id;
+    }
+
+    /**
+     * This method sets the value to the member attribute <b> policyId</b> .
+     * You cannot set null to the attribute.
+     *
+     * @param policyId
+     *            Value to set member attribute <b> policyId</b>
+     */
+    public void setPolicyId(Long policyId) {
+        this.policyId = policyId;
+    }
+
+    /**
+     * Returns the value for the member attribute <b>policyId</b>
+     *
+     * @return Long - value of member attribute <b>policyId</b> .
+     */
+    public Long getPolicyId() {
+        return this.policyId;
+    }
+
+    /**
+     * This method sets the value to the member attribute <b> roleId</b> .
+     * You cannot set null to the attribute.
+     *
+     * @param roleId
+     *            Value to set member attribute <b> roleId</b>
+     */
+    public void setRoleId(Long roleId) {
+        this.roleId = roleId;
+    }
+
+    /**
+     * Returns the value for the member attribute <b>roleId</b>
+     *
+     * @return Long - value of member attribute <b>roleId</b> .
+     */
+    public Long getRoleId() {
+        return roleId;
+    }
+
+    /**
+     * This method sets the value to the member attribute <b> roleName</b> .
+     * You cannot set null to the attribute.
+     *
+     * @param roleName
+     *            Value to set member attribute <b> roleName</b>
+     */
+    public void setRoleName(String roleName) {
+        this.roleName = roleName;
+    }
+
+    /**
+     * Returns the value for the member attribute <b>roleName</b>
+     *
+     */
+    public String getRoleName() {
+        return roleName;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), id, policyId, roleId, roleName);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+
+        XXPolicyRefRole other = (XXPolicyRefRole) obj;
+
+        return super.equals(obj) &&
+                Objects.equals(id, other.id) &&
+                Objects.equals(policyId, other.policyId) &&
+                Objects.equals(roleId, other.roleId) &&
+                Objects.equals(roleName, other.roleName);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "XXPolicyRefRole [" + super.toString() + " id=" + id + ", policyId=" + policyId + ", roleId=" + roleId
+                + ", roleName=" + roleName + "]";
+    }
+
+}
+
diff --git a/security-admin/src/main/java/org/apache/ranger/entity/XXRole.java b/security-admin/src/main/java/org/apache/ranger/entity/XXRole.java
new file mode 100644
index 0000000..779c3a0
--- /dev/null
+++ b/security-admin/src/main/java/org/apache/ranger/entity/XXRole.java
@@ -0,0 +1,76 @@
+/*
+ * 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.entity;
+
+import javax.persistence.Cacheable;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.Table;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.Objects;
+
+@Entity
+@Cacheable
+@XmlRootElement
+@Table(name = "x_role")
+public class XXRole extends XXRoleBase implements java.io.Serializable {
+    private static final long serialVersionUID = 1L;
+    @Id
+    @SequenceGenerator(name = "x_role_SEQ", sequenceName = "x_role_SEQ", initialValue = 1, allocationSize = 1)
+    @GeneratedValue(strategy = GenerationType.AUTO, generator = "x_role_SEQ")
+    @Column(name = "id")
+    protected Long id;
+
+    @Override
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    @Override
+    public Long getId() {
+        return id;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (getClass() != obj.getClass())
+            return false;
+        if (!super.equals(obj))
+            return false;
+
+        XXRole other = (XXRole) obj;
+
+        return Objects.equals(id, other.id);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), id);
+    }
+
+    @Override
+    public String toString() {
+        return "Role [id=" + id + "]";
+    }
+}
diff --git a/security-admin/src/main/java/org/apache/ranger/entity/XXRoleBase.java b/security-admin/src/main/java/org/apache/ranger/entity/XXRoleBase.java
new file mode 100644
index 0000000..0faad86
--- /dev/null
+++ b/security-admin/src/main/java/org/apache/ranger/entity/XXRoleBase.java
@@ -0,0 +1,101 @@
+/*
+ * 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.entity;
+
+import javax.persistence.Column;
+import javax.persistence.MappedSuperclass;
+import javax.persistence.Version;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.Objects;
+
+@MappedSuperclass
+@XmlRootElement
+public abstract class XXRoleBase extends XXDBBase {
+    private static final long serialVersionUID = 1L;
+
+    @Version
+    @Column(name = "version")
+    protected Long version;
+
+    @Column(name = "name")
+    protected String name;
+
+    @Column(name = "description")
+    protected String description;
+
+    @Column(name = "role_options")
+    protected String options;
+
+    @Column(name = "role_text")
+    protected String roleText;
+
+
+    public Long getVersion() { return version; }
+    public String getName() { return name; }
+    public String getDescription() { return description; }
+    public String getOptions() { return options; }
+    public String getRoleText() { return roleText; }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+    public void setDescription(String description) {
+        this.description = description;
+    }
+    public void setOptions(String options) {
+        this.options = options;
+    }
+    public void setRoleText(String roleText) {
+        this.roleText = roleText;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+
+        XXRoleBase other = (XXRoleBase) obj;
+
+        return Objects.equals(version, other.version) &&
+                Objects.equals(name, other.name) &&
+                Objects.equals(options, other.options) &&
+                Objects.equals(roleText, other.roleText);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), version, name, options, roleText);
+    }
+
+    @Override
+    public String toString() {
+        String str = "XXRoleBase={";
+        str += super.toString();
+        str += " [version=" + version + ", name=" + name + ", description=" + description + ", options=" + options + ", roleText=" + roleText + "]";
+        str += "}";
+        return str;
+    }
+}
+
diff --git a/security-admin/src/main/java/org/apache/ranger/entity/XXRoleRefGroup.java b/security-admin/src/main/java/org/apache/ranger/entity/XXRoleRefGroup.java
new file mode 100644
index 0000000..22b9447
--- /dev/null
+++ b/security-admin/src/main/java/org/apache/ranger/entity/XXRoleRefGroup.java
@@ -0,0 +1,234 @@
+/* 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.entity;
+
+import java.io.Serializable;
+import java.util.Objects;
+
+import javax.persistence.Cacheable;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.Table;
+import javax.xml.bind.annotation.XmlRootElement;
+
+
+/**
+ * The persistent class for the x_role_ref_group database table.
+ *
+ */
+@Entity
+@Cacheable
+@XmlRootElement
+@Table(name="x_role_ref_group")
+public class XXRoleRefGroup extends XXDBBase implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * id of the XXRoleRefGroup
+     * <ul>
+     * </ul>
+     *
+     */
+    @Id
+    @SequenceGenerator(name = "x_role_ref_group_SEQ", sequenceName = "x_role_ref_group_SEQ", allocationSize = 1)
+    @GeneratedValue(strategy = GenerationType.AUTO, generator = "x_role_ref_group_SEQ")
+    @Column(name = "id")
+    protected Long id;
+
+    /**
+     * roleId of the XXRoleRefGroup
+     * <ul>
+     * </ul>
+     *
+     */
+    @Column(name = "role_id")
+    protected Long roleId;
+
+    /**
+     * groupId of the XXRoleRefGroup
+     * <ul>
+     * </ul>
+     *
+     */
+    @Column(name = "group_id")
+    protected Long groupId;
+
+    /**
+     * groupName of the XXRoleRefGroup
+     * <ul>
+     * </ul>
+     *
+     */
+    @Column(name = "group_name")
+    protected String groupName;
+
+    /**
+     * groupType of the XXRoleRefGroup
+     * <ul>
+     * </ul>
+     *
+     */
+    @Column(name = "priv_Type")
+    protected Integer groupType;
+
+	/**
+     * This method sets the value to the member attribute <b> id</b> . You
+     * cannot set null to the attribute.
+     *
+     * @param id
+     *            Value to set member attribute <b> id</b>
+     */
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    /**
+     * Returns the value for the member attribute <b>id</b>
+     *
+     * @return Date - value of member attribute <b>id</b> .
+     */
+    public Long getId() {
+        return this.id;
+    }
+
+    /**
+     * This method sets the value to the member attribute <b> roleId</b> .
+     * You cannot set null to the attribute.
+     *
+     * @param roleId
+     *            Value to set member attribute <b> roleId</b>
+     */
+    public void setRoleId(Long roleId) {
+        this.roleId = roleId;
+    }
+
+    /**
+     * Returns the value for the member attribute <b>roleId</b>
+     *
+     * @return Long - value of member attribute <b>roleId</b> .
+     */
+    public Long getRoleId() {
+        return roleId;
+    }
+
+    /**
+     * This method sets the value to the member attribute <b> groupId</b> .
+     * You cannot set null to the attribute.
+     *
+     * @param groupId
+     *            Value to set member attribute <b> groupId</b>
+     */
+    public void setGroupId(Long groupId) {
+        this.groupId = groupId;
+    }
+
+    /**
+     * Returns the value for the member attribute <b>groupId</b>
+     *
+     * @return Long - value of member attribute <b>groupId</b> .
+     */
+    public Long getGroupId() {
+        return this.groupId;
+    }
+
+    /**
+     * This method sets the value to the member attribute <b> groupName</b> .
+     * You cannot set null to the attribute.
+     *
+     * @param groupName
+     *            Value to set member attribute <b> groupName</b>
+     */
+    public void setGroupName(String groupName) {
+        this.groupName = groupName;
+    }
+
+    /**
+     * Returns the value for the member attribute <b>groupName</b>
+     *
+     */
+    public String getGroupName() {
+        return groupName;
+    }
+
+    /**
+     * Returns the value for the member attribute <b>groupType</b>
+     *
+     * @return groupType - value of member attribute <b>groupType</b> .
+     */
+    public Integer getGroupType() {
+		return groupType;
+	}
+
+    /**
+     * This method sets the value to the member attribute <b> groupType</b> . You
+     * cannot set null to the attribute.
+     *
+     * @param groupType
+     *            Value to set member attribute <b> groupType</b>
+     */
+	public void setGroupType(Integer groupType) {
+		this.groupType = groupType;
+	}
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), id, roleId, groupId, groupName, groupType);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+
+        XXRoleRefGroup other = (XXRoleRefGroup) obj;
+
+        return super.equals(obj) &&
+                Objects.equals(id, other.id) &&
+                Objects.equals(roleId, other.roleId) &&
+                Objects.equals(groupId, other.groupId) &&
+                Objects.equals(groupName, other.groupName) &&
+                Objects.equals(groupType, other.groupType);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "XXRoleRefGroup [" + super.toString() + " id=" + id + ", roleId=" + roleId +", groupId=" + groupId 
+                + ", groupName=" + groupName + ", groupType=" + groupType + "]";
+    }
+}
\ No newline at end of file
diff --git a/security-admin/src/main/java/org/apache/ranger/entity/XXRoleRefRole.java b/security-admin/src/main/java/org/apache/ranger/entity/XXRoleRefRole.java
new file mode 100644
index 0000000..30867e2
--- /dev/null
+++ b/security-admin/src/main/java/org/apache/ranger/entity/XXRoleRefRole.java
@@ -0,0 +1,233 @@
+/* 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.entity;
+
+import java.io.Serializable;
+import java.util.Objects;
+
+import javax.persistence.Cacheable;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.Table;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ * The persistent class for the x_role_ref_role database table.
+ *
+ */
+@Entity
+@Cacheable
+@XmlRootElement
+@Table(name="x_role_ref_role")
+public class XXRoleRefRole extends XXDBBase implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * id of the XXRoleRefRole
+     * <ul>
+     * </ul>
+     *
+     */
+    @Id
+    @SequenceGenerator(name = "x_role_ref_role_SEQ", sequenceName = "x_role_ref_role_SEQ", allocationSize = 1)
+    @GeneratedValue(strategy = GenerationType.AUTO, generator = "x_role_ref_role_SEQ")
+    @Column(name = "id")
+    protected Long id;
+
+    /**
+     * roleId of the XXRoleRefRole
+     * <ul>
+     * </ul>
+     *
+     */
+    @Column(name = "role_id")
+    protected Long roleId;
+
+    /**
+     * subRoleId of the XXRoleRefRole
+     * <ul>
+     * </ul>
+     *
+     */
+    @Column(name = "role_ref_id")
+    protected Long subRoleId;
+
+    /**
+     * subRoleName of the XXRoleRefRole
+     * <ul>
+     * </ul>
+     *
+     */
+    @Column(name = "role_name")
+    protected String subRoleName;
+
+    /**
+     * subRoleType of the XXRoleRefRole
+     * <ul>
+     * </ul>
+     *
+     */
+    @Column(name = "priv_type")
+    protected Integer subRoleType;
+
+	/**
+     * This method sets the value to the member attribute <b> id</b> . You
+     * cannot set null to the attribute.
+     *
+     * @param id
+     *            Value to set member attribute <b> id</b>
+     */
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    /**
+     * Returns the value for the member attribute <b>id</b>
+     *
+     * @return Date - value of member attribute <b>id</b> .
+     */
+    public Long getId() {
+        return this.id;
+    }
+
+    /**
+     * This method sets the value to the member attribute <b> roleId</b> .
+     * You cannot set null to the attribute.
+     *
+     * @param roleId
+     *            Value to set member attribute <b> roleId</b>
+     */
+    public void setRoleId(Long roleId) {
+        this.roleId = roleId;
+    }
+
+    /**
+     * Returns the value for the member attribute <b>roleId</b>
+     *
+     * @return Long - value of member attribute <b>roleId</b> .
+     */
+    public Long getRoleId() {
+        return roleId;
+    }
+
+    /**
+     * This method sets the value to the member attribute <b> subRoleId</b> .
+     * You cannot set null to the attribute.
+     *
+     * @param subRoleId
+     *            Value to set member attribute <b> subRoleId</b>
+     */
+    public void setSubRoleId(Long subRoleId) {
+        this.subRoleId = subRoleId;
+    }
+
+    /**
+     * Returns the value for the member attribute <b>subRoleId</b>
+     *
+     * @return Long - value of member attribute <b>subRoleId</b> .
+     */
+    public Long getSubRoleId() {
+        return this.subRoleId;
+    }
+
+    /**
+     * This method sets the value to the member attribute <b> subRoleName</b> .
+     * You cannot set null to the attribute.
+     *
+     * @param subRoleName
+     *            Value to set member attribute <b> subRoleName</b>
+     */
+    public void setSubRoleName(String subRoleName) {
+        this.subRoleName = subRoleName;
+    }
+
+    /**
+     * Returns the value for the member attribute <b>subRoleName</b>
+     *
+     */
+    public String getSubRoleName() {
+        return subRoleName;
+    }
+
+    /**
+     * Returns the value for the member attribute <b>subRoleType</b>
+     *
+     * @return subRoleType - value of member attribute <b>subRoleType</b> .
+     */
+    public Integer getSubRoleType() {
+		return subRoleType;
+	}
+
+    /**
+     * This method sets the value to the member attribute <b> subRoleType</b> . You
+     * cannot set null to the attribute.
+     *
+     * @param subRoleType
+     *            Value to set member attribute <b> subRoleType</b>
+     */
+	public void setSubRoleType(Integer subRoleType) {
+		this.subRoleType = subRoleType;
+	}
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), id, roleId, subRoleId, subRoleName, subRoleType);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+
+        XXRoleRefRole other = (XXRoleRefRole) obj;
+
+        return super.equals(obj) &&
+                Objects.equals(id, other.id) &&
+                Objects.equals(roleId, other.roleId) &&
+                Objects.equals(subRoleId, other.subRoleId) &&
+                Objects.equals(subRoleName, other.subRoleName) &&
+        		Objects.equals(subRoleType, other.subRoleType);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "XXRoleRefRole [" + super.toString() + " id=" + id + ", roleId=" + roleId +", subRoleId=" + subRoleId 
+                + ", subRoleName=" + subRoleName + ", subRoleType=" + subRoleType + "]";
+    }
+}
\ No newline at end of file
diff --git a/security-admin/src/main/java/org/apache/ranger/entity/XXRoleRefUser.java b/security-admin/src/main/java/org/apache/ranger/entity/XXRoleRefUser.java
new file mode 100644
index 0000000..a5b17f7
--- /dev/null
+++ b/security-admin/src/main/java/org/apache/ranger/entity/XXRoleRefUser.java
@@ -0,0 +1,234 @@
+/* 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.entity;
+
+import java.io.Serializable;
+import java.util.Objects;
+
+import javax.persistence.Cacheable;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.Table;
+import javax.xml.bind.annotation.XmlRootElement;
+
+
+/**
+ * The persistent class for the x_role_ref_user database table.
+ *
+ */
+@Entity
+@Cacheable
+@XmlRootElement
+@Table(name="x_role_ref_user")
+public class XXRoleRefUser extends XXDBBase implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * id of the XXRoleRefUser
+     * <ul>
+     * </ul>
+     *
+     */
+    @Id
+    @SequenceGenerator(name = "x_role_ref_user_SEQ", sequenceName = "x_role_ref_user_SEQ", allocationSize = 1)
+    @GeneratedValue(strategy = GenerationType.AUTO, generator = "x_role_ref_user_SEQ")
+    @Column(name = "id")
+    protected Long id;
+
+    /**
+     * roleId of the XXRoleRefUser
+     * <ul>
+     * </ul>
+     *
+     */
+    @Column(name = "role_id")
+    protected Long roleId;
+
+    /**
+     * userId of the XXRoleRefUser
+     * <ul>
+     * </ul>
+     *
+     */
+    @Column(name = "user_id")
+    protected Long userId;
+
+    /**
+     * userName of the XXRoleRefUser
+     * <ul>
+     * </ul>
+     *
+     */
+    @Column(name = "user_name")
+    protected String userName;
+
+    /**
+     * userType of the XXRoleRefGroup
+     * <ul>
+     * </ul>
+     *
+     */
+    @Column(name = "priv_type")
+    protected Integer userType;
+
+    /**
+     * This method sets the value to the member attribute <b> id</b> . You
+     * cannot set null to the attribute.
+     *
+     * @param id
+     *            Value to set member attribute <b> id</b>
+     */
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    /**
+     * Returns the value for the member attribute <b>id</b>
+     *
+     * @return Date - value of member attribute <b>id</b> .
+     */
+    public Long getId() {
+        return this.id;
+    }
+
+    /**
+     * This method sets the value to the member attribute <b> roleId</b> .
+     * You cannot set null to the attribute.
+     *
+     * @param roleId
+     *            Value to set member attribute <b> roleId</b>
+     */
+    public void setRoleId(Long roleId) {
+        this.roleId = roleId;
+    }
+
+    /**
+     * Returns the value for the member attribute <b>roleId</b>
+     *
+     * @return Long - value of member attribute <b>roleId</b> .
+     */
+    public Long getRoleId() {
+        return roleId;
+    }
+
+    /**
+     * This method sets the value to the member attribute <b> userId</b> .
+     * You cannot set null to the attribute.
+     *
+     * @param userId
+     *            Value to set member attribute <b> userId</b>
+     */
+    public void setUserId(Long userId) {
+        this.userId = userId;
+    }
+
+    /**
+     * Returns the value for the member attribute <b>userId</b>
+     *
+     * @return Long - value of member attribute <b>userId</b> .
+     */
+    public Long getUserId() {
+        return this.userId;
+    }
+
+    /**
+     * This method sets the value to the member attribute <b> userName</b> .
+     * You cannot set null to the attribute.
+     *
+     * @param userName
+     *            Value to set member attribute <b> userName</b>
+     */
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
+
+    /**
+     * Returns the value for the member attribute <b>userName</b>
+     *
+     */
+    public String getUserName() {
+        return userName;
+    }
+
+    /**
+     * Returns the value for the member attribute <b>userType</b>
+     *
+     * @return userType - value of member attribute <b>userType</b> .
+     */
+    public Integer getUserType() {
+		return userType;
+	}
+
+    /**
+     * This method sets the value to the member attribute <b> userType</b> . You
+     * cannot set null to the attribute.
+     *
+     * @param userType
+     *            Value to set member attribute <b> userType</b>
+     */
+	public void setUserType(Integer userType) {
+		this.userType = userType;
+	}
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), id, roleId, userId, userName, userType);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+
+        XXRoleRefUser other = (XXRoleRefUser) obj;
+
+        return super.equals(obj) &&
+                Objects.equals(id, other.id) &&
+                Objects.equals(roleId, other.roleId) &&
+                Objects.equals(userId, other.userId) &&
+                Objects.equals(userName, other.userName) &&
+                Objects.equals(userType, other.userType);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "XXRoleRefUser [" + super.toString() + " id=" + id + ", roleId=" + roleId +", userId=" + userId 
+                + ", userName=" + userName  + ", userType=" + userType + "]";
+    }
+}
\ No newline at end of file
diff --git a/security-admin/src/main/java/org/apache/ranger/rest/PublicAPIsv2.java b/security-admin/src/main/java/org/apache/ranger/rest/PublicAPIsv2.java
index 734faef..17239c9 100644
--- a/security-admin/src/main/java/org/apache/ranger/rest/PublicAPIsv2.java
+++ b/security-admin/src/main/java/org/apache/ranger/rest/PublicAPIsv2.java
@@ -25,11 +25,13 @@ import org.apache.ranger.common.RESTErrorUtil;
 import org.apache.ranger.common.annotation.RangerAnnotationJSMgrName;
 import org.apache.ranger.plugin.model.RangerPluginInfo;
 import org.apache.ranger.plugin.model.RangerPolicy;
+import org.apache.ranger.plugin.model.RangerRole;
 import org.apache.ranger.plugin.model.RangerSecurityZone;
 import org.apache.ranger.plugin.model.RangerService;
 import org.apache.ranger.plugin.model.RangerServiceDef;
 import org.apache.ranger.plugin.util.SearchFilter;
 import org.apache.ranger.view.RangerPluginInfoList;
+import org.apache.ranger.view.RangerRoleList;
 import org.apache.ranger.view.RangerSecurityZoneList;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Scope;
@@ -61,6 +63,9 @@ public class PublicAPIsv2 {
 	SecurityZoneREST securityZoneRest;
 
 	@Autowired
+	RoleREST roleREST;
+
+	@Autowired
 	RESTErrorUtil restErrorUtil;
 
 	/*
@@ -531,4 +536,83 @@ public class PublicAPIsv2 {
 			logger.debug("<== PublicAPIsv2.deletePolicyDeltas(" + olderThan + ", " + reloadServicePoliciesCache + ")");
 		}
 	}
+
+	/*
+	 * Role Creation API
+	 */
+
+	@POST
+	@Path("/api/roles")
+	public RangerRole createRole(RangerRole role) {
+		return roleREST.createRole(role);
+	}
+
+	/*
+	 * Role Manipulation API
+	 */
+	@PUT
+	@Path("/api/roles/{id}")
+	public RangerRole updateRole(@PathParam("id") Long roleId, RangerRole role) {
+		return roleREST.updateRole(roleId, role);
+	}
+
+	@DELETE
+	@Path("/api/roles/name/{name}")
+	public void deleteRole(@PathParam("name") String roleName) {
+		roleREST.deleteRole(roleName);
+	}
+
+	@DELETE
+	@Path("/api/roles/{id}")
+	public void deleteRole(@PathParam("id") Long roleId) {
+		roleREST.deleteRole(roleId);
+	}
+
+	/*
+	 *  APIs to Access Roles
+	 */
+	@GET
+	@Path("/api/roles/name/{name}")
+	public RangerRole getRole(@PathParam("name") String roleName) {
+		return roleREST.getRole(roleName);
+	}
+
+	@GET
+	@Path("/api/roles/{id}")
+	public RangerRole getRole(@PathParam("id") Long id) {
+		return roleREST.getRole(id);
+	}
+
+	@GET
+	@Path("/api/roles")
+	public RangerRoleList getAllRoles(@Context HttpServletRequest request){
+		return roleREST.getAllRoles(request);
+	}
+
+	/*
+    	This API is used to add users and groups with/without GRANT privileges to this Role. It follows add-or-update semantics
+ 	 */
+	@PUT
+	@Path("/api/roles/{id}/addUsersAndGroups")
+	public RangerRole addUsersAndGroups(@PathParam("id") Long roleId, List<String> users, List<String> groups, Boolean isAdmin) {
+		return roleREST.addUsersAndGroups(roleId, users, groups, isAdmin);
+	}
+
+	/*
+        This API is used to remove users and groups, without regard to their GRANT privilege, from this Role.
+     */
+	@PUT
+	@Path("/api/roles/{id}/removeUsersAndGroups")
+	public RangerRole removeUsersAndGroups(@PathParam("id") Long roleId, List<String> users, List<String> groups) {
+		return roleREST.removeUsersAndGroups(roleId, users, groups);
+	}
+
+	/*
+        This API is used to remove GRANT privilege from listed users and groups.
+     */
+	@PUT
+	@Path("/api/roles/{id}/removeAdminFromUsersAndGroups")
+	public RangerRole removeAdminFromUsersAndGroups(@PathParam("id") Long roleId, List<String> users, List<String> groups) {
+		return roleREST.removeAdminFromUsersAndGroups(roleId, users, groups);
+	}
 }
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
new file mode 100644
index 0000000..8a5c812
--- /dev/null
+++ b/security-admin/src/main/java/org/apache/ranger/rest/RoleREST.java
@@ -0,0 +1,477 @@
+/*
+ * 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.rest;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Context;
+
+import org.apache.commons.codec.binary.StringUtils;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.ranger.biz.RangerBizUtil;
+import org.apache.ranger.biz.RoleDBStore;
+import org.apache.ranger.biz.ServiceDBStore;
+import org.apache.ranger.common.ContextUtil;
+import org.apache.ranger.common.RESTErrorUtil;
+import org.apache.ranger.common.RangerSearchUtil;
+import org.apache.ranger.common.RangerValidatorFactory;
+import org.apache.ranger.common.UserSessionBase;
+import org.apache.ranger.plugin.model.RangerRole;
+import org.apache.ranger.plugin.policyengine.RangerPolicyEngine;
+import org.apache.ranger.plugin.util.SearchFilter;
+import org.apache.ranger.service.RangerRoleService;
+import org.apache.ranger.service.XUserService;
+import org.apache.ranger.view.RangerRoleList;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+
+@Path("roles")
+@Component
+@Scope("request")
+@Transactional(propagation = Propagation.REQUIRES_NEW)
+public class RoleREST {
+    private static final Log LOG = LogFactory.getLog(RoleREST.class);
+
+    private static List<String> INVALID_USERS = new ArrayList<>();
+
+    @Autowired
+    RESTErrorUtil restErrorUtil;
+
+    @Autowired
+    RoleDBStore roleStore;
+
+    @Autowired
+    RangerRoleService roleService;
+
+    @Autowired
+    XUserService xUserService;
+
+    @Autowired
+    ServiceDBStore svcStore;
+
+    @Autowired
+    RangerSearchUtil searchUtil;
+
+    @Autowired
+    RangerValidatorFactory validatorFactory;
+
+    @Autowired
+    RangerBizUtil bizUtil;
+
+    static {
+        INVALID_USERS.add(RangerPolicyEngine.USER_CURRENT);
+        INVALID_USERS.add(RangerPolicyEngine.RESOURCE_OWNER);
+    }
+
+    @POST
+    @Path("/roles")
+    public RangerRole createRole(RangerRole role) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("==> createRole("+ role + ")");
+        }
+
+        RangerRole ret;
+        try {
+            ensureAdminAccess();
+            if (containsInvalidMember(role.getUsers())) {
+                throw new Exception("Invalid role user(s)");
+            }
+            sanitizeRole(role);
+            ret = roleStore.createRole(role);
+        } catch(WebApplicationException excp) {
+            throw excp;
+        } catch(Throwable excp) {
+            LOG.error("createRole(" + role + ") failed", excp);
+
+            throw restErrorUtil.createRESTException(excp.getMessage());
+        }
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("<== createRole("+ role + "):" +  ret);
+        }
+        return ret;
+    }
+
+    @PUT
+    @Path("/roles/{id}")
+    public RangerRole updateRole(@PathParam("id") Long roleId,
+                                                 RangerRole role) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("==> updateRole(id=" + roleId +", " + role + ")");
+        }
+
+        if (role.getId() != null && !roleId.equals(role.getId())) {
+            throw restErrorUtil.createRESTException("roleId mismatch!!");
+        } else {
+            role.setId(roleId);
+        }
+        RangerRole ret;
+        try {
+            ensureAdminAccess();
+            sanitizeRole(role);
+            if (containsInvalidMember(role.getUsers())) {
+                throw new Exception("Invalid role user(s)");
+            }
+            ret = roleStore.updateRole(role);
+        } catch(WebApplicationException excp) {
+            throw excp;
+        } catch(Throwable excp) {
+            LOG.error("updateRole(" + role + ") failed", excp);
+
+            throw restErrorUtil.createRESTException(excp.getMessage());
+        }
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("<== updateRole(id=" + roleId +", " + role + "):" + ret);
+        }
+        return ret;
+    }
+
+    @DELETE
+    @Path("/roles/name/{name}")
+    public void deleteRole(@PathParam("name") String roleName) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("==> deleteRole(name=" + roleName + ")");
+        }
+        try {
+            ensureAdminAccess();
+            roleStore.deleteRole(roleName);
+        } catch(WebApplicationException excp) {
+            throw excp;
+        } catch(Throwable excp) {
+            LOG.error("deleteRole(" + roleName + ") failed", excp);
+
+            throw restErrorUtil.createRESTException(excp.getMessage());
+        }
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("<== deleteRole(name=" + roleName + ")");
+        }
+    }
+
+    @DELETE
+    @Path("/roles/{id}")
+    public void deleteRole(@PathParam("id") Long roleId) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("==> deleteRole(id=" + roleId + ")");
+        }
+        try {
+            ensureAdminAccess();
+            roleStore.deleteRole(roleId);
+        } catch(WebApplicationException excp) {
+            throw excp;
+        } catch(Throwable excp) {
+            LOG.error("deleteRole(" + roleId + ") failed", excp);
+
+            throw restErrorUtil.createRESTException(excp.getMessage());
+        }
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("<== deleteRole(id=" + roleId + ")");
+        }
+    }
+
+    @GET
+    @Path("/roles/name/{name}")
+    public RangerRole getRole(@PathParam("name") String roleName) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("==> getRole(name=" + roleName + ")");
+        }
+        RangerRole ret;
+        try {
+            ret = roleStore.getRole(roleName);
+        } catch(WebApplicationException excp) {
+            throw excp;
+        } catch(Throwable excp) {
+            LOG.error("getRole(" + roleName + ") failed", excp);
+
+            throw restErrorUtil.createRESTException(excp.getMessage());
+        }
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("<== getRole(name=" + roleName + "):" + ret);
+        }
+        return ret;
+    }
+
+    @GET
+    @Path("/roles/{id}")
+    public RangerRole getRole(@PathParam("id") Long id) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("==> getRole(id=" + id + ")");
+        }
+        RangerRole ret;
+        try {
+            ret = roleStore.getRole(id);
+        } catch(WebApplicationException excp) {
+            throw excp;
+        } catch(Throwable excp) {
+            LOG.error("getRole(" + id + ") failed", excp);
+
+            throw restErrorUtil.createRESTException(excp.getMessage());
+        }
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("<== getRole(id=" + id + "):" + ret);
+        }
+        return ret;
+    }
+
+    @GET
+    @Path("/roles")
+    public RangerRoleList getAllRoles(@Context HttpServletRequest request) {
+        RangerRoleList ret = new RangerRoleList();
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("==> getAllRoles()");
+        }
+        SearchFilter filter = searchUtil.getSearchFilter(request, roleService.sortFields);
+        List<RangerRole> roles;
+        try {
+            roles = roleStore.getRoles(filter);
+            ret.setRoleList(roles);
+            if (roles != null) {
+                ret.setTotalCount(roles.size());
+                ret.setSortBy(filter.getSortBy());
+                ret.setSortType(filter.getSortType());
+                ret.setResultSize(roles.size());
+            }
+        } catch(WebApplicationException excp) {
+            throw excp;
+        } catch(Throwable excp) {
+            LOG.error("getRoles() failed", excp);
+
+            throw restErrorUtil.createRESTException(excp.getMessage());
+        }
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("<== getAllRoles():" + ret);
+        }
+        return ret;
+    }
+
+    /*
+        This API is used to add users and groups with/without GRANT privileges to this Role. It follows add-or-update semantics
+     */
+    @PUT
+    @Path("/roles/{id}/addUsersAndGroups")
+    public RangerRole addUsersAndGroups(Long roleId, List<String> users, List<String> groups, Boolean isAdmin) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("==> addUsersAndGroups(id=" + roleId + ", users=" + Arrays.toString(users.toArray()) + ", groups=" + Arrays.toString(groups.toArray()) + ", isAdmin=" + isAdmin + ")");
+        }
+
+        RangerRole role;
+
+        try {
+            // Real processing
+            ensureAdminAccess();
+            if (containsInvalidUser(users)) {
+                throw new Exception("Invalid role user(s)");
+            }
+
+            role = getRole(roleId);
+
+            Set<RangerRole.RoleMember> roleUsers = new HashSet<>();
+            Set<RangerRole.RoleMember> roleGroups = new HashSet<>();
+
+            for (RangerRole.RoleMember user : role.getUsers()) {
+                if (user.getIsAdmin() == isAdmin) {
+                    roleUsers.add(user);
+                }
+            }
+            for (String user : users) {
+                roleUsers.add(new RangerRole.RoleMember(user, isAdmin));
+            }
+
+            for (RangerRole.RoleMember group : role.getGroups()) {
+                if (group.getIsAdmin() == isAdmin) {
+                    roleGroups.add(group);
+                }
+            }
+            for (String group : groups) {
+                roleGroups.add(new RangerRole.RoleMember(group, isAdmin));
+            }
+            role.setUsers(new ArrayList<>(roleUsers));
+            role.setGroups(new ArrayList<>(roleGroups));
+
+            role = roleStore.updateRole(role);
+
+        } catch(WebApplicationException excp) {
+            throw excp;
+        } catch(Throwable excp) {
+            LOG.error("addUsersAndGroups() failed", excp);
+
+            throw restErrorUtil.createRESTException(excp.getMessage());
+        }
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("==> addUsersAndGroups(id=" + roleId + ", users=" + Arrays.toString(users.toArray()) + ", groups=" + Arrays.toString(groups.toArray()) + ", isAdmin=" + isAdmin + ")");
+        }
+
+        return role;
+    }
+
+    /*
+        This API is used to remove users and groups, without regard to their GRANT privilege, from this Role.
+     */
+    @PUT
+    @Path("/roles/{id}/removeUsersAndGroups")
+    public RangerRole removeUsersAndGroups(Long roleId, List<String> users, List<String> groups) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("==> removeUsersAndGroups(id=" + roleId + ", users=" + Arrays.toString(users.toArray()) + ", groups=" + Arrays.toString(groups.toArray()) + ")");
+        }
+        RangerRole role;
+
+        try {
+            // Real processing
+            ensureAdminAccess();
+            role = getRole(roleId);
+
+            for (String user : users) {
+                Iterator<RangerRole.RoleMember> iter = role.getUsers().iterator();
+                while (iter.hasNext()) {
+                    RangerRole.RoleMember member = iter.next();
+                    if (StringUtils.equals(member.getName(), user)) {
+                        iter.remove();
+                        break;
+                    }
+                }
+            }
+            for (String group : groups) {
+                Iterator<RangerRole.RoleMember> iter = role.getGroups().iterator();
+                while (iter.hasNext()) {
+                    RangerRole.RoleMember member = iter.next();
+                    if (StringUtils.equals(member.getName(), group)) {
+                        iter.remove();
+                        break;
+                    }
+                }
+            }
+
+            role = roleStore.updateRole(role);
+
+        } catch(WebApplicationException excp) {
+            throw excp;
+        } catch(Throwable excp) {
+            LOG.error("removeUsersAndGroups() failed", excp);
+
+            throw restErrorUtil.createRESTException(excp.getMessage());
+        }
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("<== removeUsersAndGroups(id=" + roleId + ", users=" + Arrays.toString(users.toArray()) + ", groups=" + Arrays.toString(groups.toArray()) + ")");
+        }
+
+        return role;
+    }
+
+    /*
+        This API is used to remove GRANT privilege from listed users and groups.
+     */
+    @PUT
+    @Path("/roles/{id}/removeAdminFromUsersAndGroups")
+    public RangerRole removeAdminFromUsersAndGroups(Long roleId, List<String> users, List<String> groups) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("==> removeAdminFromUsersAndGroups(id=" + roleId + ", users=" + Arrays.toString(users.toArray()) + ", groups=" + Arrays.toString(groups.toArray()) + ")");
+        }
+        RangerRole role;
+        try {
+            // Real processing
+            ensureAdminAccess();
+            role = getRole(roleId);
+
+            for (String user : users) {
+                for (RangerRole.RoleMember member : role.getUsers()) {
+                    if (StringUtils.equals(member.getName(), user) && member.getIsAdmin()) {
+                        member.setIsAdmin(false);
+                    }
+                }
+            }
+            for (String group : groups) {
+                for (RangerRole.RoleMember member : role.getGroups()) {
+                    if (StringUtils.equals(member.getName(), group) && member.getIsAdmin()) {
+                        member.setIsAdmin(false);
+                    }
+                }
+            }
+
+            role = roleStore.updateRole(role);
+
+        } catch(WebApplicationException excp) {
+            throw excp;
+        } catch(Throwable excp) {
+            LOG.error("removeAdminFromUsersAndGroups() failed", excp);
+
+            throw restErrorUtil.createRESTException(excp.getMessage());
+        }
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("==> removeAdminFromUsersAndGroups(id=" + roleId + ", users=" + Arrays.toString(users.toArray()) + ", groups=" + Arrays.toString(groups.toArray()) + ")");
+        }
+
+        return role;
+    }
+
+    private void sanitizeRole(RangerRole role) {
+        if (role != null) {
+            role.setRoles(null);
+            role.setRoles(null);
+        }
+    }
+
+    private void ensureAdminAccess() throws Exception {
+        UserSessionBase usb = ContextUtil.getCurrentUserSession();
+
+        if (usb == null || !usb.isUserAdmin()) {
+            throw new Exception("User does not have permission for this operation");
+        }
+    }
+
+    private boolean containsInvalidMember(List<RangerRole.RoleMember> users) {
+        boolean ret = false;
+        for (RangerRole.RoleMember user : users) {
+            for (String invalidUser : INVALID_USERS) {
+                if (StringUtils.equals(user.getName(), invalidUser)) {
+                    ret = true;
+                    break;
+                }
+            }
+            if (ret) {
+                break;
+            }
+        }
+        return ret;
+    }
+
+    private boolean containsInvalidUser(List<String> users) {
+        return CollectionUtils.isNotEmpty(users) && CollectionUtils.containsAny(users, INVALID_USERS);
+    }
+
+}
+
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 e1f6eec..1d9391f 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
@@ -3400,9 +3400,10 @@ public class ServiceREST {
 						if(userGroups == null) {
 							userGroups = daoManager.getXXGroupUser().findGroupNamesByUserName(userName);
 						}
+						Set<String> roles = policyEngine.getRolesFromUserAndGroups(userName, userGroups);
 
 						for (RangerPolicy policy : listToFilter) {
-							if (policyEngine.isAccessAllowed(policy, userName, userGroups, RangerPolicyEngine.ADMIN_ACCESS) 
+							if (policyEngine.isAccessAllowed(policy, userName, userGroups, roles, RangerPolicyEngine.ADMIN_ACCESS) 
 									|| (!StringUtils.isEmpty(policy.getZoneName()) && (serviceMgr.isZoneAdmin(policy.getZoneName()) || serviceMgr.isZoneAuditor(policy.getZoneName())))
 									|| isServiceAdminUser) {
 								ret.add(policy);
@@ -3498,7 +3499,8 @@ public class ServiceREST {
 		RangerPolicyEngine policyEngine = getDelegatedAdminPolicyEngine(policy.getService());
 
 		if(policyEngine != null) {
-			isAllowed = policyEngine.isAccessAllowed(policy, userName, userGroups, RangerPolicyEngine.ADMIN_ACCESS);
+			Set<String> roles = policyEngine.getRolesFromUserAndGroups(userName, userGroups);
+			isAllowed = policyEngine.isAccessAllowed(policy, userName, userGroups, roles, RangerPolicyEngine.ADMIN_ACCESS);
 		}
 
 		return isAllowed;
@@ -3673,6 +3675,8 @@ 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/RangerPolicyServiceBase.java b/security-admin/src/main/java/org/apache/ranger/service/RangerPolicyServiceBase.java
index 3e1a8e1..e1653da 100644
--- a/security-admin/src/main/java/org/apache/ranger/service/RangerPolicyServiceBase.java
+++ b/security-admin/src/main/java/org/apache/ranger/service/RangerPolicyServiceBase.java
@@ -69,6 +69,9 @@ public abstract class RangerPolicyServiceBase<T extends XXPolicyBase, V extends
 		searchFields.add(new SearchField(SearchFilter.GROUP, "xGrp.name", DATA_TYPE.STRING, SEARCH_TYPE.FULL,
 				"XXGroup xGrp , XXPolicyRefGroup refGroup", "obj.id = refGroup.policyId "
 						+ "and xGrp.id = refGroup.groupId"));
+		searchFields.add(new SearchField(SearchFilter.ROLE, "xRole.name", DATA_TYPE.STRING, SEARCH_TYPE.FULL,
+				"XXRole xRole , XXPolicyRefRole refRole", "obj.id = reRole.policyId "
+				+ "and xRole.id = refRole.roleId"));
 		//might need updation
 		/*searchFields.add(new SearchField(SearchFilter.POL_RESOURCE, "resMap.value", DATA_TYPE.STRING,
 				SEARCH_TYPE.PARTIAL, "XXPolicyResourceMap resMap, XXPolicyResource polRes",
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
new file mode 100644
index 0000000..cbdb5ce
--- /dev/null
+++ b/security-admin/src/main/java/org/apache/ranger/service/RangerRoleService.java
@@ -0,0 +1,258 @@
+/*
+ * 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.service;
+
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.ranger.authorization.utils.JsonUtils;
+import org.apache.ranger.biz.RangerPolicyRetriever;
+import org.apache.ranger.biz.ServiceDBStore;
+import org.apache.ranger.common.AppConstants;
+import org.apache.ranger.common.view.VTrxLogAttr;
+import org.apache.ranger.db.RangerDaoManager;
+import org.apache.ranger.entity.XXPolicy;
+import org.apache.ranger.entity.XXRole;
+import org.apache.ranger.entity.XXService;
+import org.apache.ranger.entity.XXTrxLog;
+import org.apache.ranger.entity.XXUser;
+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.util.RangerEnumUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Service;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+@Service
+@Scope("singleton")
+public class RangerRoleService extends RangerRoleServiceBase<XXRole, RangerRole> {
+
+    @Autowired
+    RangerEnumUtil xaEnumUtil;
+
+    @Autowired
+    ServiceDBStore serviceDBStore;
+
+    private static final Log logger = LogFactory.getLog(RangerRoleService.class);
+    private static final Gson gsonBuilder = new GsonBuilder().setDateFormat("yyyyMMdd-HH:mm:ss.SSS-Z").create();
+
+    static HashMap<String, VTrxLogAttr> trxLogAttrs = new HashMap<>();
+
+    static {
+        trxLogAttrs.put("name", new VTrxLogAttr("name", "Role Name", false));
+        trxLogAttrs.put("description", new VTrxLogAttr("description", "Role Description", false));
+        trxLogAttrs.put("options", new VTrxLogAttr("options", "Options", false));
+        trxLogAttrs.put("users", new VTrxLogAttr("users", "Users", false));
+        trxLogAttrs.put("adminUsers", new VTrxLogAttr("adminUsers", "Admin Users", false));
+        trxLogAttrs.put("groups", new VTrxLogAttr("groups", "Groups", false));
+        trxLogAttrs.put("adminGroups", new VTrxLogAttr("adminGroups", "Admin Groups", false));
+        trxLogAttrs.put("roles", new VTrxLogAttr("roles", "Roles", false));
+        trxLogAttrs.put("adminRoles", new VTrxLogAttr("adminRoles", "Admin Roles", false));    }
+
+    public RangerRoleService() {
+        super();
+    }
+
+    @Override
+    protected void validateForCreate(RangerRole vObj) {
+    }
+
+    @Override
+    protected void validateForUpdate(RangerRole vObj, XXRole entityObj) {
+    }
+
+    @Override
+    protected XXRole mapViewToEntityBean(RangerRole rangerRole, XXRole xxRole, int OPERATION_CONTEXT) {
+        XXRole ret = super.mapViewToEntityBean(rangerRole, xxRole, OPERATION_CONTEXT);
+
+        ret.setRoleText(gsonBuilder.toJson(rangerRole));
+
+        return ret;
+    }
+    @Override
+    protected RangerRole mapEntityToViewBean(RangerRole rangerRole, XXRole xxRole) {
+        RangerRole ret = super.mapEntityToViewBean(rangerRole, xxRole);
+
+        if (StringUtils.isNotEmpty(xxRole.getRoleText())) {
+            if (logger.isDebugEnabled()) {
+                logger.debug("roleText=" + xxRole.getRoleText());
+            }
+            RangerRole roleFromJsonData = gsonBuilder.fromJson(xxRole.getRoleText(), RangerRole.class);
+
+            if (roleFromJsonData == null) {
+                logger.info("Cannot read jsonData into RangerRole object in [" + xxRole.getRoleText() + "]!!");
+            } else {
+                if (logger.isDebugEnabled()) {
+                    logger.debug("Role object built from JSON :[" + roleFromJsonData +"]");
+                }
+                ret.setOptions(roleFromJsonData.getOptions());
+                ret.setUsers(roleFromJsonData.getUsers());
+                ret.setGroups(roleFromJsonData.getGroups());
+                ret.setRoles(roleFromJsonData.getRoles());
+            }
+        } else {
+            logger.info("Empty string representing jsonData in [" + xxRole + "]!!");
+        }
+
+        return ret;
+    }
+
+    public List<XXTrxLog> getTransactionLog(RangerRole current, RangerRole former, String action) {
+        if (current == null || action == null  || ("update".equalsIgnoreCase(action) && former == null)) {
+            return null;
+        }
+        List<XXTrxLog> trxLogList = new ArrayList<>();
+        Field[] fields = current.getClass().getDeclaredFields();
+
+        try {
+            Field nameField = current.getClass().getDeclaredField("name");
+            nameField.setAccessible(true);
+            String objectName = "" + nameField.get(current);
+
+            for (Field field : fields) {
+                String fieldName = field.getName();
+                if (!trxLogAttrs.containsKey(fieldName)) {
+                    continue;
+                }
+                field.setAccessible(true);
+                VTrxLogAttr vTrxLogAttr = trxLogAttrs.get(fieldName);
+                XXTrxLog xTrxLog = new XXTrxLog();
+                xTrxLog.setAttributeName(vTrxLogAttr
+                        .getAttribUserFriendlyName());
+                xTrxLog.setAction(action);
+                xTrxLog.setObjectId(current.getId());
+                xTrxLog.setObjectClassType(AppConstants.CLASS_TYPE_RANGER_ROLE);
+                xTrxLog.setObjectName(objectName);
+
+                String value;
+                if (vTrxLogAttr.isEnum()) {
+                    String enumName = XXUser.getEnumName(fieldName);
+                    int enumValue = field.get(current) == null ? 0 : Integer
+                            .parseInt("" + field.get(current));
+                    value = xaEnumUtil.getLabel(enumName, enumValue);
+                } else {
+                    value = "" + field.get(current);
+                    if ((value == null || "null".equalsIgnoreCase(value))
+                            && !"update".equalsIgnoreCase(action)) {
+                        continue;
+                    }
+                }
+                if("options".equalsIgnoreCase(fieldName)) {
+                    value = JsonUtils.mapToJson(current.getOptions());
+                }
+                if ("create".equalsIgnoreCase(action)) {
+                    xTrxLog.setNewValue(value);
+                    trxLogList.add(xTrxLog);
+                }
+                else if ("delete".equalsIgnoreCase(action)) {
+                    xTrxLog.setPreviousValue(value);
+                    trxLogList.add(xTrxLog);
+                }
+                else if ("update".equalsIgnoreCase(action)) {
+                    String formerValue = null;
+                    Field[] mFields = current.getClass().getDeclaredFields();
+                    for (Field mField : mFields) {
+                        mField.setAccessible(true);
+                        String mFieldName = mField.getName();
+                        if (fieldName.equalsIgnoreCase(mFieldName)) {
+                            if("options".equalsIgnoreCase(mFieldName)) {
+                                formerValue = JsonUtils.mapToJson(former.getOptions());
+                            }
+                            else {
+                                formerValue = mField.get(former) + "";
+                            }
+                            break;
+                        }
+                    }
+                    if (formerValue == null || formerValue.equalsIgnoreCase(value)) {
+                        continue;
+                    }
+                    xTrxLog.setPreviousValue(formerValue);
+                    xTrxLog.setNewValue(value);
+                    trxLogList.add(xTrxLog);
+                }
+            }
+            if (trxLogList.isEmpty()) {
+                XXTrxLog xTrxLog = new XXTrxLog();
+                xTrxLog.setAction(action);
+                xTrxLog.setObjectClassType(AppConstants.CLASS_TYPE_RANGER_ROLE);
+                xTrxLog.setObjectId(current.getId());
+                xTrxLog.setObjectName(objectName);
+                trxLogList.add(xTrxLog);
+            }
+        } catch (IllegalAccessException e) {
+            logger.error("Transaction log failure.", e);
+        } catch (NoSuchFieldException e) {
+            logger.error("Transaction log failure.", e);
+        }
+        return trxLogList;
+    }
+
+    public void updatePolicyVersions(Long roleId) {
+
+        List<XXPolicy> dbPolicies = roleId == null ? null : daoMgr.getXXPolicy().findByRoleId(roleId);
+        if (CollectionUtils.isEmpty(dbPolicies)) {
+            return;
+        }
+        // dbPolicies are ordered by service-id
+
+        RangerPolicyRetriever policyRetriever = new RangerPolicyRetriever(daoMgr);
+
+        Map<Long, List<RangerPolicy>> policiesByServiceId = new HashMap<>();
+
+        Long               currentServiceId        = -1L;
+        XXService          currentService          = null;
+        List<RangerPolicy> currentPolicyList       = null;
+
+        for (XXPolicy dbPolicy : dbPolicies) {
+            Long serviceId = dbPolicy.getService();
+            if (!currentServiceId.equals(serviceId)) {
+                //
+                currentService = daoMgr.getXXService().getById(serviceId);
+                currentPolicyList = new ArrayList<>();
+                policiesByServiceId.put(serviceId, currentPolicyList);
+            }
+            currentPolicyList.add(policyRetriever.getPolicy(dbPolicy, currentService));
+        }
+
+        final RangerDaoManager finalDaoManager = daoMgr;
+
+        for (Map.Entry<Long, List<RangerPolicy>> entry : policiesByServiceId.entrySet()) {
+            final Long finalServiceId = entry.getKey();
+            List<RangerPolicy> policies = entry.getValue();
+
+            for (final RangerPolicy policy : policies) {
+                Runnable serviceVersionUpdater = new ServiceDBStore.ServiceVersionUpdater(finalDaoManager, finalServiceId, ServiceDBStore.VERSION_TYPE.POLICY_VERSION, policy.getZoneName(), RangerPolicyDelta.CHANGE_TYPE_POLICY_UPDATE, policy);
+                daoMgr.getRangerTransactionSynchronizationAdapter().executeOnTransactionCommit(serviceVersionUpdater);
+            }
+        }
+    }
+}
+
diff --git a/security-admin/src/main/java/org/apache/ranger/service/RangerRoleServiceBase.java b/security-admin/src/main/java/org/apache/ranger/service/RangerRoleServiceBase.java
new file mode 100644
index 0000000..5b22a53
--- /dev/null
+++ b/security-admin/src/main/java/org/apache/ranger/service/RangerRoleServiceBase.java
@@ -0,0 +1,67 @@
+/*
+ * 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.service;
+
+import org.apache.ranger.authorization.utils.JsonUtils;
+import org.apache.ranger.common.SearchField;
+import org.apache.ranger.common.SortField;
+import org.apache.ranger.entity.XXRole;
+import org.apache.ranger.plugin.model.RangerRole;
+import org.apache.ranger.plugin.util.SearchFilter;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public abstract class RangerRoleServiceBase<T extends XXRole, V extends RangerRole> extends RangerBaseModelService<T, V> {
+
+    public RangerRoleServiceBase() {
+        super();
+
+        searchFields.add(new SearchField(SearchFilter.ROLE_ID, "obj.id", SearchField.DATA_TYPE.INTEGER, SearchField.SEARCH_TYPE.FULL));
+        searchFields.add(new SearchField(SearchFilter.ROLE_NAME, "obj.name", SearchField.DATA_TYPE.STRING, SearchField.SEARCH_TYPE.FULL));
+
+        sortFields.add(new SortField(SearchFilter.CREATE_TIME, "obj.createTime"));
+        sortFields.add(new SortField(SearchFilter.UPDATE_TIME, "obj.updateTime"));
+        sortFields.add(new SortField(SearchFilter.ROLE_ID, "obj.id", true, SortField.SORT_ORDER.ASC));
+        sortFields.add(new SortField(SearchFilter.ROLE_NAME, "obj.name"));
+
+    }
+
+    @Override
+    protected T mapViewToEntityBean(V vObj, T xObj, int OPERATION_CONTEXT) {
+        xObj.setName(vObj.getName());
+        xObj.setDescription(vObj.getDescription());
+
+        Map<String, Object> options = vObj.getOptions();
+        if (options == null) {
+            options = new HashMap<>();
+        }
+        xObj.setOptions(JsonUtils.mapToJson(options));
+
+        return xObj;
+    }
+
+    @Override
+    protected V mapEntityToViewBean(V vObj, T xObj) {
+        vObj.setName(xObj.getName());
+        vObj.setDescription(xObj.getDescription());
+
+        return vObj;
+    }
+}
+
diff --git a/security-admin/src/main/java/org/apache/ranger/view/RangerRoleList.java b/security-admin/src/main/java/org/apache/ranger/view/RangerRoleList.java
new file mode 100644
index 0000000..adbe93d
--- /dev/null
+++ b/security-admin/src/main/java/org/apache/ranger/view/RangerRoleList.java
@@ -0,0 +1,74 @@
+/*
+ * 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.view;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.apache.ranger.common.view.VList;
+import org.apache.ranger.plugin.model.RangerRole;
+import org.codehaus.jackson.annotate.JsonAutoDetect;
+import org.codehaus.jackson.annotate.JsonAutoDetect.Visibility;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+
+@JsonAutoDetect(getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE, fieldVisibility = Visibility.ANY)
+@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class RangerRoleList extends VList{
+
+    private static final long serialVersionUID = 1L;
+
+    List<RangerRole> roles = new ArrayList<RangerRole>();
+
+    public RangerRoleList() {
+        super();
+    }
+
+    public RangerRoleList(List<RangerRole> objList) {
+        super(objList);
+        this.roles = objList;
+    }
+
+    public List<RangerRole> getSecurityRoles() {
+        return roles;
+    }
+
+    public void setRoleList(List<RangerRole> roles) {
+        this.roles = roles;
+    }
+
+    @Override
+    public int getListSize() {
+        if (roles != null) {
+            return roles.size();
+        }
+        return 0;
+    }
+
+    @Override
+    public List<?> getList() {
+        return roles;
+    }
+
+}
+
diff --git a/security-admin/src/main/resources/META-INF/jpa_named_queries.xml b/security-admin/src/main/resources/META-INF/jpa_named_queries.xml
index 2fa12f9..54e34d5 100644
--- a/security-admin/src/main/resources/META-INF/jpa_named_queries.xml
+++ b/security-admin/src/main/resources/META-INF/jpa_named_queries.xml
@@ -300,6 +300,10 @@
 	<named-query name="XXPolicy.findByServiceNameAndZoneId">
 		<query>select obj from XXPolicy obj, XXService svc where obj.zoneId = :zoneId and obj.service = svc.id and svc.name = :serviceName</query>
 	</named-query>
+	<named-query name="XXPolicy.findByRoleId">
+		<query>select obj from XXPolicy obj, XXPolicyRefRole policyRefRole where policyRefRole.roleId = :roleId and policyRefRole.policyId = obj.id order by obj.service</query>
+	</named-query>
+
 	<!-- XXServiceDef -->
 	<named-query name="XXServiceDef.findByName">
 		<query>select obj from XXServiceDef obj where obj.name = :name</query>
@@ -1442,4 +1446,82 @@
 		<query>delete from XXPolicyChangeLog obj where obj.createTime &lt; :olderThan</query>
 	</named-query>
 
+	<!-- XXRole -->
+	<named-query name="XXRole.findByRoleId">
+		<query>select obj from XXRole obj where obj.id = :roleId</query>
+	</named-query>
+
+	<named-query name="XXRole.findByRoleName">
+		<query>select obj from XXRole obj where obj.name = :roleName</query>
+	</named-query>
+
+	<named-query name="XXRole.findByServiceId">
+		<query>select obj from XXRole obj, XXPolicyRefRole policyRefRole, XXPolicy policy where obj.id = policyRefRole.roleId and policyRefRole.policyId = policy.id and policy.service = :serviceId </query>
+	</named-query>
+
+	<!-- XXRoleRef* -->
+
+    <named-query name="XXRoleRefUser.findByRoleId">
+        <query>select obj from XXRoleRefUser obj  where obj.roleId = :roleId</query>
+    </named-query>
+
+    <named-query name="XXRoleRefUser.findByUserId">
+        <query>select obj from XXRoleRefUser obj where obj.userId = :userId</query>
+    </named-query>
+
+    <named-query name="XXRoleRefUser.findByUserName">
+        <query>select obj from XXRoleRefUser obj where obj.userName = :userName</query>
+    </named-query>
+
+    <named-query name="XXRoleRefGroup.findByRoleId">
+        <query>select obj from XXRoleRefGroup obj  where obj.roleId = :roleId</query>
+    </named-query>
+
+    <named-query name="XXRoleRefGroup.findByGroupId">
+        <query>select obj from XXRoleRefGroup obj  where obj.groupId = :groupId</query>
+    </named-query>
+
+    <named-query name="XXRoleRefGroup.findByGroupName">
+        <query>select obj from XXRoleRefGroup obj where obj.groupName = :groupName </query>
+    </named-query>
+
+    <named-query name="XXRoleRefRole.findByRoleId">
+        <query>select obj from XXRoleRefRole obj  where obj.roleId = :roleId</query>
+    </named-query>
+
+    <named-query name="XXRoleRefRole.findBySubRoleId">
+        <query>select obj from XXRoleRefRole obj  where obj.subRoleId = :subRoleId</query>
+    </named-query>
+
+    <named-query name="XXRoleRefRole.findBySubRoleName">
+        <query>select obj from XXRoleRefRole obj where obj.subRoleName = :subRoleName </query>
+    </named-query>
+
+	<!-- XXPolicyRefRole -->
+	<named-query name="XXPolicyRefRole.findByPolicyId">
+		<query>select obj from XXPolicyRefRole obj where obj.policyId = :policyId </query>
+	</named-query>
+
+	<named-query name="XXPolicyRefRole.findByRoleName">
+		<query>select obj from XXPolicyRefRole obj where obj.roleName = :roleName</query>
+	</named-query>
+
+	<named-query name="XXPolicyRefRole.findUpdatedRoleNamesByPolicy">
+		<query>select roleRef.policyId, roleRef.roleName, role.name
+			from XXPolicyRefRole roleRef, XXRole role
+			where roleRef.policyId    = :policy
+			and roleRef.roleId       = role.id
+			and roleRef.roleName    != role.name
+		</query>
+	</named-query>
+
+	<named-query name="XXPolicyRefRole.findUpdatedRoleNamesByService">
+		<query>select roleRef.policyId, roleRef.roleName, role.name
+			from XXPolicy policy, XXPolicyRefRole roleRef, XXRole role
+			where policy.service       = :service
+			and roleRef.policyId      = policy.id
+			and roleRef.roleId       = role.id
+			and roleRef.roleName    != role.name
+		</query>
+	</named-query>
 </entity-mappings>
diff --git a/security-admin/src/main/webapp/scripts/collection_bases/VXRoleListBase.js b/security-admin/src/main/webapp/scripts/collection_bases/VXRoleListBase.js
new file mode 100644
index 0000000..bb5ef6b
--- /dev/null
+++ b/security-admin/src/main/webapp/scripts/collection_bases/VXRoleListBase.js
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+
+define(function(require){
+    'use strict';
+
+    var XABaseCollection    = require('collections/XABaseCollection');
+    var XAGlobals           = require('utils/XAGlobals');
+    var VXRole             = require('models/VXRole');
+
+    var VXRoleListBase = XABaseCollection.extend(
+    /** @lends VXGroupListBase.prototype */
+    {
+        url: XAGlobals.baseURL + 'roles/roles',
+
+        model : VXRole,
+
+        /**
+         * VXGroupListBase initialize method
+         * @augments XABaseCollection
+         * @constructs
+         */
+        initialize : function() {
+            this.modelName = 'roles';
+            this.modelAttrName = 'roles';
+            var multiSelect = new Backbone.Picky.MultiSelect(this);
+            _.extend(this, multiSelect);
+            this.bindErrorEvents();
+            this._changes = { };
+            this.on('change', this._onChange);
+        },
+
+        _onChange : function(m){
+            this._changes[m.id] = m;
+        },
+
+        changed_models: function() {
+            return _.chain(this._changes).values();
+        },
+
+        // /*************************
+        //  * Non - CRUD operations
+        //  *************************/
+
+        // getGroupsForUser : function(userId, options){
+        //     var url = XAGlobals.baseURL + 'xusers/' + userId + '/groups';
+
+        //     options = _.extend({
+        //         //data : JSON.stringify(postData),
+        //         contentType : 'application/json',
+        //         dataType : 'json'
+        //     }, options);
+
+        //     return this.constructor.nonCrudOperation.call(this, url, 'GET', options);
+        // },
+
+        // setRolesVisibility : function(postData , options){
+        //     var url = XAGlobals.baseURL  + 'xusers/secure/roles/visibility';
+
+        //     options = _.extend({
+        //         data : JSON.stringify(postData),
+        //         contentType : 'application/json',
+        //         dataType : 'json'
+        //     }, options);
+
+        //     return this.constructor.nonCrudOperation.call(this, url, 'PUT', options);
+        // },
+
+    },{
+        // static class members
+        /**
+        * Table Cols to be passed to Backgrid
+        * UI has to use this as base and extend this.
+        *
+        */
+
+        tableCols : {}
+
+    });
+
+    return VXRoleListBase;
+});
\ No newline at end of file
diff --git a/security-admin/src/main/webapp/scripts/collections/VXRoleList.js b/security-admin/src/main/webapp/scripts/collections/VXRoleList.js
new file mode 100644
index 0000000..2503a42
--- /dev/null
+++ b/security-admin/src/main/webapp/scripts/collections/VXRoleList.js
@@ -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.
+ */
+
+
+define(function(require){
+    'use strict';
+
+    var VXRoleListBase      = require('collection_bases/VXRoleListBase');
+
+    var VXRoleList = VXRoleListBase.extend(
+    /** @lends VXRoleList.prototype */
+    {
+    },{
+        // static class members
+    });
+
+    return VXRoleList;
+});
\ No newline at end of file
diff --git a/security-admin/src/main/webapp/scripts/controllers/Controller.js b/security-admin/src/main/webapp/scripts/controllers/Controller.js
index c4a0b58..523aadb 100755
--- a/security-admin/src/main/webapp/scripts/controllers/Controller.js
+++ b/security-admin/src/main/webapp/scripts/controllers/Controller.js
@@ -189,6 +189,37 @@ define(function(require) {
 		   });	   
 	   },
 
+                roleCreateAction : function(){
+                        MAppState.set({
+                                'currentTab' : XAGlobals.AppTabs.Settings.value
+                        });
+                        var view 		= require('views/users/RoleCreate');
+                        var VXRole		= require('models/VXRole');
+                        var VXRoleList	= require('collections/VXRoleList');
+
+                        var role 		= new VXRole();
+                        role.collection = new VXRoleList();
+                        App.rContent.show(new view({
+                                model : role
+                        }));
+                },
+                roleEditAction : function(roleId){
+                        MAppState.set({
+                                'currentTab' : XAGlobals.AppTabs.Settings.value
+                        });
+                        var view 		= require('views/users/RoleCreate');
+                        var VXRole		= require('models/VXRole');
+                        var VXRoleList	= require('collections/VXRoleList');
+
+                        var role 		= new VXRole({id : roleId});
+                        role.collection = new VXRoleList();
+
+                        role.fetch({cache : true}).done(function(){
+                                App.rContent.show(new view({
+                                        model : role
+                                }));
+                        });
+                },
 
    	   /************************************************************/
    	   //************** Generic design Related *********************/
diff --git a/security-admin/src/main/webapp/scripts/model_bases/VXRoleBase.js b/security-admin/src/main/webapp/scripts/model_bases/VXRoleBase.js
new file mode 100644
index 0000000..042001c
--- /dev/null
+++ b/security-admin/src/main/webapp/scripts/model_bases/VXRoleBase.js
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+
+define(function(require){
+    'use strict';
+
+    var XABaseModel = require('models/XABaseModel');
+    var XAGlobals   = require('utils/XAGlobals');
+
+    var VXRoleBase = XABaseModel.extend(
+    /** @lends VXRoleBase.prototype */
+    {
+        urlRoot: XAGlobals.baseURL + 'roles/roles',
+
+        defaults: {},
+
+        serverSchema : {},
+
+        idAttribute: 'id',
+
+        /**
+         * VXRoleBase initialize method
+         * @augments XABaseModel
+         * @constructs
+         */
+        initialize: function() {
+            this.modelName = 'VXGroupBase';
+        },
+
+        deleteRoles : function(roleId, options){
+            var url = this.urlRoot +"/"+roleId;
+            options = _.extend({
+                contentType : 'application/json',
+                dataType : 'json',
+            }, options);
+
+            return this.constructor.nonCrudOperation.call(this, url, 'DELETE', options);
+        },
+    },{
+        // static class members
+    });
+
+    return VXRoleBase;
+
+});
diff --git a/security-admin/src/main/webapp/scripts/models/VXRole.js b/security-admin/src/main/webapp/scripts/models/VXRole.js
new file mode 100644
index 0000000..c12ac2d
--- /dev/null
+++ b/security-admin/src/main/webapp/scripts/models/VXRole.js
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+
+define(function(require){
+    'use strict';
+
+    var VXRoleBase = require('model_bases/VXRoleBase');
+    var localization = require('utils/XALangSupport');
+    var XAEnums = require('utils/XAEnums');
+    var XAUtils = require('utils/XAUtils');
+
+    var VXRole = VXRoleBase.extend(
+    /** @lends VXRole.prototype */
+    {
+        /**
+         * VXRole initialize method
+         * @augments XABaseModel
+         * @constructs
+         */
+        initialize: function() {
+            this.modelName = 'roles';
+            var selectable = new Backbone.Picky.Selectable(this);
+            _.extend(this, selectable);
+            this.bindErrorEvents();
+            this.toView();
+        },
+
+        toView : function(){
+            if(!_.isUndefined(this.get('isVisible'))){
+                var visible = (this.get('isVisible') == XAEnums.VisibilityStatus.STATUS_VISIBLE.value);
+                this.set('isVisible', visible);
+            }
+        },
+
+        toServer : function(){
+            var visible = this.get('isVisible') ? XAEnums.VisibilityStatus.STATUS_VISIBLE.value : XAEnums.VisibilityStatus.STATUS_HIDDEN.value;
+            this.set('isVisible', visible);
+        },
+        /**
+         * @function schema
+         * This method is meant to be used by UI,
+         * by default we will remove the unrequired attributes from serverSchema
+         */
+
+        schema : function(){
+            var attrs = {};
+
+            return _.extend(attrs,{
+                name : {
+                    type        : 'TextFieldWithIcon',
+                    title       : localization.tt("lbl.roleName") +' *',
+                    validators  : ['required',{type:'regexp',regexp:/^([A-Za-z0-9_]|[\u00C0-\u017F])([a-z0-9,._\-+/@= ]|[\u00C0-\u017F])+$/i,message :' Invalid group name'}],
+                    editorAttrs : { 'maxlength': 255},
+                    errorMsg    : localization.tt('validationMessages.roleNameValidationMsg'),
+                },
+                description: {
+                    type: 'TextArea',
+                    title: 'Description',
+                    validators: []
+                },
+            });
+        },
+
+        /** This models toString() */
+        toString : function(){
+            return /*this.get('name')*/;
+        }
+
+    }, {
+        // static class members
+    });
+
+    return VXRole;
+
+});
\ No newline at end of file
diff --git a/security-admin/src/main/webapp/scripts/modules/XALinks.js b/security-admin/src/main/webapp/scripts/modules/XALinks.js
index ab0fe7a..dc3e417 100755
--- a/security-admin/src/main/webapp/scripts/modules/XALinks.js
+++ b/security-admin/src/main/webapp/scripts/modules/XALinks.js
@@ -68,13 +68,13 @@ define(function(require) {
 			},
 			Users : { 
 				href : '#!/users/usertab',
-				text : 'h.usersOrGroups',
-				title: 'h.usersOrGroups'
+                                text : 'h.usersOrGroupsOrRoles',
+                                title: 'h.usersOrGroupsOrRoles'
 			},
 			Groups : { 
 				href : '#!/users/grouptab',
-				text : 'h.usersOrGroups',
-				title: 'h.usersOrGroups'
+                                text : 'h.usersOrGroupsOrRoles',
+                                title: 'h.usersOrGroupsOrRoles'
 			},
 			Kms : { 
 				href : '#!/kms/keys/new/manage/service',
@@ -324,6 +324,21 @@ define(function(require) {
                     text: 'Zone Name : ' + options
                 }
             },
+            Roles : {
+                href : '#!/users/roletab',
+                text : 'h.usersOrGroupsOrRoles',
+                title: 'h.usersOrGroupsOrRoles',
+            },
+            RoleCreate : {
+                href : '#!/role/create',
+                text : 'lbl.roleCreate',
+                title: 'lbl.roleCreate',
+            },
+            RoleEdit : {
+                href : 'javascript:void(0);',
+                text : 'lbl.roleEdit',
+                title: 'lbl.roleEdit',
+            },
 	};      
        
 	
diff --git a/security-admin/src/main/webapp/scripts/modules/globalize/message/en.js b/security-admin/src/main/webapp/scripts/modules/globalize/message/en.js
index a928745..8d921f7 100644
--- a/security-admin/src/main/webapp/scripts/modules/globalize/message/en.js
+++ b/security-admin/src/main/webapp/scripts/modules/globalize/message/en.js
@@ -269,6 +269,13 @@ define(function(require) {
                 addPolicyCondition              : 'Add Policy Condition',
                 editPolicyCondition             : 'Edit Policy Condition',
                 agentHost	                    :'Agent Host Name',
+                addNewRole                      : 'Add New Role',
+                roleName                        : 'Role Name',
+                roleCreate                      : 'Role Create',
+                roleEdit                        : 'Role Edit',
+                roles                           : 'Roles',
+                userWithGrantRolePrivilege      : 'Users (Grant privilege)',
+                groupWithGrantRolePrivilege      : 'Groups (Grant privilege)',
 
 			},
 			btn : {
@@ -294,7 +301,7 @@ define(function(require) {
 				// Menu
 				dashboard					: 'Dashboard',
 				policyManager 				: 'Policy Manager',
-				usersOrGroups 				: 'Users/Groups',
+                                usersOrGroupsOrRoles		: 'Users/Groups/Roles',
 				reports 					: 'Reports',
 				config 						: 'Config',
 				accounts					: 'Accounts',
@@ -328,6 +335,7 @@ define(function(require) {
 				searchForPermissions		:"Search for permissions...",
 				searchForYourUser 			:"Search for your users...",
 				searchForYourGroup 			:"Search for your groups...",
+                                searchForYourRole			:"Search for your roles",
 				access						: 'Access',
 				policyCondition				: 'Policy Conditions',
 				permissions					: 'Permissions',
@@ -405,8 +413,8 @@ define(function(require) {
 				noRecordsFound			  : 'No Records Found',
 				keyDeleteMsg			  : 'Key deleted successfully',
 				rolloverSuccessfully	  : 'Key rollover successfully',
-				addUserOrGroup			  : 'Please select group/user for the selected permission, else group/user will not be added.',
-				addUserOrGroupForPC		  : 'Please select group/user for the added policy condition, else group/user will not be added.',
+                                addUserOrGroupOrRole	  : 'Please select group/user/role for the selected permission, else group/user will not be added.',
+                                addUserOrGroupOrRoleForPC : 'Please select group/user/role for the added policy condition, else group/user will not be added.',
 				userCreatedSucc		      : 'User created successfully',
 				userUpdatedSucc           :     'User updated successfully',
 				grpUpdatedSucc            : 'Group updated successfully',
@@ -444,7 +452,7 @@ define(function(require) {
                 plsSelectGroupToSetVisibility:' Please select group to set visibility or selected group is already visible/hidden.',
                 activationTimeDelayMsg       :'Policy activation time delayed by more than 1hr from last update time.',
                 pleaseSelectAccessTypeForTagMasking : 'Please select access type first to enable add masking options.',
-                addUserOrGroupForDelegateAdmin      : 'Please select user/group for the selected permission(s)',
+                addUserOrGroupOrRoleForDelegateAdmin      : 'Please select user/group/role for the selected permission(s)',
                 policyLabelsinfo		: 'Enter label of policy',
                 noUserFoundText			: 'No user is associated with this group.',
                 showInitialHundredUser  : 'Initially search filter is applied for first hundred users. To get more users click on ',
@@ -462,7 +470,11 @@ define(function(require) {
                 policyTimeDetails       : '<b>Last Update: </b>Last updated time of policy.<br><b>Download: </b>Time when policy actually downloaded(sync-up with Ranger).<br>\
                                             <b>Active: </b>Time when policy actually in use for enforcement.',
                 tagPolicyTimeDetails    : '<b>Last Update: </b> Last updated time of Tag-service.<br><b>Download: </b>Time when tag-based policies sync-up with Ranger.<br>\
-                                            <b>Active: </b>Time when tag-based policies in use for enforcement.'
+                                            <b>Active: </b>Time when tag-based policies in use for enforcement.',
+                noDeleteRoleRow         :'Please select ranger role first to delete.',
+                addRolePermission       : 'Please add permission(s) for the selected role, else role will not be added.',
+                addRole                 : 'Please select role for the selected permission(s), else role will not be added.',
+
 			},
 			plcHldr : {
 				search 						:'Search',
@@ -495,6 +507,7 @@ define(function(require) {
                 jsValidationMsg        :'1. JavaScript Condition Examples :\ncountry_code == \'USA\', time_range >= 900 && time_range <= 1800 etc.\n2. Dragging bottom-right corner of javascript condition editor(Textarea) can resizable',
 				emailAddressValidationMsg  :'1. Email address should be start with alphabet / numeric / underscore / non-us characters.<br> 2. Allowed special character <b>.-@</b> .<br>3. Email address length should be greater than 9 characters.<br> 4. Email address examples : abc@de.fg, A-C@D-.FG',
                 nameValidationMsg      :'Name should not start with space, it should be less than 256 characters and special characters are not allowed(except _ - and space).',
+                roleNameValidationMsg :'1. Role name should be start with alphabet / numeric / underscore / non-us characters.<br> 2. Allowed special character ,._\-+/@= and space. <br>3. Name length should be greater than one.',
 			},
 			serverMsg : {
 
diff --git a/security-admin/src/main/webapp/scripts/routers/Router.js b/security-admin/src/main/webapp/scripts/routers/Router.js
index f60e03c..b9ea66b 100644
--- a/security-admin/src/main/webapp/scripts/routers/Router.js
+++ b/security-admin/src/main/webapp/scripts/routers/Router.js
@@ -51,6 +51,9 @@ function(Backbone, Marionette, localization, MAppState, XAUtil){
 			"!/group/create"	: "groupCreateAction",
 			"!/group/:id"		: "groupEditAction",
 
+                        "!/roles/create"		: "roleCreateAction",
+                        "!/roles/:id"			: "roleEditAction",
+
 			/************GENERIC UI *****************************************/
 			"!/service/:serviceType/create" 	: "serviceCreateAction",
 			"!/service/:serviceType/edit/:id"	: "serviceEditAction",
diff --git a/security-admin/src/main/webapp/scripts/utils/XAEnums.js b/security-admin/src/main/webapp/scripts/utils/XAEnums.js
index c6956ea..a4a4e0b 100644
--- a/security-admin/src/main/webapp/scripts/utils/XAEnums.js
+++ b/security-admin/src/main/webapp/scripts/utils/XAEnums.js
@@ -184,7 +184,8 @@ define(function(require) {
 		CLASS_TYPE_XA_TRANSACTION_LOG_ATTRIBUTE:{value:1012, label:'Transaction log attribute', rbkey:'xa.enum.ClassTypes.CLASS_TYPE_XA_TRANSACTION_LOG_ATTRIBUTE', tt: 'lbl.ClassTypes_CLASS_TYPE_XA_TRANSACTION_LOG_ATTRIBUTE'},
 		CLASS_TYPE_RANGER_POLICY:{value:1020, label:'Ranger Policy', rbkey:'xa.enum.ClassTypes.CLASS_TYPE_RANGER_POLICY', modelName:'VXRangerPolicy', type:'vXResource', tt: 'lbl.ClassTypes_CLASS_TYPE_RANGER_POLICY'},
 		CLASS_TYPE_RANGER_SERVICE:{value:1030, label:'Ranger Service', rbkey:'xa.enum.ClassTypes.CLASS_TYPE_RANGER_SERVICE', modelName:'VXRangerService', type:'vXRangerService', tt: 'lbl.ClassTypes_CLASS_TYPE_RANGER_SERVICE'},
-		CLASS_TYPE_RANGER_SECURITY_ZONE:{value:1056, label:'Ranger Security Zone', rbkey:'xa.enum.ClassTypes.CLASS_TYPE_RANGER_SECURITY_ZONE', modelName:'VXRangerService', type:'vXRangerService', tt: 'lbl.ClassTypes_CLASS_TYPE_RANGER_SECURITY_ZONE'}
+                CLASS_TYPE_RANGER_SECURITY_ZONE:{value:1056, label:'Ranger Security Zone', rbkey:'xa.enum.ClassTypes.CLASS_TYPE_RANGER_SECURITY_ZONE', modelName:'VXRangerService', type:'vXRangerService', tt: 'lbl.ClassTypes_CLASS_TYPE_RANGER_SECURITY_ZONE'},
+                CLASS_TYPE_RANGER_ROLE:{value:1057, label:'Ranger Role', rbkey:'xa.enum.ClassTypes.CLASS_TYPE_RANGER_ROLE', modelName:'VXRole', type:'vXRole', tt: 'lbl.ClassTypes_CLASS_TYPE_RANGER_ROLE'}
 	});
 
 	XAEnums.DataType = mergeParams(XAEnums.DataType, {
diff --git a/security-admin/src/main/webapp/scripts/utils/XAUtils.js b/security-admin/src/main/webapp/scripts/utils/XAUtils.js
index 18e86c9..a7c4497 100644
--- a/security-admin/src/main/webapp/scripts/utils/XAUtils.js
+++ b/security-admin/src/main/webapp/scripts/utils/XAUtils.js
@@ -509,7 +509,7 @@ define(function(require) {
 		} else
 			return '--';
 	};
-	XAUtils.showGroupsOrUsersForPolicy = function(rawValue, model, showGroups, rangerServiceDefModel) {
+        XAUtils.showGroupsOrUsersForPolicy = function(rawValue, model, showType, rangerServiceDefModel) {
 		var showMoreLess = false, groupArr = [], items = [];
 		var itemList = ['policyItems','allowExceptions','denyPolicyItems','denyExceptions','dataMaskPolicyItems','rowFilterPolicyItems']
 		if(!_.isUndefined(rangerServiceDefModel)){
@@ -521,7 +521,7 @@ define(function(require) {
 				: this.isMaskingPolicy(model.get('policyType')) ? _.difference(itemList, ["rowFilterPolicyItems"])
 				: this.isRowFilterPolicy(model.get('policyType')) ? _.difference(itemList, ["dataMaskPolicyItems"]) : itemList; 
 						
-		var type = _.isUndefined(showGroups) || showGroups ? 'groups' : 'users';
+                var type = _.isUndefined(showType) || (showType == 'groups') ? 'groups' : ((showType == 'users') ? 'users' : 'roles');
 		_.each(itemList, function(item){
 		    if(!_.isUndefined(model.get(item)) && !_.isEmpty(model.get(item))) {
 		    	items =_.union(items,  model.get(item))
@@ -655,11 +655,13 @@ define(function(require) {
 				// _.filter(policyItems,function(m){if(!_.isEmpty(m.groups))
 				// return m;});
 				_.each(policyItems, function(obj) {
-					var groupNames = null, userNames = null;
+                                        var groupNames = null, userNames = null, roleNames = null;
 					if (!_.isEmpty(obj.groups))
 						groupNames = obj.groups;
 					if (!_.isEmpty(obj.users))
 						userNames = obj.users;
+                                        if (!_.isEmpty(obj.roles))
+                                                roleNames = obj.roles;
 					var m = new Backbone.Model({
 						groupName : groupNames,
 						userName : userNames,
@@ -667,6 +669,7 @@ define(function(require) {
 						conditions : obj.conditions,
 						delegateAdmin : obj.delegateAdmin,
 						editMode : true,
+                                                roleName : roleNames,
 					});
 					if(that.isMaskingPolicy(model.get('policyType'))){
 						m.set('dataMaskInfo', obj.dataMaskInfo)
@@ -1576,5 +1579,101 @@ define(function(require) {
         });
     }
 
+    XAUtils.getUsersGroupsList = function(typeUserOrGroup, $select, domElement){
+        var that = domElement,
+            tags = [],
+            placeholder = (typeUserOrGroup) ? 'Select Group' : 'Select User',
+            searchUrl = (typeUserOrGroup) ? "service/xusers/lookup/groups" : "service/xusers/lookup/users";
+            if(that.model && !_.isEmpty(that.model.get('name'))){
+                tags.push({
+                    'id': _.escape(that.model.get('name')),
+                    'text': _.escape(that.model.get('name'))
+                });
+                domElement.ui['selectUsersOrGroups'].val(tags.map(function(val) {
+                    return val.text
+                }));
+            }
+
+        return {
+            closeOnSelect : true,
+            placeholder   : placeholder,
+            tags : true,
+            width : '300px',
+            initSelection: function(element, callback) {
+                callback(tags);
+            },
+            ajax: {
+                url: searchUrl,
+                dataType: 'json',
+                data: function(term, page) {
+                    return {
+                        name: term,
+                        isVisible : XAEnums.VisibilityStatus.STATUS_VISIBLE.value,
+                    };
+                },
+                results: function(data, page) {
+                    var results = [],
+                        selectedVals = [];
+                    //Get selected values of groups/users dropdown
+                    if (data.totalCount != "0") {
+                        console.log(that);
+                        if (typeUserOrGroup) {
+                            results = data.vXStrings.map(function(m) {
+                                return {
+                                    id: _.escape(m.value),
+                                    text: _.escape(m.value)
+                                };
+                            });
+                        } else {
+                            //remove users {USER} and {OWNER}
+                            data.vXStrings = _.reject(data.vXStrings, function(m){return (m.value == '{USER}' || m.value == '{OWNER}')})
+                            results = data.vXStrings.map(function(m) {
+                                return {
+                                    id: _.escape(m.value),
+                                    text: _.escape(m.value)
+                                };
+                            });
+                        }
+                        //remove selected values
+                        if(that.collection && that.collection.models){
+                            _.filter(that.collection.models, function(model){
+                                if(model && !_.isUndefined(model.get('name'))){
+                                    selectedVals.push(model.get('name'));
+                                }
+                            })
+                        }
+                        if (!_.isEmpty(selectedVals)) {
+                            results = XAUtils.filterResultByText(results, selectedVals);
+                        }
+                        return {
+                            results: results
+                        };
+                    }
+                    return {
+                        results: results
+                    };
+                },
+                transport: function(options) {
+                    $.ajax(options).fail(function(respones) {
+                        XAUtils.defaultErrorHandler('error', respones);
+                        this.success({
+                            resultSize: 0
+                        });
+                    });
+                }
+            },
+            formatResult: function(result) {
+                return result.text;
+            },
+            formatSelection: function(result) {
+                return result.text;
+            },
+            formatNoMatches: function(result) {
+                return typeUserOrGroup ? 'No group found.' : 'No user found.';
+            }
+
+        }
+        }
+
 	return XAUtils;
 });
\ No newline at end of file
diff --git a/security-admin/src/main/webapp/scripts/views/policies/PermissionList.js b/security-admin/src/main/webapp/scripts/views/policies/PermissionList.js
index 0c3824b..4d9cd7d 100644
--- a/security-admin/src/main/webapp/scripts/views/policies/PermissionList.js
+++ b/security-admin/src/main/webapp/scripts/views/policies/PermissionList.js
@@ -35,6 +35,8 @@ define(function(require) {
 	var VXGroupList			= require('collections/VXGroupList');
 	var VXUserList			= require('collections/VXUserList');
 	var Vent			= require('modules/Vent');
+        var VXRole			= require('models/VXRole');
+        var VXRoleList		= require('collections/VXRoleList');
 	
 	require('bootstrap-editable');
 	require('esprima');
@@ -67,14 +69,16 @@ define(function(require) {
 			addConditionsSpan  : '.add-conditions',
 			addMaskingTypeSpan : '.add-masking-type',
 			addRowFilterSpan   : '.add-row-filter',
-			
+                        selectRoles : '[data-js="selectRoles"]'
+
 		},
 		events : {
 			'click [data-action="delete"]'	: 'evDelete',
 			'click [data-js="delegatedAdmin"]'	: 'evClickTD',
 			'change [data-js="selectGroups"]': 'evSelectGroup',
 			'change [data-js="selectUsers"]': 'evSelectUser',
-			'change input[class="policy-conditions"]'	: 'policyCondtionChange'
+                        'change input[class="policy-conditions"]'	: 'policyCondtionChange',
+                        'change [data-js="selectRoles"]': 'evSelectRoles',
 		},
 
 		initialize : function(options) {
@@ -88,11 +92,13 @@ define(function(require) {
 			//To setup permissions for edit mode 
 			this.setupFormForEditMode();
 			//create select2 dropdown for groups and users  
-			this.createDropDown(this.ui.selectGroups, true);
-			this.createDropDown(this.ui.selectUsers, false);
+                        this.createDropDown(this.ui.selectGroups, 'groups');
+                        this.createDropDown(this.ui.selectUsers, 'users');
+                        this.createDropDown(this.ui.selectRoles, 'roles');
 			//groups or users select2 dropdown change vent 
 			this.dropDownChange(this.ui.selectGroups);
 			this.dropDownChange(this.ui.selectUsers);
+                        this.dropDownChange(this.ui.selectRoles);
 			//render permissions and policy conditions
 			if(XAUtil.isTagBasedDef(this.rangerServiceDefModel)){
 				this.renderPermsForTagBasedPolicies();
@@ -123,7 +129,9 @@ define(function(require) {
 				if(!_.isUndefined(this.model.get('userName')) && !_.isNull(this.model.get('userName'))){
 					this.ui.selectUsers.val(_.map(this.model.get('userName'), function(name){ return _.escape(name); }));
 				}
-				
+                                if(!_.isUndefined(this.model.get('roleName')) && !_.isNull(this.model.get('roleName'))){
+                                        this.ui.selectRoles.val(_.map(this.model.get('roleName'), function(name){ return _.escape(name); }));
+                                }
 				if(!_.isUndefined(this.model.get('conditions'))){
 					_.each(this.model.get('conditions'), function(obj){
 						this.$el.find('input[data-js="'+obj.type+'"]').val(obj.values.toString())
@@ -168,13 +176,18 @@ define(function(require) {
 		dropDownChange : function($select){
 			var that = this;
 			$select.on('change',function(e){
-				var name = ($(e.currentTarget).attr('data-js') == that.ui.selectGroups.attr('data-js')) ? 'group': 'user';
+                                var name = ($(e.currentTarget).attr('data-js') == that.ui.selectGroups.attr('data-js')) ? 'group' :
+                                (($(e.currentTarget).attr('data-js') == that.ui.selectUsers.attr('data-js')) ? 'user' : 'role');
 				var otherName = (name == 'user') ? 'group': 'user';
+                                var otherName2 = (name == 'user') ? 'role': 'user';
 				that.checkDirtyFieldForDropDown(e);
 				
 				if(_.isNull(that.model.get(otherName+'Name'))){
                     that.model.unset(otherName+'Name')
                 }
+                if(_.isNull(that.model.get(otherName2+'Name'))){
+                    that.model.unset(otherName2+'Name')
+                }
 				if(e.removed != undefined){
 					var gNameArr = [];
 					if(that.model.get(name+'Name') != undefined)
@@ -192,12 +205,12 @@ define(function(require) {
 				}
 			});
 		},
-		createDropDown :function($select, typeGroup){
+                createDropDown :function($select, type){
 			var that = this, tags = [],
-			placeholder = (typeGroup) ? 'Select Group' : 'Select User',
-					searchUrl   = (typeGroup) ? "service/xusers/lookup/groups" : "service/xusers/lookup/users";
+                        placeholder = (type == 'users') ? 'Select Users' : ((type == 'groups') ? 'Select Groups' : 'Select Roles'),
+                        searchUrl   = (type == 'users') ? "service/xusers/lookup/users" : ((type == 'groups') ? "service/xusers/lookup/groups" : "service/roles/roles");
 			if(this.model.has('editMode') && !_.isEmpty($select.val())){
-				var temp = this.model.attributes[ (typeGroup) ? 'groupName': 'userName'];
+                                var temp = this.model.attributes[ (type == 'users') ? 'userName' : ((type == 'groups') ? 'groupName' : 'roleName')];
 				_.each(temp , function(name){
 					tags.push( { 'id' : _.escape( name ), 'text' : _.escape( name ) } );
 				});
@@ -220,12 +233,12 @@ define(function(require) {
 					results: function (data, page) { 
 						var results = [] , selectedVals = [];
 						//Get selected values of groups/users dropdown
-						selectedVals = that.getSelectedValues($select, typeGroup);
+                                                selectedVals = that.getSelectedValues($select, type);
 						if(data.totalCount != "0"){
-							if(typeGroup){
+                                                        if(type == 'users' || type == 'groups'){
 								results = data.vXStrings.map(function(m){	return {id : _.escape(m.value), text: _.escape(m.value) };	});
 							} else {
-								results = data.vXStrings.map(function(m){	return {id : _.escape(m.value), text: _.escape(m.value) };	});
+                                                                results = data.roles.map(function(m){	return {id : _.escape(m.name), text: _.escape(m.name) };	});
 							}
 							if(!_.isEmpty(selectedVals)){
 								results = XAUtil.filterResultByText(results, selectedVals);
@@ -250,7 +263,7 @@ define(function(require) {
 					return result.text;
 				},
 				formatNoMatches: function(result){
-					return typeGroup ? 'No group found.' : 'No user found.';
+                                        return (type == 'users') ? 'No user found.' : ((type == 'groups') ? 'No group found.' : 'No role found');
 				}
 			}).on('select2-focus', XAUtil.select2Focus);
 		},
@@ -772,9 +785,9 @@ define(function(require) {
 			    that.model.unset('conditions');
 			}
 		},
-		getSelectedValues : function($select, typeGroup){
+                getSelectedValues : function($select, type){
 			var vals = [],selectedVals = [];
-			var name = typeGroup ? 'group' : 'user';
+                        var name = (type == 'users') ? 'user' : ((type == 'groups') ? 'group' : 'role');
 			if(!_.isEmpty($select.select2('data'))){
 				selectedVals = _.map($select.select2('data'),function(obj){ return obj.text; });
 			}
@@ -994,6 +1007,7 @@ define(function(require) {
 			}
 			permList.unshift(localization.tt('lbl.selectUser'));
 			permList.unshift(localization.tt('lbl.selectGroup'));
+                        permList.unshift(localization.tt('lbl.selectRole'));
 			permList.push("");
 			return permList;
 		},
diff --git a/security-admin/src/main/webapp/scripts/views/policies/RangerPolicyCreate.js b/security-admin/src/main/webapp/scripts/views/policies/RangerPolicyCreate.js
index 8f23e84..bb2752d 100644
--- a/security-admin/src/main/webapp/scripts/views/policies/RangerPolicyCreate.js
+++ b/security-admin/src/main/webapp/scripts/views/policies/RangerPolicyCreate.js
@@ -188,9 +188,11 @@ define(function(require){
 					  || validateObj3.userPerm || validateObj4.userPerm);
 			var groupPerm = (validateObj1.groupPermSet || validateObj2.groupPermSet 
                                         || validateObj3.groupPermSet || validateObj4.groupPermSet);
+                        var rolePerm = (validateObj1.rolePerm || validateObj2.rolePerm
+                                        || validateObj3.rolePerm || validateObj4.rolePerm);
                         var delegatePerm  = (validateObj1.delegateAdmin || validateObj2.delegateAdmin
                                         || validateObj3.delegateAdmin || validateObj4.delegateAdmin);
-                        if((!validateObj1.auditLoggin) && !(groupPerm || userPerm || delegatePerm )){
+                        if((!validateObj1.auditLoggin) && !(groupPerm || userPerm || delegatePerm || rolePerm)){
 				XAUtil.alertPopup({ msg :localization.tt('msg.yourAuditLogginIsOff') });
 				return;
 			}
@@ -204,18 +206,19 @@ define(function(require){
 		validatePolicyItem : function(validateObj){
 			var that = this, valid = false;
                         //DelegateAdmin checks
-                        if((validateObj.groupSet || validateObj.userSet) && validateObj.delegateAdmin){
+                        if((validateObj.groupSet || validateObj.userSet || validateObj.roleSet) && validateObj.delegateAdmin){
                                 return true;
-                        }else if(validateObj.delegateAdmin && !(validateObj.groupSet || validateObj.userSet)) {
-                                this.popupCallBack(localization.tt('msg.addUserOrGroupForDelegateAdmin'),validateObj);
+                        }else if(validateObj.delegateAdmin && !(validateObj.groupSet || validateObj.userSet || validateObj.roleSet)) {
+                                this.popupCallBack(localization.tt('msg.addUserOrGroupOrRoleForDelegateAdmin'),validateObj);
                                 return false;
                         }
-			valid = (validateObj.groupSet && validateObj.permSet) || (validateObj.userSet && validateObj.userPerm);
+                        valid = (validateObj.groupSet && validateObj.permSet) || (validateObj.userSet && validateObj.userPerm)
+                        || (validateObj.roleSet && validateObj.rolePerm);
 			if(!valid){
-				if((!validateObj.groupSet && !validateObj.userSet) && (validateObj.condSet)) {
-					this.popupCallBack(localization.tt('msg.addUserOrGroupForPC'),validateObj);
-				} else if((!validateObj.groupSet && !validateObj.userSet) && (validateObj.permSet)) {
-					this.popupCallBack(localization.tt('msg.addUserOrGroup'),validateObj);
+                                if((!validateObj.groupSet && !validateObj.userSet && !validateObj.roleSet) && (validateObj.condSet)) {
+                                        this.popupCallBack(localization.tt('msg.addUserOrGroupOrRoleForPC'),validateObj);
+                                } else if((!validateObj.groupSet && !validateObj.userSet && !validateObj.roleSet) && (validateObj.permSet)) {
+                                        this.popupCallBack(localization.tt('msg.addUserOrGroupOrRole'),validateObj);
 					
 				} else if(validateObj.groupSet && (!validateObj.permSet)){
 					this.popupCallBack(localization.tt('msg.addGroupPermission'),validateObj);
@@ -227,6 +230,10 @@ define(function(require){
 				} else if((!validateObj.userSet) && (validateObj.userPerm)) {
 					this.popupCallBack(localization.tt('msg.addUser'),validateObj);
 						
+                                } else if(validateObj.roleSet && (!validateObj.rolePerm)){
+                                        this.popupCallBack(localization.tt('msg.addRolePermission'),validateObj);
+                                } else if((!validateObj.roleSet) && (validateObj.rolePerm)) {
+                                        this.popupCallBack(localization.tt('msg.addRole'),validateObj);
 				} else if((!validateObj.auditLoggin) && (!validateObj.groupPermSet)){
 					return true;
 				}else{
@@ -237,12 +244,14 @@ define(function(require){
 					this.popupCallBack(localization.tt('msg.addGroupPermission'),validateObj);
 				} else if((!validateObj.groupSet) && (validateObj.permSet)) {
 					this.popupCallBack(localization.tt('msg.addGroup'),validateObj);
-						
 				} else if(validateObj.userSet && (!validateObj.userPerm)){
 					this.popupCallBack(localization.tt('msg.addUserPermission'),validateObj);
 				} else if((!validateObj.userSet) && (validateObj.userPerm)) {
 					this.popupCallBack(localization.tt('msg.addUser'),validateObj);
-						
+                                } else if(validateObj.roleSet && (!validateObj.rolePerm)){
+                                        this.popupCallBack(localization.tt('msg.addRolePermission'),validateObj);
+                                } else if((!validateObj.roleSet) && (validateObj.rolePerm)) {
+                                        this.popupCallBack(localization.tt('msg.addRole'),validateObj);
 				} else {
 					return true;
 				}
diff --git a/security-admin/src/main/webapp/scripts/views/policies/RangerPolicyForm.js b/security-admin/src/main/webapp/scripts/views/policies/RangerPolicyForm.js
index a1a1311..5a184df 100644
--- a/security-admin/src/main/webapp/scripts/views/policies/RangerPolicyForm.js
+++ b/security-admin/src/main/webapp/scripts/views/policies/RangerPolicyForm.js
@@ -592,7 +592,7 @@ define(function(require){
 		},
 		setPermissionsToColl : function(list, policyItemList) {
 			list.each(function(m){
-				if(!_.isUndefined(m.get('groupName')) || !_.isUndefined(m.get("userName"))){ //groupName or userName
+                                if(!_.isUndefined(m.get('groupName')) || !_.isUndefined(m.get("userName")) || !_.isUndefined(m.get('roleName'))){ //groupName or userName
 					var RangerPolicyItem=Backbone.Model.extend()
 					var policyItem = new RangerPolicyItem();
 					if(!_.isUndefined(m.get('groupName')) && !_.isNull(m.get('groupName'))){
@@ -601,6 +601,9 @@ define(function(require){
 					if(!_.isUndefined(m.get('userName')) && !_.isNull(m.get('userName'))){
 						policyItem.set("users",m.get("userName"));
 					}
+                                        if(!_.isUndefined(m.get('roleName')) && !_.isNull(m.get('roleName'))){
+                                                policyItem.set("roles",m.get("roleName"));
+                                        }
 					if(!(_.isUndefined(m.get('conditions')) && _.isEmpty(m.get('conditions')))){
 						var RangerPolicyItemConditionList = Backbone.Collection.extend();
 						var rPolicyItemCondList = new RangerPolicyItemConditionList(m.get('conditions'))
@@ -848,26 +851,34 @@ define(function(require){
 		},
 		formValidation : function(coll){
                         var groupSet = false , permSet = false , groupPermSet = false , delegateAdmin = false ,
-			userSet=false, userPerm = false, userPermSet =false,breakFlag =false, condSet = false,customMaskSet = true;
+                        userSet=false, userPerm = false, userPermSet =false,breakFlag =false, condSet = false,customMaskSet = true,
+                        roleSet = false, rolePermSet = false, rolePerm = false;
 			console.log('validation called..');
 			coll.each(function(m){
 				if(_.isEmpty(m.attributes)) return;
-                                if(m.has('groupName') || m.has('userName') || m.has('accesses') || m.has('delegateAdmin') ){
+                if(m.has('groupName') || m.has('userName') || m.has('accesses') || m.has('delegateAdmin') || m.has('roleName')){
 					if(! breakFlag){
 						groupSet = m.has('groupName') ? true : false;
 						userSet = m.has('userName') ? true : false;
+                                                roleSet = m.has('roleName') ? true : false;
                                                 permSet = m.has('accesses') ? true : false;
                                                 delegateAdmin = m.has('delegateAdmin') ? m.get('delegateAdmin') : false;
 						if(groupSet && permSet){
 							groupPermSet = true;
 							userPermSet = false;
+                                                        rolePermSet = false;
 						}else if(userSet && permSet){
 							userPermSet = true;
 							groupPermSet = false;
+                                                        rolePermSet = false;
+                                                }else if(roleSet && permSet){
+                                                        rolePermSet = true;
+                                                        userPermSet = false;
+                                                        groupPermSet = false;
 						}else{
-                                                        if(!((userSet || groupSet) && delegateAdmin)){
-                                                                breakFlag=true;
-                                                        }
+                            if(!((userSet || groupSet || roleSet) && delegateAdmin)){
+                                    breakFlag=true;
+                            }
 						}
 					}
 				}
@@ -887,15 +898,18 @@ define(function(require){
 						userSet 		: userSet, isUsers:userPermSet,
 						auditLoggin 	: auditStatus,
 						condSet			: condSet,
-                                                customMaskSet   : customMaskSet,
-                                                delegateAdmin	: delegateAdmin,
+                        customMaskSet   : customMaskSet,
+                        delegateAdmin	: delegateAdmin,
+                        roleSet : roleSet, rolePermSet : rolePermSet,
 					};
-			if(groupSet || userSet){
+                        if(groupSet || userSet || roleSet){
 				obj['permSet'] = groupSet ? permSet : false;
 				obj['userPerm'] = userSet ? permSet : false;
+                                obj['rolePerm'] = roleSet ? permSet : false;
 			}else{
 				obj['permSet'] = permSet;
 				obj['userPerm'] = userSet;
+                                obj['rolePerm'] = roleSet;
 			}
 			return obj;
 		},
diff --git a/security-admin/src/main/webapp/scripts/views/policies/RangerPolicyRO.js b/security-admin/src/main/webapp/scripts/views/policies/RangerPolicyRO.js
index a4b6087..e9fcd7d 100644
--- a/security-admin/src/main/webapp/scripts/views/policies/RangerPolicyRO.js
+++ b/security-admin/src/main/webapp/scripts/views/policies/RangerPolicyRO.js
@@ -242,6 +242,7 @@ define(function(require) {
 			}
 			permList.unshift(localization.tt('lbl.selectUser'));
 			permList.unshift(localization.tt('lbl.selectGroup'));
+                        permList.unshift(localization.tt('lbl.selectRole'));
 			return {
 				header : permList,
 				policyCondition : policyCondition
diff --git a/security-admin/src/main/webapp/scripts/views/policies/RangerPolicyTableLayout.js b/security-admin/src/main/webapp/scripts/views/policies/RangerPolicyTableLayout.js
index c18cfaa..f8b71e1 100644
--- a/security-admin/src/main/webapp/scripts/views/policies/RangerPolicyTableLayout.js
+++ b/security-admin/src/main/webapp/scripts/views/policies/RangerPolicyTableLayout.js
@@ -305,6 +305,18 @@ define(function(require){
 					drag : false,
 					sortable : false
 				},
+                                roles : {
+                                        reName : 'roleName',
+                                        cell	: Backgrid.HtmlCell.extend({className: 'cellWidth-1'}),
+                                        label : localization.tt("lbl.roles"),
+                                        formatter: _.extend({}, Backgrid.CellFormatter.prototype, {
+                                                fromRaw: function (rawValue, model) {
+                                                        return XAUtil.showGroupsOrUsersForPolicy(model.get('policyItems'), model, 'roles', that.rangerServiceDefModel);
+                                                }
+                                        }),
+                                        editable : false,
+                                        sortable : false
+                                },
 				policyItems : {
 					reName : 'groupName',
 					cell	: Backgrid.HtmlCell.extend({className: 'cellWidth-1'}),
@@ -312,7 +324,7 @@ define(function(require){
 					formatter: _.extend({}, Backgrid.CellFormatter.prototype, {
 						fromRaw: function (rawValue, model) {
 							if(!_.isUndefined(rawValue)){
-								return XAUtil.showGroupsOrUsersForPolicy(rawValue, model, true, that.rangerServiceDefModel);
+                                                                return XAUtil.showGroupsOrUsersForPolicy(rawValue, model, 'groups', that.rangerServiceDefModel);
 							}
 							return '--';
 						}
@@ -327,12 +339,12 @@ define(function(require){
 					label : localization.tt("lbl.users"),
 					formatter: _.extend({}, Backgrid.CellFormatter.prototype, {
 						fromRaw: function (rawValue, model) {
-								return XAUtil.showGroupsOrUsersForPolicy(model.get('policyItems'), model, false, that.rangerServiceDefModel);
-						}
-					}),
-					editable : false,
-					sortable : false
-				},
+                                                                return XAUtil.showGroupsOrUsersForPolicy(model.get('policyItems'), model, 'users', that.rangerServiceDefModel);
+                                                }
+                                        }),
+                                        editable : false,
+                                        sortable : false
+                                },
 			};
 			cols['permissions'] = {
 				cell :  "html",
diff --git a/security-admin/src/main/webapp/scripts/views/reports/AuditLayout.js b/security-admin/src/main/webapp/scripts/views/reports/AuditLayout.js
index 18dba7a..9c01eb7 100644
--- a/security-admin/src/main/webapp/scripts/views/reports/AuditLayout.js
+++ b/security-admin/src/main/webapp/scripts/views/reports/AuditLayout.js
@@ -190,7 +190,7 @@ define(function(require) {
 					<th class="renderable ruser"></th>\
                                         <th class="renderable ruser"></th>\
                                         <th class="renderable ruser"></th>\
-				</tr>');
+                    </tr>');
 		},
 		modifyPluginStatusTableSubcolumns : function(){
 			this.$el.find('[data-id="r_tableList"] table thead').prepend('<tr>\
@@ -920,6 +920,8 @@ define(function(require) {
 									 html = 	'User profile '+action+'d '+'<b>'+name+'</b>';
 								 else if(rawValue  == XAEnums.ClassTypes.CLASS_TYPE_RANGER_SECURITY_ZONE.value)
 									 html =     'Security Zone '+action+'d '+'<b>'+name+'</b>';
+                                                                else if(rawValue  == XAEnums.ClassTypes.CLASS_TYPE_RANGER_ROLE.value)
+                                                                         html =     'Role '+action+'d '+'<b>'+name+'</b>';
 								 return html;
 						    }
 						}
@@ -1296,8 +1298,7 @@ define(function(require) {
 							}
 						}),
 					},
-
-			};
+                                };
 			return this.accessAuditList.constructor.getTableCols(cols, this.accessAuditList);
 		},
 		renderLoginSessionTable : function(){
diff --git a/security-admin/src/main/webapp/scripts/views/reports/OperationDiffDetail.js b/security-admin/src/main/webapp/scripts/views/reports/OperationDiffDetail.js
index 4a73c32..93458c9 100644
--- a/security-admin/src/main/webapp/scripts/views/reports/OperationDiffDetail.js
+++ b/security-admin/src/main/webapp/scripts/views/reports/OperationDiffDetail.js
@@ -32,6 +32,8 @@ define(function(require){
 	var GroupUpdateOperationDiff_tmpl 	= require('hbs!tmpl/reports/GroupUpdateOperationDiff_tmpl');
 	var ZoneOperationDiff_tmpl 			= require('hbs!tmpl/reports/ZoneOperationDiff_tmpl');
 	var ZoneUpdateOperationDiff_tmpl 	= require('hbs!tmpl/reports/ZoneUpdateOperationDiff_tmpl');
+        var RoleOperationDiff_tmpl 		    = require('hbs!tmpl/reports/RoleOperationDiff_tmpl');
+        var RoleUpdateOperationDiff_tmpl 	= require('hbs!tmpl/reports/RoleUpdateOperationDiff_tmpl');
 	
 	var OperationDiffDetail = Backbone.Marionette.ItemView.extend(
 	/** @lends OperationDiffDetail */
@@ -180,6 +182,14 @@ define(function(require){
 				else
 					this.template = ZoneOperationDiff_tmpl;
 			}
+                        if(this.classType == XAEnums.ClassTypes.CLASS_TYPE_RANGER_ROLE.value){
+                                if(this.action == 'update'){
+                                        this.template = RoleUpdateOperationDiff_tmpl;
+                                } else{
+                                        this.template = RoleOperationDiff_tmpl;
+                                }
+                                this.templateType = XAEnums.ClassTypes.CLASS_TYPE_RANGER_ROLE.value;
+                        }
 		},
 		assetDiffOperation : function(){	
 			var that = this, configModel;
diff --git a/security-admin/src/main/webapp/scripts/views/users/AddUsersOrGroupsList.js b/security-admin/src/main/webapp/scripts/views/users/AddUsersOrGroupsList.js
new file mode 100644
index 0000000..a93e58f
--- /dev/null
+++ b/security-admin/src/main/webapp/scripts/views/users/AddUsersOrGroupsList.js
@@ -0,0 +1,154 @@
+/*
+ * 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.
+ */
+
+ /*
+ *
+ */
+define(function(require) {
+    'use strict';
+
+    var Backbone        = require('backbone');
+    var App             = require('App');
+    var XAEnums         = require('utils/XAEnums');
+    var XAUtil          = require('utils/XAUtils');
+    var localization    = require('utils/XALangSupport');
+    var VXGroup         = require('models/VXGroup');
+    var VXGroupList         = require('collections/VXGroupList');
+    var VXUserList          = require('collections/VXUserList');
+    require('bootstrap-editable');
+
+    var UsersAndGroupsItem = Backbone.Marionette.ItemView.extend({
+        _msvName : 'FormInputItem',
+
+        template : require('hbs!tmpl/users/AddUserOrGroupsItem_tmpl'),
+
+        tagName : 'tr',
+
+        templateHelpers : function(){
+            var usersGroupsName = this.model.get('name');
+            return {
+                usersGroupsName : usersGroupsName,
+            };
+        },
+
+        ui : {
+            'isRoleAdmin' : 'input[data-js="isRoleAdmin"]',
+        },
+
+        events : {
+            'click [data-action="delete"]'  : 'evDelete',
+            'click [data-js="isRoleAdmin"]' : 'evClickTD',
+        },
+
+        initialize : function(options) {
+            _.extend(this, _.pick(options, 'collection', 'fieldName'));
+        },
+
+        onRender : function() {
+            var that = this;
+            this.ui.isRoleAdmin.attr('checked', this.model.get('isAdmin'));
+        },
+
+        evClickTD : function(e){
+            var $el = $(e.currentTarget);
+            this.model.set('isAdmin', $el.is(':checked'));
+        },
+
+        evDelete : function(){
+            var that = this;
+            this.collection.remove(this.model);
+        },
+    });
+
+    var AddUserOrGroupsList =  Backbone.Marionette.CompositeView.extend({
+
+        _msvName : 'AddUserOrGroupsList',
+
+        template : require('hbs!tmpl/users/AddUserOrGroupsList_tmpl'),
+
+        templateHelpers :function(){
+            var headerName = this.fieldName === 'users' ? "User Name" : "Group Name",
+            btnLable = this.fieldName === 'users' ? 'Add Users' : 'Add Groups';
+            return {
+                headerName : headerName,
+                btnLable : btnLable
+            };
+        },
+
+        getItemView : function(item){
+            if(!item){
+                return;
+            }
+            return UsersAndGroupsItem;
+        },
+        itemViewContainer : ".js-formInput",
+
+        itemViewOptions : function() {
+            return {
+                'collection' : this.collection,
+                'fieldName'  : this.fieldName,
+            };
+        },
+
+        ui : {
+            'selectUsersOrGroups' : '[data-js="selectUsersOrGroups"]',
+        },
+
+        events : {
+            'click [data-action="addUserGroup"]' : 'addNew'
+        },
+
+        /** all events binding here */
+        bindEvents : function() {
+        },
+
+        initialize : function(options) {
+            _.extend(this, _.pick(options, 'collection', 'fieldName'));
+        },
+
+        onRender : function() {
+            var isGroup = this.fieldName === 'users' ? false : true;
+            if(this.collection.length === 0){
+                this.$el.find('[data-id="userGroupsTable"]').html('<tr data-name="'+this.fieldName+'"><td colspan="3"> No '
+                    +this.fieldName+' found</td></tr>');
+            }
+            this.ui.selectUsersOrGroups.select2(XAUtil.getUsersGroupsList(isGroup, this.fieldName, this));
+        },
+
+        addNew : function() {
+            var that =this;
+            this.$('table').show();
+            if(_.isEmpty(this.ui.selectUsersOrGroups.val())) {
+                XAUtil.alertPopup ({
+                    msg: 'Please select '+this.fieldName
+                });
+                return
+            } else {
+                this.$el.find('[data-name='+this.fieldName+']').hide();
+                _.each(this.ui.selectUsersOrGroups.val().split(','), function(name){
+                    that.collection.add(new Backbone.Model({'name' : name , 'isAdmin' : false}));
+                });
+                this.ui.selectUsersOrGroups.select2('data',[]);
+            }
+        },
+    });
+
+    return AddUserOrGroupsList;
+
+});
diff --git a/security-admin/src/main/webapp/scripts/views/users/RoleCreate.js b/security-admin/src/main/webapp/scripts/views/users/RoleCreate.js
new file mode 100644
index 0000000..f574802
--- /dev/null
+++ b/security-admin/src/main/webapp/scripts/views/users/RoleCreate.js
@@ -0,0 +1,154 @@
+/*
+ * 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.
+ */
+
+
+define(function(require){
+    'use strict';
+
+    var Backbone        = require('backbone');
+    var App             = require('App');
+    var XALinks         = require('modules/XALinks');
+    var XAUtil          = require('utils/XAUtils');
+    var XAEnums         = require('utils/XAEnums');
+    var localization    = require('utils/XALangSupport');
+
+    var UserTableLayout = require('views/users/UserTableLayout');
+    var VXRoleList     = require('collections/VXRoleList');
+    var RoleForm       = require('views/users/RoleForm');
+    var RolecreateTmpl = require('hbs!tmpl/users/RoleCreate_tmpl');
+    var SessionMgr      = require('mgrs/SessionMgr');
+
+    var RoleCreate = Backbone.Marionette.Layout.extend(
+    /** @lends RoleCreate */
+    {
+        _viewName : 'RoleCreate',
+
+        template: RolecreateTmpl,
+        breadCrumbs :function(){
+            return this.model.isNew() ? [XALinks.get('Roles'),XALinks.get('RoleCreate')]
+                : [XALinks.get('Roles'),XALinks.get('RoleEdit')];
+        },
+
+        /** Layout sub regions */
+        regions: {
+            'rForm' :'div[data-id="r_form"]'
+        },
+
+        /** ui selector cache */
+        ui: {
+            'btnSave'   : '[data-id="save"]',
+            'btnCancel' : '[data-id="cancel"]'
+        },
+
+        /** ui events hash */
+        events: function() {
+            var events = {};
+            //events['change ' + this.ui.input]  = 'onInputChange';
+            events['click ' + this.ui.btnSave]      = 'onSave';
+            events['click ' + this.ui.btnCancel]    = 'onCancel';
+            return events;
+        },
+
+        /**
+        * intialize a new RoleCreate Layout
+        * @constructs
+        */
+        initialize: function(options) {
+            console.log("initialized a RoleCreate Layout");
+
+            _.extend(this, _.pick(options, ''));
+            this.editRole = this.model.has('id') ? true : false;
+            this.bindEvents();
+            this.form = new RoleForm({
+                template : require('hbs!tmpl/users/RoleForm_tmpl'),
+                model : this.model
+            });
+        },
+
+        /** all events binding here */
+        bindEvents : function(){
+            /*this.listenTo(this.model, "change:foo", this.modelChanged, this);*/
+            /*this.listenTo(communicator.vent,'someView:someEvent', this.someEventHandler, this)'*/
+        },
+
+        /** on render callback */
+        onRender: function() {
+            var that = this
+            this.initializePlugins();
+            this.rForm.show(this.form);
+            // this.rForm.$el.dirtyFields();
+            // XAUtil.preventNavigation(localization.tt('dialogMsg.preventNavGroupForm'),this.rForm.$el);
+        },
+
+        /** all post render plugin initialization */
+        initializePlugins: function(){
+        },
+        onSave: function(){
+            var that = this, usersDetails = [], groupsDetails = [] ;
+            var errors = this.form.commit({validate : false});
+            if(! _.isEmpty(errors)){
+                return;
+            }
+            XAUtil.blockUI();
+            this.form.beforeSave()
+            this.form.usersColl.models.filter(function(m){
+                usersDetails.push ({'name' : m.get('name') , 'isAdmin' : m.get('isAdmin')});
+            })
+            this.form.groupsColl.models.filter(function(m){
+                groupsDetails.push ({'name' : m.get('name') , 'isAdmin' : m.get('isAdmin')});
+            })
+            this.model.set('users', usersDetails);
+            this.model.set('groups', groupsDetails);
+            this.model.save({},{
+                success: function () {
+                    XAUtil.blockUI('unblock');
+                    XAUtil.allowNavigation();
+                    Backbone.fetchCache._cache = {}
+                    var msg = that.editGroup ? 'Role updated successfully' :'Role created successfully';
+                    XAUtil.notifySuccess('Success', msg);
+                    App.usersGroupsListing = {'showLastPage' : true}
+                    App.appRouter.navigate("#!/users/Roletab",{trigger: true});
+                },
+                error : function (model, response, options) {
+                    XAUtil.blockUI('unblock');
+                    if ( response && response.responseJSON && response.responseJSON.msgDesc){
+                        if(response.responseJSON.msgDesc == "XRole already exists"){
+                            XAUtil.notifyError('Error', "Role name already exists");
+                        } else {
+                            XAUtil.notifyError('Error', response.responseJSON.msgDesc);
+                        }
+                    }else {
+                        XAUtil.notifyError('Error', 'Error occurred while creating/updating Role!');
+                    }
+                }
+            });
+        },
+        onCancel : function(){
+            XAUtil.allowNavigation();
+            App.appRouter.navigate("#!/users/roletab",{trigger: true});
+        },
+
+        /** on close */
+        onClose: function(){
+        }
+
+    });
+
+    return RoleCreate;
+});
\ No newline at end of file
diff --git a/security-admin/src/main/webapp/scripts/views/users/RoleForm.js b/security-admin/src/main/webapp/scripts/views/users/RoleForm.js
new file mode 100644
index 0000000..27c8aa9
--- /dev/null
+++ b/security-admin/src/main/webapp/scripts/views/users/RoleForm.js
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ */
+
+
+define(function(require){
+    'use strict';
+
+    var Backbone      = require('backbone');
+    var XAEnums       = require('utils/XAEnums');
+    var App           = require('App');
+    var XAUtils       = require('utils/XAUtils');
+    var localization  = require('utils/XALangSupport');
+    var XALinks       = require('modules/XALinks');
+    var XABackgrid    = require('views/common/XABackgrid');
+    var XATableLayout = require('views/common/XATableLayout');
+    var VXRole        = require('models/VXRole');
+    var VXRoleListBase      = require('collection_bases/VXRoleListBase');
+    var usersAndGroupsItemList = require('views/users/AddUsersOrGroupsList');
+
+    require('backbone-forms');
+    require('backbone-forms.list');
+    require('backbone-forms.templates');
+    require('backbone-forms.XAOverrides');
+    var RoleForm = Backbone.Form.extend(
+    /** @lends GroupForm */
+    {
+        _viewName : 'RoleForm',
+
+        /**
+        * intialize a new RoleForm Form View
+        * @constructs
+        */
+
+        ui : {
+            'selectUserName': '[data-id="users"]',
+            'selectGroupName': '[data-id="groups"]',
+            'usersItemList'  : '[data-name="userTableLayout"]',
+            'groupsItemList'  : '[data-name="groupTableLayout"]',
+        },
+
+        initialize: function(options) {
+            console.log("initialized a RoleForm Form View");
+            Backbone.Form.prototype.initialize.call(this, options);
+
+            this.bindEvents();
+        },
+
+        /** all events binding here */
+        bindEvents : function() {
+        },
+
+        /** fields for the form
+        */
+        fields: ['name', 'description'],
+
+        schema :{},
+
+        /** on render callback */
+        render: function(options) {
+            Backbone.Form.prototype.render.call(this, options);
+            this.addUserTbl();
+            this.addGroupTbl();
+        },
+
+        /** all custom field rendering */
+        renderCustomFields: function(collection, $filed, fieldName) {
+            this.$el.find($filed).html(new usersAndGroupsItemList({
+                collection : collection,
+                fieldName  : fieldName,
+            }).render().el);
+        },
+
+        addUserTbl : function() {
+            var that = this, models = this.model.isNew() ? [] : this.model.get('users');
+            this.usersColl = new Backbone.Collection(models);
+            this.renderCustomFields(this.usersColl, this.ui.usersItemList, 'users');
+        },
+
+        addGroupTbl : function() {
+            var that = this, models = this.model.isNew() ? [] : this.model.get('groups');
+            this.groupsColl = new Backbone.Collection(models);
+            this.renderCustomFields(this.groupsColl, this.ui.groupsItemList, 'groups');
+        },
+
+        beforeSave : function() {
+            var that = this;
+            this.usersColl.remove(that.usersColl.models.filter(function(model){
+                return _.isUndefined(model.get('name'))
+            }));
+            this.groupsColl.remove(that.groupsColl.models.filter(function(model){
+                return _.isUndefined(model.get('name'))
+            }))
+        },
+
+    });
+
+    return RoleForm;
+});
\ No newline at end of file
diff --git a/security-admin/src/main/webapp/scripts/views/users/UserTableLayout.js b/security-admin/src/main/webapp/scripts/views/users/UserTableLayout.js
index 45b672c..a18833e 100755
--- a/security-admin/src/main/webapp/scripts/views/users/UserTableLayout.js
+++ b/security-admin/src/main/webapp/scripts/views/users/UserTableLayout.js
@@ -35,8 +35,9 @@ define(function(require){
 	var VXUserList		= require('collections/VXUserList');
 	var XATableLayout	= require('views/common/XATableLayout');
 	var vUserInfo		= require('views/users/UserInfo');
-
 	var VXUser          = require('models/VXUser');
+        var VXRoleList		= require('collections/VXRoleList');
+        var VXRole			= require('models/VXRole');
 
 	var UsertablelayoutTmpl = require('hbs!tmpl/users/UserTableLayout_tmpl');
 
@@ -65,8 +66,10 @@ define(function(require){
     		btnShowHide		: '[data-action="showHide"]',
 			visibilityDropdown		: '[data-id="visibilityDropdown"]',
 			addNewBtnDiv	: '[data-id="addNewBtnDiv"]',
-                        deleteUser: '[data-id="deleteUserGroup"]',
-                       showUserList:'[data-js="showUserList"]',
+            deleteUser: '[data-id="deleteUserGroup"]',
+            showUserList:'[data-js="showUserList"]',
+            addNewRoles: '[data-id="addNewRoles"]',
+            hideShowVisibility: '[data-id="hideShowVisibility"]'
     	},
 
 		/** ui events hash */
@@ -89,8 +92,9 @@ define(function(require){
 		initialize: function(options) {
 			console.log("initialized a UserTableLayout Layout");
 
-			_.extend(this, _.pick(options, 'groupList','tab'));
+                        _.extend(this, _.pick(options, 'groupList','tab', 'roleList'));
 			this.showUsers = this.tab == 'usertab' ? true : false;
+                        this.showGroups = this.tab == 'grouptab' ? true : false;
 			this.chgFlags = [];
 			if(_.isUndefined(this.groupList)){
 				this.groupList = new VXGroupList();
@@ -112,11 +116,14 @@ define(function(require){
 			this.initializePlugins();
 			if(this.tab == 'grouptab'){
 				this.renderGroupTab();
-			} else {
+                        } else if(this.tab == 'usertab'){
 				this.renderUserTab();
+                        } else{
+                                this.renderRoleTab();
 			}
 			this.bindEventToColl(this.collection);
 			this.bindEventToColl(this.groupList);
+                        this.bindEventToColl(this.roleList);
 			this.addVisualSearch();
 		},
 		bindEventToColl : function(coll){
@@ -141,12 +148,16 @@ define(function(require){
 			var that = this;
 			this.chgFlags = [];
 			this.showUsers = $(e.currentTarget).attr('href') == '#users' ? true : false;
+                        this.showGroups = $(e.currentTarget).attr('href') == '#groups' ? true : false;
 			if(this.showUsers){				
 				this.renderUserTab();
 				this.addVisualSearch();
-			} else {				
+                        } else if(this.showGroups){
 				this.renderGroupTab();
 				this.addVisualSearch();
+                        }else{
+                                this.renderRoleTab();
+                                this.addVisualSearch();
 			}
 			$(this.rUserDetail.el).hide();
 		},
@@ -221,6 +232,8 @@ define(function(require){
 		},
 		renderUserTab : function(){
 			var that = this;
+                        this.ui.addNewRoles.hide();
+                        this.ui.hideShowVisibility.show();
 			if(_.isUndefined(this.collection)){
 				this.collection = new VXUserList();
 			}	
@@ -253,6 +266,8 @@ define(function(require){
 		},
 		renderGroupTab : function(){
 			var that = this;
+                        this.ui.addNewRoles.hide();
+                        this.ui.hideShowVisibility.show();
 			if(_.isUndefined(this.groupList)){
 				this.groupList = new VXGroupList();
 			}
@@ -282,6 +297,39 @@ define(function(require){
 				that.checkRoleKeyAdmin();
 			});
 		},
+                renderRoleTab : function(){
+                        var that = this;
+                        this.ui.hideShowVisibility.hide();
+                        if(_.isUndefined(this.roleList)){
+                                this.roleList = new VXRoleList();
+                        }
+                        this.renderRoleListTable();
+                        this.roleList.fetch({
+                                reset:true,
+                                cache: false,
+                        }).done(function(roleList){
+                                if(App.usersGroupsListing && !_.isEmpty(App.usersGroupsListing) && App.usersGroupsListing.showLastPage){
+                                        if(roleList.state.totalRecords > roleList.state.pageSize){
+                                                that.roleList.getLastPage({
+                                                        cache : false,
+                                                }).done(function(m){
+                                                        (_.last(m.models)).trigger("model:highlightUserGroupTableRow");
+                                                });
+                                        }else{
+                                                (_.last(roleList.models)).trigger("model:highlightUserGroupTableRow");
+                                        }
+                                        App.usersGroupsListing={};
+                                }
+                                that.ui.addNewUser.hide();
+                                that.ui.addNewGroup.hide();
+                                that.ui.addNewRoles.show();
+                                that.$('.wrap-header').text('Role List');
+                                that.$('ul').find('[data-js="roles"]').addClass('active');
+                                that.$('ul').find('[data-js="users"]').removeClass();
+                                that.$('ul').find('[data-js="groups"]').removeClass();
+                                // that.checkRoleKeyAdmin();
+                        });
+                },
 		renderUserListTable : function(){
 			var that = this;
 			var tableRow = Backgrid.Row.extend({
@@ -524,6 +572,91 @@ define(function(require){
 			return this.groupList.constructor.getTableCols(cols, this.groupList);
 		},
 
+                renderRoleListTable : function(){
+                        var that = this;
+
+                        var tableRow = Backgrid.Row.extend({
+                                render: function () {
+                                        tableRow.__super__.render.apply(this, arguments);
+                                        return this;
+                                },
+
+                        });
+                        this.rTableList.show(new XATableLayout({
+                                columns: this.getRoleColumns(),
+                                collection: this.roleList,
+                                includeFilter : false,
+                                gridOpts : {
+                                        row: tableRow,
+                                        header : XABackgrid,
+                                        emptyText : 'No Groups found!'
+                                }
+                        }));
+                },
+
+                getRoleColumns : function(){
+                        var cols = {
+
+                                select : {
+                                        label : localization.tt("lbl.isVisible"),
+                                        cell: "select-row",
+                                    headerCell: "select-all",
+                                        click : false,
+                                        drag : false,
+                                        editable : false,
+                                        sortable : false
+                                },
+                                name : {
+                                        label	: localization.tt("lbl.roleName"),
+                                        href: function(model){
+                                                return '#!/roles/'+ model.id;
+                                        },
+                                        editable:false,
+                                        sortable:false,
+                                        cell :'uri'
+                                },
+                                users : {
+                                        cell	: Backgrid.HtmlCell.extend({className: 'cellWidth-1'}),
+                                        label : localization.tt("lbl.users"),
+                                        formatter: _.extend({}, Backgrid.CellFormatter.prototype, {
+                                                fromRaw: function (rawValue, model) {
+                                                        if(!_.isUndefined(rawValue) && rawValue.length != 0){
+                                                                var users = rawValue.map(function(m){return m.name});
+                                                                return XAUtil.showMoreAndLessButton(users, model)
+                                                        }else{
+                                                                return '--';
+                                                        }
+                                                }
+                                        }),
+                                        editable : false,
+                                        sortable : false
+                                },
+                                groups : {
+                                        cell	: Backgrid.HtmlCell.extend({className: 'cellWidth-1'}),
+                                        label : localization.tt("lbl.groups"),
+                                        formatter: _.extend({}, Backgrid.CellFormatter.prototype, {
+                                                fromRaw: function (rawValue, model) {
+                                                        if(!_.isUndefined(rawValue) && rawValue.length != 0){
+                                                                var groups = rawValue.map(function(m){return m.name});
+                                                                return XAUtil.showMoreAndLessButton(groups, model)
+                                                        }else{
+                                                                return '--';
+                                                        }
+                                                }
+                                        }),
+                                        editable : false,
+                                        sortable : false
+                                },
+                        };
+            if(!SessionMgr.isSystemAdmin()){
+                delete cols.select;
+            }
+            if(XAUtil.isAuditorOrKMSAuditor(SessionMgr)){
+                cols.name.cell = 'string';
+            }
+                        return this.roleList.constructor.getTableCols(cols, this.roleList);
+                },
+
         showUserList :function(e){
             XAUtil.blockUI();
             var that = this , name , msg = "", content = "" , totalRecords, infoMsg = ""; this.copyUserLists = [];
@@ -646,7 +779,7 @@ define(function(require){
 		onDeleteUser: function(e){
 
 			var that = this;
-			var collection = that.showUsers ? that.collection : that.groupList;
+                        var collection = that.showUsers ? that.collection : (that.showGroups ? that.groupList : that.roleList);
 			var selArr = [];
 			var message = '';
 			collection.each(function(obj){
@@ -669,16 +802,18 @@ define(function(require){
 			if(total_selected == 0){
 				if(that.showUsers){
 					XAUtil.alertBoxWithTimeSet(localization.tt('msg.noDeleteUserRow'));
-				}else{
+                                }else if(that.showGroups){
 					XAUtil.alertBoxWithTimeSet(localization.tt('msg.noDeleteGroupRow'));
+                                }else {
+                                        XAUtil.alertBoxWithTimeSet(localization.tt('msg.noDeleteRoleRow'));
 				}
 				return;
 			}
             if(total_selected == 1) {
-                message = 'Are you sure you want to delete '+(that.showUsers ? 'user':'group')+' \''+ _.escape( jsonUsers.vXStrings[0].value )+'\'?';
+                message = 'Are you sure you want to delete '+(that.showUsers ? 'user': (that.showGroups ? 'group' : 'role'))+' \''+ _.escape( jsonUsers.vXStrings[0].value )+'\'?';
 			}
 			else {
-				message = 'Are you sure you want to delete '+total_selected+' '+(that.showUsers ? 'users':'groups')+'?';
+                                message = 'Are you sure you want to delete '+total_selected+' '+(that.showUsers ? 'user': (that.showGroups ? 'group' : 'role'))+'?';
 			}
 			if(total_selected > 0){
 				XAUtil.confirmPopup({
@@ -706,7 +841,7 @@ define(function(require){
                             		}
                             	});
                             });
-                        }else {
+                        }else if(that.showGroups) {
 							var model = new VXGroup();
                             var count = 0, notDeletedGroupName ="", errorMsgForNotDeletedGroups = "";
                             _.map(jsonUsers.vXStrings, function(m){
@@ -727,6 +862,27 @@ define(function(require){
                             		}
                             	})
                             });
+                                                }else {
+                                                        var model = new VXRole();
+                            var count = 0, notDeletedRoleName ="", errorMsgForNotDeletedRoles = "";
+                            _.map(jsonUsers.vXStrings, function(m){
+                                model.deleteRoles(m.id,{
+                                        success: function(response){
+                                                count += 1;
+                                                that.roleCollection(jsonUsers.vXStrings.length,count,notDeletedRoleName, errorMsgForNotDeletedRoles);
+                                        },
+                                        error:function(response,options){
+                                                count += 1;
+                                        if(response.responseJSON && response.responseJSON.msgDesc){
+                                            errorMsgForNotDeletedRoles += _.escape(response.responseJSON.msgDesc) +"<br>"
+                                        }else{
+                                            notDeletedRoleName += _.escape(m.value) + ", ";
+                                        }
+                                                that.roleList.find(function(model){return model.get('name') === m.value}).selected = false
+                                                that.roleCollection(jsonUsers.vXStrings.length,count, notDeletedRoleName, errorMsgForNotDeletedRoles)
+                                        }
+                                })
+                            });
 						}
 					}
 				});
@@ -764,6 +920,22 @@ define(function(require){
                         }
                 }
         },
+        roleCollection : function(numberOfRole, count ,notDeletedRoleName, errorMsgForNotDeletedRoles){
+                if(count == numberOfRole){
+                        this.roleList.getFirstPage({fetch:true});
+                        this.roleList.selected  = {};
+                        XAUtil.blockUI('unblock');
+                        if(notDeletedRoleName === "" && _.isEmpty(errorMsgForNotDeletedRoles)){
+                                XAUtil.notifySuccess('Success','Role deleted successfully!');
+                        } else {
+                            var msg = "";
+                            if(!_.isEmpty(notDeletedRoleName)){
+                                msg = 'Error occurred during deleting Users: '+ notDeletedRoleName.slice(0 , -2);
+                            }
+                            XAUtil.notifyError('Error', errorMsgForNotDeletedRoles + msg);
+                        }
+                }
+        },
 		addVisualSearch : function(){
 			var that = this;
 			var coll,placeholder;
@@ -780,7 +952,7 @@ define(function(require){
 				                   {text : "User Source", label :"userSource", 'multiple' : true, 'optionsArr' : XAUtil.enumToSelectLabelValuePairs(XAEnums.UserTypes)},
 				                   {text : "User Status", label :"status", 'multiple' : true, 'optionsArr' : XAUtil.enumToSelectLabelValuePairs(XAEnums.ActiveStatus)},
 								];
-			} else {
+            } else if(this.showGroups){
 				placeholder = localization.tt('h.searchForYourGroup');
 				coll = this.groupList;
 				searchOpt = ['Group Name','Group Source', 'Visibility'];//,'Start Date','End Date','Today'];
@@ -788,6 +960,14 @@ define(function(require){
 				                   {text : "Visibility", label :"isVisible", 'multiple' : true, 'optionsArr' : XAUtil.enumToSelectLabelValuePairs(XAEnums.VisibilityStatus)},
 				                   {text : "Group Source", label :"groupSource", 'multiple' : true, 'optionsArr' : XAUtil.enumToSelectLabelValuePairs(XAEnums.GroupTypes)},];
 
+            } else{
+                placeholder = localization.tt('h.searchForYourRole');
+                coll = this.roleList;
+                searchOpt = ['Role Name','User Name', 'Group Name'];//,'Start Date','End Date','Today'];
+                serverAttrName  = [{text : "Role Name", label :"name"},
+                                   {text : "User Name", label :"users"},
+                                   {text : "Group Name", label :"groups"},
+                                  ];
 			}
 			var query = (!_.isUndefined(coll.VSQuery)) ? coll.VSQuery : '';
 			var pluginAttr = {
diff --git a/security-admin/src/main/webapp/styles/xa.css b/security-admin/src/main/webapp/styles/xa.css
index 8b44d3a..b615bfb 100644
--- a/security-admin/src/main/webapp/styles/xa.css
+++ b/security-admin/src/main/webapp/styles/xa.css
@@ -509,7 +509,7 @@ body {
 
 .table-permission {
   float: left;
-  width: 90%
+  width: 100%
 }
 
 /* toggle */
@@ -609,6 +609,7 @@ table td.backgrid-filter .clear {
 
 .table-permission th, .table-permission td {
   border: 1px solid #dddddd;
+  padding: 7px 5px;
 }
 
 .table-permission thead {
@@ -1787,8 +1788,8 @@ margin-bottom: 5px;
 .table .table {
 	width:auto;
 }
-.width-25{
-	width:25%;
+.width-22{
+        width:22%;
 }
 .margin-left-0{
 	margin-left:0%!important;
@@ -2723,4 +2724,75 @@ textarea:read-only{
 }
 div#zoneServiceAccordion table thead {
   background: none;
-}
\ No newline at end of file
+}
+.no-margin {
+  margin: 0 !important;
+}
+.no-padding {
+  padding: 0 !important;
+}
+
+.custom-table{
+  margin-bottom: 0;
+}
+
+.custom-table thead{
+  background-color: #eeeeee;
+}
+
+.custom-table th,
+.custom-table td {
+  text-align: center !important;
+  vertical-align: middle;
+}
+
+.custom-table .js-formInput .select2-container{
+  width: 100%;
+}
+
+.m-l-50 {
+  margin-left: 50px;
+}
+
+.fixed-headertable,
+.fixed-headertable > thead,
+.fixed-headertable > tbody {
+  display: block;
+  width: 100%;
+}
+
+.fixed-headertable > tbody {
+  overflow: auto;
+  max-height: 350px;
+  overflow: overlay;
+}
+
+.fixed-headertable tr{
+  display: table;
+  table-layout: fixed;
+  width: 100%;
+}
+
+.fixed-headertable td,
+.fixed-headertable th{
+  width: 33%;
+  display: table-cell;
+}
+
+.ellipsize{
+  max-width: 100%;
+  white-space: nowrap;
+  text-overflow: ellipsis;
+  overflow: hidden;
+}
+
+/*.fixed-headertable td,
+.fixed-headertable th{
+  width: 100px;
+  display: table-cell;
+}
+
+.fixed-headertable td:first-child,
+.fixed-headertable th:first-child{
+  width: calc(100% - 200px);
+}*/
diff --git a/security-admin/src/main/webapp/templates/common/TopNav_tmpl.html b/security-admin/src/main/webapp/templates/common/TopNav_tmpl.html
index 22df5cb..8ed90aa 100644
--- a/security-admin/src/main/webapp/templates/common/TopNav_tmpl.html
+++ b/security-admin/src/main/webapp/templates/common/TopNav_tmpl.html
@@ -58,7 +58,7 @@
 			<a href="javascript:;" id="nav5"><i class="icon-gear"></i> {{tt 'h.settings'}} </a>
 			<ul class="dropdown-menu">
 				{{#hasAccessToTab  'Users/Groups'}}
-					<li><a href="#!/users/usertab"><i class="icon-group"></i>{{tt 'h.usersOrGroups'}}</a></li>
+                                        <li><a href="#!/users/usertab"><i class="icon-group"></i>{{tt 'h.usersOrGroupsOrRoles'}}</a></li>
 				{{/hasAccessToTab}}	
                                 {{#if showPermissionTab}}
 					<li><a href="#!/permissions"><i class="icon-file-alt"></i> {{tt 'h.permissions'}}</a></li>
diff --git a/security-admin/src/main/webapp/templates/policies/PermissionItem.html b/security-admin/src/main/webapp/templates/policies/PermissionItem.html
index d2b401d..3e60e6e 100644
--- a/security-admin/src/main/webapp/templates/policies/PermissionItem.html
+++ b/security-admin/src/main/webapp/templates/policies/PermissionItem.html
@@ -14,11 +14,14 @@
   See the License for the specific language governing permissions and
   limitations under the License.
 --}}
-<td class="width-25">
-	<input  type="text" data-js="selectGroups" /> 	
+<td class="width-22">
+  <input  type="text" data-js="selectRoles" />
 </td>
-<td class="width-25">
-	<input  type="text" data-js="selectUsers" /> 	
+<td class="width-22">
+        <input  type="text" data-js="selectGroups" />
+</td>
+<td class="width-22">
+        <input  type="text" data-js="selectUsers" />
 </td>
 {{#if policyConditions}}
 <td>	
diff --git a/security-admin/src/main/webapp/templates/policies/PermissionList.html b/security-admin/src/main/webapp/templates/policies/PermissionList.html
index 9972d48..96dcb95 100644
--- a/security-admin/src/main/webapp/templates/policies/PermissionList.html
+++ b/security-admin/src/main/webapp/templates/policies/PermissionList.html
@@ -17,7 +17,7 @@
 	
 <div class="control-group">
 	<!--label class="control-label">{{headerTitle}}</label-->
-	<div class="controls">
+        <div class="controls no-margin no-padding">
 		<table class="table-permission table-condensed">
 			<thead>
 				<tr>
@@ -35,7 +35,7 @@
 
 </div>
 <div class="control-group">
-	<div class="controls" style="margin-top:-14px">
+        <div class="controls no-margin" style="margin-top:-14px">
 		<button type="button" class="btn btn-small" data-action="addGroup" title="Add">
 			<i class="icon-plus"></i>
 		</button>
diff --git a/security-admin/src/main/webapp/templates/policies/RangerPolicyRO_tmpl.html b/security-admin/src/main/webapp/templates/policies/RangerPolicyRO_tmpl.html
index e76ad21..f8c6bce 100644
--- a/security-admin/src/main/webapp/templates/policies/RangerPolicyRO_tmpl.html
+++ b/security-admin/src/main/webapp/templates/policies/RangerPolicyRO_tmpl.html
@@ -192,6 +192,15 @@
 	      {{#each this.policyItems}}
 	      <tr>
           <td>
+            {{#if this.roles}}
+              {{#each this.roles}}
+               <span class="label label-info">{{this}}</span>
+              {{/each}}
+            {{else}}
+                 --
+            {{/if}}
+          </td>
+          <td>
             {{#if this.groups}}
               {{#each this.groups}}
                <span class="label label-info">{{this}}</span>
diff --git a/security-admin/src/main/webapp/templates/reports/RoleOperationDiff_tmpl.html b/security-admin/src/main/webapp/templates/reports/RoleOperationDiff_tmpl.html
new file mode 100644
index 0000000..6e3644d
--- /dev/null
+++ b/security-admin/src/main/webapp/templates/reports/RoleOperationDiff_tmpl.html
@@ -0,0 +1,79 @@
+{{!--
+  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.
+--}}
+<div class="diff-content">
+    <label class="no-margin label-size13-weightbold">Name : {{objectName}}</label>
+    <label class="no-margin label-size13-weightbold"> Date  &nbsp;&nbsp;:  {{objectCreatedDate}}</label>
+    <label class="no-margin label-size13-weightbold" > Created By  &nbsp;&nbsp;:  {{userName}}</label>
+    {{#compare action 'eq' 'create'}}
+        {{#if collection.length}}
+            <h5>Role Detail :</h5>
+            <div class="diff">
+                <div class="diff-left">
+                    <h3>Fields</h3>
+                    <ol class="attr">
+                    {{#each collection}}
+                        <li class="change-row">{{./this.attributes.attributeName}}</li>
+                    {{/each}}
+                    </ol>
+                </div>
+                <div class="diff-right">
+                    <h3>New Value</h3>
+                    <ol class="unstyled data">
+                    {{#each collection}}
+                        {{#if ./this.attributes.newValue}}
+                            {{#compare ./this.attributes.newValue "eq" ''}}
+                                <li>--</li>
+                            {{else}}
+                                <li class="change-row">{{./this.attributes.newValue}}</li>
+                            {{/compare}}
+                        {{else}}
+                            <li>--</li>
+                        {{/if}}
+                    {{/each}}
+                    </ol>
+                </div>
+            </div>
+        {{/if}}
+        {{else}}
+        <label class="no-margin label-size13-weightbold" > Deleted By  &nbsp;&nbsp;:  {{userName}}</label>
+        {{#if collection.length}}
+        <h5>Role Details:</h5>
+            <div class="diff">
+                <div class="diff-left">
+                    <h3>Fields</h3>
+                        <ol class="attr">
+                        {{#each collection}}
+                            <li class="change-row">{{./this.attributes.attributeName}}</li>
+                        {{/each}}
+                        </ol>
+                </div>
+                <div class="diff-right">
+                    <h3>Old Value</h3>
+                        <ol class="unstyled data">
+                        {{#each collection}}
+                            {{#if ./this.attributes.previousValue}}
+                                <li class="change-row">{{./this.attributes.previousValue}}</li>
+                            {{else}}
+                                <li class="change-row">--</li>
+                            {{/if}}
+                        {{/each}}
+                        </ol>
+                </div>
+            </div>
+        {{/if}}
+    {{/compare}}
+</div>
diff --git a/security-admin/src/main/webapp/templates/reports/RoleUpdateOperationDiff_tmpl.html b/security-admin/src/main/webapp/templates/reports/RoleUpdateOperationDiff_tmpl.html
new file mode 100644
index 0000000..f433ecf
--- /dev/null
+++ b/security-admin/src/main/webapp/templates/reports/RoleUpdateOperationDiff_tmpl.html
@@ -0,0 +1,74 @@
+{{!--
+  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.
+--}}
+<div class="diff-content">
+
+    <div class="row-fluid">
+        <div class="span6">
+            <label class="no-margin label-size13-weightbold">Name : {{objectName}}</label>
+            <label class="no-margin label-size13-weightbold"> Date  &nbsp;&nbsp;:  {{objectCreatedDate}}</label>
+            <label class="no-margin label-size13-weightbold" > Updated By  &nbsp;&nbsp;:  {{userName}}</label>
+        </div>
+        <div class="span6 text-right">
+            <div class="add-text legend"></div> Added
+            <div class="delete-text legend"></div> Deleted
+        </div>
+    </div>
+
+    <h5>Role Detail :</h5>
+    <div class="diff">
+        <div class="diff-left">
+            <h3>Fields</h3>
+            <ol class="attr">
+            {{#each collection}}
+                <li class="change-row">{{./this.attributes.attributeName}}</li>
+            {{/each}}
+            </ol>
+        </div>
+        <div class="diff-left">
+            <h3>Old Value</h3>
+            <ol class="unstyled data">
+            {{#each collection}}
+                {{#if ./this.attributes.previousValue}}
+                    {{#compare ./this.attributes.previousValue "eq" ''}}
+                            <li>--</li>
+                    {{else}}
+                            <li class="change-row">{{{highlightNewForAttr ./this.attributes.newValue ./this.attributes.previousValue 'old'}}}</li>
+                    {{/compare}}
+                {{else}}
+                        <li>--</li>
+                {{/if}}
+            {{/each}}
+            </ol>
+        </div>
+        <div class="diff-right">
+            <h3>New Value</h3>
+            <ol class="unstyled data">
+            {{#each collection}}
+                {{#if ./this.attributes.newValue}}
+                    {{#compare ./this.attributes.newValue "eq" ''}}
+                        <li>--</li>
+                    {{else}}
+                        <li class="change-row">{{{highlightNewForAttr ./this.attributes.newValue ./this.attributes.previousValue 'new'}}}</li>
+                    {{/compare}}
+                {{else}}
+                    <li>--</li>
+                {{/if}}
+            {{/each}}
+            </ol>
+        </div>
+    </div>
+</div>
\ No newline at end of file
diff --git a/security-admin/src/main/webapp/templates/policies/PermissionList.html b/security-admin/src/main/webapp/templates/users/AddUserOrGroupsItem_tmpl.html
similarity index 57%
copy from security-admin/src/main/webapp/templates/policies/PermissionList.html
copy to security-admin/src/main/webapp/templates/users/AddUserOrGroupsItem_tmpl.html
index 9972d48..0f264fd 100644
--- a/security-admin/src/main/webapp/templates/policies/PermissionList.html
+++ b/security-admin/src/main/webapp/templates/users/AddUserOrGroupsItem_tmpl.html
@@ -1,4 +1,4 @@
-{{!-- 
+{{!--
   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.
@@ -14,30 +14,14 @@
   See the License for the specific language governing permissions and
   limitations under the License.
 --}}
-	
-<div class="control-group">
-	<!--label class="control-label">{{headerTitle}}</label-->
-	<div class="controls">
-		<table class="table-permission table-condensed">
-			<thead>
-				<tr>
-					{{#each permHeaders}}
-					<th>{{./this}}</th>
-					{{/each}}
-
-				</tr>
-			</thead>
-			<tbody class="js-formInput permissionItemSortable">
-
-			</tbody>
-		</table>
-	</div>
-
-</div>
-<div class="control-group">
-	<div class="controls" style="margin-top:-14px">
-		<button type="button" class="btn btn-small" data-action="addGroup" title="Add">
-			<i class="icon-plus"></i>
-		</button>
-	</div>
-</div>
\ No newline at end of file
+<td width="300px">
+    <div class="ellipsize" title={{usersGroupsName}}>{{usersGroupsName}}</div>
+</td>
+<td>
+    <input data-js="isRoleAdmin" type="checkbox">
+</td>
+<td>
+    <button type="button" class="btn btn-small btn-danger" data-action="delete">
+        <i class="icon-remove"></i>
+    </button>
+</td>
\ No newline at end of file
diff --git a/security-admin/src/main/webapp/templates/users/AddUserOrGroupsList_tmpl.html b/security-admin/src/main/webapp/templates/users/AddUserOrGroupsList_tmpl.html
new file mode 100644
index 0000000..1371f47
--- /dev/null
+++ b/security-admin/src/main/webapp/templates/users/AddUserOrGroupsList_tmpl.html
@@ -0,0 +1,39 @@
+{{!--
+  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.
+--}}
+<div class="control-group m-l-50">
+    <div class="table-responsive">
+        <table class="table table-bordered custom-table table-condensed fixed-headertable">
+            <thead>
+                <tr>
+                    <th class="renderable" style="text-align: center;">{{headerName}}</th>
+                    <th class="renderable" style="text-align: center;">Is Role Admin</th>
+                    <th class="renderable" style="text-align: center;">Action</th>
+                </tr>
+            </thead>
+            <tbody class="js-formInput" data-id="userGroupsTable">
+            </tbody>
+        </table>
+    </div>
+</div>
+<div class="control-group m-l-50">
+    <div class="">
+        <input  type="text" data-js="selectUsersOrGroups"/>
+        <button type="button" class="btn btn-primary" data-action="addUserGroup" title="Add">
+            {{btnLable}}
+        </button>
+    </div>
+</div>
\ No newline at end of file
diff --git a/security-admin/src/main/webapp/templates/policies/PermissionList.html b/security-admin/src/main/webapp/templates/users/RoleCreate_tmpl.html
similarity index 57%
copy from security-admin/src/main/webapp/templates/policies/PermissionList.html
copy to security-admin/src/main/webapp/templates/users/RoleCreate_tmpl.html
index 9972d48..efcdb55 100644
--- a/security-admin/src/main/webapp/templates/policies/PermissionList.html
+++ b/security-admin/src/main/webapp/templates/users/RoleCreate_tmpl.html
@@ -1,4 +1,4 @@
-{{!-- 
+{{!--
   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.
@@ -14,30 +14,15 @@
   See the License for the specific language governing permissions and
   limitations under the License.
 --}}
-	
-<div class="control-group">
-	<!--label class="control-label">{{headerTitle}}</label-->
-	<div class="controls">
-		<table class="table-permission table-condensed">
-			<thead>
-				<tr>
-					{{#each permHeaders}}
-					<th>{{./this}}</th>
-					{{/each}}
-
-				</tr>
-			</thead>
-			<tbody class="js-formInput permissionItemSortable">
-
-			</tbody>
-		</table>
-	</div>
-
-</div>
-<div class="control-group">
-	<div class="controls" style="margin-top:-14px">
-		<button type="button" class="btn btn-small" data-action="addGroup" title="Add">
-			<i class="icon-plus"></i>
-		</button>
-	</div>
+<h4 class="wrap-header bold"> Role Detail </h4>
+<div class="wrap non-collapsible ">
+    <div data-id="r_form"></div>
+        <div class="form-actions form-policy">
+        <button type="button" data-id="save" class="btn btn-primary">
+            Save
+        </button>
+        <button type="button" data-id="cancel" class="btn btn-inverse">
+            Cancel
+        </button>
+    </div>
 </div>
\ No newline at end of file
diff --git a/security-admin/src/main/webapp/templates/policies/PermissionList.html b/security-admin/src/main/webapp/templates/users/RoleForm_tmpl.html
similarity index 55%
copy from security-admin/src/main/webapp/templates/policies/PermissionList.html
copy to security-admin/src/main/webapp/templates/users/RoleForm_tmpl.html
index 9972d48..05b4acd 100644
--- a/security-admin/src/main/webapp/templates/policies/PermissionList.html
+++ b/security-admin/src/main/webapp/templates/users/RoleForm_tmpl.html
@@ -1,4 +1,4 @@
-{{!-- 
+{{!--
   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.
@@ -14,30 +14,23 @@
   See the License for the specific language governing permissions and
   limitations under the License.
 --}}
-	
-<div class="control-group">
-	<!--label class="control-label">{{headerTitle}}</label-->
-	<div class="controls">
-		<table class="table-permission table-condensed">
-			<thead>
-				<tr>
-					{{#each permHeaders}}
-					<th>{{./this}}</th>
-					{{/each}}
-
-				</tr>
-			</thead>
-			<tbody class="js-formInput permissionItemSortable">
-
-			</tbody>
-		</table>
-	</div>
-
-</div>
-<div class="control-group">
-	<div class="controls" style="margin-top:-14px">
-		<button type="button" class="btn btn-small" data-action="addGroup" title="Add">
-			<i class="icon-plus"></i>
-		</button>
-	</div>
-</div>
\ No newline at end of file
+<form class="form-horizontal" >
+    <div class="" data-fields="name"></div>
+    <div class="" data-fields="description"></div>
+    <div class="form-horizontal">
+        <p class="formHeader"> Users : </p>
+        <div class="control-group">
+            <div class="span8">
+               <div data-name="userTableLayout"></div>
+            </div>
+        </div>
+    </div>
+    <div class="form-horizontal">
+        <p class="formHeader"> Groups : </p>
+        <div class="control-group">
+            <div class="span8">
+                <div data-name="groupTableLayout"></div>
+            </div>
+        </div>
+    </div>
+</form>
\ No newline at end of file
diff --git a/security-admin/src/main/webapp/templates/users/UserTableLayout_tmpl.html b/security-admin/src/main/webapp/templates/users/UserTableLayout_tmpl.html
index d99b3b4..6562bac 100644
--- a/security-admin/src/main/webapp/templates/users/UserTableLayout_tmpl.html
+++ b/security-admin/src/main/webapp/templates/users/UserTableLayout_tmpl.html
@@ -15,6 +15,9 @@
   limitations under the License.
 --}}
   <ul class="nav nav-tabs tabs clearfix">
+    <li data="roles" data-js="roles">
+      <a data-toggle="tab" href="#roles">Roles</a>
+    </li>
     <li data="groups" data-js="groups"> 
       <a data-toggle="tab" href="#groups">Groups</a> 
     </li>
@@ -31,10 +34,10 @@
 		</div>
 		<div class="clearfix" data-id="addNewBtnDiv">
 			{{#isSystemAdmin .}}
-				<a href="javascript:void(0);" data-id="deleteUserGroup" title="Permanently delete selected users/groups" class="btn btn-primary btn-right btn-danger"><i class="icon-trash icon-large" /></a>
+                                <a href="javascript:void(0);" data-id="deleteUserGroup" title="Permanently delete selected users/groups/roles" class="btn btn-primary btn-right btn-danger"><i class="icon-trash icon-large" /></a>
 			{{/isSystemAdmin}}
       {{#isSystemAdmin .}}
-      <div class="btn-group btn-right">
+      <div class="btn-group btn-right" data-id="hideShowVisibility">
         <a class="btn btn-primary dropdown-toggle" data-toggle="dropdown" href="javascript:void(0);">
           {{tt 'btn.setVisibility'}}
           <span class="caret"></span>
@@ -46,6 +49,7 @@
       </div>
       <a href="#!/user/create" class="btn btn-primary btn-right" type="button" data-id="addNewUser"> {{tt 'lbl.addNewUser'}} </a>
       <a href="#!/group/create" class="btn btn-primary btn-right" type="button" data-id="addNewGroup" style="display:none;"> {{tt 'lbl.addNewGroup'}} </a>
+      <a href="#!/roles/create" class="btn btn-primary btn-right" type="button" data-id="addNewRoles" style="display:none;"> {{tt 'lbl.addNewRole'}} </a>
       {{/isSystemAdmin}}
 		</div>
                 <div data-id="r_tableList">
diff --git a/security-admin/src/test/java/org/apache/ranger/biz/TestServiceDBStore.java b/security-admin/src/test/java/org/apache/ranger/biz/TestServiceDBStore.java
index 00ef5e3..dc845cf 100644
--- a/security-admin/src/test/java/org/apache/ranger/biz/TestServiceDBStore.java
+++ b/security-admin/src/test/java/org/apache/ranger/biz/TestServiceDBStore.java
@@ -1565,6 +1565,7 @@ public class TestServiceDBStore {
 		policyItemAccess.setType("1");
 		List<String> usersList = new ArrayList<String>();
 		List<String> groupsList = new ArrayList<String>();
+		List<String> rolesList = new ArrayList<String>();
                 List<String> policyLabels = new ArrayList<String>();
 		List<RangerPolicyItemCondition> conditionsList = new ArrayList<RangerPolicyItemCondition>();
 		RangerPolicyItemCondition policyItemCondition = new RangerPolicyItemCondition();
@@ -1583,7 +1584,7 @@ public class TestServiceDBStore {
 
 		List<RangerPolicyItem> policyItemsSet = new ArrayList<RangerPolicy.RangerPolicyItem>();
 		RangerPolicyItem paramPolicyItem = new RangerPolicyItem(accessesList,
-				usersList, groupsList, conditionsList, false);
+				usersList, groupsList, rolesList, conditionsList, false);
 		paramPolicyItem.setDelegateAdmin(false);
 		paramPolicyItem.setAccesses(accessesList);
 		paramPolicyItem.setConditions(conditionsList);