Thursday, December 11, 2014

Salesforce Security CRUD Enforcement

Recently I've had a few projects that have involved getting applications through the Salesforce.com security review process. I'm going to list all the steps involved in getting this to happen, but one thing that stood out was the failure of the applications to pass based on non-enforcement of CRUD operations.

What this means is, when you have Apex code that inserts records, you need to specifically write code that checks to see whether the current user actually has the permissions to insert those records. Not only that, but for every individual field that the code is modifying, you need to specifically check to see whether the current user has the ability to put data into those specific fields on that object.

The reasoning behind this is that if you write an application, it should 100% of the time honor the object and field-level security settings of the organization where it will be installed. I suppose I can get behind this sentiment, but I could totally argue for cases where I'd want my Apex to be able to ignore these things. But perhaps that's a discussion for another time.

Now, maybe I'm naive, but until just a few months ago, I was operating under the assumption that Apex code did this automatically. That if your user, let's call him Bob The User, was running code that inserted Accounts, that he would get an exception. Apparently this is not the case. I know the "with sharing" tag in an Apex class allows the code to avoid abiding by pesky sharing rules, but there is not way to globally tell Apex to "abide by all object and field-level security settings."

Furthermore, this requirement doesn't just apply to inserting records, but updating or upserting them as well.

So I got to this stage in a 500+ hour development for an application where we were waiting for the results of our security review, and we got it back saying you need to enforce CRUD rules. Meaning that I had the fun task of going through the whole project, finding every DML statement and implementing a check to see if the user had the permission to perform that DML before allowing it to run.

So, I created a handy-dandy utils class that would help me more quickly complete this undertaking.

I've posted this code in github here: https://github.com/ZergyPoo/SFDCCrudEnforcementUtils

Essentially, what the code does is allow the developer to very easily pass in any SObject (and perhaps a list of field names) to verify that the current user has the permission to do the DML that they are about to do.

So, for example, instead of running:

insert account;

I would would run:

if (CrudEnforcementUtils.canCreateObject(account)) {
  insert account;
}

To take it farther, say that your code was only setting the "name" field of the account, you want to do this:

Set<String> accountFields = new Set<String> { 'Name' };

if (CrudEnforcementUtils.canCreateObject(account) && CrudEnforcementUtils.canCreateAllFields(account, accountFields)) {
  insert account;
}

I'm not going to give examples for every method, but the highlights are:


  • You can pass in any SObject
  • You can pass in a list containing any SObject
  • There are methods for create, update and upsert (which is really just create && update).
Thank you, hopefully someone finds this helpful.