Thursday 13 February 2014

Salesforce - "System mode & User mode" and "With sharing & Without sharing" keywords

This topic has always been part of discussion where the answer is not satisfactory and convinced to others. 

Using this article, I will try to explain how system mode & user mode works in Salesforce and how with sharing, without sharing keywords affect these modes.

Before moving ahead let’s have a summary on what these modes and keywords are..

System mode -
  • System mode is nothing but running apex code by ignoring user's permissions. For example, logged in user does not have create permission but he/she is able to create a record.
  • In system mode, Apex code has access to all objects and fields— object permissions, field-level security, sharing rules aren't applied for the current user. This is to ensure that code won’t fail to run because of hidden fields or objects for a user.
  • In Salesforce, all apex code run in system mode. It ignores user's permissions. Only exception is anonymous blocks like developer console and standard controllers. Even runAs() method doesn't enforce user permissions or field-level permissions, it only enforces record sharing.


User mode - 
  • User mode is nothing but running apex code by respecting user's permissions and sharing of records. For example, logged in user does not have create permission and so he/she is not able to create a record.
  • In Salesforce, only standard controllers and anonymous blocks like developer console run in user mode.

Without Sharing keyword - 
  • The 'without sharing' keyword is to ensure that the sharing rules (not permissions) for the current user are not enforced.
  • Example - Let's consider that the OWD for Account is private, no account records are owned by or shared with an user 'u' and a "without sharing" class called MyClass is fetching account records in a list. Now if class 'MyClass' is run by user 'u' then account records will be fetched. Remember that whether the user 'u' is having full CRUD or having no CRUD, records will be fetched.

With Sharing keyword - 
  • The with sharing keyword allows you to specify that the sharing rules (and not permissions) for the current user be taken into account for a class. You have to explicitly set this keyword for the class because Apex code runs in system mode.
  • Example - Let's consider that the OWD for Account is private, no account records are owned by or shared with an user 'u' and a "with sharing" class called MyClass is fetching account records in a list. Now if class 'MyClass' is run by user 'u' then no records will be fetched. Remember that whether the user 'u' is having full CRUD or having no CRUD record will not be fetched.


Some more things to note about sharing keywords:
  1. The sharing setting of the class where the method is defined is applied, not of the class where the method is called. For example, if a method is defined in a class declared with with sharing keyword is called by a class declared with without sharing keyword, the method will execute with sharing rules enforced.
  2. If a class isn’t declared as either with or without sharing, the current sharing rules remain in effect. This means that if the class is called by a class that has sharing enforced, then sharing is enforced for the called class.
  3. Both inner classes and outer classes can be declared as with sharing. The sharing setting applies to all code contained in the class, including initialization code, constructors, and methods.
  4. Inner classes do not inherit the sharing setting from their container class.
  5. Classes inherit this setting from a parent class when one class extends or implements another.

Illustration 1 -

Let's create 'Test' user with profile having no CRUD on Case object. 






Build a trigger to insert a new case on creating a new account.

trigger InsertCase on Account (after insert) {
    list <case> caseList = new list <case>();
    for(Account acc : trigger.new) {
        caseList.add(new Case(AccountId = acc.Id, Status = 'New'));
    }
    insert caseList;
}
Let's check how many cases are created today. For this we will use system admin creds.
Let's login into Salesforce by 'Test' user having no CRUD and create a new Account. Now again let's check Today's cases.



Here we can see a new case got inserted into database on creating an account.
Writing above code in with sharing & without sharing classes and calling these classes from trigger, results the same.
Conclusion -
All apex code run into system mode and will never check user permissions.
Note - Above statement is true for both with and without sharing classes.
Illustration 2 -
Set OWD for Account and Case to private.
Create a new class

public with sharing class MyClass {

    public static void createCase() {
        list <Account> accList = [select Id from Account where name = 'My Account'];
        list <Case> caseList = new list <Case>();
        for(Account acc : accList) {
            caseList.add(new Case(AccountId = acc.Id, Status = 'New', Subject = 'Some Subject...'));
        }
        insert caseList;
    }
}




Create a new VF page.

<apex:page controller="MyClass" action="{!createCase}">
</apex:page>




Two accounts with name 'My Account' are present in database and are owned by system administrator.




No account with name 'My Account' is owned by a test user.




Delete all today's cases.

To avoid confusion, let's modify a profile so that no CRUD on case as well as account object.
Now let's login into Salesforce by test user, run above VF page and check Today's Cases. No cases are inserted.


Since no account is owned by or shared with test user, 'accList' is empty and hence no case are inserted.
Illustration 3 -
Now let's share one account named 'My Account' with test user using system admin creds by manual sharing then run above VF again using test user creds and check Today's Cases.




One new case got inserted into database as 'accList' contains one account.
Conclusion -
  1. Though there is no CRUD, an user can perform all DML operations as generally all apex run in system mode.
  2. As keywords 'With Sharing & Without Sharing' themselves suggests that they have nothing to do with permissions on object & fields. They only play role in selecting records on sharing basis.