THURSDAY, FEBRUARY 09, 2012

Controlling record access using ‘Before Query’ business rules

System security is probably one of the more challenging things to implement in Service-now.com.  While an out-of-box Service-now instance comes with the core security built-in, any implementation will inevitably have customizations in this area.  At some point, I plan on writing a basic security guide to help administrators and consultants make informed decisions about how security should be implemented in their systems.

I’ve now added the security guide I promised! Check out the ‘What Everybody Should Know about ServiceNow Security‘ article for more details!

One little-known, but extremely useful access control method is to use business rules to restrict record access in your system.  You can do this by creating what I call a ‘Before Query’ business rule.  These business rules have a ‘When’ value of ‘Before’ and also have the ‘Query’ checkbox selected.  ‘Before Query’ business rules are only used when you need to restrict access to certain rows within a table for certain groups of individuals.  Because the security is controlled by a script, the restriction can be applied based on roles, group membership, company or department information from the user record, or pretty much anything else that you can derive about the user trying to access a set of records.  There are a few of these business rules out-of-box that serve as great examples of how to implement security in this way.  When I need to implement security with a ‘Before Query’ business rule, I usually start with the ‘incident query’ business rule as my template.

The purpose of the ‘incident query’ business rule is to limit the access of records (rows) on the ‘Incident’ table.  Specifically, it says that you need to have the ‘itil’ role to access incident records unless you are the person listed as the Caller or Opened by on the Incident.  It is because of this business rule that your end-users can only see their own incident records in the system!  Below is the script (along with comments explaining exactly how it works).

if (!gs.hasRole('itil') && gs.getSession().isInteractive()) { //Check if the user has the 'itil' role and if the session is an actual user session
   //If they DON'T have the 'itil' role then do the following...
   var u = gs.getUserID(); //Get the sys_id value of the current user
   var q = current.addQuery('caller_id', u); //Modify the current query on the incident table so that if the user is listed in the 'caller_id' field they can see the record
   q.addOrCondition('opened_by', u); //Also allow the user access if they are the one who opened the incident (even if they aren't the caller)
   gs.print('query restricted to user: ' + u);
}

Here’s another example. This time we will restrict visibility to records if the user is a member of the current assignment group.

if (!gs.getUser().isMemberOf(current.assignment_group) && gs.getSession().isInteractive()) { //Check if the user is a member of the current assignment group
   //If they DO NOT belong to the Assignment group listed on the ticket...
   var u = gs.getUserID(); //Get the sys_id value of the current user
   var q = current.addQuery('caller_id', u); //Modify the current query on the incident table so that if the user is listed in the 'caller_id' field they can see the record
}
Any time you’re working with ‘Before Query’ business rules you’ll want to be sure you account for a specific scenario you may encounter when you’re referencing the records you’re limiting access to. Setting things up incorrectly may mean that you end up with blank reference fields!

Comments

Posted On
Jun 14, 2010
Posted By
Garrett Griffin

Thanks for this. Exactly what I was looking for. When in doubt, I turn to Service-Now Guru :-) .

Posted On
May 03, 2011
Posted By
Matt

Would you happen to know if visibility restrictions can be applied to Support Skills? For instance, can I restrict the appearance of a Support Skill to specific roles?

Posted On
May 04, 2011
Posted By
Mark Stanger

I haven’t ever seen that done for the specific requirement you mention, but it should be possible to limit the visibility of those records using this technique.

Posted On
May 12, 2011
Posted By
Karen

Thank you for the link to your site – very useful, I shall enjoy exploring it.

I’ve taken a look at the script above and was wondering if this will restrict the view for all users? What I want to do is restrict it just for a specific group.

I.e. all staff with an ITIL role can see all Incidents, except for members of a specific group who should only see those that are assigned to their group.

Is this possible?

Thanks

Karen

Posted On
May 13, 2011
Posted By
Mark Stanger

It will apply the restriction for ALL users. If you only wanted to apply it to a specific group you would need to wrap the whole thing in an additional ‘if’ statement to check and see if they were part of the specific group (or if they have some additional role).

//Only apply this to members of a specific group
if(gs.getUser().isMemberOf('GROUP_SYS_ID_HERE')){
   if(!gs.getUser().isMemberOf(current.assignment_group) && gs.getSession().isInteractive()){ //Check if the user is a member of the current assignment group
      //If they DO NOT belong to the Assignment group listed on the ticket...
      var u = gs.getUserID(); //Get the sys_id value of the current user
      var q = current.addQuery('caller_id', u); //Modify the current query on the incident table so that if the user is listed in the 'caller_id' field they can see the record
   }
}
Posted On
Jul 20, 2011
Posted By
Mohammed

Hi Mark,

This is exactly what I’m looking for but ran into what looks like a problem.
I’ve implemented this but it doesn’t apply the restriction to the closed records.

I pretty much copied and pasted the business rule.

Thank you,

Posted On
Jul 20, 2011
Posted By
Mark Stanger

Hard to say what the problem might be without having access to the instance you’re working in. The scripts here work correctly and have been tested and confirmed. If you pasted directly into a business rule with the syntax editor on then you might have some errant spaces in there. You might try pasting into the script field with the syntax editor disabled if that’s the case.

Posted On
Jul 23, 2011
Posted By
Dhanraj Poojari

Hello Mark, We have run into a situation with our MSP instance where the customers security team has exposed security holes where any system table is readable by any users by accessing it from the url example https://demo.service-now.com/sys_user_has_role_list.do Since we are on “Allow all” model of our instance. What would be the best way to

1) Identify the System tables Total count of tables in the instance 870.
2) Should ACL be used or the business rule mentioned above.
3) In either case we need to create entries for approximately 500 system tables(rest of the tables being data tables) what is the best way to automate this.

Any guidance with this regards woud be appreciated.

Regards,
Dhanraj Poojari

Posted On
Jul 23, 2011
Posted By
Mark Stanger

I don’t think you’re going to find a quick and easy solution to this problem. If I were you, I would probably start by moving to a default deny model and working from there. You’re still going to have to make some ACL modifications, but I think you’ll end up with a much cleaner solution when you’re done. You’ll need to make sure to go through a thorough QA cycle after turning on the plugin to make sure the default deny doesn’t break anything but I still think that’s the best route.
http://wiki.service-now.com/index.php?title=High_Security_Settings

Posted On
Aug 16, 2011
Posted By
Alex Rivera

Hey Mark,

In your article you state that the Before Query can be applied to an attribute from the User table. What is the proper way/syntax to use for this? For example, we have an “External Customer” check box on the user table and I want to start by stating “If the user is external, current.AddQuery…”

Thanks!

Posted On
Aug 16, 2011
Posted By
Mark Stanger

Check out my user object cheat sheet for details on accessing specific user information in script. In this case, I think you’ll just need an ‘if’ statement like this…

if(gs.getUser().getRecord().getValue('u_external_customer') == true){
   current.addQuery...
}
Posted On
Jan 16, 2012
Posted By
Before query BR on sc_category table

Hallo everybody,

I tried to apply the logic on to the sc_category table in order to hide some elements dynamically from the service catalog. But whatever I did – the business rule didn’t get executed when the service catalog is requested (catalog_home.do?sysparm_view=catalog_default)

Regards
Thomas

Posted On
Jan 17, 2012
Posted By
Mark Stanger

I don’t think a before query rule will work there because the query logic works a bit differently for that page. There are some very robust ways to limit access to catalog categories and items though. Check out this wiki article for details.

http://wiki.service-now.com/index.php?title=Service_Catalog_Security

Leave a Reply


Notify me of followup comments via e-mail. You can also subscribe without commenting.

Latest Comments

  • Aric: Finally figured out what I was doing wrong, incase someone else wants to do this. Mark is correct about needing...
  • Mark Stanger: You’ll probably need at least 3 total ACLs then. You’ll need one...
  • Mark Stanger: Hey Paul, I assume you’re talking about ‘task_ci’, not ‘task_group. If so, the...
  • ND: Hi Mark, This is cool. How can I do same at the form level. I have created a slushbucket variable and I want to...