I am working on an assignment where I need to expose Contact
data to a webservice via REST API
. I was able to get the REST API
call working thru Postman/SoapUI only when the Profile has the View All
permission checked for the Contact
of the running user. My objective is to restrict the access for the webservice to specific fields on Contacts, not on all fields. Is there anyway I can get this done without having to give the View All
permission?
1 Answer
Permissions and the Salesforce REST API
The Salesforce REST API respects field-level security and record-level security. In order for you to obtain access to a specific Contact record, the user account under which you authenticate to Salesforce must be able to see it.
"View All" permission controls record-level visibility. A context user with View All permission ignores the effects of sharing rules and Organization-Wide Defaults, meaning it can see every Contact in the system at the record level. It does not mean that every field on the Contact is visible.
Field visibility is controlled by Field-Level Security. You can configure this on the Profile and/or assigned Permission Sets for the user under which you authenticate. That user will only be able to obtain data for the fields for which the user has Read access, on Contacts which Record-Level Security allows them to see.
You can leave the View All permission turned on if it meets your specific record-level visibility needs while restricting access to individual fields with Field-Level Security.
You can illustrate this FLS enforcement for yourself using Workbench. For example, if you remove FLS for yourself from the Industry
field on Account, and then use REST Explorer to issue the following GET request:
/services/data/v43.0/sobjects/Account/001360000XXXXXXXXX?fields=Name,Id,Industry
You will get back
SELECT Name,Id,Industry FROM Account ^ ERROR at Row:1:Column:16 No such column 'Industry' on entity 'Account'. If you are attempting to use a custom field, be sure to append the '__c' after the custom field name. Please reference your WSDL or the describe call for the appropriate names
Because you don't have permission to see that field. This applies even to a System Administrator, who has Modify All Data permission - which trumps View All.
Custom API Classes
The material below is less relevant to your situation, since you explained that you are using the native Salesforce API directly rather than writing your own API class.
Because Apex runs in system mode, you need to manually enforce CRUD and FLS based on the permissions of the current running user in your Apex REST API classes. The document Enforcing CRUD and FLS actually has an example just for your use case, "CRUD and FLS Enforcement in Apex Web Services" (it's written with SOAP web services in mind, but REST would be the same logic).
Read enforcement looks like this, from the linked document:
webservice static String getContactPhone (Id contactId) {
// Check if the user has read access on the Phone field
if (!Schema.sObjectType.Contact.fields.Phone.isAccessible()){
return null;
}
return [SELECT Phone FROM Contact WHERE
Id=:contactId].Phone;
}
Another critical piece to consider is the sharing model declared on your REST service class. If you're seeing a need to have the Contact View All permission on your authenticated user, you probably have declared your class with sharing
or inherited sharing
. That's good, in most situations, because it applies your org's sharing rules to queries performed by the class. In select use cases, you might want to use without sharing
, but it's better to permission that level of access at the user level.
-
Thanks for your response. I don't have any wrapper class in Salesforce and hence I cannot enforce CRUD in code. The service is directly calling the REST API by providing the contact Id as /services/data/v43.0/sobjects/Contact/{salesforce_id_of_contact}?fields=Id,Name. The problem is I cannot get this REST API working without giving the "View All" permission on contact object. If I uncheck and just leave the "Read" permission, it still doesn't work. So, it appears that I cannot enforce FLS in this case, correct? Oct 24, 2018 at 15:06
-
I misunderstood your question. You are calling the Salesforce REST API directly, not writing your own REST API in Apex. I will update my answer.– David Reed ♦Oct 24, 2018 at 15:08
-
again thanks for updating the answer. Without the "View All" permission, the REST API is not working for me. With the "View All" and have the FLS checked on Id and Name, I assume the webservice user cannot see any info other Id and Name, correct? However, this is not the case. The webservice user is able to see all fields on Contact even though all contact fields are not visible under his profile. Only Id and Name are checked for 'Read' access. Oct 24, 2018 at 16:17
-
Where are you configuring the FLS? That is not how enforcement works on API access (I added an example in my answer).– David Reed ♦Oct 24, 2018 at 16:34
-
1Does the Basic User profile itself have field permissions on Contact? The Permission Set is additive to the Profile; it does not override existing FLS.– David Reed ♦Oct 24, 2018 at 16:40