You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ranger.apache.org by ni...@apache.org on 2020/10/26 13:20:49 UTC

[ranger] branch master updated: RANGER-2996 : Add search by Roles and Auditor user should be able to see Roles tab.4

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

ni3galave 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 72a3f94  RANGER-2996 : Add search by Roles and Auditor user should be able to see Roles tab.4
72a3f94 is described below

commit 72a3f9442ef7084323036c0682d5ff65b981d65e
Author: Nitin Galave <ni...@apache.org>
AuthorDate: Mon Oct 19 18:09:45 2020 +0530

    RANGER-2996 : Add search by Roles and Auditor user should be able to see Roles tab.4
---
 .../java/org/apache/ranger/biz/RoleDBStore.java    |  59 +++++++++-
 .../main/java/org/apache/ranger/db/XXRoleDao.java  |  15 +++
 .../main/java/org/apache/ranger/rest/RoleREST.java |  26 ++++-
 .../ranger/service/RangerPolicyServiceBase.java    |   2 +-
 .../main/resources/META-INF/jpa_named_queries.xml  |   9 ++
 .../views/policymanager/ServiceLayoutSidebar.js    |   3 +-
 .../scripts/views/reports/UserAccessLayout.js      | 125 ++++++++++++++++++---
 .../webapp/scripts/views/users/UserTableLayout.js  |   2 +
 .../common/ServiceManagerSidebarLayout_tmpl.html   |   2 +
 .../templates/reports/UserAccessLayout_tmpl.html   |   2 +
 10 files changed, 227 insertions(+), 18 deletions(-)

diff --git a/security-admin/src/main/java/org/apache/ranger/biz/RoleDBStore.java b/security-admin/src/main/java/org/apache/ranger/biz/RoleDBStore.java
index 6ef5fe5..6483bbe 100644
--- a/security-admin/src/main/java/org/apache/ranger/biz/RoleDBStore.java
+++ b/security-admin/src/main/java/org/apache/ranger/biz/RoleDBStore.java
@@ -30,9 +30,12 @@ import org.apache.commons.lang.StringUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.ranger.authorization.hadoop.config.RangerAdminConfig;
+import org.apache.ranger.common.ContextUtil;
 import org.apache.ranger.common.MessageEnums;
 import org.apache.ranger.common.RESTErrorUtil;
+import org.apache.ranger.common.RangerConstants;
 import org.apache.ranger.common.RangerRoleCache;
+import org.apache.ranger.common.UserSessionBase;
 import org.apache.ranger.common.db.RangerTransactionSynchronizationAdapter;
 import org.apache.ranger.db.RangerDaoManager;
 import org.apache.ranger.entity.*;
@@ -43,7 +46,9 @@ import org.apache.ranger.plugin.store.RoleStore;
 import org.apache.ranger.plugin.util.RangerRoles;
 import org.apache.ranger.plugin.util.SearchFilter;
 import org.apache.ranger.service.RangerRoleService;
+import org.apache.ranger.service.XUserService;
 import org.apache.ranger.view.RangerRoleList;
+import org.apache.ranger.view.VXUser;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
@@ -60,6 +65,9 @@ public class RoleDBStore implements RoleStore {
     RangerRoleService roleService;
 
     @Autowired
+    XUserService xUserService;
+
+    @Autowired
     RangerDaoManager daoMgr;
 
     @Autowired
@@ -282,7 +290,56 @@ public class RoleDBStore implements RoleStore {
     	rangerRoleList.setRoleList(roles);
     	return rangerRoleList;
     }
-    
+
+    public RangerRoleList getRolesForUser(SearchFilter filter, RangerRoleList rangerRoleList) throws Exception {
+		List<RangerRole> roles = new ArrayList<RangerRole>();
+		List<XXRole> xxRoles = null;
+		UserSessionBase userSession = ContextUtil.getCurrentUserSession();
+		if (userSession != null && userSession.getUserRoleList().size() == 1
+				&& userSession.getUserRoleList().contains(RangerConstants.ROLE_USER)
+				&& userSession.getLoginId() != null) {
+			VXUser loggedInVXUser = xUserService.getXUserByUserName(userSession.getLoginId());
+			xxRoles = daoMgr.getXXRole().findByUserId(loggedInVXUser.getId());
+
+			if (CollectionUtils.isNotEmpty(xxRoles)) {
+				for (XXRole xxRole : xxRoles) {
+					roles.add(roleService.read(xxRole.getId()));
+				}
+			}
+			if (predicateUtil != null && filter != null && !filter.isEmpty()) {
+                List<RangerRole> copy = new ArrayList<>(roles);
+
+                predicateUtil.applyFilter(copy, filter);
+                roles = copy;
+            }
+			int totalCount = roles.size();
+			int startIndex = filter.getStartIndex();
+			int pageSize = filter.getMaxRows();
+			int toIndex = Math.min(startIndex + pageSize, totalCount);
+			if (CollectionUtils.isNotEmpty(roles)) {
+				roles = roles.subList(startIndex, toIndex);
+				rangerRoleList.setResultSize(roles.size());
+				rangerRoleList.setPageSize(filter.getMaxRows());
+				rangerRoleList.setSortBy(filter.getSortBy());
+				rangerRoleList.setSortType(filter.getSortType());
+				rangerRoleList.setStartIndex(filter.getStartIndex());
+				rangerRoleList.setTotalCount(totalCount);
+			}
+		} else {
+			xxRoles = (List<XXRole>) roleService.searchResources(filter, roleService.searchFields,
+					roleService.sortFields, rangerRoleList);
+
+			if (CollectionUtils.isNotEmpty(xxRoles)) {
+				for (XXRole xxRole : xxRoles) {
+					roles.add(roleService.read(xxRole.getId()));
+				}
+			}
+		}
+		rangerRoleList.setRoleList(roles);
+
+		return rangerRoleList;
+	}
+
     @Override
     public List<String> getRoleNames(SearchFilter filter) throws Exception {
         return daoMgr.getXXRole().getAllNames();
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
index 8528652..35d7188 100644
--- a/security-admin/src/main/java/org/apache/ranger/db/XXRoleDao.java
+++ b/security-admin/src/main/java/org/apache/ranger/db/XXRoleDao.java
@@ -96,5 +96,20 @@ public class XXRoleDao extends BaseDao<XXRole> {
             return new ArrayList<String>();
         }
     }
+
+    @SuppressWarnings("unchecked")
+	public List<XXRole> findByUserId(Long UserId) {
+		if (UserId == null) {
+			return null;
+		}
+		List<XXRole> ret;
+		try {
+			ret = getEntityManager().createNamedQuery("XXRole.findByUserId", tClass).setParameter("userId", UserId)
+					.getResultList();
+		} catch (NoResultException e) {
+			ret = ListUtils.EMPTY_LIST;
+		}
+		return ret;
+	}
 }
 
diff --git a/security-admin/src/main/java/org/apache/ranger/rest/RoleREST.java b/security-admin/src/main/java/org/apache/ranger/rest/RoleREST.java
index be3bf2f..86cda07 100644
--- a/security-admin/src/main/java/org/apache/ranger/rest/RoleREST.java
+++ b/security-admin/src/main/java/org/apache/ranger/rest/RoleREST.java
@@ -316,7 +316,7 @@ public class RoleREST {
         return ret;
     }
 
-    /* This operation is allowed only when effective User has ranger admin privilege
+    /* This operation is allowed only when effective User has ranger admin or auditor privilege
      * if execUser is not same as logged-in user then effective user is execUser
      * else  effective user is logged-in user.
      * This logic is implemented as part of ensureAdminAccess(String serviceName, String userName);
@@ -331,7 +331,6 @@ public class RoleREST {
         }
         SearchFilter filter = searchUtil.getSearchFilter(request, roleService.sortFields);
         try {
-            ensureAdminAccess(null, null);
             roleStore.getRoles(filter,ret);
         } catch(WebApplicationException excp) {
             throw excp;
@@ -346,6 +345,29 @@ public class RoleREST {
         return ret;
     }
 
+    @GET
+    @Path("/lookup/roles")
+    public RangerRoleList getAllRolesForUser(@Context HttpServletRequest request) {
+        RangerRoleList ret = new RangerRoleList();
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("==> getAllRolesForUser()");
+        }
+        SearchFilter filter = searchUtil.getSearchFilter(request, roleService.sortFields);
+        try {
+            roleStore.getRolesForUser(filter,ret);
+        } 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 operation is allowed only when effective User has ranger admin privilege
      * if execUser is not same as logged-in user then effective user is execUser
      * else  effective user is logged-in user.
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 bcbca09..e8c593d 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
@@ -71,7 +71,7 @@ public abstract class RangerPolicyServiceBase<T extends XXPolicyBase, V extends
 				"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 "
+				"XXRole xRole , XXPolicyRefRole refRole", "obj.id = refRole.policyId "
 				+ "and xRole.id = refRole.roleId"));
 		//might need updation
 		/*searchFields.add(new SearchField(SearchFilter.POL_RESOURCE, "resMap.value", DATA_TYPE.STRING,
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 0cf9295..d608ff8 100755
--- a/security-admin/src/main/resources/META-INF/jpa_named_queries.xml
+++ b/security-admin/src/main/resources/META-INF/jpa_named_queries.xml
@@ -1783,4 +1783,13 @@
 		<query>select obj from XXRMSMappingProvider obj where obj.name = :name</query>
 	</named-query>
 
+	<named-query name="XXRole.findByUserId">
+		<query>SELECT obj FROM XXRole obj
+				WHERE obj.id IN (SELECT roleRefUser.roleId FROM XXRoleRefUser roleRefUser WHERE roleRefUser.userId = :userId)
+				OR obj.id IN (SELECT roleRefGroup.roleId FROM XXRoleRefGroup roleRefGroup WHERE roleRefGroup.groupId IN
+				(SELECT groupUser.parentGroupId FROM XXGroupUser groupUser WHERE groupUser.userId = :userId))
+				order by obj.id
+		</query>
+	</named-query>
+
 </entity-mappings>
diff --git a/security-admin/src/main/webapp/scripts/views/policymanager/ServiceLayoutSidebar.js b/security-admin/src/main/webapp/scripts/views/policymanager/ServiceLayoutSidebar.js
index 42722b0..67a577c 100644
--- a/security-admin/src/main/webapp/scripts/views/policymanager/ServiceLayoutSidebar.js
+++ b/security-admin/src/main/webapp/scripts/views/policymanager/ServiceLayoutSidebar.js
@@ -111,7 +111,8 @@ define(function(require){
             'searchBtn'           : '[data-js="searchBtn"]',
             'userName'            : '[data-js="userName"]',
             'selectServiceName'   : '[data-js="serviceName"]',
-            'profileTab'          : '.profile-tab'
+            'profileTab'          : '.profile-tab',
+            'roleName'            : '[data-js="roleName"]',
 
         },
 
diff --git a/security-admin/src/main/webapp/scripts/views/reports/UserAccessLayout.js b/security-admin/src/main/webapp/scripts/views/reports/UserAccessLayout.js
index df052cb..146e3f3 100644
--- a/security-admin/src/main/webapp/scripts/views/reports/UserAccessLayout.js
+++ b/security-admin/src/main/webapp/scripts/views/reports/UserAccessLayout.js
@@ -87,6 +87,7 @@ define(function(require) {'use strict';
 			policyLabels		: '[data-id="policyLabels"]',
 			zoneName			: '[data-id="zoneName"]',
             selectUserGroup		: '[data-id="btnUserGroup"]',
+            roleName 			: '[data-js="roleName"]',
 
 		},
 
@@ -169,6 +170,7 @@ define(function(require) {'use strict';
 				this.ui.selectUserGroup = sidebarUiElement.selectUserGroup;
 				this.ui.userName = sidebarUiElement.userName;
 				this.ui.searchBtn = sidebarUiElement.searchBtn;
+				this.ui.roleName = sidebarUiElement.roleName;
 			}
 			this.initializePlugins();
                         if( this.urlQueryParams) {
@@ -184,13 +186,25 @@ define(function(require) {'use strict';
                                         this.setupUserAutoComplete();
                                         this.ui.userGroup.select2('destroy');
                                         this.ui.userGroup.val('').hide();
-                                        this.ui.selectUserGroup.find('span').first().text('Username')
-                                } else {
+                                        this.ui.roleName.select2('destroy');
+                                        this.ui.roleName.val('').hide();
+                                        this.ui.selectUserGroup.text('Username')
+                                } else if (!_.isUndefined(this.urlParam['group']) && !_.isEmpty(this.urlParam['group'])) {
                                         this.ui.userGroup.show();
                                         this.setupGroupAutoComplete();
                                         this.ui.userName.select2('destroy');
                                         this.ui.userName.val('').hide();
-                                        this.ui.selectUserGroup.find('span').first().text('Group')
+                                        this.ui.roleName.select2('destroy');
+                                        this.ui.roleName.val('').hide();
+                                        this.ui.selectUserGroup.text('Group')
+                                } else {
+                                        this.ui.roleName.show();
+                                        this.setupRoleAutoComplete();
+                                        this.ui.userGroup.select2('destroy');
+                                        this.ui.userGroup.val('').hide();
+                                        this.ui.userName.select2('destroy');
+                                        this.ui.userName.val('').hide();
+                                        this.ui.selectUserGroup.text('Rolename')
                                 }
                         } else {
                                 this.setupGroupAutoComplete();
@@ -263,7 +277,39 @@ define(function(require) {'use strict';
 		getSubgridColumns:function(coll,collName,serviceDefName){
 			var that = this;
 
-			var subcolumns = [{
+			var subcolumns = [
+				{
+					name: 'roles',
+					cell: 'html',
+					label: 'Roles',
+					formatter: _.extend({}, Backgrid.CellFormatter.prototype, {
+						fromRaw: function (rawValue,model, coll) {
+							var role_str = '';
+							if(_.isEmpty(model.get('roles'))){
+								return '<center>--</center>';
+							} else {
+								_.each(model.get('roles'),function(role,index){
+									if(index < 4) {
+										role_str += '<span class="badge badge-info cellWidth-1 float-left-margin-2" role-policy-id="'+model.cid+'" style="">' + _.escape(role) + '</span>'  + " ";
+									} else {
+										role_str += '<span class="badge badge-info cellWidth-1 float-left-margin-2" role-policy-id="'+model.cid+'" style="display:none">' + _.escape(role) + '</span>'  + " ";
+									}
+								});
+								if(model.get('roles').length > 4) {
+									role_str += '<span class="pull-left float-left-margin-2">\
+									<a href="javascript:void(0);" data-id="showMoreAccess" policy-id="'+
+									model.cid+'"><code style=""> + More..</code></a></span>\
+									<span class="pull-left float-left-margin-2" ><a href="javascript:void(0);" data-id="showLessAccess" policy-id="'+
+									model.cid+'" style="display:none;"><code style=""> - Less..</code></a></span>';}
+									return role_str;
+								}
+						}
+					}),
+					editable: false,
+					click: false,
+					sortable: false
+				},
+				{
 					name: 'groups',
 					cell: 'html',
 					label: 'Groups',
@@ -633,15 +679,13 @@ define(function(require) {'use strict';
 				//maximumSelectionSize : 1,
                                 value : (!_.isUndefined(that.urlParam) && !_.isUndefined(that.urlParam['serviceType']) && !_.isEmpty(that.urlParam['serviceType'])) ?
                                                 this.ui.componentType.val(that.urlParam['serviceType']) : this.ui.componentType.val(""),
-				width: '220px',
 				allowClear: true,
 				data: options
 			});
 			this.ui.policyType.select2({
 				closeOnSelect: false,
 				maximumSelectionSize : 1,
-				width: '220px',
-                                value : (!_.isUndefined(that.urlParam) && !_.isUndefined(that.urlParam['policyType']) && !_.isEmpty(that.urlParam['policyType'])) ?
+				value : (!_.isUndefined(that.urlParam) && !_.isUndefined(that.urlParam['policyType']) && !_.isEmpty(that.urlParam['policyType'])) ?
                                                 this.ui.policyType.val(that.urlParam['policyType']) : this.ui.policyType.val("0"),
 				allowClear: false,
 				data: policyTypes
@@ -650,7 +694,6 @@ define(function(require) {'use strict';
                                 multiple: true,
                 closeOnSelect : true,
                 placeholder : 'Policy Label',
-                width :'220px',
                 allowClear: true,
                 tokenSeparators: ["," , " "],
                 tags : true,
@@ -700,7 +743,6 @@ define(function(require) {'use strict';
 			this.ui.zoneName.select2({
 				closeOnSelect: false,
 				maximumSelectionSize : 1,
-				width: '220px',
 				allowClear: true,
 				data: zoneListOptions,
 				placeholder: 'Select Zone Name',
@@ -763,7 +805,6 @@ define(function(require) {'use strict';
 				closeOnSelect : true,
 				placeholder : 'Select Group',
 				maximumSelectionSize : 1,
-				width :'220px',
 				tokenSeparators: [",", " "],
 				allowClear: true,
 				// tags : this.groupArr,
@@ -810,7 +851,6 @@ define(function(require) {'use strict';
 			this.ui.userName.select2({
 				closeOnSelect : true,
 				placeholder : 'Select User',
-				width :'220px',
 				allowClear: true,
 				initSelection : function (element, callback) {
                                         var data = {};
@@ -851,6 +891,52 @@ define(function(require) {'use strict';
                                 this.ui.userName.val(this.urlParam['user']).trigger('change');
                         }
 		},
+
+		setupRoleAutoComplete : function(){
+			var that = this;
+			this.ui.roleName.select2({
+				closeOnSelect : true,
+				placeholder : 'Select Role',
+				allowClear: true,
+				initSelection : function (element, callback) {
+                                        var data = {};
+                                        data = {id: element.val(), text: element.val()};
+					callback(data);
+				},
+				ajax: {
+					url: "service/roles/roles",
+					dataType: 'json',
+					data: function (term, page) {
+						return {roleNamePartial : term};
+					},
+					results: function (data, page) {
+						var results = [],selectedVals=[];
+						if(!_.isEmpty(that.ui.roleName.select2('val')))
+							selectedVals = that.ui.roleName.select2('val');
+						if(data.totalCount != "0"){
+							results = data.roles.map(function(m){	return {id : _.escape(m.name), text: _.escape(m.name) };});
+							if(!_.isEmpty(selectedVals))
+								results = XAUtil.filterResultByIds(results, selectedVals);
+							return {results : results};
+						}
+						return {results : results};
+					}
+				},
+				formatResult : function(result){
+					return result.text;
+				},
+				formatSelection : function(result){
+					return result.text;
+				},
+				formatNoMatches: function(result){
+					return 'No user found.';
+				}
+			})//.on('select2-focus', XAUtil.select2Focus);
+                        if(this.urlParam && this.urlParam['role'] && !_.isEmpty(this.urlParam['role'])) {
+                                this.ui.roleName.val(this.urlParam['role']).trigger('change');
+                        }
+		},
+
 		/** all post render plugin initialization */
 		initializePlugins : function() {
 			var that = this;
@@ -890,9 +976,10 @@ define(function(require) {'use strict';
 			//Get search values
                         var groups = (this.ui.selectUserGroup.text().trim() == "Group" ) ? this.ui.userGroup.select2('val'):undefined;
                         var users = (this.ui.selectUserGroup.text().trim() == "Username") ? this.ui.userName.select2('val'):undefined;
+                        var roles = (this.ui.selectUserGroup.text().trim() == "Rolename") ? this.ui.roleName.select2('val'):undefined;
 			var rxName = this.ui.resourceName.val(), policyName = this.ui.policyName.val() , policyType = this.ui.policyType.val(),
 			policyLabel = this.ui.policyLabels.val(), zoneName = this.ui.zoneName.val()
-			var params = {group : groups, user : users, polResource : rxName, policyNamePartial : policyName, policyType: policyType, policyLabelsPartial:policyLabel,
+			var params = {group : groups, user : users, role : roles, polResource : rxName, policyNamePartial : policyName, policyType: policyType, policyLabelsPartial:policyLabel,
 				zoneName : zoneName};
 			var component = (this.ui.componentType.val() != "") ? this.ui.componentType.select2('val'):undefined;
                         urlParam = _.extend(params, {'serviceType': this.ui.componentType.val()});
@@ -972,12 +1059,24 @@ define(function(require) {'use strict';
 				this.setupGroupAutoComplete();
 				this.ui.userName.select2('destroy');
 				this.ui.userName.val('').hide();
-			} else {
+				this.ui.roleName.select2('destroy');
+				this.ui.roleName.val('').hide();
+			} else if ($el.data('id')== "userSel") {
 				this.ui.userGroup.select2('destroy');
 				this.ui.userGroup.val('').hide();
 				this.ui.userName.show();
 				this.setupUserAutoComplete();
 				$button.text('Username');
+				this.ui.roleName.select2('destroy');
+				this.ui.roleName.val('').hide();
+			}else {
+				this.ui.userGroup.select2('destroy');
+				this.ui.userGroup.val('').hide();
+				this.ui.roleName.show();
+				this.setupRoleAutoComplete();
+				$button.text('Rolename');
+				this.ui.userName.select2('destroy');
+				this.ui.userName.val('').hide();
 			}
 		},
 		setDownloadFormatFilter : function(e){
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 4d58b21..b8270d9 100755
--- a/security-admin/src/main/webapp/scripts/views/users/UserTableLayout.js
+++ b/security-admin/src/main/webapp/scripts/views/users/UserTableLayout.js
@@ -109,6 +109,7 @@ define(function(require){
 			}
 			if(_.isUndefined(this.roleList)){
 				this.roleList = new VXRoleList();
+				this.roleList.url = "service/roles/lookup/roles";
 			}
 
 			this.bindEvents();
@@ -323,6 +324,7 @@ define(function(require){
                         this.ui.hideShowVisibility.hide();
                         if(_.isUndefined(this.roleList) || _.isUndefined(this.urlQueryParams) || _.isEmpty(this.urlQueryParams)){
                                 this.roleList = new VXRoleList();
+                                this.roleList.url = "service/roles/lookup/roles";
                         }
                         this.ui.addNewUser.hide();
                         this.ui.addNewGroup.hide();
diff --git a/security-admin/src/main/webapp/templates/common/ServiceManagerSidebarLayout_tmpl.html b/security-admin/src/main/webapp/templates/common/ServiceManagerSidebarLayout_tmpl.html
index b61dd45..9b64a21 100644
--- a/security-admin/src/main/webapp/templates/common/ServiceManagerSidebarLayout_tmpl.html
+++ b/security-admin/src/main/webapp/templates/common/ServiceManagerSidebarLayout_tmpl.html
@@ -214,10 +214,12 @@
                                     <ul class="dropdown-menu">
                                         <a data-id="grpSel" class="autoText dropdown-item" href="javascript:;">Group</a>
                                         <a data-id="userSel" class="autoText dropdown-item" href="javascript:;">Username</a>
+                                        <a data-id="roleSel" class="autoText dropdown-item" href="javascript:;">Rolename</a>
                                     </ul>
                                 </div>
                                 <input type="text" data-js="selectGroups">
                                 <input type="text" style="display: none" data-js="userName">
+                                <input type="text" style="display: none" data-js="roleName">
                             </div>
                         </div>
                     </div>
diff --git a/security-admin/src/main/webapp/templates/reports/UserAccessLayout_tmpl.html b/security-admin/src/main/webapp/templates/reports/UserAccessLayout_tmpl.html
index 99d04cb..d69a6ec 100644
--- a/security-admin/src/main/webapp/templates/reports/UserAccessLayout_tmpl.html
+++ b/security-admin/src/main/webapp/templates/reports/UserAccessLayout_tmpl.html
@@ -89,10 +89,12 @@
                                     <div class="dropdown-menu">
                                         <a data-id="grpSel" class="autoText dropdown-item" href="javascript:;">Group</a>
                                         <a data-id="userSel" class="autoText dropdown-item" href="javascript:;">Username</a>
+                                        <a data-id="roleSel" class="autoText dropdown-item" href="javascript:;">Rolename</a>
                                     </div>
                                 </div>
                                 <input type="text" class="form-control" data-js="selectGroups">
                                 <input type="text" class="form-control" style="display: none" data-js="userName">
+                                <input type="text" class="form-control" style="display: none" data-js="roleName">
                             </div>
                         </div>
                     </div>