+ Start a Discussion
Thibault WeberThibault Weber 

UserRecordAccess issue



Today I encountered a problem that I can't explain:


I got a record 'recA' shared with a user 'userU' through manual sharing (read-only)


When I request the UserRecordAccess object in a 'without sharing' class, all works fine:

[SELECT RecordId, HasEditAccess FROM UserRecordAccess WHERE UserId = :userUid AND RecordId = :recAid LIMIT 1]

=> {RecordId=a0kM0000000jWMxIAM, Id=000000000000000AAA, HasEditAccess=false}


 But when I execute the same code in a 'with sharing' class, i get 


{RecordId=a0kM0000000jWMxIAM, Id=000000000000000AAA, HasEditAccess=true}  //HasEditAccess should be false}



It seems like a bug, because when I do this query:


[SELECT RecordId FROM UserRecordAccess WHERE UserId = :userUid AND RecordId = :recAid AND HasEditAccess = true LIMIT 1]

 I get not results...



Please let me know if you have already encountered some problems with the UserRecordAccess object.


I'm in API 26





Salesforce SolutionsSalesforce Solutions

I'm very glad to have come across your post, because I have run into a similar problem in a Visualforce page.
A custom controller queries for attachments and then runs a query against UserRecordAccess with the returned attachment ids.
(There also appears to be a separate issue where, no matter if the containing class is declared "with sharing" or "without sharing, a user may get some attachment records returned for which they do not have access rights. Hence the need to query UserRecordAccess.)
When logged in as a particular user with restricted access, the following query returns one record in the Workbench (the correct result), but two records in the Visualforce page (as I have verified in the logs).



SELECT RecordId FROM UserRecordAccess WHERE UserId = '005d0000001VTbLAAW'  AND HasReadAccess = true AND RecordId IN ('00Pd0000002rqE4EAI','00Pd0000002rNi8EAE')

Even though the user does not have read access to the attachment with ID '00Pd0000002rqE4EAI', the query in Visualforce returns it in the result set.
However, when I change the class declaration to "without sharing" the query in Visualforce is returning the correct results (i.e. the one record the user is allowed to access).

Not sure if it's relevant, but in the one instance where I'm seeing this problem so far,the attachment is on a custom object that is inaccessible to this user at the object level.


This post helps. It would be even better if the underlying issue was addressed, so we don't need to create APEX platform bug-avoidance code.


Note the before (/*...*/) and after code below. It works like a charm.


	private void loadAccess() {
		if(objectId!=null) {
			UserAccess ua = new UserAccess(this);
			Id userId = UserInfo.getUserId();
			list<UserRecordAccess> uRaList= [Select RecordId,  HasTransferAccess, HasReadAccess, HasEditAccess, HasDeleteAccess, HasAllAccess From UserRecordAccess Where UserId =:userId And RecordId=:objectId];
			UserRecordAccess uRa = uRaList.isEmpty()?null:uRaList[0];
			this.HasTransferAccess = uRa==null?false:uRa.HasTransferAccess==true;
			this.HasReadAccess	 = uRa==null?false:uRa.HasReadAccess==true;
			this.HasEditAccess = uRa==null?false:uRa.HasEditAccess==true;
			this.HasDeleteAccess = uRa==null?false:uRa.HasDeleteAccess==true;
			this.HasAllAccess = uRa==null?false:uRa.HasAllAccess==true;
	// We are creating a class without sharing as a work-around to an SF bug related to UserRecordAccess and classes with sharing 
	public without sharing class UserAccess {
		public UserAccess (SObjectMethods som) {
			if(som!=null?som.objectId!=null:false) {
				Id userId = UserInfo.getUserId();
				list<UserRecordAccess> uRaList= [Select RecordId,  HasTransferAccess, HasReadAccess, HasEditAccess, HasDeleteAccess, HasAllAccess From UserRecordAccess Where UserId =:userId And RecordId=:som.objectId];
				UserRecordAccess uRa = uRaList.isEmpty()?null:uRaList[0];
				som.HasTransferAccess = uRa==null?false:uRa.HasTransferAccess==true;
				som.HasReadAccess	 = uRa==null?false:uRa.HasReadAccess==true;
				som.HasEditAccess = uRa==null?false:uRa.HasEditAccess==true;
				som.HasDeleteAccess = uRa==null?false:uRa.HasDeleteAccess==true;
				som.HasAllAccess = uRa==null?false:uRa.HasAllAccess==true;

 This is in api version 27.

Bhupendra yadavBhupendra yadav
I also had the same problem that the query was not returning any row. However when I tried using dynamic query it worked fine.
pradeepkumar danipradeepkumar dani

@Bhupendra yadav -- Thak you s much, You saved my day.... Its not working in set but it will work in List---- My controller is without sharing
Salesforce guys please look at this bug, and fix it.
sample code:

List<Id> recIdLst = new List<Id>([Select ID FROM Account]);

MAP<ID,UserRecordAccess> usrAcsMap = new MAP<ID,UserRecordAccess>( [SELECT RecordId, HasReadAccess FROM UserRecordAccess WHERE UserId =:UserInfo.getUserId() AND RecordId IN :recIdLst] );