You need to sign in to do that
Don't have an account?
How can I find a user's access level on a record?
I want to know what level of CRUD access the current user has on a particular record. In other words, can this user read, update and/or delete this record. On the surface this seems like it should be simple using Apex. However I'm at a loss.
This is particularly painful because the UI gives me the answer. Go to a Record Detail page, click Sharing, click Expand List. Voila! A complete list of users that have access to that record, and what that access is.
So what's the best way to achieve this programmatically?
At least 3 things to consider:
1) Profile Permissions. This part is simple. The sObject's various Describe Result methods tell me whether a User's Profile permits him to read (isAccessible()) or update (isUpdatable()) or delete (isDeletable()) records of this object type. This is a top-level check. It doesn't address this particular record, just records of this type.
2) Record ownership. If 1) is satisfied, and the current user is the owner of this particular record, all CRUD operations should be available
3) Managed and Manual Sharing. **Here's where I'm having trouble.** Is there a simple way to discover if this record is shared with this user and with what level of access? The sharing information for a record can be found by querying its equivalent Share object (AccountShare is the sharing object for the Account object). But if a sharing rule is defined on a Role (or Role plus subordinates), you cannot see all users given access by that rule! As far as I can tell, you must:
a) query the Share object's userOrGroupId column
b) figure out if that Id is a User, Group or Role
c) If it's a Role, query the groups table to find all users in that role
d) If it's a Role, use recursive logic to find all users above that role in the role heirarchy
e) If it's a Role and the sharing applies to this Role *and subordinates*, use recursive logic to find all users subordinate to that role in the role heirarchy
Isn't there a simpler way?
Here, a save point could be useful. Create a save point, grab a copy of the in-memory reference, attempt to update it, check results for a sharing violation error, attempt to delete, check for a deletion error, then roll back your changes. Without a formal API to just query sharing easily, I believe this is the easiest approach to determining sharing permissions. Any other input would be appreciated. You do need "with sharing" on your class though.
All Answers
I wouldn't recommend the approach you took as it's difficult to get it right and keep it in synch as Salesforce sharing logic evolves further. One easy way that I can think of is to query the record using its id from an Apex class with "with sharing" enabled. This would return 0 results if user doesn't have read access to that record. It's a different story with updates and deletes though. Let's see if others can come up with an idea for those.
Here, a save point could be useful. Create a save point, grab a copy of the in-memory reference, attempt to update it, check results for a sharing violation error, attempt to delete, check for a deletion error, then roll back your changes. Without a formal API to just query sharing easily, I believe this is the easiest approach to determining sharing permissions. Any other input would be appreciated. You do need "with sharing" on your class though.
For Profile Level security, I think you can do DescribeObject to see whether the user has write access or not.
For sharing, for example... if you are trying to find out about Opportunity Record.. :
Since sharing is involved, you need to start looking at opportunityShare entity.
Below check in your code should help you implement your solution.
1. Get the RoleID for the current logged in user.
2. Get all records related to "RoleId" from the "Group" table
4. Check whether group "ID" is present in OpportunityShare table for a particular opportunity record. The check should be made against "UserOrGroupId" column in OpportunityShare entity. Column "OpportunityAccessLevel" will give access information for that particular record.
Cheers !!
Short of an adequate api, sfdcfox's suggested brute force approach seems to be the way to go. Thanks for the tip!
Promote the following idea:
API call for checing [sic] user access level for a record
See also this post by BudVieira.