2

1- I am using fflib for my managed package.

2- By default CRUD/FLS are enabled for all domain/selector flows (Using Base class)

3- In a specific method which is used by site guest users, I want to bypass CRUD/FLS check.

4- "Configuration.disableTriggerCRUDSecurity();" is not working in a domain specific method.

5- I know same is possible in Selector layer (See Accepted Answer) . I want same thing in domain layer.

How to By pass CRUD/FLS from Domain layer in any specific Flow?

Sample Code which should work but it is not working

public inherited sharing abstract class BaseDomain extends fflib_SObjectDomain {
    public BaseDomain(List<SObject> records) {
        super(records);
        Configuration.enforceTriggerCRUDSecurity();
    }
}

public inherited sharing class ABCs extends BaseDomain implements IABCs{

    public ABCs(List<ABC__c> abcs) {
        super(abcs);
    }
    ..........................
    public list<Boolean> incrementViewCount(fflib_ISObjectUnitOfWork uow){
        Configuration.disableTriggerCRUDSecurity();
        //Business Logic
        for(SObject urlObj:Records){
            ABC__c abc = (ABC__c)urlObj;
            Double viewCount = 0;
            if(abc.TotalView__c != null){
                dataDumpViewCount = abc.TotalView__c;
            }
            abc.TotalView__c = dataDumpViewCount +1;
            uow.registerDirty(abc);
        }
    }
}

public with sharing class ABCServiceImpl implements IABCServiceService{

    public void createViewCountByGuestUser(list<ID> abcIds){
        
        new ElevatedViewStatus().saveViewStatus(abcIds);
    }

    private without sharing class ElevatedViewStatus{
        public ViewStatusBO  saveViewStatus(list<ID> abcIds){
            fflib_ISObjectUnitOfWork uow = Application.UnitOfWork.newInstance();
            .........................
            IABCs abcsDomain = (IABCs) Application.Domain.newInstance(abcIds);
            abcsDomain.incrementViewCount(uow);
            ........................
        }
    }
}
7
  • 1
    So, to bypass CRUD/FLS for specific flows, the Domain layer needs contextual information - such as running user. If the Domain layer is acting as your trigger handler, then it is not supposed to care about how invoked only info about the running user and running user's permissions would vary by invocation unless you set a field on the object from the flow and then clear it in the onBeforeInsert/Update domain handlers. Use edit to provide some more info
    – cropredy
    Jan 18, 2022 at 19:02
  • Added one sample code which should work for me but not working. Custom Object is created by Standard Salesforce users but I like to track how many times this data is shown to Site Guest Users. And according to this count I want to update one field from Site Guest user. Jan 19, 2022 at 6:34
  • so if you look in fflib_SObjectDomain, you'll see that Configuration.EnforcingTriggerCRUDSecurity applies only to handleAfterInsert/Update/Delete/Undelete. Your domain method incrementViewCount is not associated with trigger events. fflib is a red herring here - you need to think about why a Flow executed by a guest user can't update the custom object
    – cropredy
    Jan 19, 2022 at 6:41
  • actually, above comment is wrong since you are registerDirty ABC__c and when committed, will execute the domain onAfterUpdate and bypass the isUpdateable check. Is your flow defined to run in System Context rather than the default User Context?
    – cropredy
    Jan 19, 2022 at 16:43
  • My flow is defined to run in the user context. This code is executed by Site guest user. Jan 20, 2022 at 5:10

2 Answers 2

3

I have find one workaround for my requirement.

My flow is

  1. Create a static variable isSupportCRUD with default value true in Base domain class.
  2. Create a new method disableTriggerCRUDSecurity() in the BaseDomain which changes isSupportCRUD value from true to false.
  3. Now change constructor code of Domain Class(ABCs) to disable CRUD according to the value of isSupportCRUD in which you like to disable CRUD security check at runtime.
  4. Remove the Configuration.disableTriggerCRUDSecurity() from Domain method (From my question code)
  5. Call Domain.disableTriggerCRUDSecurity() method before instancing Domain class

Sample Code

public inherited sharing abstract class BaseDomain extends fflib_SObjectDomain {
public static Boolean isSupportCRUD = true;
public BaseDomain(List<SObject> records) {
    super(records);
    Configuration.enforceTriggerCRUDSecurity();
}
public static void disableTriggerCRUDSecurity(){
    isSupportCRUD = false;
 }
}

public inherited sharing class ABCs extends BaseDomain implements IABCs{
public ABCs(List<ABC__c> abcs) {
    super(abcs);
    if(!isSupportCRUD){
       Configuration.disableTriggerCRUDSecurity();
    }
}

..........................
public list<Boolean> incrementViewCount(fflib_ISObjectUnitOfWork uow){
    //Business Logic
    for(SObject urlObj:Records){
        ABC__c abc = (ABC__c)urlObj;
        Double viewCount = 0;
        if(abc.TotalView__c != null){
            dataDumpViewCount = abc.TotalView__c;
        }
        abc.TotalView__c = dataDumpViewCount +1;
        uow.registerDirty(abc);
    }
  }
}

public with sharing class ABCServiceImpl implements IABCService{
public void createViewCountByGuestUser(list<ID> abcIds){
    new ElevatedViewStatus().saveViewStatus(abcIds);
}

private without sharing class ElevatedViewStatus{
    public ViewStatusBO  saveViewStatus(list<ID> abcIds){
        fflib_ISObjectUnitOfWork uow = Application.UnitOfWork.newInstance();
        .........................
        ABCs.disableTriggerCRUDSecurity();
        IABCs abcsDomain = (IABCs) Application.Domain.newInstance(abcIds);
        abcsDomain.incrementViewCount(uow);
        ........................
    }
 }
}
0

As an alternate solution I disable crud in the unit of work by using without sharing in the IDML interface, and use it in my UOW instance

Usage:

 fflib_SObjectUnitOfWork uow = new fflib_SObjectUnitOfWork(
        new List<SObjectType> { Account.SObjectType, 
                                Opportunity.SObjectType, 
                                Case.SObjectType},
        new Disable_CRUD_UOW()
    );

IDML class:

public without sharing class Disable_CRUD_UOW implements 
   fflib_SObjectUnitOfWork.IDML{
        public virtual void dmlInsert(List<SObject> objList)
        {
            insert objList;
        }
        public virtual void dmlUpdate(List<SObject> objList)
        {
            update objList;
        }
        public virtual void dmlDelete(List<SObject> objList)
        {
            delete objList;
        }
        public virtual void eventPublish(List<SObject> objList)
        {
            EventBus.publish(objList);
        }
        public virtual void emptyRecycleBin(List<SObject> objList)
        {
            if (objList.isEmpty())
            {
                return;
            }
    
            Database.emptyRecycleBin(objList);
        }
    }

this will not check for crud and can be used when you want the dml to be in system context, add this wherever you may. Rest of the usage of unit work remains same after the declaration specified in the "Usage" section.

2
  • I'm confused -- without sharing affects record access (i.e. which records can be accessed) - it has no impact on whether running user has ability to create/update/delete an SObjectType. Plus, OP is about domain layer, not uow layer
    – cropredy
    Jul 19 at 16:42
  • the parent class fflib_SObjectUnitOfWork and fflib_SObjectDomain enforces with sharing so no matter what I tried It always ended up checking for crud, only way to run in system mode was to use without sharing in the idml interface, this is not safe for use everywhere but for my case I needed this for triggers and it was better to add this to a class than adding access for unwanted access for limited access profiles. P.S: This is my specific case for using unit of work in trigger handlers that extended fflib_SObjectDomain aka domain layer for triggers Jul 20 at 18:06

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .