Saturday 11 March 2023

Apex Roadmap: User Mode with Permission Sets

As has been the case since the first TrailheaDX in 2016, the stars didn't align so that I could attend in person. Luckily a lot of the content is already up on Salesforce+, including a very interesting session on the Apex roadmap from Daniel Ballinger and Chris Peterson. One feature that is currently in development really stood out for me - User Mode with Permission Sets. 

User Mode

User Mode went GA in the Spring 23 release of Salesforce, and is a real benefit for those of us with app exchange packages containing Apex code. For those who haven't attempted this and the associated security review, here's a brief summary of what you are up against with the previous tooling:

  • You need to respect the CRUD and FLS permissions set by the subscriber org (the Salesforce instance into which the package has been installed) administrator. This is of course quite right, otherwise your package could just help itself to confidential information that it has no business accessing.
  • There isn't much support in the platform for this, so you need to either create your own methods to check this for each object and field, or use one of the myriad third party offerings.
I've always been in agreement with this governance being enforced in the security review, and also of the strong opinion that if this is a requirement it should be baked into the platform, rather than pushed back on everyone that is developing a package with code. There must be tens of thousands of lines of code in all the packages out there, all re-solving the same problem. 

There were previous attempts to solve this, but they all had compromises. User Mode genuinely takes the transaction out of system mode so that all configured permissions apply for the database operation. If the database operation attempts to use fields or objects that aren't accessible, errors are returned for every disallowed item.

All well and good when you are respecting the admin's decision about access, but what happens if access to objects and fields managed by the package is required in order for the package to function correctly? You could put the user through death by a thousand cuts, allowing them to get slightly further each time before an error is thrown and they request additional permissions from their admin, or you can execute your database operations in System Mode.  This is quite the nuclear option though, as it opens up access to every object and field in the instance. If all you need is to get at the value for a single checkbox, it's an extremely large hammer to crack a small nut.

User Mode with Permission Sets

User Mode with Permission Sets allows you to select an appropriate sized hammer for the nut in question. Rather than elevating the user's access to everything, everywhere, you can give them the minimal amount of additional privilege required for your package to function correctly, just for the database operations that it is needed. To continue the example of needing access to a single checkbox value, you'd also package a permission set that grants access to just that field and execute the database operation in user mode plus that permission set. Much better from a security and governance perspective. 

Here's a code snippet snatched from the session - note that as this is still in development the syntax is likely to change, but it gives a sense of the direction of travel:

Packages aren't the only use case for this though, limiting the data that your Apex code has access to is good practice regardless of whether it's going into a package or being deployed directly to an org. Sadly it wouldn't stop my Evil Co-Worker, as when they have access to the code they can simply change it to run in System Mode in all cases. It will limit the impact of simple mistakes though, and keep your Information Security department a little happier.

More Information

1 comment:

  1. I wonder if a mode which allows system access to package owned fields would help. A package would tend to want system mode to maintain internal state or access internal control information. This will involve fields and objects that are in its own namespace. It may not always be desirable to all the user direct access to that state - a fundamental flaw I think with the model that requires the user to be granted granular permission to every object touched on their behalf.

    A risk with system mode READ is information becoming available to the end user that they should not see. I can imagine many packages needing a mix - "I need to restrict records here by Sharing so the user can only interact with what they are allowed to see, but I need these fields that the user cannot see". Maybe a useful thing for security scanning would be to trace data from the database to the UI or other system boundary to make sure information does not leak.

    At the moment you'd need to perform two queries, using precious SOQL limit. One query works out the sharing situation, the other pulls in the system level fields. The UserAccess special fields seem to always return true when you perform a system mode query, so rendering them useless. The proposed permission set solution would help here.