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.

8 comments:

  1. Simply the best tutorial on this topic! I Really appreciate your clarity of concepts and the way you penned it down to make the reader understand with the same amount of clarity :)

    ReplyDelete
  2. Really good and Clear Expalanation

    ReplyDelete
  3. Hi Amit,

    A requirement-- when approver click on approve button, in after trigger, I'm creating a contract(custom object) record and putting it's Id in all related quote lines.

    Problem-- when approver don't have edit access on quote it throws error as code try to edit quote line bt user don't have access.

    Query-- Is there anyway to do it from code without giving access to the approver ??

    Ideally it should work as Trigger runs with Sytem Permission and I tried marking class Without Sharing also. No luck. What do you think can be an issue ?

    Thanks,
    Jitendra

    ReplyDelete
  4. Thanks for sharing, it helped me in interview.

    ReplyDelete
  5. Really Appreciable!
    You have shared very valuable information that people should recognise. Thank you for sharing such an informative post with us. I would like share my contribution, sharing with you all my Salesforce app specially for Salesforce admins and developers and saves their most of time in performing bulk operations such as Bulk object/field creation, updation, deletion, cloning, etc., which is also available on appexchange:
    Bulk Object Field Creator
    Appexchange Url

    ReplyDelete
  6. Thank you for sharing such a valuable article. It helped me to understand concepts thoroughly.

    ReplyDelete
  7. Casino - Las Vegas, NV - Mapyro
    Casino. Las Vegas, NV 청주 출장안마 89169. East Las 서귀포 출장샵 Vegas 제주 출장샵 Boulevard. A pedestrian crossing 수원 출장마사지 the street. North 제천 출장샵 Las Vegas Boulevard. Directions · Map.

    ReplyDelete