ACLs to have Restrict functionality for Customer service Case records
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
06-26-2024 09:55 PM
Hi ServiceNow techies!
I have the following requirements:
In Cases where there is a conflict of interest (or other business need), we must be able to restrict visibility of a given record from a specific user or user group
In cases where there is confidential information (or other business need), we must be able to restrict access to a record for all users, and define specific users or groups that can view the record
Good to have: A super user group that can always access records, in addition to system admins
We need to create following 3 fields in the Case form:
‘Restrict access’ checkbox - This field toggles the access pattern between open or restricted by default. When unticked, the record is visible to all, when ticked, the record is hidden from all.
‘Hidden from’ user list – Only visible when Restrict access is unticked. Any users added to this list will be unable to view/access the unrestricted record
‘Visible to’ user list – Only visible when Restrict access is ticked. Any users added to this list will be able to view/access the restricted record
What should be the best possible solution to achieve this?
I tried using Query rules but no luck with that.
Other option would be to update ACLs - can someone tell what would be the best approach to achieve this through ACLs? or query rules if possible?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
06-27-2024 12:53 AM
Query rule should be able to achieve this with ease, but you can do it with ACL's as well.
First check all your read ACL's for record level. You want to make sure you update all with scripts that block access in your required case.
For example you can update your ACL's logic like so:
1. Check if user is in super group -> Always grant access if they are.
2. Check if restrict access is ticked. If ticked, check if the user is part of the "Visible to" list.
3. If not ticked check if user is in "Hidden from" list -> Always block if they are.
4. Your original logic on the ACL.
var answer = false;
if (gs.getUser().isMemberOf('super_group')) {
answer = true;
}else if(current.restrict_access == true){
if(current.u_visible_to.indexOf(gs.getUserID()) > -1){
answer = true;
}
}else if(current.u_hidden_from.indexOf(gs.getUserID()) > -1){
answer = false;
}else{
//Original logic
}
That's a quick example.
Previously query rules didn't work if you had a "^NQ" or query. That is the type of OR where it checks two separate conditions. Not sure if that's fixed yet, but this might require that and possible make it so you can't use it on a query rule.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
07-07-2024 02:39 PM - edited 07-07-2024 03:20 PM
Hello @Weird
Thank you for the solution.
Do I need to update all the read, write, and create ACLs, as well as delete ACL? This is a new case type, so there are only 4 that I have created - read, write, create, delete.
I updated the read ACL with the script, and now the cases are not visible to the roles that were previously defined.
Can you please suggest the conditions and scripts to use if I decide to employ Query rules? Additionally, if I need to add the "visible to group" and "restricted from group" fields so that users have the option of restricting access to a specific person or group, what changes do we need to make in the script that you provided?
I believe using Query rules would make sense and would not impact performance as much as ACLs. If we use addEncodedQuery in the Query rule, I believe it should allow for OR conditions as well.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
07-21-2024 11:42 PM
That depends. If your requirement is to simply restrict visibility, then you need to only update the READ rules.
Let's look at the previous script I wrote.
In it we set the initial value of the ACL to false.
Then if the user is a member of the "super_group" they get read access.
If not, we then check if the current "restric_access" field is set to true. If it is we check if the current user is in the "u_vsible_to" field and give them access. If not, we then check if the user is in the "u_hidden_from" field and block access. If they're not in the super_group, access is not restricted and the user is not in the hidden from field, then we can apply the original ACL logic.
var answer = false;
if (gs.getUser().isMemberOf('super_group')) {
answer = true;
}else if(current.restrict_access == true){
if(current.u_visible_to.indexOf(gs.getUserID()) > -1){
answer = true;
}
}else if(current.u_hidden_from.indexOf(gs.getUserID()) > -1){
answer = false;
}else{
//Original logic
}
You basically need to just modify the original ACL to fit in the else part of the code or it might go there without problems directly.
The ACL won't really affect performance either if you don't have multiple overlapping and looping ones.
You can test the code by running it in background
https://YOURINSTANCE.service-now.com/now/nav/ui/classic/params/target/sys.scripts.modern.do
Then run this code:
var current = new GlideRecord('TABLE');
current.get('SYS_ID');
var answer = false;
if (gs.getUser().isMemberOf('super_group')) {
gs.info("inside super_group check");
answer = true;
}else if(current.restrict_access == true){
gs.info("inside restrict_access");
if(current.u_visible_to.indexOf(gs.getUserID()) > -1){
answer = true;
}
}else if(current.u_hidden_from.indexOf(gs.getUserID()) > -1){
gs.info("inside hidden from check");
answer = false;
}else{
gs.info("inside original else check");
//Original logic
}
gs.info(answer);
Just replace TABLE with the table your ACL is run on and the SYS_ID with one of the records you want to test this on and it will print out the true of false depending on whether access would be given.
Now you can test this by adding your user to the super_group and this should print out "inside super_group check" and true.
Then you can remove your user from the group and set the record to restricted and add your self into the visible to field. Again you should get "inside restrict_access" and true. Now remove yourself from the field and you should get the same log and false.
Then set the record to not restricted and add yourself to the hidden from field. You should now get "inside hidden from check" and false.
Finally remove yourself from the field and check if you get "inside original else check" at the end.
Do note that this will always return false if restrict_access is true and you're not on the visible to field and it will not go to the else part of the script.
You can try query rules as well but they get a bit hard with this logic.
Basically query rule is just an addQuery on a GlideRecord query.
Imagine trying to build GlideRecord query where you return all records where restricted is true and you're on the visible to field and where you're not on the hidden from field.
You'd need to apply additional logic like
"If member of super group -> Skip"
"Else restricted is false and I'm not on the restricted list OR restricted is true and I'm on the allowed list."
Well, the OR here might break query rules for you. It did that to me before, but I haven't tried in new versions, but I'll assume it's still broken.
NOTE! You can use regular or, but not the "bigger" or (on top) seen here and that's what you'd need to use for your query.