Hi ,
Here we are going to learn about Security.StripInaccessible method.
- This method mainly used for field- and object-level data protection
- This allows developers to remove all fields from the records that the running user does not have access to.
- This makes it easier to allow graceful degradation of application behavior on security violation by omitting fields rather than failing.
How does it work?
- The field- and object-level data protection is accessed through the Security and SObjectAccessDecision classes.
- We can use the StripInaccessible method to strip fields that the current user can’t access from query and subquery results.
- It helps to remove inaccessible fields from sObjects before a DML operation to avoid exceptions.
- This method helps sanitize sObjects that have been deserialized from an untrusted source.
- The stripInaccesible method checks the source records for fields that don’t meet the field- and object-level security check for the current user and creates a return list of sObjects.
- The return list is identical to the source records, except that fields inaccessible to the current user are removed.
- The sObjects returned by the getRecords method contain records in the same order as the sObjects in the sourceRecords parameter of the stripInaccessible method.
- Fields that aren’t queried are null in the return list, without causing an exception.
Note: Previously we were using dynamic apex for identifying access on particular object or field.
How to identify inaccessible fields that were removed:
We can use 'isSet' method.
For example, the return list contains the Contact object and the custom field social_security_number__c is inaccessible to the user. Because this custom field fails the field-level access check, the field is not set and "isSet" returns false.
SObjectAccessDecision securityDecision = Security.stripInaccessible(sourceRecords);
Contact c = securityDecision.getRecords()[0];
System.debug(c.isSet('social_security_number__c')); // prints "false"
Eg:(1)
This example removes fields from the query result that the current user does not have update access to.
SObjectAccessDecision securityDecision =
Security.stripInaccessible(AccessType.UPDATABLE,
[SELECT Name, BudgetedCost, ActualCost FROM Campaign]);
Eg:(2)
This example performs a query and then removes inaccessible fields from the query result.
List<Contact> records = [SELECT Id, Name, Phone, HomePhone FROM Contact];
SObjectAccessDecision securityDecision = Security.stripInaccessible(AccessType.READABLE, records);
Example class before applying "stripInaccessible".
global with sharing class ApexSecurityRest {
global static Contact doGet() {
Id recordId = RestContext.request.params.get('id');
Contact result;
if (recordId == null) {
throw new FunctionalException('Id parameter is required');
}
if (Schema.SObjectType.Contact.isAccessible()
&& Schema.SObjectType.Contact.fields.Name.isAccessible()
&& Schema.SObjectType.Contact.fields.Top_Secret__c.isAccessible()
) {
List<Contact> results = [SELECT id, Name, Title, Top_Secret__c, Account.Name FROM Contact WHERE Id = :recordId];
if (!results.isEmpty()) {
result = results[0];
if (Schema.sObjectType.Contact.fields.Description.isUpdateable()){
result.Description = result.Account?.Name;
}
}
} else {
throw new SecurityException('You don\'t have access to all contact fields required to use this API');
}
return result;
}
public class FunctionalException extends Exception{}
public class SecurityException extends Exception{}
}
After applying stripInaccessible
global with sharing class ApexSecurityRest {
global static Contact doGet() {
Id recordId = RestContext.request.params.get('id');
Contact result;
if (recordId == null) {
throw new FunctionalException('Id parameter is required');
}
List<Contact> results = [SELECT id, Name, Title, Top_Secret__c, Account.Name FROM Contact WHERE Id = :recordId];
SObjectAccessDecision securityDecision = Security.stripInaccessible(AccessType.READABLE, results);
if (!results.isEmpty()) {
result = results[0];
if (Schema.sObjectType.Contact.fields.Description.isUpdateable()){
result.Description = result.Account?.Name;
}
}
return result;
}
public class FunctionalException extends Exception{}
public class SecurityException extends Exception{}
}
Considerations:
References:
------------------
No comments:
Post a Comment