Understanding Apex Class Sharing Settings is the key to mastering data access and security of the Salesforce platform.
In this blog post, delve into the nuances of with sharing
,
without sharing
, and inherited sharing
keywords, the
default sharing behavior of the apex classes.
Why use sharing keywords for the apex class?
We are all very well-informed about Salesforce's sharing model. The record-level security is managed through various low-code tools like Sharing settings, Ownership, Role Hierarchy, Sharing rules, etc. These tools ensure that the records are shared only with intended users, with great control and flexibility.
But what about the apex code? There are scenarios where we need the apex code
to respect these sharing rules but sometimes bypass them. That is where the
keywords with sharing
, without sharing
, and
inherited sharing
are useful. With their help, we can control the
record-level security of the apex classes.
Let us understand these keywords with examples.
Hypothetical Scenario
Let us consider a hypothetical scenario to demonstrate the usage of these
keywords. A recruiting agency has an Application (Application__c
)
custom object with a sharing setting set to private. All the code examples in
this post are based on this scenario.
- There are two user roles -
- Manager
- Recruiter
- The Recruiter can only see the Application records owned by themselves.
- The Manager can see all Applications of their subordinates.
-
I have assigned myself the manager role and created another user called
Recruiter
for the sake of this demo. -
I have created five Application records in the org and two are shared with
the user
Recruiter
.
With Sharing Keyword
The with sharing
enforces the sharing rules for the current
user. This ensures that the apex code runs in the current user's context.
Any records not shared with the current user are not accessed by the apex
code in this context.
Here is a sample code for with sharing
keyword.
public with sharing class DemoWithSharing { @AuraEnabled(cacheable=true) public static List<Application__c> getApplications() { return [SELECT Name, Owner.Name FROM Application__c]; } }
According to our hypothetical scenario, this code will only return 2 records
out of five for the user Recruiter
because only those records
are shared with them. On the other hand, the same code will return all
records to the Manager
.
Without Sharing Keyword
The without sharing
keyword empowers developers to bypass
sharing rules, granting them flexibility in certain scenarios. When a class
is declared with the without sharing
keyword all the records
are returned regardless of the sharing rules and ownership.
This is useful for scenarios where we must open access to users through apex programming to custom components.
For example, in our hypothetical scenario, we need to show the total count of Active applications across the org to all users on the Lightning web component screen, including the recruiters who can't see records owned by others. See the below apex code for the same.
public without sharing class DemoWithoutSharing { @AuraEnabled(cacheable=true) public static Integer getTotalApplicationCount() { return [ SELECT COUNT() FROM Application__c WHERE Status__c = 'Active' ]; } }
The above code returns the total number of active applications regardless of the records accessible to users.
Inherited Sharing
As the name suggests, inherited sharing behaves based on the context of the calling class the automation, or the trigger.
When you call the inherited sharing
class from a
with sharing
class, it will respect the sharing rules and
restrict any data from being accessed.
When the inherited sharing
class is called from the
without sharing
class, it will not respect the sharing rules and expose all the data.
Let's see a code example:
This is my inherited sharing
class:
inherited-sharing-class
public inherited sharing class DemoInheritedSharing { @AuraEnabled(cacheable=true) public static List<Application__c> getApplications() { return [SELECT Name, Owner.Name FROM Application__c]; } }
When inherited sharing
class called from
with sharing
class
public with sharing class DemoWithSharing { @AuraEnabled(cacheable=true) public static List<Application__c> getApplicationsInherited() { return DemoInheritedSharing.getApplications(); } }
The above code returns only 2 records in the context of the
Recruiter
user as the calling class respects the sharing rules.
When inherited sharing
class called from
without sharing
class
public without sharing class DemoWithoutSharing { @AuraEnabled(cacheable=true) public static List<Application__c> getApplicationsInherited() { return DemoInheritedSharing.getApplications(); } }
The above code returns all records in the context of the
Recruiter
user as the calling class does not respect the
sharing rules.
Now you understand the power of inherited sharing, as the name suggests it inherits the sharing setting from the calling class. However, there are some exceptions to the inherited sharing, as mentioned below.
Important things to remember about inherited sharing class
-
When not defined anything the class behaves as an
inherited sharing
class -
The
inherited sharing
class always run aswith sharing
when used as - An Aura component/LWC controller
- A Visualforce controller
- An Apex REST service
- Any other entry point to an Apex transaction such as an asynchronous Apex class.
Default Sharing or Omitted Sharing
When you don't mention anything like with sharing
or
without sharing
in an Apex class, it is called
Default Sharing
or Omitted Sharing
. Understanding
this behavior is very important as this is the most complicated and
unpredictable sharing setting for the apex classes.
Some people say it is with sharing
, and some say it is
without sharing
, both are partially true. The behavior of the
omitted sharing class is very unpredictable and you can read about it here in
detail - Inherited Sharing vs No Sharing declaration.
As a thumb rule always avoid omitted sharing class, unless that is your last option.
default-sharing-class
Creating a default sharing class is easy, see the below class.
public class DefaultSharing { @AuraEnabled(cacheable=true) public static List<Application__c> getApplications() { return [SELECT Name, Owner.Name FROM Application__c]; } }
TLDR, Best Practices for sharing keywords in Apex
-
Always start your class with the
with sharing
keyword by default, and you can always open up the access if needed later. - Never use the default or omitted sharing, unless that is your last option.
-
Always use
with sharing
for external entry points like the apex rest class, LWC component controller, or aura component controller. Create internal utility classes if there is a need to expose data instead of making the entry classwithout sharing
. -
Keep track of all classes that are
without sharing
andinherited sharing
in the organization's known risk register, if you don't have one, create one. So that everybody on your team is aware of the risks. -
List down the objects that are exposed using the
without sharing
method in the risk register. - Apex class sharing does not handle field-level security, so ensure you have security checks for it.
- Test your code in the context of different users to make sure that the sharing model is not compromised.
- Add unit tests to cross-check the apex sharing settings.
Summary
As we conclude our exploration of sharing keywords in Apex, it's clear that mastering these nuances is essential for Salesforce developers. Choosing the right sharing settings, whether through with sharing, without sharing, or default sharing, is important for creating robust, secure applications.
Encouraging developers to experiment, ask questions, and continually refine their understanding will undoubtedly lead to more adept and confident Salesforce coding.
No comments :
Post a Comment
Hi there, comments on this site are moderated, you might need to wait until your comment is published. Spam and promotions will be deleted. Sorry for the inconvenience but we have moderated the comments for the safety of this website users. If you have any concern, or if you are not able to comment for some reason, email us at rahul@forcetrails.com