📢 Attention Salesforce Certified Trailblazers! Maintain your credentials and link your Trailhead and Webassessor accounts by April 19th. Learn more.
close
•
Start tracking your progress
Trailhead Home
Trailhead Home

Identify and Prevent Sharing Violations

Learning Objectives

After completing this unit, you’ll be able to:

  • Define sharing in Salesforce.
  • Identify sharing violations in Apex classes.
  • Enforce sharing rules securely in Apex classes.

What Is Sharing?

As we learned in the first unit, Salesforce lets developers and admins control access to data at many different levels. Sharing is a specific setting that gives you record-level access control for all custom objects, and many standard objects. To learn more about different types of sharing, see Understanding Sharing in the Apex Developer Guide.

Back in the Kingdom Management developer org, our admin has configured sharing rules for some of the objects in the org. One of these is the Coin_ Purse__c object. The admin has configured this object to have private sharing.

Screenshot of Custom Sharing Setup for the Coin Purse object in the Kingdom Management org

By setting the organization-wide default sharing to “private,” our admin has restricted access to this object so users can see only their own records. This means that while Astha the Mighty can see that she has 400 pieces of gold and silver in her coin purse, she can’t see that the king currently has 50,000 pieces of gold. 

How Is Sharing Enforced in Custom Force.com Apps?

Remember that Apex classes execute in system context, so by default Apex executes without enforcing sharing rules. This means that the sharing rules our admin configured are bypassed by default in custom apps. Let’s explore this.

  1. Log in to your Kingdom Management developer org.
  2. Select the CRUD/FLS & Sharing app in the top right.
  3. Click on the Sharing Demo tab.

    Screenshot of the Sharing Violation Demo App in the Kingdom Management developer org

    In this app, users can view an inventory of the gold, silver, and copper coins that they have in their coin purses. As this data is potentially sensitive, we want to make sure that users can only see the contents of their own coin purses, and don’t have access to others.

    Similar to the other apps we’ve looked at in this module, you can use the dropdown on the top left to simulate different users in the kingdom and verify that we’ve configured our access controls correctly.

  4. Using the dropdown, select the Farmer to simulate what this user sees in the UI.
  5. Click View Contents of Coin Purse.

    Screenshot of Sharing violation in the Sharing Demo app

    Oh, no. As the Farmer, you’re able to see how much gold many other users in the system have, not just your own. This is a sharing violation. Remember, our admin set the Coin_Purse__c object sharing setting to private. Let’s see what’s happening.

  6. Click Return to User selection to return to the Admin user.
  7. Click the Apex Controller link to view the code.

    The code is fairly straightforward.
          public class Sharing_Demo {
            public List<Coin_Purse__c> whereclause_records {get; set;}
            public PageReference whereclause_search(){
              if(Coin_Purse__c.sObjectType.getDescribe().isAccessible() && Schema.sObjectType.Coin_Purse__c.fields.Name.isAccessible() && Schema.sObjectType.Coin_Purse__c.fields.Gold_coins__c.isAccessible() && Schema.sObjectType.Coin_Purse__c.fields.Silver_Coins__c.isAccessible() && Schema.sObjectType.Coin_Purse__c.fields.Copper_Coins__c.isAccessible()) {
                String query = 'SELECT Name,Gold_coins__c,Silver_Coins__c, Copper_Coins__c FROM Coin_Purse__c';
                whereclause_records = Database.query(query);
                return null;
              }
              else {
                return null;
              }
            }
          }
        

    The app queries the database and returns objects back to Visualforce to be rendered. However as we learned Apex operates in system context, so this query doesn’t take sharing rules into account. This is why additional records are displayed in the app. How do we fix this?

Sharing Enforcement in Apex

Luckily the platform provides an apt keyword, “with sharing,” which you can add to your class definition to enforce sharing rules in Apex. 

It’s as simple as that! To take advantage of this benefit, you need to declare all classes (including virtual and abstract classes) with “with sharing” keywords. Now let’s fix our app.

  1. Click on the Sharing Demo tab.
  2. Click on the Apex Controller link.
  3. Click Edit to modify the Apex. Change the class definition from
    public class Sharing_Demo {
    to
    public with sharing class Sharing_Demo {
  4. Navigate back to the Sharing Demo tab and select the Farmer user from the dropdown.
  5. Click View Contents of Coin Purse.

    Screenshot of the properly restricted Sharing Demo app showing only one record

    Now you see only the Farmer’s gold supply, not information about other users. Perfect!

Where Do You Need to Add “with sharing”?

Now that you see how important the “with sharing” keyword is, you may be asking where exactly you need to apply it. The best approach is to apply it everywhere you need to enforce sharing rules. This includes inner classes, asynchronous Apex, and Apex triggers.

Sharing in Inner Classes

When working with classes that define an inner class, make sure you apply sharing to both class definitions. Sharing isn’t inherited from an outer class. Below is an example of how to apply sharing to both outer and inner classes.

  public with sharing outerClass{
    public with sharing innerclass {
      [...]
    }
  }
  

Sharing in Asynchronous Apex

It’s important to enforce sharing on your asynchronous Apex classes as well. Sharing doesn’t depend on whether the class executes asynchronously as a scheduled job or batch job. If your class accesses standard or custom fields, prevent sharing violations by declaring the “with sharing” keyword. 

For example:

public class asyncClass  implements Queueable {

Should be declared as:

public with sharing class asyncClass implements Queueable {

Sharing in Apex Triggers

Invoking a trigger from a class without sharing is also insecure. Remember that Apex triggers run in system context. By default they run without taking sharing rules into account. 

Here’s an example. 

  public class OpportunityTriggerHandler extends TriggerHandler {
    public override void afterUpdate() {
      List opps = [SELECT Id, AccountId FROM Opportunity WHERE Id IN :Trigger.newMap.keySet()];
      Account acc = [SELECT Id, Name FROM Account WHERE Id = :opps.get(0).AccountId];
      Case c = new Case();
      c.Subject = 'My Bypassed Case';
      TriggerHandler.bypass('CaseTriggerHandler');
      insert c; // won't invoke the CaseTriggerHandler
      
      TriggerHandler.clearBypass('CaseTriggerHandler');
      c.Subject = 'No More Bypass';
      update c; // will invoke the CaseTriggerHandler
    }
  }

Because the class isn’t defined “with sharing,” it lets the user see all Opportunities that he/she does not have the access to view.

To prevent this sharing violation, define the class with sharing.

public with sharing class OpportunityTriggerHandler extends TriggerHandler {

So remember that whenever you write Apex, whether you’re writing a trigger, async, or just a regular controller, always define the class with the “with sharing” keyword to ensure that sharing rules are enforced.

Resources

Note

Note

Remember, this module is meant for Salesforce Classic. When you launch your hands-on org, switch to Salesforce Classic to complete this challenge.

retargeting