ACLs Archives - ServiceNow Guru https://servicenowguru.com/tag/acls/ ServiceNow Consulting Scripting Administration Development Tue, 11 Jun 2024 11:35:52 +0000 en-US hourly 1 https://wordpress.org/?v=6.8.2 https://servicenowguru.com/wp-content/uploads/2024/05/cropped-SNGuru-Icon-32x32.png ACLs Archives - ServiceNow Guru https://servicenowguru.com/tag/acls/ 32 32 Leveraging User Criteria in your custom applications https://servicenowguru.com/scripting/leveraging-user-criteria-custom-applications/ https://servicenowguru.com/scripting/leveraging-user-criteria-custom-applications/#comments Mon, 03 Jun 2024 12:44:36 +0000 https://servicenowguru.com/?p=15374 User Criteria (UC) have been around on the ServiceNow platform for quite some time now. They were a welcome extension to providing a more flexible way for controlling the set of users who should or shouldn’t have access to specific records. With UCs you can define a grouping of users either by name, groups they

The post Leveraging User Criteria in your custom applications appeared first on ServiceNow Guru.

]]>
User Criteria (UC) have been around on the ServiceNow platform for quite some time now. They were a welcome extension to providing a more flexible way for controlling the set of users who should or shouldn’t have access to specific records. With UCs you can define a grouping of users either by name, groups they belong to, roles they have, or through a script.

Standard User Criteria definition form.

You can then take that UC and add/configure it on a record as having the ability to ‘can read’ or ‘cannot read’ a specific record or group of records. Probably the best known examples of this are in the OOB knowledge base and service catalog applications.

KB article can read/cannot read attributes.

Available For/Not Available For related lists on catalog items.

But what if you wanted to be able to use UCs in your custom applications? The following will provide a roadmap on how you can do this!

Lets review how UCs are used for security by using the concrete example from the knowledge base. For the Knowledge Base application there are can/cannot read attributes (KB article image shown above) on the knowledge base record as well as the individual article record.  On the knowledge base record the UCs are associated as related records and shown in the ‘Can Read’/’Cannot Read’ related lists.  On the knowledge base articles there are ‘Can Read’/’Cannot Read’ glidelist attributes directly on the record. The way the OOB security has been implemented to use those UC lists for determining if a user can read a specific knowledge article is that:

  • A user can NOT be in either the knowledge base or knowledge articles cannot read UCs to be able to read the article.
  • If there is a can read UC on the knowledge base, the user must be in the UC to read articles in the knowledge base.
  • If there is a can read UC on the knowledge article, the user must be in the UC to read the article.
  • If there are no UCs defined on either the knowledge base or article, the article is readable by any user.

This is generally the way the service catalog works as well with the catalog and catalog item.

There are other OOB applications using UCs as well….but what if you wanted to be able to use UCs in other places to control access that aren’t part of OOB applications? To do this you’d need some way of evaluating a user’s inclusion in a UC. Thankfully there is a scriptable object that does just that: UserCriteriaLoader.

UserCriteriaLoader was a utility Mike Sherman (also a long-time ServiceNow employee) and I found while trying to develop the security model for a project we were working on. It’s relatively easy to use and just needs some fairly straightforward wrappers to make it reusable for our needs.

UserCriteriaLoader has several functions on it but the main one we are going to make use of is userMatches(). The userMatches() function takes the sys_id of a user you’re checking and an array of UC sys_id’s to check against. The function then evaluates the user against those UCs and returns true/false indicating if the user is in at least one of the UCs. Something like the following:

var user = gs.getUserId();
var uc_array = [“<uc_sys_id_1>”, “<uc_sys_id_2>”, “<uc_sys_id_3>”];
var ret = sn_uc.UserCriteriaLoader.userMatches( user, uc_array);


The above is a great start as it gives you the base capability to evaluate a user’s inclusion in a set of UCs, but what we really want is a utility that wrappers the above to give us a generic way of evaluating users against UCs in the way that UCs tend to be applied to records.

The script include below gives us a reusable utility to do this in the two primary ways we found UCs to be applied to a record:

  • A glidelist directly on the record
  • A related list with references to the record and to UC’s


UserCriteriaLoader.userMatches() requires the user’s sys_user record sys_id and an array of UC record sys_ids. The ‘trick’ to the utility is converting either the glidelist or a list of related records into that array of UC record sys_ids. Let’s look at some specific examples of how to use each function.

//'UserCriteriaLoader.userMatches()' Sample Usage
var gr = new GlideRecord("my_custom_table"); //Table name of record for which are evaluating access
gr.get(""); //sys_id of record for which you are evaluating access
var user_can_read = new UserCriteria(gs.getUserID(), gr).evalUCGlideList("my_can_read", "my_cannot_read");

The above would return true/false depending on the user’s inclusion in the can/cannot read UCs. A couple of things to note:

  • The cannot read parameter on the function is optional.  If not included it is assumed that the user is NOT part of any cannot read UCs.
  • If given a cannot read parameter, the function will take it into account by determining if the given user is part of the cannot read UC(s) and if they are returning false as the ‘answer’ as being included in any can read UCs would no longer matter for functionality to be consistent with the way OOB applications us UCs.
  • The above is somewhat contrived as one of the biggest use cases is where you’d already HAVE a glide record to work with as part of the platform (BRs & ACLs mainly).

Usage when the UCs are associated via a related list is a bit more complicated….but just because data model is a more complicated. The overall approach is the same in that we want to build an array of UCs for the can read and cannot read related lists and feed them to base function. 

var gr = new GlideRecord("my_custom_table");
gr.get("");
var user_can_read = new UserCriteria(gs.getUserID(), gr).evalUCRelatedList("m2mCanTable", "canGrRefFieldName", "canUCRefFieldName", "m2mCannotTable", "cannotGrRefFieldName", "cannotUCRefFieldName");

//m2mCanTable: name of the table that contains the list of can read UCs related to the record in my_custom_table.
//canGrRefFieldName: reference to a record on my_custom_table.
//canUCRefFieldName: reference to a UC record
//m2mCannotTable: name of the table that contains the list of cannot read UCs related to the record in my_custom_table.
//cannotGrRefFieldName: reference to a record on my_custom_table
//cannotUCRefFieldName: reference to a UC record

Hopefully, this is helpful and gives the ServiceNow community an extra tool in their toolbox to solve their problems with the power of the ServiceNow platform!

NOTE:

  • UserCriteriaLoader is NOT documented on docs.servicenow.com or in developer.servicenow.com. However, if you search in OOB script includes you will see it being used. So a bit of ‘buyer beware’ but we believe it’s relatively safe to use….i.e. while not formally documented it seems unlikely that ServiceNow would deprecate the object/functions.
  • The script include given was factored for the use case/need we had at the time, it can certainly be reworked to fit your needs…but the building blocks are there for most use cases.

var UserCriteria = Class.create();
UserCriteria.prototype = {
    /**
    name: initialize
    description: Initializes the UserCriteria object by setting the user sys_id and the GlideRecord.
    param: {String} [userSysId] - sys_id of the user we want to check.
    param: {GlideRecord} [grToCheck] - GlideRecord of the record we want to check against.
    example:
    var matches = new UserCriteria(userSysID, grToCheck)
    returns: {UserCriteria} returns a initialized UserCriteria Object.
    */
    initialize: function(userSysId, grToCheck) {
        this.userSysId = userSysId;
        this.grToCheck = grToCheck;
    },

    /**
    name: evalUCGlideList
    description: Takes the field names on the table/GlideRecord that are GlideList(s) pointing too User Criteria for "Can" & "Cannot".
    param: {String} [ucCanField] - The field name of the GlideList for the "Can" User Criteria.
    param: {String} [ucCannotField] - The field name of the GlideList for the "Cannot" User Criteria.
    example:
    var matches = new UserCriteria(userSysID, grToCheck).evalUCGlideList("<can_read_uc_glidelist_field>", "<cannot_read_uc_glidelist_field>");
    returns: {boolean} Returns true if user passed in is part of any of the user criteria in the GlideList. 
    */
    evalUCGlideList: function(ucCanField, ucCannotField) {
        var ret = false;
        if (ucCannotField)
            ret = (!this._matchesUCListField(ucCannotField, false) && this._matchesUCListField(ucCanField, true));
        else
            ret = (this._matchesUCListField(ucCanField, true));

        return ret;

    },

    /**
    name: evalUCRelatedList
    description: Takes m2m tables for can and can't mappings, with ref field names of "connectors", that connects a record to User Criteria and returns true/false indicating a users access depending on related lists.
    param: {String} [m2mCanTable] - Name of the m2m table connecting the record with User Criteria 'can' access.
    param: {String} [canGrRefFieldName] - Name of the field on the m2m table that points to the GlideRecord (can access).
    param: {String} [canUCRefFieldName] - Name of the field on the m2m table that points to the User Criteria (can access).
    param: {String} [m2mCannotTable] - Name of the m2m table connecting the record with User Criteria for can't access
    param: {String} [cannotGrRefFieldName] - Name of the field on the m2m table that points to the GlideRecord (can't access).
    param: {String} [cannotUCRefFieldName] - Name of the field on the m2m table that points to the User Criteria (can't access).
    example:
    var matches = new UserCriteria(userSysID, grToCheck).evalUCRelatedList(m2mCanTable, canGrRefFieldName, canUCRefFieldName, m2mCannotTable, cannotGrRefFieldName, cannotUCRefFieldName)
    returns: {boolean} Returns true if user passed in is part of any of the user criteria in the GlideList. 
    */
    evalUCRelatedList: function(m2mCanTable, canGrRefFieldName, canUCRefFieldName, m2mCannotTable, cannotGrRefFieldName, cannotUCRefFieldName) {

        var ret = false;
        if (m2mCannotTable)
            ret = (!this._matchesUCListTable(m2mCannotTable, cannotGrRefFieldName, cannotUCRefFieldName, false) && this._matchesUCListTable(m2mCanTable, canGrRefFieldName, canUCRefFieldName, true));
        else
            ret = this._matchesUCListTable(m2mCanTable, canGrRefFieldName, canUCRefFieldName, true);
        return ret;

    },

    /**
    name: _matchesUCListField
    description: Takes the field name on the table/GlideRecord that is a GlideList pointing too User Criteria.
    param: {String} [ucField] - The field name of the GlideList for the User Criteria.
    param: {boolean} [emptyListReturn] - What to return in case the list of criteria is empty (false: for cannot read; true: for can read).

    returns: {boolean} Returns true if user passed in is part of any of the user criteria in the GlideList. 
    */
    _matchesUCListField: function(ucField, emptyListReturn) {

        var ucArray = [];
        var ucFieldValue = this.grToCheck.getValue(ucField);
        if (ucFieldValue != null)
            ucArray = ucFieldValue.split(",");

        return (ucFieldValue && !gs.isLoggedIn()) ? !emptyListReturn : this._matchesUCList(ucArray, emptyListReturn);

    },

    /**
    name: _matchesUCListTable
    description: Takes a m2m table, with ref field names of "connectors", that connects a record to User Criteria and returns true/false indicating if the user is in any of the User Criteria.
    param: {String} [m2mTable] - Name of the m2m table connecting the record with User Criteria
    param: {String} [grRefFieldName] - Name of the field on the m2m table that points to the GlideRecord.
    param: {String} [ucRefFieldName] - Name of the field on the m2m table that points to the User Criteria.
    param: {boolean} [emptyListReturn] - What to return in case the list of criteria is empty.
    
    returns: {boolean} Returns true if user passed in is part of any of the user criteria in the GlideList. 
    */
    _matchesUCListTable: function(m2mTable, grRefFieldName, ucRefFieldName, emptyListReturn) {

        //var ret = false;
        var ucArray = this._glideQuerytoArray(m2mTable, grRefFieldName, ucRefFieldName);
        return (ucArray.length > 0 && !gs.isLoggedIn()) ? !emptyListReturn : this._matchesUCList(ucArray, emptyListReturn);

    },


    /**
    name: individualUserCriteriaCheck
    description: Used to check the includance of a user in a single User Criteria. 
    param: {String} [uc] - Sys_id of a single User Criteria
    example:
    var matches = new UserCriteria(userSysID, grToCheck).individualUserCriteriaCheck("<uc_sys_id>")
    returns: {boolean} Returns true if user passed in is part of any of the user criteria. 
    */
    individualUserCriteriaCheck: function(uc) {

        var ucArrayofOne = [uc];
        return this._matchesUCList(ucArrayofOne, false);

    },

    /**
    name: _matchesUCList
    description: Makes call to OOB UserCriteriaLoader for evaluation of user/criteria and takes in to account empty user criteria.
    param: {Array} [ucArray] - Array of relevent User Criteria sys_ids.
    param: {boolean} [emptyListReturn] - what to return if User Criteria array is empty.

    returns: {boolean} boolean if user is in User Criteria passed.
    */
    _matchesUCList: function(ucArray, emptyListReturn) {

        var ret = false;
        if (this.isEmpty(ucArray))
            ret = emptyListReturn;
        else
            ret = sn_uc.UserCriteriaLoader.userMatches(this.userSysId, ucArray);
        return ret;

    },

    /**
    name: isEmpty
    description: Checks if the inpur array is empty or contains only inactive records.
    param: {Array} [ucArray] - Array of relevent User Criteria sys_ids.
    example:
    this.isEmpty(ucArray)
    returns: {boolean} True if array has no elements or if all associated records are inactive.
    */
    isEmpty: function(ucArray) {
        if (ucArray.length == 0) {
            return true;
        }
        var ucGr = new GlideRecord("user_criteria");
        ucGr.addActiveQuery();
        ucGr.addQuery("sys_id", "IN", ucArray);
        ucGr.setLimit(1);
        ucGr.query();
        return !ucGr.hasNext();
    },

    /**
    name: getAllUserCriteria
    description: Given a user sys_id returns the list of User Criteria that user is part of.
    example:
    new UserCriteria(userSysID, grToCheck).getAllUserCriteria()
    returns: {String} - List of User Criteria sys_id's that the user is part of.
    */
    getAllUserCriteria: function() {

        return sn_uc.UserCriteriaLoader.getAllUserCriteria(this.userSysId);

    },

    /**
    name: _glideQuerytoArray
    description: An internal/hidden function used to look up the related User Criteria records and build them in to an array.
    param: {String} [m2mTable] - Name of the m2m table connecting the record with User Criteria
    param: {String} [grRefFieldName] - Name of the field on the m2m table that points to the GlideRecord.
    param: {String} [ucRefFieldName] - Name of the field on the m2m table that points to the User Criteria.
    
    returns: {Array} An array of User Criteria that are related to the record via the m2m table.
    */
    _glideQuerytoArray: function(m2mTable, grRefFieldName, ucRefFieldName) {

        var ucArray = [];
        var grUC = new GlideRecord(m2mTable);
        grUC.addQuery(grRefFieldName, this.grToCheck.sys_id);
        grUC.query();
        while (grUC.next()) {
            ucArray.push(grUC.getValue(ucRefFieldName).toString());
        }

        return ucArray;
    },

    type: 'UserCriteria'
};

 

The post Leveraging User Criteria in your custom applications appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/scripting/leveraging-user-criteria-custom-applications/feed/ 6
What Everybody Should Know About ServiceNow Security https://servicenowguru.com/system-definition/servicenow-security-tips/ https://servicenowguru.com/system-definition/servicenow-security-tips/#comments Thu, 30 Jun 2011 16:56:51 +0000 https://servicenowguru.wpengine.com/?p=3638 Follow these guidelines to make sure you’re using the right security technique for every situation! Security in ServiceNow is a very important, but often very confusing subject to get the hang of. ACLs, business rules, client scripts, and UI policies can all affect the security in your system to varying levels. Improper use of any

The post What Everybody Should Know About ServiceNow Security appeared first on ServiceNow Guru.

]]>
Follow these guidelines to make sure you’re using the right security technique for every situation!

Security in ServiceNow is a very important, but often very confusing subject to get the hang of. ACLs, business rules, client scripts, and UI policies can all affect the security in your system to varying levels. Improper use of any of these security mechanisms can cause you some pretty serious problems so it’s important to know what you’re doing. In my experience as a ServiceNow consultant and administrator I’ve learned some things about ServiceNow security that I want all of my clients to know. I’ll explain these things in this article.


ServiceNow Security

Although they are often a critical part of the overall security approach for a ServiceNow instance, this article will not address the details of security restrictions that are initiated outside of a ServiceNow system. These restrictions generally fall into the following categories…

What this article will address are the details of security restrictions within the system that affect the fields on a form or list, and rows within tables.

1 – Meet your new best friend…The Access Control List (ACL)

The Contextual Security Manager should be your FIRST AND PRIMARY line of defense when it comes to security in ServiceNow. If an element or record really needs to be secured from all angles, this is the way to do it! You need to become very familiar with how to use ACLs.

2 – Client scripts and UI policies ARE NOT security!

I feel like I should have put a few more exclamation points in on this one.:) This is such an important point to make though because it’s a very common point of confusion for people getting started with ServiceNow.

It’s very simple to set up a client script or UI policy to make a field read only. This works great when you’re looking at a form because that’s the only place where client scripts and UI policies run! What isn’t as obvious is that this “security” can easily be bypassed in a variety of ways. I’m not going to detail all of these, but I will show you the most common scenario…list editing. The following screenshots show the difference in a list between a field that has been secured by an ACL and and field that has been secured by a client script or UI policy. The client script method has no effect in any place other than a loaded form so it doesn’t secure anything in the list.

Priority field locked down by an ACL

Priority Field ACL Security

State field “locked down” by a client script or UI policy

State Field Client Script UI Policy Security

While it is possible to supplement a client script or UI policy with a ‘list_edit’ ACL, this is still a poor substitute for a truly locked-down field through the use of a full ‘write’ ACL. The bottom line here is that if it really needs to be secure, client-side methods aren’t going to do the job. Client-side methods obviously have their place, but they are designed for masking certain field inputs on a form to control the process of record creation, not permanent security of a field.

3 – Don’t use dictionary settings for security

Each dictionary entry in the system has a few fields that could potentially be used to secure fields in the system. There is a ‘Read only’ checkbox, and ‘Read roles’, ‘Write roles’, ‘Create roles’, and ‘Delete roles’ fields available. The ‘Read only’ checkbox will work, but it will interfere with any ACL security that you put in place and it’s almost guaranteed to cause serious grief for someone trying to troubleshoot a security issue with that element. The ‘roles’ fields only work with the extremely old simple security model that was used several years ago before contextual security ACLs came along. Contextual security ACLs have been the default security model for several years now. The best advice I can give here is to remove these fields from your dictionary form and don’t use them. :)

If you have an instance that was created several years ago and still uses simple security, this should be readily apparent by the absence of the ‘System Security’ application in the left nav. You’re killing yourself by using the old security model and you really need to upgrade. Contact ServiceNow customer support for assistance.

 

4 – Pay attention to the ‘Row-level read’ ACL exception

There is a major exception to the use of ACLs when it comes to the read operation. It’s probably best to illustrate this with a screenshot of something that you might have seen before…
Row Level Read ACL Problem

What this screenshot illustrates is that ACLs securing the read operation for an entire row (TABLENAME instead of TABLENAME.FIELDNAME or TABLENAME.*) do not work well if you’re limiting access to some of the records within a table. The records aren’t visible, but you end up with a list that only shows you the records available for each page in the list (along with a count of all of the records that the user isn’t seeing) rather than a normal, compressed list of just those results that are available. ‘Row-level read’ ACLs should only be used when you want to restrict or grant access to every record in a table to a certain set of users. Any situation that only limits access to some of the records in a table requires the use of a ‘Before query’ business rule to avoid this problem.

I’ve written a couple of articles on ServiceNowGuru explaining how ‘Row-level read’ business rules work. You should read these articles for more details.
Controlling record access with ‘before query’ business rules
Fixing the ‘Before query’ business rule flaw

‘Before query’ business rules are also a great way to set up company or department separation in your instance. It is extremely rare for a company to need to implement something like domain separation. It’s almost always completely overkill and can be avoided through the use of a few ‘Before query’ business rules on the tables that need to be separated. You should only consider domain separation or company separation if you are working with an MSP or if you simply cannot get ‘Before query’ business rules to work.

 

5 – ‘Before’ business rules and onSubmit client scripts can be used to prevent record submission

There may be specific scenarios where you want to prevent the insertion or update of a record based on something going on in that record or form. In these cases you may use a business rule or client script to accomplish your goal. Full details on this technique can be found here.

6 – Don’t forget to add ACLs for new tables you create

It’s inevitable that you’ll need to create new tables in your ServiceNow instance. It’s important to remember that ACLs for tables don’t automatically get created for you so you have to create them if you want that table to be secure. Usually it’s enough to create some simple read, write, and delete row-level ACLs but it will depend on your setup and the purpose of the particular table.

7 – Introducing or modifying any top-level (*.*) ACL can cause SERIOUS problems

Top Level ACLs

Top-level ACLs impact the entire security structure of your system. It’s just usually not a good idea to modify them or introduce new ones, so leave them alone.

8 – Understand the ACL rule search order and precedence

This information is critical if you’re working with ACLs because there is a hierarchy of tables and fields and a precedence between different types of rules that needs to be considered. If you’ll educate yourself on this ordering, you’ll be able to make sense of contextual security much more quickly.

The post What Everybody Should Know About ServiceNow Security appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/system-definition/servicenow-security-tips/feed/ 8
Identifying the Client or Session IP Address https://servicenowguru.com/scripting/identifying-client-session-ip-address/ https://servicenowguru.com/scripting/identifying-client-session-ip-address/#comments Mon, 28 Feb 2011 15:28:09 +0000 https://servicenowguru.wpengine.com/?p=3421 As a Service-now administrator or consultant, you may run into situations where it is necessary to identify the IP address of a user session before performing some action. These situations are almost always security-related. For example, you may want to restrict the ‘Delete’ operation for Change request tickets to users at a specific location, or

The post Identifying the Client or Session IP Address appeared first on ServiceNow Guru.

]]>
As a Service-now administrator or consultant, you may run into situations where it is necessary to identify the IP address of a user session before performing some action. These situations are almost always security-related. For example, you may want to restrict the ‘Delete’ operation for Change request tickets to users at a specific location, or you may want to show a particular UI action button to users whose sessions originate from a particular IP address.

I haven’t seen this type of request very often, but it is pretty simple to get this type of information in Service-now. This post shows you how.

To get the IP address of a user session you simply have to use the ‘getClientIP()’ method to pull the IP address from the current user’s session object.

//Return the current user session's IP address in string format
gs.getSession().getClientIP().toString();

Here’s another example that shows how you could use this in a security ACL script.

//Only allow permission for sessions with '101.11.41.134' IP address
var answer = false;
if(gs.getSession().getClientIP().toString() == '101.11.41.134'){
   answer = true;
}
answer;

This information is also available via the user transaction log. You can see the full transaction log by navigating to ‘System Logs -> Transactions (All User) or by navigating to ‘User Administration -> Logged in Users’ and opening one of the user session records. This method is sometimes more useful since the transactions are grouped by user session in a related list at the bottom of the transaction record.

User Transaction Log Entry

The post Identifying the Client or Session IP Address appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/scripting/identifying-client-session-ip-address/feed/ 8
Allow Group Managers to Manage Group Members https://servicenowguru.com/system-definition/group-managers-manage-group-members/ https://servicenowguru.com/system-definition/group-managers-manage-group-members/#comments Mon, 09 Aug 2010 19:48:22 +0000 https://servicenowguru.wpengine.com/?p=1882 I often get the request to set up access for group managers to be able to manage the members of their groups in ServiceNow. This configuration isn’t too difficult to set up but it does involve a few different pieces. It’s also important to consider your group setup in your system before allowing access in

The post Allow Group Managers to Manage Group Members appeared first on ServiceNow Guru.

]]>
I often get the request to set up access for group managers to be able to manage the members of their groups in ServiceNow. This configuration isn’t too difficult to set up but it does involve a few different pieces. It’s also important to consider your group setup in your system before allowing access in this way. If you are bringing in group memberships from a data source like LDAP for example, the last thing you want is to have your managers manually changing those group memberships within ServiceNow. The configuration shown below could be easily customized to allow access only to non-LDAP groups if you needed to do both however.



This solution requires you to modify the out-of-box ACLs for the ‘sys_user_grmember’ table. You’ll also need to modify the ‘Omit Edit Condition’ field for the ‘Group Members’ related list on the ‘Group’ form. These configurations are outlined below.

Write and Delete ACLs (‘sys_user_grmember’)
The following script can be used within your Write and Delete ACLs on the ‘sys_user_grmember’ table. No other roles or conditions are necessary for this configuration.

var answer = false; //Restrict access by default
if(gs.hasRole('user_admin') || current.group.manager == gs.getUserID()){
answer = true; //Allow access if user has 'user_admin' role or is group manager
}

Create ACL(‘sys_user_grmember’)
The create ACL works a little bit differently because we don’t have access to ‘current.group.manager’ before the record is created. Because of this, you need to open up create permissions to the role that your group managers will have. Typically these managers will have the ‘itil’ role anyway so you can just set up your ‘create’ ACL with the ‘itil’ role defined in the related list at the bottom of the ACL.
‘Restrict Changes to Group Managers’ business rule
Opening up the create ACL is necessary for this configuration to work, but needs to be backed up by some additional security in the form of a ‘before’ business rule. The business rule performs a secondary check on insert/update of the group member record to ensure that the user is actually a group manager or has the ‘user_admin’ role. If not, it aborts the insert/update and alerts the user.Name: Restrict Changes to Group Managers
Table: Group Member [sys_user_grmember]
Name: Restrict Changes to Group Managers
Before: True
Insert/Update: True
Script:

(function executeRule(current, previous /*null when async*/) {
if(!gs.hasRole('user_admin') && current.group.manager != gs.getUserID()){
//Abort the insert or update
gs.addErrorMessage('You do not have permission to modify this group membership.');
current.setAbortAction(true);
}})(current, previous);
List Control ‘Omit Edit Condition’
The final piece of controlling ‘Create’ access is to limit the visibility of the ‘Edit’ button on the ‘Group Members’ related list on the ‘Group’ form. You can manage this by right-clicking the related list header and selecting ‘Personalize -> List control’ from the context menu. You can place this script in the ‘Omit Edit Condition’ field to restrict visibility of the ‘Edit’ button on the related list to those who have the ‘user_admin’ role or are listed as the manager of the given group.

If the ‘Omit Edit Condition’ field is not visible you can add it by personalizing the ‘List Control’ form
var answer = true; //Hide the 'Edit' button by default
if(gs.hasRole('user_admin') || parent.manager == gs.getUserID()){
answer = false; //Show the 'Edit' button if user has 'user_admin' role or is group manager
}
answer;

That should do it! You may also want to create a ‘Groups’ module that is available for the role that your group managers have. This will allow your group managers easy access to the groups in the system (and with a filter access to the groups that they manage).

The post Allow Group Managers to Manage Group Members appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/system-definition/group-managers-manage-group-members/feed/ 32
One Field Shared Between Many Tables https://servicenowguru.com/scripting/one-field-shared-between-many-tables/ https://servicenowguru.com/scripting/one-field-shared-between-many-tables/#comments Fri, 01 Jan 2010 00:06:58 +0000 https://servicenowguru.wpengine.com/?p=594 One common problem I encounter with Service-now deployments has to do with the sharing of a field between many tables extended off of the same parent table. Because the Task table and the Configuration Item table make heavy use of extended tables this is where I see the problem most often. What is the best way to make changes to a shared field for the table that I'm working on, but not impact other tables that may be using the same field?

The post One Field Shared Between Many Tables appeared first on ServiceNow Guru.

]]>
One common problem I encounter with ServiceNow deployments has to do with the sharing of a field between many tables extended off of the same parent table. Because the Task table and the Configuration Item table make heavy use of extended tables this is where I see the problem most often. What is the best way to make changes to a shared field for the table that I’m working on, but not impact other tables that may be using the same field?

Let’s say that I’m in the middle of a Change management deployment and I’m using the ‘Configuration item’ field on my Change form. At the same time, my company is trying to roll out Incident management so there’s also someone from another department trying to make configuration changes to the ‘Configuration item’ field on the Incident form. The Incident management process says that the Configuration item field is optional while Change management says that it should be mandatory. Incident management has a very complex reference qualifier for the field, but Change management doesn’t want a reference qualifier at all. Since there is only one dictionary entry for the Configuration item field, we can’t both have our way if we are making configuration changes on the dictionary entry. Below are a few of the common scenarios where you might see this problem and how you can make it work for all tables that access the shared field.

If there’s a central theme to all of these scenarios it is that you need to pay very close attention to what you’re doing when you personalize the dictionary, label, or choices for any field on an extended table. Chances are that the field you’re personalizing is shared between other tables and you’ll end up impacting another area of the application. Hopefully if you do it’s intentional :).

1- Mandatory fields:

Although there is a checkbox on the dictionary table to make a field mandatory, it should be used ONLY when the field in question should always be mandatory in every situation for every table that uses the field. As this is very rarely the case, it’s usually much more effective just to make the decision early on to use UI policies or Client scripts to make the field mandatory when it should be.

2- Read-only fields:

See #1. The solution to this problem is a little bit different though. Because security in ServiceNow can be applied in a few different ways, you’ll want to make sure to evaluate the options closely. Most of the time, Access Control Rules are your best bet through the System Security application. Depending on the situation (and how critical it is to secure the field in question) you may want to use a UI policy or a Client script to restrict access to the field. Just remember that UI policies and Client scripts only secure an object when it is loaded on the form which may leave your field open via list editing or some other method.

3- Reference qualifiers:

If the field in question is a reference field, then it’s very likely that you’ll end up using a reference qualifier to filter the records presented by the field at some point. If the tables sharing the field don’t all need the same reference qualifier (or if some don’t need one at all) then you’ll want to use an advanced reference qualifier. Constructed properly, an advanced reference qualifier gives you the ability to identify the querying table before reference qualifier is returned. This means that you can give each table its own reference qualifier, or no qualifier at all. Here’s a sample script that could be used for a Configuration item field shared between various task tables.

function myRefQualFunction() {
var answer;
switch (current.getTableName()) {
case 'incident':
answer = 'sys_class_name=cmdb_ci_computer^ORsys_class_name=cmdb_ci_service^';
break;
case 'problem':
answer = 'sys_class_name=cmdb_ci_server^';
break;
case 'change_request':
answer = 'sys_class_name=cmdb_ci_service^';
break;
case 'change_task':
answer = 'sys_class_name=cmdb_ci_service^';
break;
default: answer = '';
}
return answer;
}

4- Labels:

This isn’t a dictionary setting, but the concept here is the same. Before you go and personalize the label for a field, you really need to be aware of all of the places that field is used. Changing the label of the ‘Configuration item’ field on the Incident form to ‘Incident CI’ would work great for incidents, but not so great for Change requests. It is possible to set up a separate label entry for the same field on each individual extended table.

5- Default values:

Setting multiple default values for extended tables has now been made much simpler (as of the Spring 2010 Stable 2 release). The solution outlined below is no longer necessary for instances running on Spring 2010 Stable 2 or later. See here for details on Dictionary Overrides.

There’s only one place to set a true default value for a field…the dictionary entry for the field. Client scripts can set default values, but that value is only applied when the form loads for a particular record. Here’s a script that I’ve used before to set different default values for the ‘State’ field on the Task table. You would place this in the ‘Default value’ field on the dictionary entry of the field in question.

javascript:
switch (current.getTableName()) {
case 'incident': '1'; break;
case 'problem': '2'; break;
case 'change_request': '1'; break;
case 'change_task': '-5'; break;
default: '1';
}

6- Choice lists:

It’s very easy just to right-click on a choice field and select ‘Personalize choices’. While this option is very simple, it doesn’t always supply you with all of the information you need to make an informed decision about how and where the choice should be added. By selecting ‘Show choice list’ you can see exactly how the choice list is set up for all tables involved. Personalizing choices for a choice field is very straight-forward, you just need to be sure of the scope of the choices you are personalizing. A ‘State’ value of ‘Pending acknowledgment’ may make perfect sense in the Incident world, but might not be useful or needed for a Change task. Fortunately, you can specify unique choice values for each extended table that shares the same field.

The post One Field Shared Between Many Tables appeared first on ServiceNow Guru.

]]>
https://servicenowguru.com/scripting/one-field-shared-between-many-tables/feed/ 8