Name
sn_grc.GRCSecurityManagerBase
Description
No description available
Script
var GRCSecurityManagerBase = Class.create();
GRCSecurityManagerBase.prototype = {
initialize: function() {
this.confidentialFields = ["is_confidential","confidential_users","confidential_user_groups"];
},
isRecordConfidential: function(record){
return this._isRecordConfidential(record);
},
isUserMemberOfGroup: function(groups){
return this._isUserMemberOfAnyGroup(groups);
},
_isConfidentialityEnabled: function(){
return gs.getProperty('sn_grc.enable_record_confidentiality') == "true";
},
_isRecordConfidential: function(record){
var fields = this._getCustomConfidentialFields(record.getTableName());
if(fields){
return this._isConfidentialityEnabled() && record.getValue(fields['confidentialFlag']) == 1;
}
return false;
},
shouldCheckExistingACL: function(record){
return this._shouldCheckExistingACL(record);
},
_shouldCheckExistingACL: function(record){
var fields = this._getCustomConfidentialFields(record.getTableName());
if(fields){
var value = record.getValue(fields['confidentialFlag']);
return gs.getProperty('sn_grc.enable_record_confidentiality') == "false" || gs.getProperty('sn_grc.enable_record_confidentiality') == "true" && (gs.nil(value) || value == 0);
}
return true;
},
getUserGroupListToBeNotified: function(current, previous){
return this._getUserGroupListToBeNotified(current, previous);
},
canReadConfidentialRecord: function(record){
return this._canReadConfidentialRecord(record);
},
canAccessConfidentialRecord: function(record) {
return this._canAccessConfidentialRecord(record);
},
getCustomConfidentialFields: function(table){
return this._getCustomConfidentialFields(table);
},
isConfidentialTable: function(tableName) {
return this._isConfidentialTable(tableName);
},
getConfidentialitySourceUserGroups: function(tableName, sysId, usersCopySource, groupsCopySource, usersOnForm, groupsOnForm,referenceTableValuesForUsers,referenceTableValuesForGroups){
return this._getConfidentialitySourceUserGroups(tableName, sysId, usersCopySource, groupsCopySource, usersOnForm, groupsOnForm,referenceTableValuesForUsers,referenceTableValuesForGroups);
},
setScratchpadVars: function(record){
return this._setScratchpadVars(record);
},
_checkIfColumnsExists: function(tableName, columnNameArr){
var table = new GlideTableHierarchy(tableName);
var dictionaryGr = new GlideRecord("sys_dictionary");
dictionaryGr.addQuery("name","IN",table.getTables());
dictionaryGr.addQuery("element","IN", columnNameArr);
dictionaryGr.query();
if(dictionaryGr.hasNext()){
return (dictionaryGr.getRowCount() == columnNameArr.length);
}
return false;
},
_setScratchpadVars: function(record){
var fields = this._getCustomConfidentialFields(record.getTableName());
g_scratchpad.isConfidentialityPropertyEnabled = this._isConfidentialityEnabled();
g_scratchpad.canReadRecord = record.canRead();
if(fields){
g_scratchpad.isConfidentialChecked = record.getValue(fields['confidentialFlag']) == 1;
}
else{
gs.error(gs.getMessage("Confidential fields not present in the table"));
}
},
_getConfidentialitySourceUserGroups: function(tableName, sysId, usersCopySource, groupsCopySource, usersOnForm, groupsOnForm,referenceTableValuesForUsers,referenceTableValuesForGroups){
var usersOrGroups = {'confidentialUsers': [], 'confidentialGroups': []};
var confidentialUsers, confidentialGroups;
var record = new GlideRecord(tableName);
if(record.get(sysId)) {
confidentialUsers = this._copyFields(record, usersCopySource, usersOnForm);
confidentialGroups = this._copyFields(record, groupsCopySource, groupsOnForm);
} else {
confidentialUsers = this._getConfidentialUsersGroupsForNewRecord(tableName,usersCopySource, usersOnForm,referenceTableValuesForUsers);
confidentialGroups = this._getConfidentialUsersGroupsForNewRecord(tableName,groupsCopySource, groupsOnForm,referenceTableValuesForGroups);
}
usersOrGroups.confidentialUsers = confidentialUsers;
usersOrGroups.confidentialGroups = confidentialGroups;
return usersOrGroups;
},
_copyFields: function(record, field, ids){
var sysIdList = [];
if(!gs.nil(ids)){
sysIdList = ids.split(",");
}
if(!gs.nil(field)){
var usersGroupArr = field.split(",");
for (var i = 0; i < usersGroupArr.length; i++) {
var value = record.getElement(usersGroupArr[i]) + '';
//Value can be a user/group or list of users/groups
if (value && value != "null") {
var arr = value.split(",");
for (var temp in arr) {
if (sysIdList.indexOf(arr[temp]) == '-1') {
sysIdList.push(arr[temp]);
}
}
}
}
}
return sysIdList;
},
_getConfidentialUsersGroupsForNewRecord: function(tableName,dotWalkedFields,directFields,referenceIds) {
/*
tableName - current table on which confidentiality is marked
dotWalkedFields - fields which are not present on form
directFields - fields which are on form
referenceIds - reference table record Ids to fetch fields which are not on form
*/
var sysIdList = [];
if(!gs.nil(dotWalkedFields))
var allDotWalkedFields = dotWalkedFields.split(",");
if(!gs.nil(referenceIds))
var references = referenceIds.split(",");
var currentTable = new GlideRecord(tableName);
var table,value;
if(!gs.nil(directFields)){
sysIdList = directFields.split(",");
}
if(!gs.nil(allDotWalkedFields) || !gs.nil(references)) {
for(var i=0;i<allDotWalkedFields.length; i++) {
var field = allDotWalkedFields[i];
var fieldArr = field.split(".");
//fetching table record from reference value present on form
table = new GlideRecord(currentTable.getElement(fieldArr[0]).getReferenceTable());
table.get(references[i]);
//removing first element and quering referenced table for actual field value
fieldArr.shift();
value = table.getElement(fieldArr.join(","));
//value can be user/grp or list of users/groups
if (value && value != "null") {
var arr = value.split(",");
for (var temp in arr) {
if (sysIdList.indexOf(arr[temp]) == '-1') {
sysIdList.push(arr[temp]);
}
}
}
}
}
return sysIdList;
},
_isConfidentialTable: function(tableName){
var table = new GlideTableHierarchy(tableName);
var dictionaryGr = new GlideRecord("sys_dictionary");
dictionaryGr.addQuery("name","IN",table.getTables());
dictionaryGr.addQuery("element","CONTAINS","confidential");
dictionaryGr.query();
if(dictionaryGr.hasNext()) {
while(dictionaryGr.next()) {
if(this.confidentialFields.indexOf(dictionaryGr.getValue("element")) == "-1") {
return false;
}
}
} else {
return false;
}
return true;
},
_getCustomConfidentialFields: function(tableName){
var fields;
var table = new GlideRecord("sn_grc_confidentiality_configuration");
table.addActiveQuery();
table.addQuery("table",tableName);
table.query();
if(table.next()){
if(!gs.nil(table.confidentiality_field) && !gs.nil(table.allowed_users_field) && !gs.nil(table.allowed_groups_field)){
if(this._checkIfColumnsExists(tableName, [table.getValue('confidentiality_field'), table.getValue('allowed_users_field'), table.getValue('allowed_groups_field')])){
fields = {
'confidentialFlag': table.getValue('confidentiality_field'),
'confidentialUsers': table.getValue('allowed_users_field'),
'confidentialGroups': table.getValue('allowed_groups_field'),
'doesConfidentialityConfigExist': true,
'autoPopulate': (table.getValue('auto_populate') == "1")
};
if(fields.autoPopulate){
var allowedFieldSources = {
'confidentialUsersSource': table.getValue('user_fields'),
'confidentialGroupsSource': table.getValue('group_fields')
};
fields.allowedFieldSources = allowedFieldSources;
}
}
}
}
else if(this._isConfidentialTable(tableName)){
fields = {
'confidentialFlag': this.confidentialFields[0],
'confidentialUsers': this.confidentialFields[1],
'confidentialGroups': this.confidentialFields[2],
'doesConfidentialityConfigExist': false
};
}
return fields;
},
/* checks if record is confidential given confidentiality property is enabled
If yes, checks current user is part of allowed users/groups and grants access */
_canAccessConfidentialRecord: function(record) {
if(this._isRecordConfidential(record)){
return this._checkForConfidentialRecordAccess(record);
}
return true;
},
_checkForConfidentialRecordAccess: function(record) {
var fields = this._getCustomConfidentialFields(record.getTableName());
var allowedUsers = record.getValue(fields['confidentialUsers']);
var allowedUserGroups = record.getValue(fields['confidentialGroups']);
var isAllowedUser = false, isAllowedGroup = false;
if(!gs.nil(allowedUsers)){
isAllowedUser = allowedUsers.includes(gs.getUserID());
}
if(!gs.nil(allowedUserGroups)){
isAllowedGroup = this._isUserMemberOfAnyGroup(allowedUserGroups);
}
return isAllowedUser || isAllowedGroup;
},
_isUserMemberOfAnyGroup: function(groups){
if(!gs.nil(groups)){
var currentUser = gs.getUserID();
if(this._isMemberOfGroup(groups, currentUser))
return true;
}
return false;
},
_isMemberOfGroup: function(groups, userID){
var userGrrec = new GlideRecord("sys_user_grmember");
userGrrec.addQuery("user", userID);
userGrrec.addQuery("group",'IN',groups);
userGrrec.setLimit(1);
userGrrec.query();
if(userGrrec.next())
return true;
return false;
},
_canReadConfidentialRecord: function(record){
if(this._isRecordConfidential(record)){
return this._checkForConfidentialRecordAccess(record);
}
return false;
},
_getUserGroupListToBeNotified: function(current, previous){
var receipentList = [];
var fields = this._getCustomConfidentialFields(current.getTableName());
if(fields){
if(current.getElement(fields['confidentialUsers']).changes()){
this._getNewlyAddedSysIds(previous, current, fields['confidentialUsers'], receipentList, fields);
}
if(current.getElement(fields['confidentialGroups']).changes()){
this._getNewlyAddedSysIds(previous, current, fields['confidentialGroups'], receipentList, fields);
}
}
return receipentList;
},
_getNewlyAddedSysIds: function(previous, current, fieldName, receipentList, confFields){
var newValue = current.getValue(fieldName);
var receipentArr = newValue ? newValue.split(',') : [];
var prevValue = previous.getValue(fieldName);
for(var i = 0; i < receipentArr.length; i++){
if(!prevValue || prevValue && prevValue.indexOf(receipentArr[i]) == -1){
this._addUser(receipentArr[i],fieldName, receipentList, confFields);
}
}
},
_addUser: function(receipentSysid, fieldName, receipentList, confFields){
var receipent, type;
if(fieldName == confFields['confidentialUsers']){
receipent = new GlideRecord('sys_user');
type = 'users';
}
else{
receipent = new GlideRecord('sys_user_group');
type = 'groups';
}
if(receipent.get(receipentSysid)){
receipentList.push({'sysId': receipentSysid, 'name': receipent.getValue('name'),'type': type});
}
},
getO2MRelationshipData: function(mainTable,inheritingTable) {
return this._getO2MRelationshipData(mainTable,inheritingTable);
},
getM2MRelationshipData: function(mainTable,inheritingTable) {
return this._getM2MRelationshipData(mainTable,inheritingTable);
},
getScriptedRelationshipData: function(mainTable,inheritingTable) {
return this._getScriptedRelationshipData(mainTable,inheritingTable);
},
getM2MTableFields: function(mainTable,inheritingTable) {
return this._getM2MTableFields(mainTable,inheritingTable);
},
getExistingRelationshipTypes: function(mainTable,inheritingTable) {
var o2mResult = this._getO2MRelationshipData(mainTable,inheritingTable);
var m2mResult = this._getM2MRelationshipData(mainTable,inheritingTable);
var scriptedResult = this._getScriptedRelationshipData(mainTable,inheritingTable);
return {
"isO2M":o2mResult.isO2M,
"isM2M":m2mResult.isM2M,
"isScripted":scriptedResult.isScripted
};
},
/* Returns the fields on inheritingTable which have references to the tables in mainTable hierarchy ,
if one to many relationship type exists between main and inheriting tables. */
_getO2MRelationshipData: function(mainTable,inheritingTable) {
var mainTableHierarchy = new GlideTableHierarchy(mainTable).getTables();
var inheritingTableHierarchy = new GlideTableHierarchy(inheritingTable).getTables();
var fields = [] , isO2M = false;
fields = this._getReferencingFields(inheritingTableHierarchy,mainTableHierarchy);
if(fields.length) {
isO2M = true;
}
return {
"isO2M":isO2M,
"fields":fields
};
},
/* Returns many to many relationship tables existing between main table and inheriting table */
_getM2MRelationshipData: function(mainTable,inheritingTable) {
var mainTableHierarchy = new GlideTableHierarchy(mainTable).getTables();
var inheritingTableHierarchy = new GlideTableHierarchy(inheritingTable).getTables();
var fields = [] , isM2M = false;
var data = this._getM2MTables(mainTableHierarchy,inheritingTableHierarchy);
var m2mTables = data.m2mTables;
if(m2mTables.length) {
isM2M = true;
}
var m2mTableFields = this._getM2MTableFields(mainTable,m2mTables[0]);
return {
"isM2M":isM2M,
"m2mTables":m2mTables,
"m2mTablesData":data.m2mTablesData,
"m2mTableFields":m2mTableFields
};
},
/* Returns fields on m2m table which have references to tables in mainTable hierarchy */
_getM2MTableFields: function(mainTable,m2mTable) {
var mainTableHierarchy = new GlideTableHierarchy(mainTable).getTables();
var m2mTableHierarchy = new GlideTableHierarchy(m2mTable).getTables();
var fields = this._getReferencingFields(m2mTableHierarchy,mainTableHierarchy);
return fields;
},
/* Returns scripted relationship existing between main and inheriting tables */
_getScriptedRelationshipData: function(mainTable,inheritingTable) {
var mainTableHierarchy = new GlideTableHierarchy(mainTable).getTables();
var inheritingTableHierarchy = new GlideTableHierarchy(inheritingTable).getTables();
var isScripted = false, relationships = [];
var data = this._getM2MTables(mainTableHierarchy,inheritingTableHierarchy);
var m2mTables = data.m2mTables;
var relationshipGr = new GlideRecord("sys_relationship");
relationshipGr.addQuery("basic_apply_to","IN",mainTableHierarchy);
relationshipGr.addQuery("basic_query_from","IN",inheritingTableHierarchy + "," + m2mTables);
relationshipGr.query();
if(relationshipGr.hasNext()) {
isScripted = true;
while(relationshipGr.next()) {
relationships.push({
"name":relationshipGr.getUniqueValue(),
"label":relationshipGr.getValue("name")
});
}
}
return {
"isScripted":isScripted,
"relationships":relationships
};
},
_getM2MTables: function(mainTableHierarchy,inheritingTableHierarchy) {
var tables = [],m2mTables = [],m2mTablesData = [];
/* sys_collection contains OOTB many to many relationships */
var collectionGr = new GlideRecord("sys_collection");
collectionGr.addQuery("name","IN", mainTableHierarchy + "," + inheritingTableHierarchy);
collectionGr.query();
while(collectionGr.next()) {
// storing unique tables from sys_collection table
if(tables.indexOf(collectionGr.getValue("collection")) < 0) {
tables.push(collectionGr.getValue("collection"));
}
}
for(var i=0; i < tables.length; i++) {
var tableHierarchy = new GlideTableHierarchy(tables[i]).getTables();
var hasMainTableReference = false, hasInheritingTableReference = false , fields = [];
var dictionaryGr = new GlideRecord("sys_dictionary");
dictionaryGr.addQuery("name","IN",tableHierarchy);
dictionaryGr.addQuery("internal_type","reference");
dictionaryGr.query();
while(dictionaryGr.next()) {
fields.push(dictionaryGr.getValue("reference"));
}
for(var j=0; j<fields.length; j++) {
if(mainTableHierarchy.indexOf(fields[j]) >= 0) {
hasMainTableReference = true;
fields.splice(j,1);
break;
}
}
for(var k=0; k<fields.length; k++) {
if(inheritingTableHierarchy.indexOf(fields[k]) >= 0) {
hasInheritingTableReference = true;
break;
}
}
if(hasMainTableReference && hasInheritingTableReference) {
m2mTables.push(tables[i]);
m2mTablesData.push({
"name":tables[i],
"label":new GlideRecord(tables[i]).getClassDisplayValue()
});
}
}
/* sys_m2m contains custom many to many relationships */
var table;
var query = "from_tableIN" + mainTableHierarchy + "^to_tableIN" + inheritingTableHierarchy + "^NQfrom_tableIN" + inheritingTableHierarchy + "^to_tableIN" + mainTableHierarchy;
var customM2M = new GlideRecord("sys_m2m");
customM2M.addEncodedQuery(query);
customM2M.query();
if(customM2M.hasNext()) {
while(customM2M.next()) {
table = customM2M.getValue("m2m_table");
m2mTables.push(table);
m2mTablesData.push({
"name":table,
"label":new GlideRecord(table).getClassDisplayValue()
});
}
}
return {
"m2mTables":m2mTables,
"m2mTablesData":m2mTablesData
};
},
_getReferencingFields: function(tableHierarchy,referenceTableHierarchy) {
var fields = [];
var dictionaryGr = new GlideRecord("sys_dictionary");
dictionaryGr.addQuery("name","IN",tableHierarchy);
dictionaryGr.addQuery("internal_type","reference");
dictionaryGr.addQuery("reference","IN",referenceTableHierarchy);
dictionaryGr.query();
while(dictionaryGr.next()) {
fields.push({
"name": dictionaryGr.getValue("element"),
"label": dictionaryGr.getValue("column_label")
});
}
return fields;
},
processConfidentialityInheritance: function(current) {
var inheritanceConfigExists = this._checkIfInheritanceConfigExists(current.getTableName());
if (inheritanceConfigExists) {
gs.addInfoMessage(gs.getMessage("Related records will be marked as confidential based on {0} confidentiality inheritance configuration done by admin. This process may take some time to complete.",[current.getClassDisplayValue()]));
this._createRecordToBeProcessed(inheritanceConfigExists, current,true,gs.getUserID());
}
},
getConfidentialityConfigRecord: function(sysId) {
return this._getConfidentialityConfigRecord(sysId);
},
createRecordToBeProcessed: function(inheritanceConfig,current,type,userId) {
return this._createRecordToBeProcessed(inheritanceConfig,current,type,userId);
},
checkIfInheritanceConfigExists:function(table) {
return this._checkIfInheritanceConfigExists(table);
},
/* checks inheritance status table for records in ready state to be processed */
checkRecordsForProcessingInQueue: function() {
var inheritanceStatus = new GlideRecord("sn_grc_confidentiality_inheritance_status");
inheritanceStatus.addQuery("state","1");
inheritanceStatus.query();
if(inheritanceStatus.hasNext())
return true;
return false;
},
handleRecordsInQueue: function() {
return this._handleRecordsInQueue();
},
processRecordForConfidentialityInheritance: function(table,sysId,processingGr) {
return this._processRecordForConfidentialityInheritance(table,sysId,processingGr);
},
/* fetches records which are in ready state from conf_inhertanc_status table */
_handleRecordsInQueue: function() {
var batch_size = 5;
var inheritanceStatus = new GlideRecord("sn_grc_confidentiality_inheritance_status");
inheritanceStatus.addQuery("state","1");
inheritanceStatus.orderBy("sys_created_on");
inheritanceStatus.setLimit(batch_size);
inheritanceStatus.query();
while(inheritanceStatus.next()) {
// updating state to processing
inheritanceStatus.setValue("state","2");
inheritanceStatus.update();
this._processRecordForConfidentialityInheritance(inheritanceStatus.getValue("table"),inheritanceStatus.getValue("source"),
inheritanceStatus);
//updating state to processed
inheritanceStatus.setValue("state","3");
inheritanceStatus.update();
}
},
/* fetches confidentiality configuration and inheritance configuration for given parent table and processes the child records*/
_processRecordForConfidentialityInheritance: function(table,sysId,processingGr) {
var parentRecord = new GlideRecord(table);
parentRecord.get(sysId);
var inheritanceGr = new GlideRecord("sn_grc_confidentiality_inheritance_configuration");
inheritanceGr.addQuery("main_table.table",table);
inheritanceGr.addQuery("active",true);
inheritanceGr.query();
while(inheritanceGr.next()) {
var parentConfidentialRecord = this._getConfidentialityConfigRecord(inheritanceGr.getValue("main_table"));
var childConfidentialRecord = this._getConfidentialityConfigRecord(inheritanceGr.getValue("inheriting_table"));
this._markORunmarkChildRecordsConfidential(parentConfidentialRecord,childConfidentialRecord,inheritanceGr,
parentRecord,processingGr);
}
},
/* returns confidentiality config record for given sys_id */
_getConfidentialityConfigRecord: function(sysId) {
var confidentialGr = new GlideRecord("sn_grc_confidentiality_configuration");
confidentialGr.get(sysId);
return confidentialGr;
},
/* checks if inheritance configuration exists for a given table */
_checkIfInheritanceConfigExists: function(table) {
var inheritanceGr = new GlideRecord("sn_grc_confidentiality_inheritance_configuration");
inheritanceGr.addQuery("main_table.table",table);
inheritanceGr.addQuery("active",true);
inheritanceGr.query();
if(inheritanceGr.hasNext()) {
return true;
}
return false;
},
/* marks/unmarks child records of parent table depending upon relationships existing between them
Parameters -- Confidentiality config records of both parent and child
Confidentiality inheritance config existing between parent and child
Parent record on which childs needs to be marked/unmarked as confidential
processingGr -- confidentiality inheritance status record which maintains information about parentRecord
*/
_markORunmarkChildRecordsConfidential: function(parentConfidentialRecord,childConfidentialRecord,inheritanceConfig,
parentRecord,processingGr) {
var relationshipType = inheritanceConfig.getValue("relationship_type");
var relationshipTable = inheritanceConfig.getValue("relationship_table");
var relationshipData = inheritanceConfig.getValue("relationship_data");
var childTable = childConfidentialRecord.getValue("table");
if(relationshipType == "one_to_many") {
this._markORunmarkO2MRelationshipRecordsConfidential(parentConfidentialRecord,childConfidentialRecord
,parentRecord,childTable,relationshipData,processingGr);
} else if(relationshipType == "many_to_many") {
this._markORunmarkM2MRelationshipRecordsConfidential(parentConfidentialRecord,childConfidentialRecord
,parentRecord,childTable,relationshipData,relationshipTable,processingGr);
} else {
this._markORunmarkScriptedRelationshipRecordsConfidential(parentConfidentialRecord,childConfidentialRecord
,parentRecord,childTable,relationshipData,processingGr);
}
},
/* marks/unmarks confidentiality on child records if parent is connected to child in one-to-many relationship */
_markORunmarkO2MRelationshipRecordsConfidential: function(parentConfidentialRecord,childConfidentialRecord,parentRecord,childTable,
referenceField,processingGr) {
var childConfidentialityField = childConfidentialRecord.getValue("confidentiality_field");
var type = processingGr.getValue("confidentiality");
var currentUser = processingGr.getValue("user_id");
/* checks if inheritance configuration exists on child table */
var inheritanceConfigExists = this._checkIfInheritanceConfigExists(childTable);
var childGr = new GlideRecord(childTable);
childGr.addQuery(referenceField,parentRecord.getUniqueValue());
/* If type is marking,child records should be made confidential
if type is unmarking, child records should be made non-confidential */
if(type == "marking") {
childGr.addNullQuery(childConfidentialityField).addOrCondition(childConfidentialityField,false);
childGr.query();
if(childGr.hasNext()) {
this._setConfidentialityFieldValues(parentConfidentialRecord,childConfidentialRecord,parentRecord,childGr,
inheritanceConfigExists);
}
} else if(type == "unmarking") {
childGr.addQuery(childConfidentialityField,true);
this._removeConfidentialityFieldValues(childConfidentialRecord,parentRecord,childGr,currentUser,inheritanceConfigExists);
}
},
/* marks/unmarks confidentiality on child records if parent is connected to child in many-to-many fashion */
_markORunmarkM2MRelationshipRecordsConfidential: function(parentConfidentialRecord,childConfidentialRecord
,parentRecord,childTable,referenceField,m2mTable,processingGr) {
var childSysIds = [],childTableReference;
var childConfidentialityField = childConfidentialRecord.getValue("confidentiality_field");
var type = processingGr.getValue("confidentiality");
var currentUser = processingGr.getValue("user_id");
/* fetching fields which are references on m2m Table to child table.
M2M contains 2 references , one reference to parent table and other to child table, identifying reference to child tables
helps marking/unmarking child table records as confidential.
Also handling case when parent and child table are same.In this case we have to identify which field is referencing child records.
*/
var fields = this._getM2MTableFields(childTable,m2mTable);
if((fields.length == 1) || (fields[0].name != referenceField)) {
childTableReference = fields[0].name;
} else
childTableReference = fields[1].name;
/* Identifying child records based on reference field on m2m table*/
var m2mGr = new GlideRecord(m2mTable);
m2mGr.addQuery(referenceField,parentRecord.getUniqueValue());
m2mGr.query();
if(m2mGr.hasNext()) {
while(m2mGr.next()) {
childSysIds.push(m2mGr.getValue(childTableReference));
}
}
var inheritanceConfigExists = this._checkIfInheritanceConfigExists(childTable);
/* If type is marking,child records should be made confidential
if type is unmarking, child records should be made non-confidential
*/
var childGr = new GlideRecord(childTable);
childGr.addQuery("sys_id","IN",childSysIds);
if(type == "marking") {
childGr.addNullQuery(childConfidentialityField).addOrCondition(childConfidentialityField,false);
childGr.query();
if(childGr.hasNext()) {
this._setConfidentialityFieldValues(parentConfidentialRecord,childConfidentialRecord,parentRecord,childGr,
inheritanceConfigExists);
}
} else if(type == "unmarking") {
childGr.addQuery(childConfidentialityField,true);
this._removeConfidentialityFieldValues(childConfidentialRecord,parentRecord,childGr,currentUser,inheritanceConfigExists);
}
},
/* marks/unmarks confidentiality on child records if parent is connected to child in scripted fashion */
_markORunmarkScriptedRelationshipRecordsConfidential: function(parentConfidentialRecord,childConfidentialRecord
,parentRecord,childTable,relationship,processingGr) {
var fields,childTableReference,childSysIds = [],isRelationshipTableM2M;
var type = processingGr.getValue("confidentiality");
var currentUser = processingGr.getValue("user_id");
var inheritanceConfigExists = this._checkIfInheritanceConfigExists(childTable);
/* fetching scripted relationship existing btw parent and child */
var relationshipGr = new GlideRecord("sys_relationship");
relationshipGr.get(relationship);
var queryTable = relationshipGr.getValue("basic_query_from");
var currentGr = new GlideRecord(queryTable);
/* executing script */
var variables = {"parent":parentRecord,"current":currentGr};
var evaluator = new GlideScopedEvaluator();
evaluator.evaluateScript(relationshipGr,"query_with",variables);
var current = evaluator.getVariable("current");
/*
A scripted relationship between parent and child can exist in 2 ways
CASE-1. Querying directly from child table to fetch records.
CASE-2. Querying from m2m(many-to-many) tables existing between parent and child.
In second case , we have to identify reference to child table from m2m table and then identify child records.
*/
/* In below case child table is different and query from table in scripted relationsip is different
Ex -- If configuration is to pass confidentiality from entity to downstream entities then
PARENT table and child table are same which is entity (sn_grc_profile) but query from table in
Downstream entities scripted relationship is a m2m table (Entity hierarchy)
*/
if(queryTable != childTable) {
isRelationshipTableM2M = true;
fields = this._getM2MTableFields(childTable,queryTable);
/* If both parent and child tables are different. Ex -- Entity to entity type */
if(childTable != parentRecord.getTableName()) {
childTableReference = fields[0].name;
}
/* If both parent and child tables are same. Ex -- Entity to downstream entities
In this case we have to identify which field in m2m table is referencing child record.
*/
else{
var m2mGr = evaluator.getVariable("current");
m2mGr.query();
if(m2mGr.hasNext()) {
m2mGr.next();
if(m2mGr.getValue(fields[0].name) == parentRecord.getUniqueValue())
childTableReference = fields[1].name;
else
childTableReference = fields[0].name;
}
}
// capturing sysIds of child table from m2m table based on reference field
current.query();
if(current.hasNext()) {
while(current.next())
childSysIds.push(current.getValue(childTableReference));
}
}
var childConfidentialityField = childConfidentialRecord.getValue("confidentiality_field");
/* In this case query from table and child table are same and not m2m */
if(!isRelationshipTableM2M) {
if(type == "marking") {
current.addNullQuery(childConfidentialityField).addOrCondition(childConfidentialityField,false);
current.query();
if(current.hasNext()) {
this._setConfidentialityFieldValues(parentConfidentialRecord,childConfidentialRecord,parentRecord,current,
inheritanceConfigExists);
}
} else if(type == "unmarking") {
current.addQuery(childConfidentialityField,true);
this._removeConfidentialityFieldValues(childConfidentialRecord,parentRecord,current,currentUser,inheritanceConfigExists);
}
}
// #CASE-2
else {
var childGr = new GlideRecord(childTable);
childGr.addQuery("sys_id","IN",childSysIds);
if(type == "marking") {
childGr.addNullQuery(childConfidentialityField).addOrCondition(childConfidentialityField,false);
childGr.query();
if(childGr.hasNext())
this._setConfidentialityFieldValues(parentConfidentialRecord,childConfidentialRecord,parentRecord,childGr,
inheritanceConfigExists);
} else if(type == "unmarking") {
childGr.addQuery(childConfidentialityField,true);
this._removeConfidentialityFieldValues(childConfidentialRecord,parentRecord,childGr,currentUser,inheritanceConfigExists);
}
}
},
/* Marks child records as confidential.While marking child records as confidential
----- Parent allowed users and allowed groups should get access to child records
----- Based on child's confidentiality configuration ,important users and groups from child table needs to be given access.
*/
_setConfidentialityFieldValues: function(parentConfidentialRecord,childConfidentialRecord,parentRecord,childRecords,
inheritanceConfigExists) {
/* fetching confidentiality fields on parent and child tables from confidentiality config */
var parentAllowedUsersField = parentConfidentialRecord.getValue("allowed_users_field");
var parentAllowedGroupsField = parentConfidentialRecord.getValue("allowed_groups_field");
var childAllowedUsersField = childConfidentialRecord.getValue("allowed_users_field");
var childAllowedGroupsField = childConfidentialRecord.getValue("allowed_groups_field");
var childConfidentialityField = childConfidentialRecord.getValue("confidentiality_field");
var autoPopulate = childConfidentialRecord.auto_populate;
var childUserField = childConfidentialRecord.getValue("user_fields");
var childGroupField = childConfidentialRecord.getValue("group_fields");
var allowedUsers,allowedGroups,uniqueAllowedUsers,uniqueAllowedGroups;
if(autoPopulate) {
/* Fetching user fields and group fields from confidentiality config for giving users/groups access to child record */
var userFields=[],dotWalkedUserFields=[],groupFields=[],dotWalkedGroupFields=[],childUsers,childGroups;
if(childUserField) {
childUsers = childUserField.split(',');
for(var i=0;i<childUsers.length;i++) {
if(childUsers[i].contains("."))
dotWalkedUserFields.push(childUsers[i]);
else
userFields.push(childUsers[i]);
}
}
if(childGroupField) {
childGroups = childGroupField.split(',');
for(var j=0;j<childGroups.length;j++) {
if(childGroups[j].contains("."))
dotWalkedGroupFields.push(childGroups[j]);
else
groupFields.push(childGroups[j]);
}
}
}
while(childRecords.next()) {
allowedUsers = parentRecord.getValue(parentAllowedUsersField);
allowedGroups = parentRecord.getValue(parentAllowedGroupsField);
if(autoPopulate) {
var userValues = this._getConfidentialUsersAndGroups(userFields,dotWalkedUserFields,childRecords);
var groupValues = this._getConfidentialUsersAndGroups(groupFields,dotWalkedGroupFields,childRecords);
if(userValues) {
if(allowedUsers)
allowedUsers = userValues.toString() + "," + allowedUsers;
else
allowedUsers = userValues.toString();
}
if(groupValues) {
if(allowedGroups)
allowedGroups = groupValues.toString() + "," + allowedGroups;
else
allowedGroups = groupValues.toString();
}
}
// handling null values
if(!allowedUsers)
allowedUsers = "";
if(!allowedGroups)
allowedGroups = "";
// removing duplicate values if any
uniqueAllowedUsers = this._removeDuplicateValues(allowedUsers.split(","));
uniqueAllowedGroups = this._removeDuplicateValues(allowedGroups.split(","));
childRecords.setValue(childConfidentialityField,true);
childRecords.setValue(childAllowedUsersField,uniqueAllowedUsers.toString());
childRecords.setValue(childAllowedGroupsField,uniqueAllowedGroups.toString());
if(childRecords.update() == null) {
this._createGRCException("mark",childRecords.getTableName(),childRecords.getUniqueValue(),parentRecord.getTableName(),childRecords.getLastErrorMessage());
}
}
},
/* Unmarks confidentiality from child records.While unmarking
----- User who unmarked parent record and who has access to child records are only considered
*/
_removeConfidentialityFieldValues: function(childConfidentialRecord,parentRecord,childRecords,userId,inheritanceConfigExists) {
var childAllowedUsersField = childConfidentialRecord.getValue("allowed_users_field");
var childAllowedGroupsField = childConfidentialRecord.getValue("allowed_groups_field");
var childConfidentialityField = childConfidentialRecord.getValue("confidentiality_field");
childRecords.addNotNullQuery(childAllowedGroupsField).addOrCondition(childAllowedUsersField,"CONTAINS",userId);
childRecords.query();
if(childRecords.hasNext()) {
while(childRecords.next()) {
var childAllowedUsers = childRecords.getValue(childAllowedUsersField);
var childAllowedGroups = childRecords.getValue(childAllowedGroupsField);
if((childAllowedGroups && this._verifyUserIsPartOfaGroup(childAllowedGroups,userId)) || (childAllowedUsers && childAllowedUsers.includes(userId))) {
childRecords.setValue(childConfidentialityField,false);
childRecords.setValue(childAllowedUsersField,"");
childRecords.setValue(childAllowedGroupsField,"");
if(childRecords.update() != null) {
this._createRecordToBeProcessed(inheritanceConfigExists,childRecords,false,userId);
} else {
this._createGRCException("unmark",childRecords.getTableName(),childRecords.getUniqueValue(),parentRecord.getTableName(),childRecords.getLastErrorMessage());
}
}
}
}
},
/* Returns users and groups of a particular record based on confidentiality configuration */
_getConfidentialUsersAndGroups: function(fields,dotWalkedFields,recordGr) {
var fieldsArr = [],dotWalkedFieldsArr,result = [];
if(fields.length || dotWalkedFields) {
var field;
for(var i=0; i<fields.length; i++) {
field = recordGr.getValue(fields[i]);
/* removing duplicate values */
if(field && fieldsArr.indexOf(field)<0)
fieldsArr.push(field);
}
dotWalkedFieldsArr = this._getDotWalkedUsersAndGroups(dotWalkedFields,recordGr);
/* removing duplicate values from dotwalkedFields */
for(var a=0; a<dotWalkedFieldsArr.length; a++) {
if(fieldsArr.indexOf(dotWalkedFieldsArr[a]) >= 0)
dotWalkedFieldsArr.splice(a,1);
}
result = fieldsArr.concat(dotWalkedFieldsArr);
}
return result;
},
/* removes duplicate values from given array */
_removeDuplicateValues:function(array) {
var uniqueArr = [];
for(var k=0;k<array.length;k++) {
if(uniqueArr.indexOf(array[k]) < 0) {
uniqueArr.push(array[k]);
}
}
return uniqueArr;
},
/* Returns users and groups value of dot walked fields on a particular record
--- Handling n levels of dot walking
*/
_getDotWalkedUsersAndGroups: function(fields,recordGr) {
var usersORgroups=[];
for(var j=0; j<fields.length; j++) {
var dotWalkedFields = fields[j].split(".");
var arrLength = dotWalkedFields.length;
var record = recordGr;
for (var k=0; k<(dotWalkedFields.length); k++) {
if((k == (arrLength-1)) && record.getValue(dotWalkedFields[arrLength-1])) {
usersORgroups.push(record.getValue(dotWalkedFields[arrLength-1]));
break;
}
if(record.getValue(dotWalkedFields[k])) {
var dotWalkedTable = record.getElement(dotWalkedFields[k]).getReferenceTable();
var tableGr = new GlideRecord(dotWalkedTable);
tableGr.get(record.getValue(dotWalkedFields[k]));
record = tableGr;
} else
break;
}
}
return usersORgroups;
},
/* verifies if a user is member of given group */
_verifyUserIsPartOfaGroup: function(groups,userId) {
if(!groups)
return false;
var grpArray = groups.split(",");
var groupGr = new GlideRecord("sys_user_grmember");
groupGr.addQuery("group","IN",grpArray);
groupGr.addQuery("user",userId);
groupGr.query();
if(groupGr.hasNext())
return true;
return false;
},
/* creates a processing record for given current record to mark/unmark confidentiality to its childs */
_createRecordToBeProcessed: function(inheritanceConfigExists,current,type,userId) {
// create processing record , if and only if inheriance config exists for current record
if(inheritanceConfigExists) {
// prevent duplicate record creation
var inheritanceStatus = new GlideRecord("sn_grc_confidentiality_inheritance_status");
inheritanceStatus.addQuery("table",current.getTableName());
inheritanceStatus.addQuery("source",current.getUniqueValue());
inheritanceStatus.addEncodedQuery("stateIN1,2");
if(type)
inheritanceStatus.addQuery("confidentiality","marking");
else
inheritanceStatus.addQuery("confidentiality","unmarking");
inheritanceStatus.orderByDesc("sys_created_on");
inheritanceStatus.setLimit(1);
inheritanceStatus.query();
if(inheritanceStatus.hasNext())
return;
//create record for processing
inheritanceStatus.initialize();
inheritanceStatus.setValue("table",current.getTableName());
inheritanceStatus.setValue("source",current.getUniqueValue());
if(type)
inheritanceStatus.setValue("confidentiality","marking");
else
inheritanceStatus.setValue("confidentiality","unmarking");
if(userId)
inheritanceStatus.setValue("user_id",userId);
inheritanceStatus.setValue("state","1");
inheritanceStatus.insert();
}
},
verifyInherianceConfigBtwParentAndChild: function(child,parent) {
return this._verifyInherianceConfigBtwParentAndChild(child,parent);
},
markRelatedListRecordsConfidential: function(childSysIds,childTable,parentSysId,parentTable,relation) {
return this._markRelatedListRecordsConfidential(childSysIds,childTable,parentSysId,parentTable,relation);
},
/* shows/hides related list actions */
_verifyInherianceConfigBtwParentAndChild: function(child,parent) {
var inheritanceGr = new GlideRecord("sn_grc_confidentiality_inheritance_configuration");
inheritanceGr.addQuery("main_table.table",parent.getTableName());
inheritanceGr.addQuery("inheriting_table.table",child.getTableName()).addOrCondition("relationship_table",child.getTableName());
inheritanceGr.addQuery("active",true);
inheritanceGr.query();
/* Enable actions when parent record is confidential and inheritance config exists between parent and child table in related list */
if(inheritanceGr.hasNext()) {
inheritanceGr.next();
var childConfidentialRecord = this._getConfidentialityConfigRecord(inheritanceGr.getValue("inheriting_table"));
if(parent.getValue(childConfidentialRecord.getValue("confidentiality_field")) != "0") {
return true;
}
return false;
} else {
return false;
}
},
/* marks related list records as confidential, given inheritance config exists between parent and child related table */
_markRelatedListRecordsConfidential: function(childSysIds,childTable,parentSysId,parentTable,relation) {
var arr,childTableReference;
var recordIds = childSysIds.split(",");
if(childSysIds == "")
return gs.getMessage("Select atleast one record to mark confidentiality.");
var inheritanceGr = new GlideRecord("sn_grc_confidentiality_inheritance_configuration");
inheritanceGr.addQuery("main_table.table",parentTable);
inheritanceGr.addQuery("active",true);
/* If relation contains REL it means marking confidentiality is done on records of scripted relationship */
if(relation.contains("REL")) {
inheritanceGr.addQuery("relationship_type","scripted");
arr = relation.split(":");
var scriptedId = arr[1];
inheritanceGr.addQuery("relationship_data",scriptedId);
} else {
/* If not scripted , relation contains dot walked reference to parent table
Ex -- Parent table is issue
child table is remediation task
Relation is sn_grc_task.issue
*/
arr = relation.split(".");
var reference = arr[1];
inheritanceGr.addQuery("inheriting_table.table",childTable).addOrCondition("relationship_table",childTable);
inheritanceGr.addQuery("relationship_data",reference);
}
inheritanceGr.setLimit(1);
inheritanceGr.query();
if(!inheritanceGr.hasNext())
return gs.getMessage("No inheritance configuration exists between {0} and {1} tables.",[parentTable,childTable]);
inheritanceGr.next();
var relationshipType = inheritanceGr.getValue("relationship_type");
var parentConfidentialRecord = this._getConfidentialityConfigRecord(inheritanceGr.getValue("main_table"));
var childConfidentialRecord = this._getConfidentialityConfigRecord(inheritanceGr.getValue("inheriting_table"));
var inheritingTable = childConfidentialRecord.getValue("table");
var inheritanceConfigExists = this._checkIfInheritanceConfigExists(inheritingTable);
var parentRecord = new GlideRecord(parentTable);
parentRecord.get(parentSysId);
if(relationshipType == "many_to_many") {
recordIds = [];
/* fetching fields which are references on m2m Table to child table.
M2M contains 2 references , one reference to parent table and other to child table, identifying reference to child tables
helps marking child table records as confidential.
Also handling case when parent and child table are same.In this case we are going to get two references to childTable.
*/
var fields = this._getM2MTableFields(inheritingTable,childTable);
if((fields.length == 1) || (fields[0].name != reference)) {
childTableReference = fields[0].name;
} else
childTableReference = fields[1].name;
/* Identifying child records based on reference field on m2m table*/
var m2mGr = new GlideRecord(childTable);
m2mGr.addQuery("sys_id","IN",childSysIds);
m2mGr.query();
if(m2mGr.hasNext()) {
while(m2mGr.next()) {
recordIds.push(m2mGr.getValue(childTableReference));
}
}
}
var childConfidentialityField = childConfidentialRecord.getValue("confidentiality_field");
var childRecords = new GlideRecord(inheritingTable);
childRecords.addQuery("sys_id","IN",recordIds.toString());
childRecords.addNullQuery(childConfidentialityField).addOrCondition(childConfidentialityField,false);
childRecords.query();
if(!childRecords.hasNext())
return gs.getMessage("Please select records which are not confidential.");
var count = childRecords.getRowCount();
/* marks records in related list as confidential */
this._setConfidentialityFieldValues(parentConfidentialRecord,childConfidentialRecord,parentRecord,childRecords,
inheritanceConfigExists);
if(count == "1")
return gs.getMessage("{0} record have been marked as confidential.",[count]);
if(count>1)
return gs.getMessage("{0} records have been marked as confidential.",[count]);
},
_createGRCException: function(type,childTable,sysId,parentTable,Error) {
var message = "Failed to " + type + " this record as confidential because of this reason - " + Error + ".\nFix the error thrown by system.To mark/unmark this record as confidential again, you can individually open this record and mark/unmark it as confidential.";
var scope = new GlideRecord("sys_db_object");
scope.addQuery("name",childTable);
scope.query();
scope.next();
var exception = new GlideRecord("sn_grc_exception");
exception.setValue("exception_category","92bc656377841010fb0984689a106133");
exception.setValue("description",message);
exception.setValue("table",childTable);
exception.setValue("source_record",sysId);
exception.setValue("application",scope.getValue("sys_scope"));
exception.insert();
},
type: 'GRCSecurityManagerBase'
};
Sys ID
bee376845332301028c4ddeeff7b12bd