
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
02-15-2019 08:17 AM
Hello SN Comm,
I want to see if anyone knows a good way to protect attachments that are attached to an HR Case form? Can it be locked to only the Assigned To (and maybe also certain users with a special role, etc.)?
Maybe even having to enter in a password when trying to view the attachment from the Case?? I feel like that idea is pretty far out there, but hey - ya never know what the system can to until you go through it and/ or ask!
Thank you,
-Rob
Solved! Go to Solution.

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
02-17-2019 03:25 PM
Rob,
I see most of the replies have been to provide technical solutions within the HR Scoped app using ACLs.
I'm going to suggest another approach for you to think about. The HR Scoped App has an extra application "Employee Document Management". (https://docs.servicenow.com/bundle/london-hr-service-delivery/page/product/human-resources/concept/hr-employee-doc-management.html)
One of the key points with EDM is that it allows you to put security controls around documents associated with Employee's Profile (from cases, etc) via Document Types:
Use document types to:
- Associate a security policy. Security policies determine who can access employee documents and determine purge authorization.
- Associate a retention policy. Retention policies determine how long to keep a document and who the document is applicable to.
- Place a legal hold. Legal holds temporarily prevent document purging or changes to the document.-
- Allow access to employees.
- Configure employee documents to be moved automatically when an HR case is closed. Assign a topic detail associated with an HR service that has the Automatically move attachments box checked. See Configure an HR service.
Keep in mind EDM is an extra license cost.
Thanks,
Kevin
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
02-15-2019 08:54 AM
I would recommend to use this:
answer = getAns();
function getAns()
{
if(current.table_name == 'hr_case'){
if(current.sys_created_by == gs.getUserName() || gs.hasRole('The Role you are looking for')){
return true;
}else{
return false;
}
}
}
Please mark my response as correct and helpful if it helped solved your question.
-Thanks

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
02-15-2019 11:28 AM
Thank you both for helping out with this. I have done both of your suggestions and it is not working. I added in the actual Case table (as we are using Scoped), along with the role I wanted to test it against. And someone without that role and did not create the Case, can see the attachment attached to the Case.
Is there something missing/I am doing wrong?
Thank you!
-Rob
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
02-15-2019 11:34 AM
can you try including some log statements and see if its entering the loop at all?
Please mark my response as correct and helpful if it helped solved your question.
-Thanks

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
02-15-2019 11:42 AM
You might have another ACL for sys_documentation that says
answer = new global.AttachmentSecurity().canRead(current);
If thats the case, change the script in that record to add your new script before it.
answer = false;
if (current.table_name == 'sn_hr_core_case_relations') {
if (current.sys_created_by == gs.getUserName() || gs.hasRole('sn_hr_core.relations1')) {
answer = true;
} else {
answer = new global.AttachmentSecurity().canRead(current);
}
}

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
02-15-2019 11:59 AM
So I do have an ACL for read, called sys_documentation. However, there is no advanced script within it. It only has a role attached which is personalize_dictionary - that is it.
for the sys_attachment ACLs, I show 5 Read types. 4 ar global and one is HR Core (the one we created today from this post). Then one is actually called sys_attachment_doc.
There is one that has a larger script within it - that I think could be the reason why our smaller ACL from this post is not working..
answer = getAttachmentReadAnswer();
function getAttachmentReadAnswer() {
if (current.table_name.nil())
return true;
// If the attachment is from live feed,
// grant it the read access
if (current.table_name.indexOf("live_profile") > -1 || current.table_name.indexOf("live_group_profile") > -1)
return true;
// Remove Prefix
var tableName = current.table_name + '';
if (tableName.startsWith("invisible."))
tableName = tableName.substring(10);
else if (tableName.startsWith("ZZ_YY"))
tableName = tableName.substring(5);
var parents = SNC.CMDBUtil.getTables0(tableName);
if (!parents.contains('hr_case') && !parents.contains('hr_task') && !parents.contains('sn_hr_core_case') && !parents.contains('sn_hr_le_case') && !parents.contains('sn_hr_core_task') && tableName != 'signature_image')
if (gs.hasRole('admin'))
return true;
var parentRecord = new GlideRecord(tableName);
parentRecord.setWorkflow(false);
if (!parentRecord.isValid() || !parentRecord.get(current.table_sys_id)) {
if (current.sys_created_by.equals(gs.getUserName()))
return true;
return false;
}
if (parents.contains('hr_case') || parents.contains('hr_task'))
return verifyReadAccessToHR(parentRecord, tableName);
if (parents.contains('sn_hr_core_case') || parents.contains('sn_hr_le_case') || parents.contains('sn_hr_core_task'))
return verifyReadAccessToScopedHR(parentRecord, tableName);
if (tableName == 'signature_image')
return verifyReadAccessToSignatureImage(parentRecord);
return parentRecord.canRead();
}
function verifyReadAccessToHR(gr, name){
if (GlideImpersonate().isImpersonating() && gs.getProperty('com.snc.hr.core.impersonateCheck') == 'true')
return false;
var roles = gs.getUser().getRoles();
var parents = SNC.CMDBUtil.getTables0(name);
if (parents.contains('hr_case')){
if (roles.indexOf("hr_case_reader") > -1||(new global.hr_Case(gr, gs).canEditCase()))
return true;
else
return false;
}
if (parents.contains('hr_task')){
if (roles.indexOf("hr_task_reader") > -1||(new global.hr_Task(gr, gs).canEditTask()))
return true;
else
return false;
}
}
function verifyReadAccessToScopedHR(gr, name) {
if (GlideImpersonate().isImpersonating() && gs.getProperty('sn_hr_core.impersonateCheck') == 'true')
return false;
var roles = gs.getUser().getRoles();
var parents = SNC.CMDBUtil.getTables0(name);
if (parents.contains('sn_hr_core_case')) {
if (roles.indexOf("sn_hr_core.case_reader") > -1 || (new sn_hr_core.hr_Case(gr).canEditCase()))
return true;
else
return false;
}
if (parents.contains('sn_hr_le_case')) {
if (roles.indexOf("sn_hr_le.case_reader") > -1 || sn_hr_le.hr_LECaseAccess.canEditCase(gr))
return true;
else
return false;
}
if (parents.contains('sn_hr_core_task')){
if (roles.indexOf("sn_hr_core.case_reader") > -1 || (new sn_hr_core.hr_Task(gr).canEditTask()))
return true;
else
return false;
}
}
function verifyReadAccessToSignatureImage(parentRecord){
if (GlideImpersonate().isImpersonating() && (gs.getProperty('com.snc.hr.core.impersonateCheck') == 'true' || gs.getProperty('sn_hr_core.impersonateCheck') == 'true'))
return false;
var roles = gs.getUser().getRoles();
if (roles.indexOf("hr_basic") > -1)
return true;
if (roles.indexOf("sn_hr_core.basic") > -1)
return true;
if (parentRecord.user == gs.getUserID())
return true;
else
return false;
}