際際滷

際際滷Share a Scribd company logo
Field Level Security in Apex
Learn MOAR in Spring 20
Rajesh Gupta
Senior Tech Lead
iBirds Software Services Pvt. Ltd., Ajmer
LinkedIn: https://www.linkedin.com/in/bitrajindia
Salesforce provides a comprehensive and flexible data security model to secure data at
different levels....
In Salesforce
Data is stored in three key constructions:
 Objects
 Fields
 Records
As a Admin, you can control WHO SEE WHAT using Sharing rules, field and object
permissions.
Salesforce uses
 Object-level : Profiles and Permission sets.
 Field-level : Profiles also control field-level access.
 Record-level security : OWD, Role, Sharing Rules, Manual Sharing
In Apex
public With Sharing class Sharingclass
{
//code
}
public Without Sharing class nonsharing
{
//code
}
With sharing keywords when declaring a class enforces Sharing Rules, but not object
and field-level permissions
 Using Schema Methods
 Using WITH SECURITY_ENFORCED clause
 Using stripInaccessible Method
There are some ways in which you can enforce object-level and field-level
permissions in Apex.
Check if the Email field on the Contact Object is accessible/readable by the logged in user.
if (Schema.sObjectType.Contact.fields.Email.isAccessible()) {
Contact c = [SELECT Email FROM Contact WHERE Id= :Id];
}
For example,
Imagine that you have a bunch of fields in your query, and you have inner
queries . This if statement becomes complex to maintain.
Drawback:
Using WITH SECURITY_ENFORCED clause
Starting Spring 20, the WITH SECURITY_ENFORCED clause can be
used in SOQL queries to enforce field and object level security
permissions in Apex code, including subqueries and cross-object
relationships.
Field-level permissions are checked for all the fields that are retrieved in
the SELECT clause(s) of the query. Since this clause only works inside
an SOQL query, its only useful when you want to check for read access
on a field
Using WITH SECURITY_ENFORCED clause
Example 1:
List<Account> act1 = [ SELECT Id, Name, (SELECT LastName FROM Contacts)
FROM Account WHERE Name like 'Acme'
WITH SECURITY_ENFORCED ];
The above query will return the Id and Name of Accounts, and the LastName of the related
contacts, only if the user has read access to all of these three fields. If the user doesnt have
access to at least one of these fields, the query throws a System.QueryException exception,
and no results are returned. As a best practice, SOQL queries that use this clause, have to
be enclosed in a try/catch block, so that errors can be gracefully handled.
Using WITH SECURITY_ENFORCED clause
try{
List<Account> act1 = [ SELECT Id, Name, (SELECT LastName FROM Contacts)
FROM Account
WHERE Name like 'Acme'
WITH SECURITY_ENFORCED
];
}
catch(System.QueryException) {
//TODO: Handle Errors
}
Using WITH SECURITY_ENFORCED clause
Example 2:
List<Contact> contacts = [SELECT Id, Name, BirthDate
FROM Contact
WHERE Picture_URL__c != null WITH SECURITY_ENFORCED];
However, it is important to note that this clause doesnt verify field-level
security for fields used in the WHERE clause of the query. For example, if a
user doesnt have access a custom field called Picture_URL__c on the
Contact object, the below query doesnt throw an error, and the results are
returned as usual.
Using stripInaccessible Method
The stripInaccessible method from the new Security class to enforce field and
object level security in Apex.
Like the name suggests, this method can be used to strip the fields from
sObject lists to which the user doesnt have appropriate access, depending on
the operation being performed.
stripInaccessible(System.AccessType accessCheckType, List<sObject>
sourceRecords, [Boolean enforceRootObjectCRUD])
Using stripInaccessible Method
 accessCheckType: This parameter defines the type of field-level access check to be
performed. It accepts System.AccessType enum values: CREATABLE, READABLE,
UPDATABLE, UPSERTABLE.
 sourceRecords: A list of sObjects to be checked for fields that arent accessible in the
context of the current users operation.
 enforceRootObjectCRUD: An optional parameter that indicates whether object-level access
check has to be performed. If set to true, and the user doesnt have the necessary CRUD
permissions on the object, this method throws an exception. It defaults to true.
Using stripInaccessible Method
This method returns an object of type SObjectAccessDecision. You use the
getRecords() method to access the list of sObjects which are stripped of
fields that fail the field-level security checks for the current user
For error handling purposes, you can use the getRemovedFields() method to
access a map of sObject types and their corresponding inaccessible fields.
Using stripInaccessible Method
Here is an example of a DML operation, where the current user doesnt have access to a
custom field Picture_URL__c on the Contact Object:
List<Contact> contacts = new List<Contact>{
new Contact(FirstName='Jane', LastName='Doe', Picture_URL__c='someurl'),
new Contact(FirstName='John', LastName='Doe', Picture_URL__c='someurl'),
};
// Strip fields that are not creatable
SObjectAccessDecision decision =
Security.stripInaccessible(AccessType.CREATABLE,contacts);
//DML
try{
insert decision.getRecords();
}catch(NoAccessException e){
//TODO: Handle Error if the user lacks create permission on the Object
}
// OPTIONAL: Print removed fields
System.debug(decision.getRemovedFields());
Using stripInaccessible Method
The DML operation written above runs successfully without exceptions, but the Picture URL
field on the inserted records would be blank because the current user doesnt have
appropriate permissions on it, therefore the value has been stripped off. However, if the user
lacked the create permission on the Contact object itself, the DML statement would throw an
exception.
Here is another example of the methods usage in a query operation, where the current user
doesnt have access to a custom field Picture_URL__c on the Contact Object.
Security.SObjectAccessDecision securityDecision =
Security.stripInaccessible(AccessType.READABLE,[SELECT Name, Picture_URL__c
FROM Contact ];);
for (Contact c : securityDecision.getRecords()) {
system.debug(c.Name); //Prints: Jane, John
system.debug(c.Picture_URL__c); //Prints: null, null
}
Inaccessible fields are removed from the query result, therefore those fields would return
a NULL value.
If you are using the stripInaccessible method on a list of sObject records that have already
been retrieved by a query, remember to use the getRecords() method to access the list of
records with inaccessible fields removed. The original list of records is not updated by the
stripInaccessible method and would still contain the values of inaccessible fields.
List<Contacts> contacts = [SELECT Name, Picture_URL__c from Contact];
Security.SObjectAccessDecision securityDecision =
Security.stripInaccessible(AccessType.READABLE, contacts);
system.debug(contacts); //Insecure access
system.debug(securityDecision.getRecords()); //Secure access
To sum up, this method can be used to:
 Strip fields from query results that the user doesnt have read access to.
 Remove inaccessible fields before a DML operation without causing an exception.
 Sanitize sObjects that have been deserialized from an untrusted source.
Using stripInaccessible Method
Summary
These new techniques make the code less verbose and more efficient.
 The WITH SECURITY_ENFORCED clause can be used directly in an SOQL query to
check for read access on fields, and the query will throw an exception if a single field isnt
accessible.
 stripInaccessible method can be used in read, create, update and upsert operations to strip
the fields from sObject Lists that are inaccessible.
Points To Remember -
 stripInaccessible method is a preview and isnt part of the Services under your master
subscription agreement with Salesforce. This feature is for evaluation purposes only, not for
production use. Its offered as is and isnt supported, and Salesforce has no liability for any
harm or damage arising out of or in connection with it.
 The return list is identical to the source records, except that the fields that are inaccessible to
the current user are removed. the getRecords method contain records in the same order as
the sObjects in the sourceRecords parameter of the stripInaccessible method.
 The ID field is never stripped by the stripInaccessible method to avoid issues when
performing DML on the result.
Points To Remember -
 The ID field is never stripped by the stripInaccessible method to avoid issues when
performing DML on the result.
 The stripInaccessible method doesnt support AggregateResult SObject. If the source records
are of AggregateResult SObject type, an exception is thrown.
Field Level Security  -  Spring 20

More Related Content

Field Level Security - Spring 20

  • 1. Field Level Security in Apex Learn MOAR in Spring 20 Rajesh Gupta Senior Tech Lead iBirds Software Services Pvt. Ltd., Ajmer LinkedIn: https://www.linkedin.com/in/bitrajindia
  • 2. Salesforce provides a comprehensive and flexible data security model to secure data at different levels....
  • 3. In Salesforce Data is stored in three key constructions: Objects Fields Records As a Admin, you can control WHO SEE WHAT using Sharing rules, field and object permissions.
  • 4. Salesforce uses Object-level : Profiles and Permission sets. Field-level : Profiles also control field-level access. Record-level security : OWD, Role, Sharing Rules, Manual Sharing
  • 5. In Apex public With Sharing class Sharingclass { //code } public Without Sharing class nonsharing { //code } With sharing keywords when declaring a class enforces Sharing Rules, but not object and field-level permissions
  • 6. Using Schema Methods Using WITH SECURITY_ENFORCED clause Using stripInaccessible Method There are some ways in which you can enforce object-level and field-level permissions in Apex.
  • 7. Check if the Email field on the Contact Object is accessible/readable by the logged in user. if (Schema.sObjectType.Contact.fields.Email.isAccessible()) { Contact c = [SELECT Email FROM Contact WHERE Id= :Id]; } For example,
  • 8. Imagine that you have a bunch of fields in your query, and you have inner queries . This if statement becomes complex to maintain. Drawback:
  • 9. Using WITH SECURITY_ENFORCED clause Starting Spring 20, the WITH SECURITY_ENFORCED clause can be used in SOQL queries to enforce field and object level security permissions in Apex code, including subqueries and cross-object relationships. Field-level permissions are checked for all the fields that are retrieved in the SELECT clause(s) of the query. Since this clause only works inside an SOQL query, its only useful when you want to check for read access on a field
  • 10. Using WITH SECURITY_ENFORCED clause Example 1: List<Account> act1 = [ SELECT Id, Name, (SELECT LastName FROM Contacts) FROM Account WHERE Name like 'Acme' WITH SECURITY_ENFORCED ]; The above query will return the Id and Name of Accounts, and the LastName of the related contacts, only if the user has read access to all of these three fields. If the user doesnt have access to at least one of these fields, the query throws a System.QueryException exception, and no results are returned. As a best practice, SOQL queries that use this clause, have to be enclosed in a try/catch block, so that errors can be gracefully handled.
  • 11. Using WITH SECURITY_ENFORCED clause try{ List<Account> act1 = [ SELECT Id, Name, (SELECT LastName FROM Contacts) FROM Account WHERE Name like 'Acme' WITH SECURITY_ENFORCED ]; } catch(System.QueryException) { //TODO: Handle Errors }
  • 12. Using WITH SECURITY_ENFORCED clause Example 2: List<Contact> contacts = [SELECT Id, Name, BirthDate FROM Contact WHERE Picture_URL__c != null WITH SECURITY_ENFORCED]; However, it is important to note that this clause doesnt verify field-level security for fields used in the WHERE clause of the query. For example, if a user doesnt have access a custom field called Picture_URL__c on the Contact object, the below query doesnt throw an error, and the results are returned as usual.
  • 13. Using stripInaccessible Method The stripInaccessible method from the new Security class to enforce field and object level security in Apex. Like the name suggests, this method can be used to strip the fields from sObject lists to which the user doesnt have appropriate access, depending on the operation being performed. stripInaccessible(System.AccessType accessCheckType, List<sObject> sourceRecords, [Boolean enforceRootObjectCRUD])
  • 14. Using stripInaccessible Method accessCheckType: This parameter defines the type of field-level access check to be performed. It accepts System.AccessType enum values: CREATABLE, READABLE, UPDATABLE, UPSERTABLE. sourceRecords: A list of sObjects to be checked for fields that arent accessible in the context of the current users operation. enforceRootObjectCRUD: An optional parameter that indicates whether object-level access check has to be performed. If set to true, and the user doesnt have the necessary CRUD permissions on the object, this method throws an exception. It defaults to true.
  • 15. Using stripInaccessible Method This method returns an object of type SObjectAccessDecision. You use the getRecords() method to access the list of sObjects which are stripped of fields that fail the field-level security checks for the current user For error handling purposes, you can use the getRemovedFields() method to access a map of sObject types and their corresponding inaccessible fields.
  • 16. Using stripInaccessible Method Here is an example of a DML operation, where the current user doesnt have access to a custom field Picture_URL__c on the Contact Object: List<Contact> contacts = new List<Contact>{ new Contact(FirstName='Jane', LastName='Doe', Picture_URL__c='someurl'), new Contact(FirstName='John', LastName='Doe', Picture_URL__c='someurl'), }; // Strip fields that are not creatable SObjectAccessDecision decision = Security.stripInaccessible(AccessType.CREATABLE,contacts);
  • 17. //DML try{ insert decision.getRecords(); }catch(NoAccessException e){ //TODO: Handle Error if the user lacks create permission on the Object } // OPTIONAL: Print removed fields System.debug(decision.getRemovedFields());
  • 18. Using stripInaccessible Method The DML operation written above runs successfully without exceptions, but the Picture URL field on the inserted records would be blank because the current user doesnt have appropriate permissions on it, therefore the value has been stripped off. However, if the user lacked the create permission on the Contact object itself, the DML statement would throw an exception. Here is another example of the methods usage in a query operation, where the current user doesnt have access to a custom field Picture_URL__c on the Contact Object.
  • 19. Security.SObjectAccessDecision securityDecision = Security.stripInaccessible(AccessType.READABLE,[SELECT Name, Picture_URL__c FROM Contact ];); for (Contact c : securityDecision.getRecords()) { system.debug(c.Name); //Prints: Jane, John system.debug(c.Picture_URL__c); //Prints: null, null }
  • 20. Inaccessible fields are removed from the query result, therefore those fields would return a NULL value. If you are using the stripInaccessible method on a list of sObject records that have already been retrieved by a query, remember to use the getRecords() method to access the list of records with inaccessible fields removed. The original list of records is not updated by the stripInaccessible method and would still contain the values of inaccessible fields.
  • 21. List<Contacts> contacts = [SELECT Name, Picture_URL__c from Contact]; Security.SObjectAccessDecision securityDecision = Security.stripInaccessible(AccessType.READABLE, contacts); system.debug(contacts); //Insecure access system.debug(securityDecision.getRecords()); //Secure access
  • 22. To sum up, this method can be used to: Strip fields from query results that the user doesnt have read access to. Remove inaccessible fields before a DML operation without causing an exception. Sanitize sObjects that have been deserialized from an untrusted source. Using stripInaccessible Method
  • 23. Summary These new techniques make the code less verbose and more efficient. The WITH SECURITY_ENFORCED clause can be used directly in an SOQL query to check for read access on fields, and the query will throw an exception if a single field isnt accessible. stripInaccessible method can be used in read, create, update and upsert operations to strip the fields from sObject Lists that are inaccessible.
  • 24. Points To Remember - stripInaccessible method is a preview and isnt part of the Services under your master subscription agreement with Salesforce. This feature is for evaluation purposes only, not for production use. Its offered as is and isnt supported, and Salesforce has no liability for any harm or damage arising out of or in connection with it. The return list is identical to the source records, except that the fields that are inaccessible to the current user are removed. the getRecords method contain records in the same order as the sObjects in the sourceRecords parameter of the stripInaccessible method. The ID field is never stripped by the stripInaccessible method to avoid issues when performing DML on the result.
  • 25. Points To Remember - The ID field is never stripped by the stripInaccessible method to avoid issues when performing DML on the result. The stripInaccessible method doesnt support AggregateResult SObject. If the source records are of AggregateResult SObject type, an exception is thrown.