[SalesForce] Salesforce UserRecordAccess query not returning results

I have an apex class that is declared 'without sharing'. This class does some background processing and as a part of that processing, determines whether or not record owners have access to other records. This is accomplished by querying the UserRecordAccess object and filtering on RecordId and UserId (this is not the running user by instead different record owners from the system).

When I run controller as a System Administrator, I get the expected results (results from the UserRecordAccess query with values in MaxAccessLevel). However, when I run the controller as a user with limited record access, queries to UserRecordAccess for any records that the running user does not have access to simply return no results. I see there is a line in the documentation for the object that says:

SOQL restrictions for API version 29.0 and earlier:

When the running user is querying a user's access to a set of records, records that the running user does not have read access to are
filtered out of the results.

I am using API version 35 for my class so I would expect to get results back even when the current running user does not have read access to the record in question (I can query for that record without issue because I am in a 'without sharing' context). Am I missing something here for why I cannot get UserRecordAccess records? This seems like a bug to me since the purpose of the UserRecordAccess object is to be able to check access levels for a user that is not the current running user.

** EDIT – Additional findings **

I have discovered an additional detail for this problem. If the current user does not have access to a record, the user can get their own UserRecordAccess, but not for a different user. This is still a problem because I am trying to answer the question 'Does the record owner for this record have access to another record?'. The record owner is frequently not the running user.

** EDIT – Gist **

Here is a link to a gist for the basic controller/page I am using when I see these results: https://gist.github.com/dsharrison/b0b03c661bf65fc18348.

Thanks for any insight,

D.S.

Best Answer

This could be related to sharing changes on the User Object that happened with API 34.

Beginning in API version 34.0, the User object is no longer exempt from the additional filtering that results from the with sharing keyword. This change is versioned. Update your code to API version 34.0 or later to access the new behavior.

If you didn't explicitly declare it as without sharing, this behavior would be expected. From the docs:

  • If a class isn’t declared as either with or without sharing, the current sharing rules remain in effect. This means that the class doesn’t enforce sharing rules except if it acquires sharing rules from another class. For example, if the class is called by another class that has sharing enforced, then sharing is enforced for the called class.

But, as you say you've explicitly declared your class as without sharing, that wouldn't seem to be the only issue involved. But, as you say you did, the below would apply:

  • The sharing setting of the class where the method is defined is applied, not of the class where the method is called. For example, if a method is defined in a class declared with with sharing is called by a class declared with without sharing, the method will execute with sharing rules enforced.

So, that would seem to leave possibilities like these:

  • Both inner classes and outer classes can be declared as with sharing. The sharing setting applies to all code contained in the class, including initialization code, constructors, and methods.
  • Inner classes do not inherit the sharing setting from their container class.
  • Classes inherit this setting from a parent class when one class extends or implements another.

Might it be possible that the problematic code in question is called from an inner class? If so, that code wouldn't be without sharing unless it too, was defined as being without sharing. Alternatively, is the without sharing class calling another class that's with sharing for providing the final interface? Those would seem to be two scenarios that could be the cause of your issues.

Related Topic