ITIL role users must only be able to see incidents assigned to groups they are member of AND child groups

scott111
Kilo Expert

REQUIREMENT: ITIL role users must only be able to see incidents assigned to groups they are member of AND that group's child groups unless the user is the caller and then they can see the incident.

Assume a usergroup called Security with three child groups and several grandchild groups. If itil user Fred is a member of a second tier group called Security Physical he would see incidents assigned to that group and to any child groups under Security Physical  --even though he is not a member of said child groups. Fred can see all incidents where he is the caller.

What is the best way to do this?

I am creating a business rule to determine member group and child hierarchy using the code below which adds to the current query to restrict access as per the requirement. You can paste this code into a Fix script, change the var TopLevelGroup to a top tier usergroup and then run it. My output is (note level numbers):

*** Script: SCOTT111: GROUPS=1 Security
*** Script: SCOTT111: GROUPS=2 Security Operations
*** Script: SCOTT111: GROUPS=2 Security Policy & Compliance
*** Script: SCOTT111: GROUPS=3 Security Standard Compliance
*** Script: SCOTT111: GROUPS=4 Security Cloud FedRamp Compliance
*** Script: SCOTT111: GROUPS=2 Security Physical & Personnel
*** Script: SCOTT111: GROUPS=3 Security Physical
[0:00:00.020] Total Time

 

var TopLevelGroup = 'Security';   // Name of top level parent group
var A_Group_Sysid = GetGroupSysidByName(TopLevelGroup);
var ListOfGroupAndChildren = []; // List of sysIDs for top parent group and ALL descendents
var ListOfGroupAndChildrenLevel = [];    //  hierarchy level
var ListOfGroupUNPROCESSED = []; // "UNPROCESSED"= list of groups (by sysid) not yet searched for its child groups
var ListOfGroupUNPROCESSEDLevel = [1];      // save group level number when you first read it in
var LoopLimiter = 0;     // let's not take any chance of this loop getting infinite
var GroupLevel = 1;
var ChildGrps = [];
var NumOfChildGrps = 1;
var i;
var x = 0;
var y;
ListOfGroupUNPROCESSED[0]	= A_Group_Sysid;
while (ListOfGroupUNPROCESSED.length > 0) {
	LoopLimiter++;
	A_Group_Sysid = ListOfGroupUNPROCESSED[0];   //returns 1st element in array
	ChildGrps = GetChildren(A_Group_Sysid); 
	ListOfGroupAndChildren.push(ListOfGroupUNPROCESSED.shift()); //children of A_Group_Sysid search done now move to final list
	ListOfGroupAndChildrenLevel.push(ListOfGroupUNPROCESSEDLevel.shift());
	NumOfChildGrps = ChildGrps.length;
	if (NumOfChildGrps > 0) {
		GroupLevel++;
		Array.prototype.unshift.apply(ListOfGroupUNPROCESSED, ChildGrps);   // prepend ALL newly found children to UNPROCESSED list
		for (y = 0; y < NumOfChildGrps; y++)  { ListOfGroupUNPROCESSEDLevel.unshift(GroupLevel); }
		}
	else {                      // NumOfChildGrps == 0
		if (ListOfGroupUNPROCESSEDLevel.length > 0)  { GroupLevel = ListOfGroupUNPROCESSEDLevel[0]; }
		}
// 	gs.print("SCOTT111: ListOfGroupUNPROCESSEDLevel so far=" + ListOfGroupUNPROCESSEDLevel);
// 	gs.print("SCOTT111: ListOfGroupUNPROCESSED so far=" + ListOfGroupUNPROCESSED);
// 	gs.print("SCOTT111: ListOfGroupAndChildren so far=" + ListOfGroupAndChildren);
// 	gs.print("SCOTT111: ListOfGroupAndChildrenLevel so far=" + ListOfGroupAndChildrenLevel);
	if (LoopLimiter > 100) { throw "SCOTT111: LoopLimiter too high";  }
}

//gs.print("SCOTT111: Using sys_ids in ListOfGroupAndChildren create array of same groups by name");	
var ListOfGroupAndChildrenNames = [];
for (i = 0; i < ListOfGroupAndChildren.length; i++) { 
	ListOfGroupAndChildrenNames.push([GetGroupNameBySysid(ListOfGroupAndChildren[i])]);
	}
for (x = 0; x < ListOfGroupAndChildrenLevel.length; x++) {
		gs.print("SCOTT111: GROUPS=" + ListOfGroupAndChildrenLevel[x] + " " + ListOfGroupAndChildrenNames[x] + "-----------------------------------  sysid=" + ListOfGroupAndChildren[x]);
	}
//gs.print("SCOTT111: ListOfGroupAndChildrenNames=" + ListOfGroupAndChildrenNames);
//gs.print("SCOTT111: ListOfGroupAndChildrenLevel=" + ListOfGroupAndChildrenLevel);

/* ==================================================================== functions =============================*/

function GetChildren(group_sys_id)  {
 var Childgroups = [];
 var Thesys_id = "";
 var gr = new GlideRecord('sys_user_group');
 gr.addQuery('parent', group_sys_id);
 gr.query();
 while (gr.next()) {
  Thesys_id = gr.sys_id.toString();    // must assign this temp var using toString !
  Childgroups.push(Thesys_id);
  }
 //gs.print("SCOTT111: Childgroups=" + Childgroups.toString());
 return Childgroups;
}

function GetGroupSysidByName(group) {        
 var gr = new GlideRecord("sys_user_group");
    if(gr.get('name', group)) 
    {
		//gs.print('SCOTT111: GetGroupSysidByName name is ' + gr.name + ' sys_id=' + gr.sys_id);
		return gr.sys_id;
    }
}

function GetGroupNameBySysid(ThesysID) {       
 var gr = new GlideRecord("sys_user_group");
    if(gr.get('sys_id', ThesysID)) 
    { return gr.name; }
}
8 REPLIES 8

The Dynamic Reference Qualifier "Dynamic IS MY GROUP" as well as the function getMyGroups() and gs.getUser.getMyGroups() already returns the group hierarchy. 

find_real_file.png

find_real_file.png

I am not sure why custom code needs to be developed?


ServiceNow Nerd
ServiceNow Developer MVP 2020-2022
ServiceNow Community MVP 2019-2022

scott111
Kilo Expert

The code does not find all children. 

Hi Scott,

I have tested it in my instance and it works perfectly fine. It lists incidents assigned to the groups a user is part of or child groups of those groups.

Please give it a try here:

https://dev43809.service-now.com/login.do

User ID- luke.wilson

Password - April@2018

Luke a is Member of 2 groups and other 2 groups are child of CAB Approval group. Refer to below screenshots.

find_real_file.png

find_real_file.png

Duplicate Sys Ids does not give any issues coz they are in OR condition.

Please let me know if you see any error while testing this.

Also, could you please share screenshot of your script?

scott111
Kilo Expert

Thanks for your help!

Unlike your instance mine had a third and fourth tier of usergroups (grandchildren and great-grand children). In my test, your code did not retrieve these third and fourth tiers.