Understanding with sharing, without sharing, inherited sharing and omitted sharing in apex

Telegram logo Join our Telegram Channel
with-sharing-without-sharing-inherited-sharing-omitted-sharing-in-apex.jpg

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 as with 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 class without sharing.
  • Keep track of all classes that are without sharing and inherited 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