Monday, April 20, 2015

Surprises with and without sharing in Apex

I'll admit that I never dug too deep into the with sharing and without sharing keywords. At a high level I felt that if I want to enforce security and visibility, I should use with sharing. Otherwise I should use without sharing, which I also assumed was the default.

The Object-Oriented Programming in Apex training module surprised me by telling me that CRUD permissions and field-level security ("FLS") are ignored both with sharing and without sharing! Also, system mode simply means that record-level read and edit privileges are ignored, since CRUD and FLS are always ignored.

This is contrary to what I'd inferred from the Apex Code Developer's Guide, which writes, "In system context, Apex code has access to all objects and fields— object permissions, field-level security, sharing rules aren’t applied for the current user." My interpretation of this statement was that on the flip side, when with sharing is applied, "object permissions, field-level security, sharing rules" would all be applied for the current user.

It was a bit hard for me to believe that Apex would not respect CRUD (if not FLS) permissions, so I created a Visualforce page to test this in my org. And it seemed to me that indeed, an Apex controller created using the with sharing keyword would allow a user without the Delete object permission to delete a record. Crazy... am I missing something?

Well! What's more interesting was that with a standard controller, CRUD permissions are always observed with actions like delete(), regardless of whether an extension class is defined with sharing or without sharing. For example, a button that invoked the StandardController.delete() action would automatically be hidden if a user didn't have the Delete object permission. Furthermore, if a custom action in the extension class invoked the standard controller's action, the custom action would also be subject to the user's CRUD permission, generating an "insufficient privileges" error.

So, I guess the way to enforce CRUD is to use standard controllers, which I don't think is always feasible, especially with mass actions.