Cracking Security Review Example Code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public with sharing class AppException extends Exception {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public with sharing virtual class DAO{ | |
private static boolean isPassSecurity;// = Test.isRunningTest() ? True : null ; | |
public static Boolean isAccessible(sObject sObj, List < String > fields) { | |
if( isPassSecurity != null && isPassSecurity ){isPassSecurity = false; return true;} | |
Schema.DescribeSObjectResult describeResult = sObj.getSObjectType().getDescribe(); | |
if (describeResult.isAccessible() ) { | |
Map < String, Schema.SObjectField > fieldMap = describeResult.fields.getMap(); | |
for (String fieldToCheck: fields) { | |
if (!fieldMap.get(fieldToCheck).getDescribe().isAccessible()) { | |
throw new AppException('Insufficient read access. ( Field: '+fieldToCheck + ' )' ); | |
} | |
} | |
return true; | |
} else { | |
throw new AppException('Insufficient read access. ( Object: '+sObj.getSObjectType() +' )' ); | |
} | |
} | |
public static Boolean isAccessible(String sObjName, List < String > fields) { | |
if( isPassSecurity != null && isPassSecurity ){isPassSecurity = false; return true;} | |
Schema.DescribeSObjectResult describeResult = Schema.getGlobalDescribe().get(sObjName).getDescribe(); | |
if (describeResult.isAccessible() ) { | |
Map < String, Schema.SObjectField > fieldMap = describeResult.fields.getMap(); | |
for (String fieldToCheck: fields) { | |
if (!fieldMap.get(fieldToCheck).getDescribe().isAccessible()) { | |
throw new AppException('Insufficient read access. ( Field: '+fieldToCheck + ' )' ); | |
} | |
} | |
return true; | |
} else { | |
throw new AppException('Insufficient read access. ( Object: '+sObjName+' )' ); | |
} | |
} | |
//Call this method before calling any any DML method. This will disobey the security rule for that DML operation. | |
public static void byPassSecurity(){ | |
isPassSecurity = true; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public with sharing class DAOUser extends DAO{ | |
private static final sObject SOBJ = new User(); | |
public static list<user> selectAll(){ | |
if( isAccessible(SOBJ, new List<String>{'Name'} ) ){ | |
return [SELECT Name FROM User where isActive= true]; | |
} | |
return null; | |
} | |
public static user selectById(string uid){ | |
if( isAccessible(SOBJ, new List<String>{'Name'} ) ){ | |
return [SELECT Name,TimeZoneSidKey,Email FROM User where id =: uid]; | |
} | |
return null; | |
} | |
public static List<user> selectByIds(Set<String> uids){ | |
if( isAccessible(SOBJ, new List<String>{'Name'} ) ){ | |
return [SELECT Name FROM User where id in: uids]; | |
} | |
return null; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public with sharing class DML{ | |
private static boolean isPassSecurity; | |
/* | |
Examples: | |
List<Contact> cons = new List<Contact>(); | |
DML.doInsert(cons,new list<string>{'FirstName','LastName'} ); | |
DML.doUpdate(cons,new list<string>{'FirstName','LastName'} ); | |
DML.doDelete(cons); | |
*/ | |
//Insert Method for Bulk data | |
public static void doInsert(list < Sobject > listOfData, list < String > fields) { | |
if( !listOfData.isEmpty() && isCreateable( listOfData, fields ) ){ | |
insert listOfData; | |
} | |
} | |
//Update Method for Bulk data | |
public static void doUpdate(list < Sobject > listOfData, list < String > fields) { | |
if( !listOfData.isEmpty() && isUpdateable( listOfData, fields ) ){ | |
update listOfData; | |
} | |
} | |
//Update Method for Bulk data with Partial Update | |
public static void doUpdate(list < Sobject > listOfData, list < String > fields, boolean allOrNone) { | |
if( !listOfData.isEmpty() && isUpdateable( listOfData, fields ) ){ | |
Database.update(listOfData, allOrNone); | |
} | |
} | |
//Delete Method for Bulk data | |
public static void doDelete(list < Sobject > listOfData) { | |
if( !listOfData.isEmpty() && isDeletable( listOfData ) ){ | |
delete listOfData; | |
} | |
} | |
/*---------------------------------------------FLS AND CRUD-----------------------------------------------------------*/ | |
public static Boolean isDeletable(List<sObject> sObj) { | |
if( isPassSecurity != null && isPassSecurity ){isPassSecurity = false; return true;} | |
for( sObject sOb : sObj ){ | |
Schema.DescribeSObjectResult describeResult = sOb.getSObjectType().getDescribe(); | |
if (describeResult.isDeletable()) { | |
return true; | |
} else { | |
throw new AppException('Insufficient delete access. ( Object: '+sOb.getSObjectType() +' )' ); | |
} | |
} | |
return false; | |
} | |
public static Boolean isCreateable(List<sObject> sObj, List < String > fields) { | |
if( isPassSecurity != null && isPassSecurity ){isPassSecurity = false; return true;} | |
for( sObject sOb : sObj ){ | |
Schema.DescribeSObjectResult describeResult = sOb.getSObjectType().getDescribe(); | |
if (describeResult.isCreateable()) { | |
Map < String, Schema.SObjectField > fieldMap = describeResult.fields.getMap(); | |
for (String fieldToCheck: fields) { | |
if (!fieldMap.get(fieldToCheck).getDescribe().isCreateable()) { | |
throw new AppException('Insufficient create access. ( Field: '+fieldToCheck + ' )' ); | |
} | |
} | |
return true; | |
} else { | |
throw new AppException('Insufficient create access. ( Object: '+sOb.getSObjectType() +' )' ); | |
} | |
} | |
return false; | |
} | |
public static Boolean isUpdateable(List<sObject> sObj, List < String > fields) { | |
if( isPassSecurity != null && isPassSecurity ){ isPassSecurity = false; return true;} | |
for( sObject sOb : sObj ){ | |
Schema.DescribeSObjectResult describeResult = sOb.getSObjectType().getDescribe(); | |
if (describeResult.isUpdateable()) { | |
Map < String, Schema.SObjectField > fieldMap = describeResult.fields.getMap(); | |
for (String fieldToCheck: fields) { | |
if (!fieldMap.get(fieldToCheck).getDescribe().isUpdateable()) { | |
throw new AppException('Insufficient update access. ( Field: '+fieldToCheck + ' )' ); | |
} | |
} | |
return true; | |
} else { | |
throw new AppException('Insufficient update access. ( Object: '+sOb.getSObjectType() +' )' ); | |
} | |
} | |
return false; | |
} | |
//Call this method before calling any any DML method. This will disobey the security rule for that DML operation. | |
public static void byPassSecurity(){ | |
isPassSecurity = true; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment