ACL Troubleshooting Guide: How to Resolve Access Control List Issues Effectively






Demystifying ServiceNow ACLs: Your Guide to Resolving Access Issues



Demystifying ServiceNow ACLs: Your Guide to Resolving Access Issues

Ah, ServiceNow Access Control Lists (ACLs). Just the mention of them can send shivers down a new admin’s spine, or elicit a weary sigh from a seasoned developer. We’ve all been there – a user can’t see a field they swear they should, an integration fails because of a mysterious “security constraint,” or an approval workflow grinds to a halt. These, my friends, are ACL issues, and they’re a core part of securing your ServiceNow instance.

But fear not! This isn’t some dry, textbook explanation. We’re going to walk through ACLs like seasoned detectives, unraveling the mysteries of who can do what, where, and when. By the end of this journey, you’ll not only be able to troubleshoot those pesky access problems but also design a more robust and secure instance from the get-go. Let’s dive in!

What Exactly Are ACLs, Anyway?

Think of Access Control Lists (ACLs) as the digital bouncers of your ServiceNow instance. They stand at every door (table) and scrutinize every action (field), deciding who gets in and what they can do once they’re inside. At their heart, ACLs are security rules that restrict access to data and functionality within your ServiceNow applications.

Every ACL record defines specific permissions for a specific object (like a table, a field, or even a UI page operation) based on roles, conditions, and scripts. If a user tries to perform an action (read, write, create, delete, execute, etc.) on a record or field, ServiceNow checks the relevant ACLs. If they don’t pass, access is denied. Simple, right? (Mostly!).

To even begin working with ACLs, you need a special badge: the security_admin role. This is your master key, allowing you to create, modify, and delete ACLs. Without it, you’re just looking at the locked doors, unable to change anything. This is a crucial detail, especially if you’re ever asked in an interview: “Which role is required to work on access control?” – The answer is always security_admin.

The Pillars of Access: Users, Groups, and Roles

Before we dissect ACLs themselves, we need to understand the “who” behind the “what.” In ServiceNow, access is fundamentally managed through a triumvirate of entities: Users, Groups, and Roles.

Users: The Individuals in Your System

Users are the individual accounts representing people who interact with your ServiceNow instance. Every user has a unique identity. The user table is aptly named sys_user. Here’s a quick peek at how you might create a user account using a server-side script:

var userGr = new GlideRecord('sys_user');
userGr.initialize();
userGr.username='jdoe';
userGr.firstname='John';
userGr.lastName = 'Doe';
userGr.email = 'jdoe@example.com';
userGr.insert();

Beyond regular users, you might encounter “Web services users.” These aren’t people logging into ServiceNow to fill out forms. Instead, they’re dedicated accounts for third-party applications to connect and exchange data with your instance. They can’t log in via the standard UI.

Knowing your current user is also critical for dynamic access control. On the client-side (think browser scripts), you can fetch user details using the GlideUser API (g_user):

// Get current logged-in user's system ID (sys_id)
var currentUserId = g_user.userID;

// Get other user details
var userFirstName = g_user.firstName;
var userFullName = g_user.getFullName();

On the server-side (Business Rules, Script Includes), the gs object provides similar capabilities:

// Get current logged-in user's system ID (sys_id)
var currentUserId = gs.getUserID();

These methods are super handy for tailoring UI elements or backend logic based on the logged-in user, and definitely something an interviewer might probe!

Groups: Power in Numbers

Groups are collections of users who share a common purpose or set of permissions. Instead of assigning roles to each individual, you assign them to groups. The group table is sys_user_group, and the table linking users to groups (group members) is sys_user_grmember.

Creating a group via script is straightforward:

var newGr = new GlideRecord('sys_user_group');
newGr.initialize();
newGr.name='My New Team';
newGr.manager='62826bf03710200044e0bfc8bcbe5df1'; // Sys_id of a user
newGr.email='mynewteam@example.com';
newGr.description='This is my new fantastic team.';
newGr.insert();

And managing group members:

// Adding a Group Member
var grMem = new GlideRecord('sys_user_grmember');
grMem.initialize();
grMem.user='62826bf03710200044e0bfc8bcbe5df1'; // Sys_id of the user
grMem.group='477a05d153013010b846ddeeff7b1225'; // Sys_id of the group
grMem.insert();

// Removing a Group Member
var grMem = new GlideRecord('sys_user_grmember');
grMem.addQuery('user','62826bf03710200044e0bfc8bcbe5df1'); // Sys_id of the user
grMem.addQuery('group','477a05d153013010b846ddeeff7b1225'); // Sys_id of the group
grMem.query();
if(grMem.next()){
    grMem.deleteRecord();
}

You can also check if the current user is a member of a specific group using gs.getUser.isMemberOf('group name'). This is a common requirement for dynamic UI policies or business rules.

Roles: The Permissions Themselves

Roles are collections of permissions. They grant access to features, applications, modules, and ACLs. When a user has a role, they inherit all the permissions associated with that role. The fundamental best practice in ServiceNow security is to assign roles to groups, not directly to individual users.

Why? Imagine “Bob” leaves the company. If Bob had 10 roles directly assigned to him, you’d have to remove all 10 roles manually. But if Bob was part of “IT Support” group, which had those 10 roles, simply removing Bob from the “IT Support” group revokes all those roles automatically. It’s cleaner, more efficient, and reduces error.

Adding roles via script:

// Adding a role to a User (less preferred best practice, but possible)
var userRole = new GlideRecord('sys_user_has_role');
userRole.setValue('user','62826bf03710200044e0bfc8bcbe5df1'); // User's sys_id
userRole.setValue('role','2831a114c611228501d4ea6c309d626d'); // Role's sys_id
userRole.insert();

// Adding a role to a Group (BEST PRACTICE!)
var grpRole = new GlideRecord('sys_group_has_role');
grpRole.setValue('group','477a05d153013010b846ddeeff7b1225'); // Group's sys_id
grpRole.setValue('role','2831a114c611228501d4ea6c309d626d'); // Role's sys_id
grpRole.insert();

Deep Dive into ACLs: The “What” and “How” of Access

Now that we understand who gets the access, let’s talk about the rules themselves. ACLs are stored in the sys_security_acl table. When you create a new table in ServiceNow, by default, four basic ACLs are automatically created for it (read, write, create, delete) if the “Create access controls” checkbox is checked. This gives basic table-level security right out of the box.

Understanding ACL Operations

Each ACL is tied to a specific operation. These operations define what action the ACL is controlling:

  • Execute: Controls execution of scripts on records or UI pages.
  • Create: Determines if a user can create new records (e.g., see the ‘New’ UI action, or insert via API).
  • Read: Governs if a user can view records in forms or lists, or retrieve them via API.
  • Write: Defines if a user can modify records (fields become read-only if denied, or updates via API fail).
  • Delete: Controls if a user can remove records (e.g., see the ‘Delete’ UI action, or delete via API).
  • List_edit: Allows/denies editing records directly from a list view.
  • Report_on: Determines if a user can create reports based on the object’s data.
  • Personalize_choices: Controls the ability to configure choice lists.
  • edit_task_relations: For defining relationships between task tables.
  • edit_ci_relations: For defining relationships between Configuration Item tables.
  • save_as_template: Controls which fields are saved when a template is created.
  • add_to_list: Controls viewing or personalizing specific columns in lists.

The Hierarchy: Table vs. Field ACLs

This is a crucial concept for troubleshooting. ACLs apply at two main levels:

  1. Table ACLs: These apply to the entire table. For example, incident.None for read access.
  2. Field ACLs: These apply to specific fields on a table. For example, incident.short_description for write access.

Here’s the golden rule: A user must pass *both* table and field ACL rules to access a field. If a user fails a table ACL, they are denied access to ALL fields in that table, regardless of any field ACLs. If they pass the table ACL but fail a field ACL, they are denied access only to that specific field.

This means if a user can’t see *any* fields on an Incident, you likely have a table-level read ACL issue. If they can see most fields but one is missing or read-only, you’re probably looking at a field-level ACL issue.

Dictionary Overrides and the Collection Field

Sometimes, you want a field in a child table (like ‘Incident’) to behave differently from its parent table (‘Task’). That’s where dictionary overrides come in. They allow you to change properties (like default value, mandatory status, read-only, etc.) of a field for a specific child table without affecting the parent. You can only apply dictionary overrides to tables within the same scope as the parent table.

Related to this is the ‘Collection’ field type. Dictionary entries with the ‘Collection’ type don’t represent a field but the table itself. Changes made here (like adding attributes) apply to the entire table. For example, to disable attachments on a form, you’d add the no_attachment attribute to the ‘Collection’ dictionary entry for that table.

Troubleshooting ACL Issues: Your Detective Toolkit

So, a user complains, “I can’t see the ‘Priority’ field on an Incident!” or “I can’t create a new Change Request!” This is where your troubleshooting skills shine. Here’s a systematic approach:

Step 1: Understand the Symptom and Impersonate

Get specific. What exactly can the user NOT do or see? Is it a whole form, a specific field, a UI action, or an inability to save? Once you know, the first and most powerful troubleshooting step is to impersonate the affected user (if you have the admin role). This allows you to experience the instance exactly as they do. This is a common interview question: “What is impersonation?” – it’s logging in as another user for testing purposes.

Step 2: Activate the ACL Debugger

This is your ultimate weapon. As a security_admin, go to User menu (your profile icon) -> Elevate Roles -> check security_admin. Then, go to User menu -> Debug Security. Now, as you navigate or impersonate, you’ll see detailed information at the bottom of the page about every ACL evaluated, why it passed or failed, and which roles, conditions, or scripts were involved. This is invaluable!

Step 3: Verify User, Group, and Role Assignments

Before diving into complex ACLs, check the basics:

  • Is the user active?
  • Is the user in the correct group(s)? (Check sys_user_grmember for the user’s sys_id).
  • Does the group have the necessary role(s)? (Check sys_group_has_role for the group’s sys_id and the required role’s sys_id).
  • Crucial: Is the role assigned to the group, or directly to the user? If it’s directly to the user, this violates best practice, but could still be the source of the problem.

Step 4: Examine the Relevant ACL Records

Navigate to sys_security_acl.list and filter. For example, if the issue is with the ‘Incident’ table and ‘Read’ access, you’d search:

  • Table: incident
  • Operation: read

Look for ACLs targeting the specific table and field (if applicable) and the operation that’s failing. Each ACL has three main components:

  • Roles: Does the user possess any of the roles listed? (An “OR” condition: if they have *any* of these roles, this part passes).
  • Condition: Does the record meet the specified condition? (e.g., Active is true, Assigned to is current user).
  • Script: Does the script return true?

All three must pass (an “AND” condition) for the ACL to grant access. If any part fails, the ACL fails.

Step 5: Remember the ACL Hierarchy

If a field is hidden, first check table-level read ACLs (e.g., incident.None). If the user fails this, no field-level ACLs will matter for read access. Only if they pass the table-level read ACL do you then investigate field-level read ACLs (e.g., incident.short_description).

Step 6: Common Pitfalls and Solutions

  • Caching: Sometimes, after an ACL change, the system cache doesn’t immediately reflect it. Clear the cache by typing cache.do in the left navigator.
  • Order of ACLs: ServiceNow evaluates ACLs from the most specific to the most general. If multiple ACLs apply, the most specific one takes precedence. Debugger helps clarify this.
  • Missing security_admin: If you can’t edit ACLs, ensure you’ve elevated your role to security_admin.
  • Script Errors: ACL scripts are powerful but prone to error. Check for syntax errors or logical flaws that might always return false.
  • Default Deny: If no ACL explicitly grants access, access is denied. This is the “default deny” principle of security. If a user can’t access something, it’s because no ACL allows it, not necessarily because one explicitly forbids it.

Advanced Scenarios: Delegation and User Criteria

Sometimes access issues aren’t about direct roles but temporary permissions:

  • User Delegation: This is when a user (e.g., on vacation) allows another user to act on their behalf. The delegated user can then perform tasks (like approvals) and access resources normally available to the original user. You set this up from the original user’s account -> scroll down -> Delegates related list. This can include permissions for assignments, notifications, and approvals.
  • User Criteria: This powerful feature restricts access to Catalog Items, Record Producers, and Knowledge Articles. Instead of complex ACLs on the underlying tables, User Criteria defines “who can see this item” or “who cannot see this item” based on roles, groups, users, and even script conditions. It’s used in the ‘Available For’ and ‘Not Available For’ related lists on catalog items or knowledge bases.

ACL Management Best Practices (Preventing Issues)

A good offense is the best defense. Following best practices will minimize your ACL troubleshooting headaches:

1. Role Management is Key: Groups, Groups, Groups!

We can’t stress this enough. Assign roles to groups, not directly to individual users. This is fundamental for maintainability, auditing, and efficient user offboarding. It’s also a common “best practice” interview question you’ll encounter.

2. Principle of Least Privilege

Only grant the necessary roles and permissions. Don’t give admin or broad roles like itil to users who only need specific access to a few records. Over-permissioning is a huge security risk.

3. Clear Naming Conventions

Use consistent and descriptive names for your roles, groups, and ACLs. For example, itil_hr_read or u_my_app_admin. This makes it much easier to understand at a glance what each permission set does.

4. Document Complex ACL Logic

If an ACL has a complicated script or a very specific condition, document its purpose directly in the ACL’s description field. Your future self (or your teammates) will thank you.

5. Regular Audits

Periodically review who has which roles, especially privileged roles. Ensure that access aligns with current job responsibilities. User delegation should also be audited regularly.

6. Update Set Management for ACLs

ACLs are configuration data, so they are captured in update sets. Update sets are stored in the sys_update_set table, and individual customizations in sys_update_xml. Remember these best practices for update sets:

  • Keep Update Sets Small: Don’t dump everything into one giant update set. Smaller, focused update sets are easier to review, test, and troubleshoot.
  • Name Them Well: Include the story number or a clear description.
  • Transactional Data vs. Configuration: Update sets capture system configuration changes (tables, fields, form layouts, business rules, ACLs, etc.), but NOT transactional data (Incidents, Users, Groups). Tables with the update_synch=true attribute are captured.
  • Moving Uncaptured Development: If something wasn’t captured (e.g., data or a specific record), you can manually export it as XML and import it into the target instance. Alternatively, you can use the GlideUpdateManager2 API to script the capture of specific records into an update set.

Connecting the Dots: Relevant Concepts for ACL Context

ACLs don’t live in a vacuum. They interact heavily with other core ServiceNow functionalities. Understanding these connections is key to mastering ACLs and is often a topic in interviews.

GlideRecord: Your Database Interaction Tool

GlideRecord is the server-side API for performing CRUD (Create, Read, Update, Delete) operations on ServiceNow database tables. It’s the workhorse for almost any server-side script.

// Creating a record
var gr = new GlideRecord('incident');
gr.initialize();
gr.short_description = 'Network problem';
gr.insert();

// Updating records
var gr = new GlideRecord('incident');
gr.addQuery('active',true);
gr.query();
while (gr.next()) {
    gr.active = false;
    gr.update();
}

// Deleting records
var gr = new GlideRecord('incident');
gr.addQuery('active',false);
gr.query();
while (gr.next()) {
    gr.deleteRecord();
}

GlideRecord vs. GlideRecordSecure: This is a classic interview question! Both perform CRUD. The key difference is that GlideRecordSecure automatically enforces ACLs by default. With standard GlideRecord, you have to explicitly check permissions using methods like canCreate(), canWrite(), canDelete(), canRead() if you want ACL enforcement.

Client Scripts and GlideRecord: While technically possible, using GlideRecord directly in client scripts is generally a bad practice due to performance issues. It forces the client to make a synchronous call to the server, which can freeze the user interface. For server calls from client scripts, GlideAjax is the preferred method, using a Script Include as the backend.

Script Includes: Reusable Server-Side Logic

Script Includes are server-side scripts (JavaScript) that are stored in ServiceNow and can be called from other server-side scripts (Business Rules, Workflow activities, other Script Includes, or via GlideAjax from client scripts). They are vital for reusing code and promoting modularity.

There are different types (Class, Classless, Extended/Client Callable). A common use case for ACLs is to call a function from a Script Include within an ACL’s script field. This keeps your ACLs clean and centralizes complex logic.

// Calling a Script Include from server-side
new MyUtils().myMethod(current); // Pass current record if needed
// OR
var util = new MyUtils();
util.someOtherMethod();

Script Include vs. Business Rule: Another common interview topic. Business Rules run automatically based on record operations (insert, update, delete, query, display). Script Includes run ONLY when explicitly called. Business rules are event-driven, Script Includes are function-driven.

Dot-Walking: Navigating Related Data

Dot-walking is a powerful feature that allows you to access fields on related tables from a form, list, or script. If a table has a reference field to another table, you can “walk” through that reference to access fields on the referenced table. For example, incident.assigned_to.company would get the company of the user assigned to an incident. This is incredibly useful in ACL conditions and scripts to evaluate permissions based on related data.

Table Administration Basics

Since ACLs operate on tables and fields, a foundational understanding of table administration is crucial:

  • Tables: A collection of records, each record a row, each field a column.
  • Table Extension: A child table can extend a parent table, inheriting its fields and records. You can only extend tables during creation.
  • Child/Parent/Base Class: A table extending another is a child class; the extended table is the parent. A parent not extending anything else is a base class.
  • Extension Models: ServiceNow offers ‘Table per class’ (separate DB table for parent/child), ‘Table per hierarchy’ (one DB table for parent/children), and ‘Table per partition’ (like hierarchy but dynamically adds storage partitions).
  • System vs. Custom Tables: System tables usually start with sys_; custom tables start with u_ (global scope) or x_ (scoped applications).
  • Global Default Fields: All tables get fields like sys_id, sys_created_on, sys_created_by, sys_mod_count, sys_updated_by, sys_updated_on, and sys_class_name (if extensible).

Conclusion: Embrace the ACL Journey

Resolving ACL issues can sometimes feel like solving a complex puzzle, but with a systematic approach, the right tools (like the ACL Debugger!), and a solid understanding of users, groups, roles, and best practices, you’ll master it. Remember to always question, always impersonate, and always debug. By adhering to best practices like assigning roles to groups and practicing the principle of least privilege, you’ll not only fix immediate access problems but also build a more secure, maintainable, and headache-free ServiceNow environment. Happy troubleshooting!


Scroll to Top