Secure Apex Code with User Mode DML

on

|

views

and

comments

The generation model for Apex Security is almost here. Now you can declare the database operation mode in the DML. You can specify if the DML will run in user mode or system mode.

The feature is in beta release check this out Summer 22′ release

The new database method accepts a new AccessLevel type parameter which will accept USER_MODE or SYSTEM_MODE.

The USER_MODE checks the following things

  1. Sharing Rules
  2. Object Access
  3. Field Access

What is System vs User Mode

System mode means running apex code by ignoring the userโ€™s permissions.

User mode means running apex code by respecting the userโ€™s permissions and sharing of records. System mode is trusted, and admin-vetted logic run with extra rights.
โ€ข For trusted business logic
โ€ข For data consistency

With Sharing vs Without Sharing

There is a big misconception out there among developers about sharing and without sharing keywords.

with sharing – If you use with sharing keyword with a class then the Apex Code will enforce the sharing setting of the current user, user roles, manually sharing &, etc. All record level sharing will be enforced. This doesย not enforce the Profile permissionย settings.

without sharing – If you do without sharing keyword then Apex Code will execute in system mode.

Enforcing the current userโ€™s sharing rules can impact:

  1. SOQL and SOSL queries. A query may return fewer rows than it would operate in the system context.
  2. DML operations. An operation may fail because the current user doesnโ€™t have the correct permissions.

Now again what options do we have for Enforcing Object & FLS Permissions in Apex? Let’s see that in detail.

Enforcing Object & FLS Permissions

Apex doesnโ€™t enforce object and field level permissions by default. As a developer, we have to forcefully enforce the CRUD & FLS in Apex.

Below is the table with more information about Field and Object Level Security.

Record Level Security

  1. WITH SECURITY_ENFORCED
  2. WITH USER_MODE ( currently in beta )
  3. StripInAccessible
  4. Schema Methods

Object Level Security

  1. Schema Methods
  2. insert as user ( currently in beta )
  3. StripinAccessible
  4. Database user mode operations ( currently in beta )

Using WITH USER_MODE or WITH SYSTEM_MODE

let’s first run a query without any keywords

				
					[SELECT Id, Name, Rating, Owner.Name FROM Account];
				
			

Schema Class

The above query will run without checking the field-level access.ย  Let’s make the changes and use the Schema class to check the accessibility of the Fields on Account Object.

				
					if (Schema.SObjectType.Account.isAccessible() &&
            Schema.SObjectType.Account.fields.Name.isAccessible() &&
            Schema.SObjectType.Account.fields.Id.isAccessible() &&
            Schema.SObjectType.Account.fields.OwnerId.isAccessible() &&
            Schema.SObjectType.Account.fields.Rating.isAccessible() &&
            Schema.SObjectType.Account.fields.OwnerId.getReferenceTo().get(0).getDescribe().isAccessible()) {
            return [SELECT Id, Name, Rating, Owner.Name FROM Account];
        } else {
            throw new AuraHandledException('Access Denied');
        }
				
			

WITH SECURITY_ENFORCED

The above code which we have written will work well without any error, now suppose that you are querying more than 20 fields then you have to put a check for all 20 fields.ย 

So to solve this problem Salesforce Introduced the new keyword that is WITH Security_Enforced

Below is the example for the same which will check the field level permission.

Note: – WITH Security_Enforced keyword does not enforce the record level security

				
					[SELECT Id, Name, Rating, Owner.Name FROM Account WITH SECURITY_ENFORCED];
				
			

WITH USER_MODE

Congratulations! you were able to write the SOQL query in one line which enforces all the security for the user. Now, if you also wanted to enforce the record level access then how you can do that from Query itself?

For this, Salesforce recently came with a new Keyword which is in Beta mode that is WITH USER_MODE

				
					[SELECT Id, Name, Rating, Owner.Name FROM Account WITH USER_MODE];
				
			

StripInAccessible Class

WITH USER_MODE and WITH SECURITY_ENFORCED will throw an exception if the running user does not have permission to any field referred to in Query.

To run the query without any exception we have the StripInAccessible class which will strip the fields to which you do not have access.

We can write the same query in the following way

				
					SObjectAccessDecision securityDecision = Security.stripInaccessible(AccessType.READABLE,
            [SELECT Id, Name, Rating, Owner.Name FROM Account]
        );
    // Print Secured Access Records
    System.debug('Secure record access: '+securityDecision.getRecords());
    // Print modified indexes
    System.debug('Records modified by stripInaccessible: '+securityDecision.getModifiedIndexes());
    
    // Print removed fields
    System.debug('Fields removed by stripInaccessible: '+securityDecision.getRemovedFields());
				
			

DML Enforcement

So far we talked about SOQL Enforcement. Now, let’s talk about various ways to enforce permission for DML.

Below is an example for a simple DML we always used to do

				
					Case caseRecord = new Case(
        Subject = 'Generator is Not Working',
        Description = 'Generator is Not Working',
        Status = 'Open',
        Priority = 'Urgent'
    );
    insert caseRecord;
				
			

In the above example, the record will be created regardless if the running user has access to the case object or not because the DML is running in System Context.

Schema Class

The most common and widely used method is using Schema classes and enforcing the security for the object and each field being referenced.

Here is the modified version of the above DML

				
					Case caseRecord = new Case(
        Subject = 'Generator is Not Working',
        Description = 'Generator is Not Working',
        Status = 'Open',
        Priority = 'Urgent'
    );
    
    if( Schema.SObjectType.Case.isCreateAble()
        && Schema.SObjectType.Case.fields.Subject.isCreateAble() 
        && Schema.SObjectType.Case.fields.Description.isCreateAble()
        && Schema.SObjectType.Case.fields.Status.isCreateAble()
        && Schema.SObjectType.Case.fields.Priority.isCreateAble()){
            insert caseRecord;
    }else{
        throw new AuraHandledException('Insufficient Access');
    }
				
			

Database methods for User Mode

In the above example, We have put the check for every field which is included in DML again here the question is what if we have 30+ fields included?

To address this problem, Salesforce introduced user mode operations which are in beta version.

ACCESSLVEL is an apex class which have two variables that are used to make the DML or Query in either USER_MODE or SYSTEM_MODE

Let’s see how we can modify the above DML statement to use user mode

				
					Case caseRecord = new Case(
        Subject = 'Generator is Not Working',
        Description = 'Generator is Not Working',
        Status = 'Open',
        Priority = 'Urgent'
    );
    insert as user caseRecord;
				
			
				
					Case caseRecord = new Case(
        Subject = 'Generator is Not Working',
        Description = 'Generator is Not Working',
        Status = 'Open',
        Priority = 'Urgent'
    );
    Database.SaveResult sr = Database.insert( caseRecord, false, AccessLevel.USER_MODE);
    if(!sr.isSuccess()){
        String errors = String.join( sr.getErrors(), ' ' );
        System.debug('Error While Creating the Recruiter Records \n '+ errors);
    }
				
			

Log Error not just report

				
					Case caseRecord = new Case(
        Subject = 'Generator is Not Working',
        Description = 'Generator is Not Working',
        Status = 'Open',
        Priority = 'Urgent'
    );
    
    try {
        Database.SaveResult sr = Database.insert( caseRecord, false, AccessLevel.USER_MODE);
    } catch (QueryException qe) {
        Map<String, Set<String>> inaccessibleFields = qe.getInaccessibleFields();
        // Log Error here
    }
				
			
Amit Singh
Amit Singhhttps://www.pantherschools.com/
Amit Singh aka @sfdcpanther/pantherschools, a Salesforce Technical Architect, Consultant with over 8+ years of experience in Salesforce technology. 21x Certified. Blogger, Speaker, and Instructor. DevSecOps Champion
Share this

Leave a review

Excellent

SUBSCRIBE-US

Book a 1:1 Call

Must-read

How to Utilize Salesforce CLI sf (v2)

The Salesforce CLI is not just a tool; itโ€™s the cornerstone of development on the Salesforce Platform. Itโ€™s your go-to for building, testing, deploying, and more. As one of the most important development tools in our ecosystem

Save the day of a Developer with Apex Log Analyzer

Table of Contents What is Apex Log Analyzer? Apex Log Analyzer, a tool designed with Salesforce developers in mind, is here to simplify and accelerate your...

Salesforce PodCast

Introduction Hey Everyone, Welcome to my podcast, the first-ever podcast in India for Salesforce professionals. Achievement We are happy to announce that we have been selected as Top...

Recent articles

More like this

LEAVE A REPLY

Please enter your comment!
Please enter your name here

5/5

Stuck in coding limbo?

Our courses unlock your tech potential