3

It seems that the Apex row-level security enforcement by with sharing keyword is not applied to the field OwnerId, when it is directly passed to update statement.

public with sharing class MyRecordUpdate {
  // ...
  public void changeOwnerToMe(Id recordId) {
    MyRecord__c rec = new MyRecord__c(Id=recordId, OwnerId=UserInfo.getUserId());
    update rec;
  }
}

In the above code, supposing that the MyRecord__c object is private in Organization-Wide sharing defaults, and each records are shared by manually. Its Object-level security = CRUD enabled, and Field-level security = Not set.

If the record specified by recordId is owned by other user and granted read-only access to the current user, the modification of OwnerId should raise an insufficient privilege error (it actually behaves that from standard UI or REST API). But when executing MyRecordUpdate#changeOwnerId() in the context of user with standard profile (not admin user), it silently succeeds the owner modification.

This only happens when the update statement argument record is created by new, not applied when queried from SOQL. Also it will not happen to other fields, like Name.

public with sharing class MyRecordUpdate {
  // ...

  // supposing that context user is granted read-only access to `recordId` record

  public void changeOwnerToMeUsingQuery(Id recordId) {
    MyRecord__c rec = [SELECT Id FROM MyRecord__c WHERE Id = :recordId];
    rec.OwnerId = UserInfo.getUserId();
    update rec; // throws INSUFFICIENT_ACCESS_OR_READONLY error
  }

  public void updateName(Id recordId, String name) {
    MyRecord__c rec = new MyRecord__c(Id=recordId, Name=name);
    update rec; // throws INSUFFICIENT_ACCESS_OR_READONLY error
  }
}

Is there anyone who encountered to this situation? I've tested the above in my scratch org.

EDIT: Added the code to demonstrate this issue. https://github.com/stomita/apex-rls-ownerid-issue

  • I tried this scenario in a developer org. Both changeOwnerToMe & changeOwnerToMeUsingQuery methods were able to update the OwnerId field (code run under Standard User context, following the instructions you have mentioned). But I did get insufficient access exceptions for the Name and Text01__c fields, which was expected. While the OwnerId update can be restricted with some additional apex code, its weird that the field is getting updated by an user having read only access to the record. – arut May 9 at 10:59
  • Also, I noted the following: The following field types don’t return a FieldPermissions record because they are assumed to always be readable and writable. OwnerId in the SOAP API developer guide [developer.salesforce.com/docs/atlas.en-us.api.meta/api/…. While its not directly related to the problem here, it sounds like OwnerId field is handled quite differently by Salesforce when compared to the other field. – arut May 9 at 11:01
  • In a new scratch org I found changeOwnerToMeUsingQuery doesn't throw insufficient privilege error (unexpected), but the other environment it throws (expected). I cannot figure the difference of them. – stomita May 9 at 21:43
  • Sounds like a Salesforce bug to me. I'll try and run few more scenarios on this. – arut May 10 at 3:52

Your Answer

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

Browse other questions tagged or ask your own question.