6

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.

  • Given this statement: records that the running user does not have read access to are filtered out why would you think that this so I would expect to get results back even when the current running user does not have read access to the record in question is correct? I read it as you will get no records back – Eric Dec 12 '15 at 2:17
  • I agree, but that statement is listed as a limitation for API version 29 and earlier. That makes it sound like using API version 30 and up does not have this restriction. If the restriction is still present I would expect the documentation to just read 'SOQL restrictions' or 'SOQL restrictions in the current API', not 'SOQL restructions for API versions 29.0 and earlier'. – dsharrison Dec 12 '15 at 4:59
  • Ahhh...did not catch that...I know there is a known issue when querying for user access via the relationship on the record but do not recall anything when querying the access object itself – Eric Dec 12 '15 at 5:00
  • Yeah, this had kept me from using UserRecordAccess before, but when I re-read the documentation recently I was excited that I could finally implement a feature that I had been waiting on. Now that I am seeing this behavior still I am not sure what is going on. I tried to raise a case with Salesforce but they filed this under needing premier developer support so would not provide any information. – dsharrison Dec 12 '15 at 5:02
3

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.

  • I was thinking the same for this, so I created a reduced test case that consists of a 'without sharing' class that queries for the UserRecordAccess for the System Admin user and an account Account, and the Account record itself. When running the class as the System Admin, I get back both the UserRecordAccess and the Account. When running the class as a restricted user I get back no UserRecordAccess but I do get the Account. If I update the UserRecordAccess to look for access as the running user it will work, but not as a different user. I will update my question to include this new detail. – dsharrison Dec 13 '15 at 19:32
  • 1
    I'm going to tweet to @askSalesforce (Salesforce Support) and ask them to take a look at this for you. Hopefully someone will drop in that can shed some light on it for you. – crmprogdev Dec 13 '15 at 22:28
  • 1
    Thank you so much, I wasn't aware of @askSalesforce. When support closed my case for needing premier support, they tried to direct me to developer.force.com, but I find that I have much better interactions with the community on this site. – dsharrison Dec 13 '15 at 22:54
  • 1
    Support responded with: These links might help. success.salesforce.com/answers?id=90630000000i46yAAA and success.salesforce.com/answers?id=906300000010xX8AAI. I've only glanced at them. Perhaps one of the links within them might prove fruitful. I didn't see anything in the main content that provided an obvious answer. – crmprogdev Dec 14 '15 at 15:18
  • 1
    Thanks for posting to them, I checked out those links and those are indeed the links I looked at before originally posting to SE with my issue. I will see if there are any other ways that I can get in touch with support that won't result in them immediately closing my case. – dsharrison Dec 14 '15 at 15:31

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.