+ Start a Discussion
Nitin ParandeNitin Parande 

How to find list of Accounts a User has access to ?

I have a requirment to create a service which takes input as a user ( userid) and the service needs to return the list of Accounts the user has access to. The user can get access to account  to all possible ways that salesforce can provide (Sharing rules, Role Hierharchies, Record Ownership, Account Team etc...).

I looked around on AccountShare object, GroupMember, UserRecordAcess, Role  object. but could not really connect all the dots together to come up with logic to accomplish this.

USerRecordAccess has the details but you have to provide the USerid and Recordid in order to pull the records which does not fit my requirment.

Looking for any guidance.
Just add with sharing keyword to your class may be ?
Nitin ParandeNitin Parande
Any user will be passed as an input to the service for which the accounts needs to be determined. The webservice call/authentication  will be  through a different eneric user.  The webservice logic will NOT be run under the user for which we want to determine the accounts.
Jai ChaturvediJai Chaturvedi
public with sharing class accountList{

    public List<Account> accList{get;set;}
    public accountList(){
        accList = new List<Account>();
        for(Account a : [SELECT Name FROM Account]){
Nitin ParandeNitin Parande
@Jai >>  I am looking for list of account NOT for the running user but for any user that is provided as input to the webservice by the consumer of the webservice.

Here is a link of a blog which help you to find the record is accessable or not for a user. 


IF it helps you than please mark it as a solution and ENJOY APEX (http://www.codespokes.com/2014/06/salesforce-record-accessibility.html)

Nitin ParandeNitin Parande
@Ashleskh  I had looked at the userrecordaccess table earlier. We have more than 10,000 accounts. This table needs you to pass userid and recordid. Recordid (recordid can be list). However this approach is not flexible as I would be scanning 10,000 accounts across the userrecordaccess table every time which will not be feasible for a synchronous webservice and also governor limit. I though the best starting point will be to start from what is in the Accountshare (based on group, group members and roles tables ) which will limit the record scanned.

I am ignoring OWD. Permission Sets, profiles as we won't be providing access to accounts through that. Our access to account will be mimited to Sharing and Role Hierarchy access. I stumbled on the some notes where users are using combination of Accountshare, Group, Group member and userrole tables to derive this. I am trying to understand the data model for this to determine the logic/joins.
Jai ChaturvediJai Chaturvedi
Ok. You can use Accountshare object. It has some fields like UserOrGroupId, AccountId etc. So using these fields u can pass provided user ids and get the account ids and then u can query account using collected account ids.

List<AccountShare> shareList = [SELECT AccountId,  UserOrGroupId FROM AccountShare WHERE UserOrGroupId =: useridList ];
for(AccountShare s : shareList){

List<Account> acc = [SELECT Name FROM Account WHERE Id IN : accountIds];

Hope this works.
Nitin ParandeNitin Parande
@Jai >>  Do you know how the record is created in Accountshare if the user gets access through Role Hierarchy or through nested groups. I meant if the top Role user has access to the account of the subbordinated roles how the data gets stored. If user is part of group which is nested in other group the the original group is given access, how to retrieve the information. I stumbled on some notes on the internet which the Groups gets created automatically based on RoleSubbordinates but could not correctly undestand that. Basically I am trying to understand the AccountShare object relation with Group object and Group member object (in relation with Role Hierarchy, nested groups) to correctly derive this information.
If the access is provided directly to user or the group he is in, the accountshare object will store the direct entry which you can retrieve. The complexity is in the case where the access is not provided directly but the user inherits through Role Hierarchy or groups within groups. Some kind of recursuve logic will need to be written for this. BAsed on some notes in the net looks like salesforce automatically explodes the role hierarchy and creates this internal groups which you can use. I could not get that part, the documentation of the Group and Group member table gives some explanation but it not very clear. I opened a SR with Salesforce to get their opinion. Lets see. So far it does not look encouraging.
@Nitin, your reply to Jai above is quite accurate. The access provided by the Role and Territory hierarchies (as well as nested public groups) is managed through group membership. Each role or territory in the hierarchies is actually supported by multiple groups that support both the general inheritance of access to data owned by subordinate users, and the operation of sharing rules that are defined with the "and Subordinates" attribute. There is no record written in AccountShare when a user gains access through group membership, only when a record is shared directly with a user, Role, Territory or Public Group. Instead we determine the user's access by consulting the group membership tables in addition to AccountShare when the user requests access.The Sharing code that supports this *is* highly recursive and extensively optimized, and would be extremely difficult to try to reproduce in a performant way.

Would it be useful for your purposes to be able to test a user's access against a known set of Accounts? If so, you can use the UserRecordAccess function documented here: http://www.salesforce.com/us/developer/docs/api/Content/sforce_api_objects_userrecordaccess.htm
Bud VieiraBud Vieira
@Nitin, reading more above, I see you have already tried the UserRecordAccess route, but were concerned about the length of the callout and our governor limits. Are you aware of the new Asynchronous Callout feature that Josh Kaplan announced earlier in tihs blog post? http://sfdc.co/bfAQqt

That feature allows you to manage a long-running callout that is synchronous to the user, but processes on our message queues and so not constrained by our long-running callout limit.
Nitin ParandeNitin Parande
@Bud, Thanks for your response. I reviewed the User RecordAccess approach but because of functional inability to pre-limit the data set for scanning  through the UserRecordAccess table and the  performance/Governor limit reasons, eliminated this approach. However will check the Asyncronous Callout as you suggested. Just for quick background, we decided to store the Record Access through Role/Herarchies in Salesforce and utlize that through service calls from our external systems. Intention is to centralise the Access definition in one place and not replicate the logic in other systems. So the real time component is critical.

Secondly, the recursive derivation of the Record Access through Group(Member) tables - Is the performance only the issue OR is there any other technical limitation for this (apart from the complexity) ?  I was going to limit the Role/Hierarchy Tree traversing up to fixed level  - based on our needs here the tree should not be more then 4 level deep. Can you point to any other documentation which clearly defines the data model AND  how the records are stored for the Hierarchies through Role and nested Groups.? Want to study this approch before I discard. Also, some one mentioned we can run apex code under a specifc user context but that feature is only available in Sandbox not Production. Is this correct ?
Salesforce BlitzSalesforce Blitz
Hi Nithin,

I have a similar situatuin where i need to query all records of Opportunity accessible to a user.

How did u solve the issue. Let me know if u see this msg asa.

Thanks in advance.
Sheakar KrishnaSheakar Krishna
I am trying to solve the same problem, I think a combination AccountShare + GroupMember tables will provide the record level access
Could you solve the problem by using AccountShare+GroupMember?