Feedback

Salesforce permissions applied to Apex

The Welkin Suite
Salesforce Tutorials
Posted by
17 Mar 2017 36651

Permissions are the main fundamental Salesforce element, which are present in both declarative development and Apex programming.

Salesforce permissions applied to Apex 

The majority of Apex classes are run in system context without considering the privileges, sharing rules and levels of access to the fields. This guarantees that the triggers and web services have access all of the entries in the organization - which, in most cases, is a good thing.

However, to make sure that confidential data is not accessible for users that are not supposed to have access to it, you can set an Apex class to be run considering the privileges, sharing rules, levels of access to the fields by the user, under whose name the class was launched. This can impact SOQL, SOSL, and DML expressions.

When using declarative development, one can easily share entries (read more about permissions model here). However, there are cases when this should be done dynamically, following a certain business logic. Apex has this cases covered with the help of a specific mechanism, which is called Apex Managed Sharing.

System Mode

System mode - is a mode in which the code that is being executed ignores user’s privileges. In this mode, Apex code has access to all objects and fields, and the sharing rules are not applied for the current user. This guarantees that the code will work regardless of the fact whether a user that executes Apex code has access to the objects and their fields.

User Mode

User mode - is a mode in which the code is executed considering the privileges of a user, under whose name this code is run. In Salesforce, only the standard controllers and Anonymous Apex are executed in the User mode.

With/Without Sharing

In addition, Apex has such keywords as “with sharing” and “without sharing”, which can be used for a class (this does not impact FLS).

Without Sharing

The keywords ‘without sharing’ mean that sharing rules WILL NOT be applied for the current user. ‘Without sharing’ is used in the cases, when a user does not have an access to the entry, but still needs to edit it.

Let’s say, the OWD for the Account were set to ‘private’. A user does not own any account, and no one shared the entries with them manually. The following class can return the selected accounts from the database:

public WITHOUT sharing class AccountSelector {
public List<Account> getAccts() {
return[SELECT id, Name FROM Account LIMIT 5000];
}
}

The organization features 15 accounts owned by user Y. The code is executed from user X.

Without sharing keyword

AccountSelector acctSel = new AccountSelector();
System.debug(acctSel.getAccts().size());

Once the code is executed, all the accounts in the organization will be selected - regardless of the fact whether a user, under whose name the code is executed, has an access to these entries or not.

With sharing

The keywords ‘with sharing’ mean that sharing rules WILL be applied for the current user.

Let’s take a look at the same case that we have just examined. The OWD for the Account were set to ‘private’. A user does not own any account, and no one shared the entries with them manually. The following class can return the selected accounts from the database:

public WITH sharing class AccountSelector {
public List<Account> getAccts() {
return[SELECT id, Name FROM Account LIMIT 5000];
}
}

The organization features 15 accounts owned by user Y. The code is executed from user X.

With sharing keyword

AccountSelector acctSel = new AccountSelector();
System.debug(acctSel.getAccts().size());

The results of the executed code demonstrate that no account is visible for user X. How so? That is where ‘with sharing’ keywords go into effect.

NB: The keywords ‘with/without sharing’ only feature sharing rules. They do not include field-level security or CRUD.

  1. The sharing setting that was specified for the class is used as a sharing variant for this class. For instance, if the method, which was declared as ‘with sharing’ in the class, is called in a class that is declared as ‘without sharing’, this method will be called as ‘with sharing’.
  2. In case the class is not declared as either ‘with sharing’ or ‘without sharing’, the current sharing rules still apply. This means that if a class that is declared as neither ‘with sharing’ or ‘without sharing’ gets called by a class, which is declared as ‘with/without sharing’ - the sharing keyword of the second class (the one that calls the class without a sharing keyword) will be applied.
  3. Both internal and external classes can be declared with ‘with sharing’ keyword. The sharing settings are applied to the entire code in the class, including the static initialization blocks, constructors and methods.
  4. Internal classes do not inherit sharing settings from their external class.
  5. Classes inherit sharing settings from the base class.
  6. In case a class is not declared as either ‘with sharing’ or ‘without sharing’ - it will be run in the system mode
  7. All SOQL and SOSL queries that feature PriceBook2 ignore ‘with sharing’.

Key takeaways concerning with/without sharing

‘With sharing’ shall be used when you need to refresh the data on the part of the user. If the user X cannot edit entry Y, an error will appear. In case the user X does not see the entry Y, they cannot select this entry. ‘With sharing’ are mainly used for the pages that should work considering the sharing rules.

Let’s say, the page controller for editing an Opportunity should be declared ‘with sharing’ to make sure that the users cannot edit the Opportunity that they cannot access.

‘Without sharing’ should be used when it is necessary to see the entries that cannot be accessed. For example, users cannot see other users’ Leads, but the system should be able to make the potential duplicates and notify someone about duplicating Leads.

Dynamic declaration of CRUD and Field-level security

If, when executing the code as user, Apex class is trying to get the access to an object or field that it doesn’t have CRUD rights to access, an exception will be thrown, and the code will fail to be executed. To avoid this, you can use the dynamic declaration of CRUD and field-level security.

You can modify object-level permissions within the standard Salesforce UI as on the screenshot below.

Object-level security

Alternatively, you can use The Welkin Suite's built-in Objects Permissions Editor to avoid switching between applications. Read more about the Objects Permissions Editor.

Object-level security in The Welkin Suite UI

Absolutely the same applies to the Field-Level security - you can modify these settings in the Salesforce UI, however, there is a much more efficient built-in tool in The Welkin Suite.

This way, everything that is shown above can be checked with Apex code.

For instance, let’s check if a user can:

  • create an Account:
Account.sObjectType.getDescribe().isCreateable();
  • delete an object:
Account.sObjectType.getDescribe().isDeletable();
Schema.sObjectType.Account.isDeletable()
  • update an object:
 Account.sObjectType.getDescribe().isUpdateable();

Also, you can check the access not only to the object in general, but also to each field of the object.

Say, let’s check if the user can see the Name field:

Account.Name.getDescribe().isAccessible()
Schema.sObjectType.Account.fields.Name.isAccessible()

Or, let’s execute Anonymous Apex code:

System.debug(Account.Name.getDescribe().isAccessible());


Executing Anonymous Apex

And this is how you can check if a user can update the field:

Account.Name.getDescribe().isUpdateable();
The Welkin Suite
Developer friendly Salesforce IDE
Try Now For Free

Sharing the entries using Apex

To have the access to sharing through code, you need to use the object of sharing, which is associated with a standard or custom object. For instance, AccountShare is a sharing object for the standard Account object, while ContactShare is a sharing object for the Contact, etc. Apart from that, all of the custom sharing objects are named in the following way:

MyCustomObject__Share

where MyCustomObject - is the name of the custom object created by the user.

The objects on the detail side of the master-detail relationship do not have their own sharing objects. The access to the detail entry is determined by the master sharing object.

Below is the list of properties with brief descriptions:

  • AccessLevel - level of access that is assigned to a certain user or a group of users. Its possible values include: Edit, Read, and All. This level should exceed the objects OWD.
  • ParentID - an ID of the object, which cannot be changed
  • RowCase - the reason for assigning the access to some user or group. Cannot be changed.
  • UserOrGroupID - an ID of a user or a group that the access is assigned to. This field also cannot be changed.

You can share the entries to a user or a group manually, by using Apex. In case the owner of the entry is changed, the sharing object is deleted automatically.

The following example of a class has a method that shares a Stuff object by the specified ID with a user or a group, the ID of which is specified with the second method parameter. The Read access level is assigned.

public class StuffSharing {
  public static void manualShareRead(Id recordId, Id userOrGroupId){
     // Create new sharing object for the custom Stuff object
     Stuff__Share StuffShr  = new Stuff__Share();
     //Define object’s ID
     StuffShr.ParentId = recordId;
     // Define ID of a user/group
     StuffShr.UserOrGroupId = userOrGroupId;
     // Define access level
     StuffShr.AccessLevel = 'Read';
     // Define rowCause as 'manual' for manual sharing.
     // This line can be ommitted, as ‘manual’ is the default value.
     StuffShr.RowCause = Schema.Stuff__Share.RowCause.Manual;
     // Insert the created object
    insert StuffShr;
  }   

NB: You cannot create a sharing object for the entry owner. Executing such code will throw an exception:

Exception with creating share object for owner 1

Exception with creating share object for owner 2

Analyzing: we are trying to share an object with an entry owner, providing a Read-only permission. But they already have the access to the entry, which apart from reading, also includes editing and deleting this entry. That is why an exception appears.

Creating Apex Managed Sharing

Apex Managed Sharing allows the developer to programmatically control the sharing process to maintain the work of the application through Apex or SOAP API. This type of sharing is similar to Force.com managed sharing. Please note that only the users with “Modify All Data” permission can add or change Apex managed sharing for the entry.

Apex Managed Sharing should use an Apex sharing reason - a way the developer can track the reason behind an entry being shared to a user/group. Using several Apex sharing reasons can simplify writing the code that is necessary to update or delete the shared entry. Apex sharing reason also allows the developer to share the entries with the same user/group multiple times, using various Apex sharing reasons.

All Apex sharing reasons are named in the following format:

MyReasonName__c

You can get the access to the Apex sharing reasons through code the following way:

Schema.CustomObject__Share.rowCause.SharingReason__c

For instance, there is an Apex sharing reason called Leader for the Stuff object. Hence, it will be named the following way:

Schema.Stuff__Share.rowCause.Leader__c


To create the new Apex sharing reason, you need to move to "Apex sharing reasons" section from the View custom object page, and then click ‘New’.

New Apex Sharing Reason

When done, please fill in the label and the name.

Label and name of sharing reason

Then click ‘Save’.

Now let’s take a closer look on how can you share an object using the newly created Apex sharing reason.

public class StuffSharing {
  
  public static void manualShareRead(Id recordId, Id userOrGroupId){

     // Create new sharing object for the custom Stuff object

     Stuff__Share StuffShr  = new Stuff__Share();
  
     //Define object’s ID
     StuffShr.ParentId = recordId;
       
     // Define ID of a user/group
     StuffShr.UserOrGroupId = userOrGroupId;
       
     // Define access level
     StuffShr.AccessLevel = 'Read';

     // Fill in this field with a newly created Apex sharing reason
     StuffShr.RowCause = Schema.Stuff__Share.RowCause.Leader__c;
       
     // Insert the created object
      insert StuffShr;
  }
}

Now that you know the difference and all the peculiarities, you should be able to use ‘with/without sharing’ keywords correctly. Also, we hope that CRUD, field level security and Apex managed sharing are also clear and easily comprehensible.

Salesforce permissions applied to Apex
The Welkin Suite
Developer friendly Salesforce IDE
Try Now For Free

1 comment

  1. neeleshcynixit Posted

    Great blog. You can learn salesforce online at https://onlineitguru.com/salesforce-training.html

Please log in to post a comment
ERROR:

Boost Your Productivity. Get Started Today

Try Free Trial