
- Post History
- Subscribe to RSS Feed
- Mark as New
- Mark as Read
- Bookmark
- Subscribe
- Printer Friendly Page
- Report Inappropriate Content
on 02-14-2018 08:07 AM
Quite frequently we hit the requirement that certain data in a customer instance needs to be secured / protected against accidental access. The obvious choice and also in-line with technical best practice is to use an Access control rules aka ACL.
So far so good, but what if the rule is not as simple as defining a condition or checking a system role? ¨
Assume we have users from multiple companies accessing our system. The easy part is to allow access to the records based on company, i.e. Company A can only see their own incidents. But if we have another company - maybe a partner - who also needs access to Company A's incidents we are screwed. Let's see how we can tackle it.
Allow configuration to define access
Create a new field on the user record to store which companies a user is allowed to see
This field has to be of type glide_list so we can store more than one company.
We could also do a separate table if we do not want to pollute / enhance the sys_user record. In the end all we need is a place where we find what records are ok to be seen for the given user.
Create Access Control Rule (ACL)
With the persisted information on what a user can access, we can define appropriate Read-ACL using a script to read that information from the user record. While this will work perfectly, it does have a significant impact to the performance. Imagine we load a list of 20 incidents, for each and every incident the system now needs to go back to the user record and find our new custom field. This means we fire 20 new select statements to the database always returning the same value. Of course a cache would probably sort most of it out, but imagine your rule being even more complex. I have seen customer scenarios where the information could not be stored directly on the user record, but on related information like a specific other data set that needed to be loaded. Anyhow, fetching this information for every record is surely not recommendable for a read operation.
Store user specific information in session object
With every login to the instance the platform will create a session object. If we store the information we need in here, our ACL has no need to fetch it from the database for every record. Here is how this can be achieved:
With the login the platform will fire an event called 'session.established'. Usually this is used for reporting purposes, but we can leverage it for our case.
Create a script action
Create a new Script action listening to our event 'session.established'. There is one important gotcha in getting this to work. Usually all script actions will run asynchronously causing the session to be established properly, but whatever your script does will have no effect to the session. To avoid that we need to change our action to run synchronously. To do so we need to cheat a little. There is a field on our script action table called synchronous (sysevent_script_action.synchronous), but this column is being hidden from us by ACLs. So elevate your privileges to security admin and search of ACLs with name 'sysevent_script_action.synchronous' - you should find two of them. Simple deactivate them for now. As the column is not on the form we will need to add it to our list view, this will not cause any future harm. Once your see it, change it to 'true' for our new script action. Should look like this:
Awesome. Now to the script content:
var session = gs.getSession();
session.putClientData('test1', 'Harry');
With this example we store the value of 'Harry' as property named 'test1'. Obviously this needs to be amended to first find the data we need, like querying the user record for the companies we want to allow.
Change the ACL script
Within our read ACL where we used to lookup the user record we now need to change it to fetch the information from the user session:
var session = gs.getSession();
var clientData = session.getClientData('test1');
// now check current record
if (current.company == clientData) {
answer = true;
} else {
answer = false;
}
Now we can use the 'clientData' variable to validate the current record. In my example I am using a simple '==' operator, if clientData contains a list of objects make sure you do amend as necessary.
Optional: Create Before Query Business Rule
With the ACL's in place we can rest assured our data is safe. However it is still showing the message to the user that certain records are removed due to security constraints. If we want to avoid that we can add a before query business rule. This would look something like this:
current.addQuery("company", "IN", gs.getSession().getClientData('test1'));
Now the query to the database will be modified before it hits the database even filtering the records in the first place. This will completely avoid the ACL Read scripts as the data is not even there anymore. Much better as we removed unnecessary operations from the execution making the system faster for our end users.
- 3,204 Views
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi - I am about to do some work in this area and was wondering if you had any follow up thoughts or lessons learned on this a year later? also if any developments in the platform capability in the last 12 months have changed any of this advice?

- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi Marcus,
good question. There are quite a set of features or functionality better which could help make your life easier: Customer Service Management, Application Scopes, Domain Separation, Simple Record Separation (share app) just to name a few.
Which one fits best depends on your exact use case. I personally still use above setup as a good example in new customers.
Fogg
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi Fogg, hope you're well!
Thanks for your post.. I'm trying use in my company, but I missed something.. because I really isnt good with codes yet. Can you help me?
I created the u_client_data field in the sys_user table
And I created a script action:
var session = gs.getSession();session.putClientData('test1', 'Harry');
ACL read:
var session = gs.getSession();
var clientData = session.getClientData('test1');
if (current.u_requisitado_por_task.company == clientData){
answer = true;
} else {
answer = false;
}
I can't get to the right script 😞
Thanks in advance!

- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi g_0710,
As long as your script action has been set to synchronous you have this part correct.
In your ACL script though it seems you do a dot-walking to 'company'. In this case the u_requisitado_por_task field would need to be a reference field. I would not recommend doing that as the dot-walking forces the platform to do another database query to get the referenced record.
You really want the information required to determine access rights to be on the current record.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Daniel.Draes could this possibly improve performance if implemented properly rather than hinder it?

- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
There is probably more to this, especially when you start to add additional conditions to the queries. User can do so by narrowing down their searches or creating reports. Hitting the right indexes will get more complex, I would then recommend to involve a good DBA to make sure the queries produced are optimal.