ACL and permissions based upon employee's manager, and the manager's manager

erikbos
Giga Contributor

Hi,

I have got a security   requirement for a table.

- Each employee only sees the rows in a table where he/she is referenced.

- Each employee's manager can see his own rows and the rows of the employees reporting to him

- Each manager's manager can see his own rows and the rows of the employees reporting to him

[etc]

In my SN instance each user has its manager referenced (as imported from Active Directory) Each manager does not have its reports listed in sys_user. So going "up" the tree is easy, but I am not sure if it possible to traverse down is possible.

What would be the best approach such security requirement?

thx

e

1 ACCEPTED SOLUTION

Felipe, thanks for your quick follow up.



row = new GlideRecord('sys_user').get(row[column].manager);



does not work as I initially thought: it returns the output of the get() method which is true or false. Not a new object for a particular user. Oops


My code was flawed, I have rewritten the function and it now works properly. Function code:



// check if a user is the management chain of another user


managementChainCheck : function(employee, manager) {


  // direct report ?


  if (employee.manager == manager)


            return true;



  row = new GlideRecord('sys_user');


  var manager_to_check = employee.manager;



  // let's go up the management chain 10 times


  for (i = 0; i < 10; i++) {


            row.get(manager_to_check);


            if (row.manager == manager) {


                      return true;


            } else {


                      // Not found, let's try this employee's manager


                      manager_to_check = row.manager;


            }


  }


  return false;


},



View solution in original post

10 REPLIES 10

felipe_barbosa
ServiceNow Employee
ServiceNow Employee

This one is tricky as the possibility of having an ACL that runs for a bit of time is high.



I think you need two ACLs:



- The first is easy and straight forward - ACL that allows access if the person is referenced in the table


- A second one that allows access if the person is a manager of the employee referenced in the table, or the manager of the manager. You will have to decide the max number of iterations you will have (manager of manager of manager of manager ...) so you won ´t run in a endless loop.



You should do this via script, returning true if you detected that the current person trying to see the record is in the manager chain.



I hope it helps.



Best of luck,



Felipe


Think about the next:



1/ Save at [sys_user] row the upper manager chain:



+ A


      + B


              + D


              + E


        + C


              + F



So, A.manager_chain = ["A"] , B.manager_chain = ["B","A"], D.manager_chain = ["D","B","A"], F.manager_chain = ["F","C","A"] and so on.



So, from this moment, it's only necessary to look for the manager at the entire [sys_user] looking for the manager in the manager_chain.



2/ Create a Business Rule to rebuild the manager chain for each user that has been affected by a manager change, looking for the old manager at the chain in order to rebuild that nodes. (Easy Script, but slightly expensive to run if the manager changed is in a hight level)... I think this is not so frequently to change a manager...


    - Two passes, ( ¿O(n)?) --> 1 : Look for the candidates to reconstruct; 2 : Reconstruct candidates --> No iterative



3/ ACL will check for all registers that references the user at the manager_chain. (I added the user at the chain in order to do only one query, for the direct reference, and managed_by also). (Cheap to run an easy to code).



Finally, in this way, you can also show to user his little slaves from a related list, for example...



This is more or less as LDAP nodes works with the ou's...



Best Regards


Thx, thought about that as well: prepping sys_user and building a lookup table to limit the number of recursive queries.. But for now I am going to skip it as the usage on this table is not going to be much.


Hi,



Thanks for replies. As scripted ACL I have used:



var answer = current.contract_administrator == gs.getUserID() ||


                        gs.getUser().isMemberOf('SpecialGroup') ||


                        XXX.managementChainCheck(current, 'account_administrator', gs.getUserID());



as script include function:



XXX.managementChainCheck : function(row, column, logged_in_user) {


        gs.addInfoMessage("managementChainCheck| liu: " + logged_in_user + " column: " + column);



          // if this user has a manager and recursion up the chain is below 10 we will evaluate


          for (i = 0; !row[column].manager.isNil() && i < 10; i++) {


                  gs.addInfoMessage("managementChainCheck|manager (" + i + ") m: " + row[column].manager);



                  // is this user's manager the currently logged in one?


                  if (row[column].manager == logged_in_user) {


                        return true;


                  } else {


                      // go one up the management chain


                      row = new GlideRecord('sys_user').get(row[column].manager);


                }


            }


            return false;


  },



The ACL "works":


1) my function is called


2) the employee's first manager is being compared correctly. first for loop iteration is ok (so a manager's sees the rows of a report)



but getting the gliderecord of an employee's manager does not appear to work I have not done a lot of coding yet.. Any suggestions ?