Sunday, October 20, 2019

Enforce Field-Level Security Permissions for SOQL Queries

This post will explain how to enforce field level security permissions for SOQL queries,

  • In Spring' 19 release salesforce introducing this fantastic feature, WITH_SECURITY_ENFORCED clause, you can use this to enable checking for field- and object-level security permissions on SOQL SELECT queries, including subqueries and cross-object relationships.
  • If you include a field in a SQOL query (Without WITH SECURITY_ENFORCED Clause) and a user doesn’t have access to that field, the field will be returned and can be used by the code without any exception, but the data to that user should not have access.
  • If you use WITH SECURITY_ENFORCED clause for same SOQL Select query, it will throw exception and no data will be returned.
  • The WITH SECURITY_ENFORCED clause is only available in Apex. Using WITH SECURITY_ENFORCED in Apex classes or triggers with an API version earlier than 45.0 is not recommended.

Below are some of the examples.

1. If on the Opportunity object, suppose field-level security for  Stage , Amount, and LeadSource is hidden, it will throw an exception insufficient permissions and no data will return.

String query = ’Select Id, Name, ‘;
if(Schema.sObjectType.Opportunity.fields.Amount.isAccessible()){
query += ‘Amount, ’;
} else{
//Exception handling code will go here
}
if(Schema.sObjectType.Opportunity.fields. LeadSource.isAccessible()){
query += ‘LeadSource, ’;
}
if(Schema.sObjectType.Opportunity.fields.StageName.isAccessible()){
query += ‘StageName, ’;
}
query = query.subString(0, query.length()-2);
query += ‘ FROM Opportunity’;
List<Opportunity> oppty = Database.query(query);
And after this awesome feature introduced, developers need to write below lone of code.
List<Opportunity> oppty = [SELECT Id, Name, LeadSource ,StageName, Amount FROM Opportunity WITH SECURITY_ENFORCED];

2. If field access for Website is hidden, this query throws an exception indicating insufficient permissions.

List<Account> acct = [SELECT Id, parent.Name, parent.Website
FROM Account WITH SECURITY_ENFORCED]

How to use in Apex Method

In below code example, the comparison can be understand that how the field
accessibility were getting checked before introduction of this awesome feature.

Checking field accessibility before this feature:

 if (Schema.SObjectType.Contact.isAccessible()
            && Schema.SObjectType.Contact.fields.Name.isAccessible()
            && Schema.SObjectType.Contact.fields.Secret_Key__c.isAccessible()){
            List results = [SELECT id, Name, Secret_Key__c FROM Contact WHERE Id = :recordId];
            if (!results.isEmpty()) {
                result = results[0];
            }
        } else{
        throw new SecurityException('You don\'t have access to all contact fields'); }

Checking field accessibility after this feature:

try
{
List results = [SELECT id, Name, Secret_Key__c FROM Contact WHERE Id = :recordId 
WITH SECURITY_ENFORCED];
if (!results.isEmpty()) {
result = results[0];
}
}
catch( System.QueryException exception)
{
     throw new SecurityException('You don\'t have access to all contact fields'); }