Restricting specific records in a table using ACL
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎12-16-2016 11:10 AM
Hi, all. I'm just learning how to manage a ServiceNow instance, and I need help writing an ACL. I've created an application on a personal developer instance, and within that app, I've created and populated a few tables. The app is basically just flashcards (a la Quizlet or Cram), but implemented in SN. Users can create "decks" of flashcards, and I want to make sure that a deck can only be viewed by the user who "owns" it.
This is a summary of the schema; names are not exact. A "term" is basically a flashcard. Tables that start with "m2m" are many-to-many relations that allow me to associate multiple terms to multiple decks, and multiple decks to multiple users. Fields that start with an ampersand (&) are references to records in other tables.
* deck_of_terms( deck_name, &owner );
* terms( term, definition );
* m2m_deck_to_terms( &deck_of_terms_reference, &term );
* m2m_deck_to_user( &deck_of_terms_reference, &sys_user_reference );
Onto the ACLs. I created a new ACL with the following settings:
* type=record
* operation=read
* name=x_65763_studyapp_deck_of_terms.*
* requires_role=[x_65763_studyapp_deck_of_terms_user]
* condition="Owner is(dynamic) Me"
Here's a screenshot of the ACL form:
So I saved this ACL, and then impersonated a user who owns a deck (Joe Employee). Then I navigate to the deck_of_terms table. There's a total of six decks, and exactly one of them is owned by Joe Employee. Thus, I expected for there to only be one record, but instead there are six. Actually, it's weirder than that. Joe Employee's deck appears as normal, but all the other records on the table are completely blank. Here's a screenshot:
Furthermore, when I actually click on Joe's deck, the Related List of terms is blank. Instead of terms, I see "Number of rows removed from this list by Security constraints: 3" (Joe's deck has 3 cards in it, so 100% of cards are being blocked). Here's another screenshot:
I've read some of the product documentation, and that's gotten me this far, but I don't know what to do at this point. I'm vaguely aware of ACLs applying to different "levels" of object (e.g. tables, records, fields), and I suspect that's the part I'm getting wrong. Maybe I should be writing a script instead of using the condition builder?
TL;DR: I have a table called [deck_of_terms] that has a column (called "owner") that references [sys_user]. I want to make sure that, when viewing [deck_of_terms.list], a user can only see records that he/she "owns". I've written an ACL rule, but it's probably all kinds of wrong.
EDIT: Solution
I got some outside help (thanks Slack user ajb), and made the following changes.
1) I removed the ".*" from the ACL name definition. Apparently the ".*" indicates that the ACL rule should apply to the fields of the record in question, and not to the record itself. At this point, all the records appear on [deck_of_terms.list], but the terms are blocked when I click into any record. So it's better, but not yet fully fixed.
2) I disabled the default ACL-Read rule on this table, because (for whatever reason) the system would evaluate the default rule and then refuse to evaluate any rules after that. This is bad, because I want it to evaluate my custom ACL rule, which has the `Owner is(dynamic) Me` condition.
3) I had to create yet another ACL rule on the table [m2m_deck_to_terms.read], where I sort-of repeat the previous condition. The (modified) condition here is `deck_of_terms.owner is(dynamic) Me`. This step is necessary because the records that I'm restricting are not just on the table [deck_of_terms]; I am also restricting the records on [m2m_deck_to_terms].
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎12-16-2016 11:35 AM
I noticed your application is scoped. I have run into issues before using the "Me" dynamic filter in the ACL condition. To overcome this, I had to change it to use the same function that the Me dynamic filter is calling: gs.getUserID()
So try changing your ACL to Owner is javascript: gs.getUserID() and see if that fixes it.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎12-16-2016 12:33 PM
Thank you for the suggestion! I tried removing the condition and replacing it with the script `answer = ( current.getValue('owner')==gs.getUserID() );`, which I think is what you suggested. It didn't change the results, however. But there is good news! I found a solution. Will edit the original post to include the fix.
Thanks for your prompt response, though! The condition builder wasn't the problem this time, but I'll definitely keep in mind the fact that it can cause issues in scoped applications.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎12-16-2016 12:53 PM
Glad you got it working. Just to make sure though, I meant to set your condition to this:
So basically change the qualifier from is dynamic to is and then just put javascript:gs.getUserID() in the value field. This was the old way of accomplishing these queries before dynamic filter options was introduced in Dublin (I believe).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎12-16-2016 01:09 PM
Oh wow, I didn't know I could do that! I'll definitely keep that trick in mind for the future. Thanks!