0

CURRENT STRUCTURE

We're working on an app where we need to display the records if user has access to it. We're following below given algorithm:

  1. If User's profile has View All permission then display all records.
  2. If User's profile has View All permission on specific object then display all records of that object.
  3. If sharing setting is Public * or more than Public then show all records of that object.
  4. If sharing setting is private then:

    a). If user is added as member on MyCustomObject __Share then display record.

    b). If user belongs to a group and and that group has access to this record then display record.

ISSUE

Problem is at point 4-b) when we check group is added in MyCustomObject __Share then make the record visible to it's member. But problem is that when group is standard one "Internal User" - Query select UserOrGroupId from MyCustomObject __Share does return Id of group "All Internal Users". But when we query to find out member based on that Id like select id, UserOrGroupId from GroupMember where GroupId = '00G9xxxxxxxxx' it does not return any result. When we query on Group we find a group with type "Organization".

So, question is how can we make sure that a user belongs to this standard group? I read through doc (https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_objects_group.htm), it says:

Organization—Public group that includes all the User records in the organization. This group is read-only.

Is it safe to assume that if this group is added on record then show this record to all internal user?

Please feel free to provide a better suggestion if you have.

Please note that we can not use UserRecordAccess because it has some limitation lie works only 200 records ....works only in context with current user if you query it on specific object.

1

Why not use with sharing keyword, whatever you specified can be done with standard salesforce functionality.

public with sharing MyAccountAccessClass{

  public boolean hasAccessToAccountRecord(Id recordId){    
            List<Account> accountList =[Select id from Account where id=:recordId];   
             if(accountList.isEmpty()){
                  return false;    
              }    
              return true; 
     }

}

You can replace query with a dynamic query if there are different objects, I wont try to reimplement the whole wheel if an apex class can handle it. As you haven't mentioned if you want it for edit purpose, the above solution will work.

source : https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_keywords_sharing.htm

  • My bad! actually...we are not developing the app native to salesforce! ...we are using REST API and building it in different tech and on different platform... don't think this approach would help. – Ayub May 28 '18 at 10:24
  • Actually it will, just make it as a Rest webservice with sharing, cant see any issues – Pranay Jaiswal May 28 '18 at 10:30
  • But would it not run in context of current user (with which connection to salesforce and end server is built) only?...what if we need to pass the User parametrized...? For example, integration is built with single admin but want to process another non-admin user's accessibility .. – Ayub May 28 '18 at 10:35
1

There's a few flaws with your algorithm, unfortunately, that would make this task less than ideal. In addition to checking View All Data and Object View All Data, and Organization Wide Defaults, and the Share table, you might also need to deal with implicit sharing, territory management, role hierarchy sharing, queue ownership, ownership sharing, Apex Managed Sharing, and recursive groups (a public group may contain other public groups, which can contain other public groups, ad nauseam).

Your best choice, if possible, is to log in as the user directly and use the default security mechanisms. In other words, just let each user log in to the app and do normal queries via the REST API. This is by far the easiest, and most recommended, solution. It's incredibly easy to mess up writing your own security checking algorithm, and impossible to bypass the APIs security checking algorithm. Also worth noting that future security enhancements may cause your algorithm to behave differently than the API directly.

If you absolutely need to parameterize your calls, then you're going to need to use UserRecordAccess. Yes, it has a limit of 200 rows at a time. This is because you're literally evaluating the user's entire situation, including profile, permission sets, role, public group membership, sharing rules, implicit and owner sharing, and so on. While you haven't really gone in to detail about specifics about this app, it's probably safe to say that if you need to do all these calculations across millions of records, your app is going to perform very poorly, if at all.

  • Thanks much! I was waiting for your answer..I know my algorithm is still not looking at multiple parameters..But I don't have any other option..We are building an enterprise search solution that crawl data from salesforce and keeps at server..And further we make this record available on search page using Elastic...So there is going to be high volume of data...So I can not ise userrecordacess..Similarly..This search app may be host on any other platform...Like Zendesk...Lithium...Etc..So....It's hard to develop per user login implementation. So at this moment I got stuck! – Ayub May 28 '18 at 17:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.