[SalesForce] Cannot delete a record without ModifyAll feature in the Permission Set

I'm getting some issues making my permission set works.

This is the use case. I have:

  1. A custom object with a single field and a button.
  2. Above button call a vf page that shows a button that execute a process
  3. Controller related to above vf page and runJob method that create some records, update them and delete a single record.
  4. A permission set with CRUD access but no ViewAll and ModifyAll checked. It has access to above vf page too.
  5. Object sharing settings are public Write/Read
  6. Grant access using hierarchies false
  7. A user related to a profile that has no access to anything (only custom object tab visibility)
  8. Permission Set is assigned to the user

Having above scenario, admin creates some records and run the job via the button.

If I login as the second user and open a record that was created by the admin, and run the process via the button I get this error:

enter image description here

If I try it manually, Update and Creation is ok, but Delete fails.

If I set ModifyAll value as true in the permission set, then I can execute my process without issues.

Why I cannot delete a record that other user has created? My object is public and the permission set gives me CRUD access. What am I missing?

This is the code just in case you want to reproduce by yourself

Controller

public with sharing class A_TestSecurityController
{
private Id recordId;
private ApexPages.StandardController theController;

    public A_TestSecurityController(ApexPages.StandardController controller)
    {
        theController = controller;
        recordId = theController.getId();
    }

    public PageReference runJob()
    {
        try
        {
            List<TestSecurity__c> listToUpdate = new List<TestSecurity__c>();
            for(TestSecurity__c item : [Select Id, Check__c From TestSecurity__c])
            {
                item.Check__c = false;
                listToUpdate.add(item);
            }
            update listToUpdate;

            TestSecurity__c item = [Select Id From TestSecurity__c limit 1];
            delete item;

            List<TestSecurity__c> listToInsert = new List<TestSecurity__c>();
            for(integer i=0; i<3; i++)
            {
                TestSecurity__c newItem = new TestSecurity__c();
                listToInsert.add(newItem);
            }
            insert listToInsert;

            return theController.view();
        }
        catch(Exception ex)
        {
            ApexPages.addMessages(ex);
            return null;
        }
    }
}

Visualforce

<apex:page standardController="TestSecurity__c" extensions="A_TestSecurityController" >
    <apex:form >
        <apex:sectionHeader title="Test Security"/>
        <apex:pageBlock title="Information">
            <apex:pageBlockButtons >
                <apex:commandButton value="Run Job" action="{!runJob}"/>
                <apex:commandButton value="Cancel" action="{!cancel}"/>
            </apex:pageBlockButtons>

            <apex:pageMessages />
            <apex:pageMessage summary="Please confirm you wish to start the job?" severity="info" strength="2" />
        </apex:pageBlock>
    </apex:form>
</apex:page>

Thanks

Best Answer

You're missing "full" control of the record.

The levels of control are, in ascending order:

  • None
  • Read
  • Edit
  • Transfer
  • Full

Each level of control implies the additional permissions that are lower than that, unless prohibited by the profile.

Full control can generally only be granted by:

  1. owning the record
  2. being a manager of the owner of the record (if enabled), or
  3. having Modify All Data for that object (included automatically if you have the global Modify All Data permission).

See the Help & Training modules on Sharing for more details, as well as other answers here on the SFSE.

"Full" control is also referred to as "Owner" permissions when viewed in Sharing, but basically just means "Delete", as that is the only additional permission it grants. You can have Transfer independently of Delete on some objects by Sharing Rules or Organization Wide Defaults, and you're also explicitly granted Transfer when a record is owned by a queue you are a member of or is in the same Territory as you with Territory Management and the appropriate settings.

As an exception to granting Full access, the "Financial Edition" of salesforce.com, used by companies like Merrill Lynch, offers the ability to create sharing rules that grant Full access to a record despite not meeting the usual criteria.

Related Topic