`

CRUD Operation check

To pass Salesforce security review all DML operations must be checked if user who wants to execute them have permissions to do it. For this purpose a public with sharing class should be created, with methods responsible for checking CRUD Access.

Before every Update, Insert, Upsert or Delete operation, there is a CRUDEnforcementCheck method from HelperSecurity class called. It is responsible for checking if user have permissions to perform database operations. If a user does not have permissions a CustomException is thrown.

Example of security method call: There are two params with API object name and database operation type.

HelperSecurity.CRUDEnforcementCheck('Contact',HelperSecurity.OPERATION_TYPE.DB_DELETE);
delete contactToDelete;

HelperSecurity.CRUDEnforcementCheck('Contact',HelperSecurity.OPERATION_TYPE.DB_UPSERT);
upsert contactToUpsert;;

Called method code: If provided object name exist method for checking user permissions is execute.

public static void CRUDEnforcementCheck(String objType, HelperSecurity.OPERATION_TYPE operation) {
   if (Schema.getGlobalDescribe().containsKey(objType)) 
      CRUDEnforcementCheck(Schema.getGlobalDescribe().get(objType), operation);
   else 
      noSuchObjectException(objType);
}

Actual code with CRUD check: Main method responsible for checking if user has permissions. Autonumber fields, formula fields and fields for which permissions can not be specified are ommited.

public static void CRUDEnforcementCheck(SObjectType objType, HelperSecurity.OPERATION_TYPE operation) {
   if (objType != null) {
      Map < String, Schema.SObjectField > m = objType.getDescribe().fields.getMap();
         if (operation == null) {
            return;
         } else if (operation == OPERATION_TYPE.DB_INSERT) {
            if (!canCreateObject(objType)) 
    noAccessException(objType, null, operation);
            for (String fieldToCheck: m.keySet())
    if (!BlockedTypes.contains(String.valueOf(m.get(fieldToCheck).getDescribe().getType())) && 
    m.get(fieldToCheck).getDescribe().isPermissionable() &&
    !m.get(fieldToCheck).getDescribe().isAutoNumber() && 
    !m.get(fieldToCheck).getDescribe().isCalculated() && !m.get(fieldToCheck).getDescribe().isCreateable()) 
            noAccessException(objType, fieldToCheck, operation);
         } else if (operation == OPERATION_TYPE.DB_UPDATE) {
             if (!canUpdateObject(objType)) 
    noAccessException(objType, null, operation);
             for (String fieldToCheck: m.keySet()) {
    if (!BlockedTypes.contains(String.valueOf(m.get(fieldToCheck).getDescribe().getType()))  &&
    m.get(fieldToCheck).getDescribe().isPermissionable() &&
    !m.get(fieldToCheck).getDescribe().isAutoNumber() &&
    !m.get(fieldToCheck).getDescribe().isCalculated() &&
    !m.get(fieldToCheck).getDescribe().isUpdateable())
             noAccessException(objType, fieldToCheck, operation);
              }
          } else if (operation == OPERATION_TYPE.DB_SELECT) {
    if (!canReadObject(objType)) 
       noAccessException(objType, null, operation);
    for (String fieldToCheck: m.keySet())
       if (!m.get(fieldToCheck).getDescribe().isAccessible()) 
          noAccessException(objType, fieldToCheck, operation);
          } else if (operation == OPERATION_TYPE.DB_UPSERT) {
    if (!canCreateObject(objType) || !canUpdateObject(objType)) 
       noAccessException(objType, null, operation);
    for (String fieldToCheck: m.keySet())
       if (!BlockedTypes.contains(String.valueOf(m.get(fieldToCheck).getDescribe().getType())) &&
      m.get(fieldToCheck).getDescribe().isPermissionable() &&
      !m.get(fieldToCheck).getDescribe().isAutoNumber() &&
      !m.get(fieldToCheck).getDescribe().isCalculated() &&
      (!m.get(fieldToCheck).getDescribe().isCreateable() ||
      !m.get(fieldToCheck).getDescribe().isUpdateable())) 
              noAccessException(objType, fieldToCheck, operation);
            } else if (operation == OPERATION_TYPE.DB_DELETE) {
    if (!canDeleteObject(objType)) 
        noAccessException(objType, null, operation);
    }
           }
}

Custom exeptions code:

When user does not have permissions to perform CRUD operation Custom Exeption with name of an sObject, type of operation and additional field name is thrown.

private static void noAccessException(SObjectType sobjType, String field, OPERATION_TYPE operation) {
   system.debug(
      (operation != null? operation + ': ' : '' ) +
      'No access to object ' + sobjType + 
      (field != null? ' (' + field + ')' : '')
   );
        
   throw new CustomException(
      (operation != null? operation + ': ' : '' ) +
      'No access to object ' + sobjType + 
      (field != null? ' (' + field + ')' : '')
   );
}


private static void noAccessException(SObject sobj) {
   system.debug('No access to object ' + sobj.getSObjectType());
   throw new CustomException('No access to object ' + sobj.getSObjectType());
}

2016-11-18.jpg

Jakub - Salesforce Developer with over 1 year of consulting experience. Outside of my work, fan of basketball, especially NBA games and newest technology.

Comment