4

I've added the WITH SECURITY_ENFORCED clause to my SOQL queries. I'm testing them with a user who has a permission set that grants all object permissions (read, create, etc.), and also has read and edit rights to all fields. I'm getting the System.QueryException: Insufficient permissions: secure query included inaccessible field error. The user in question is a community user, so I've given External Users Public read access to the object as well. I'm stumped on what could be causing this issue. How do I troubleshoot, to understand what the clause is complaining about?

UPDATE:

I'm trying out the SObjectAccessDecision test recommended below. For both of the objects included in my query, the results returned by the securityDecision are null.

SObjectAccessDecision securityDecision = 
            Security.stripInaccessible(AccessType.READABLE,
                 [SELECT Id, Name
                    , Logo_Height__c
                    , Logo_Width__c
                    , Logo_URL__c
                    , Import_Font__c
                    , Font_Family__c
                    , Storefront__c
                    , Custom_CSS__c
                    , CC_Account_Group__c
                    , For_Anonymous_Users__c
                    , Use_Header_Logo_in_Footer__c
                    , Footer_Logo_Height__c
                    , Footer_Logo_URL__c
                    , Footer_Logo_Width__c
                    , Header_Logo_Display_Preference__c
                    , Favicon_Url__c
                    , Override_Logo_Size_Unit__c
                    , Footer_Override_Logo_Size_Unit__c
                    , (
                    SELECT Id, Name, Background_Color__c, Text_Color__c, Text_Decoration__c, Text_Font_Weight__c, Link_State__c, Type__c, Text_Size__c, Border__c FROM Quick_Theme_Elements__r
                    WHERE Active__c = TRUE
            )
            FROM Quick_Theme__c
            WHERE Active__c = TRUE
            AND CC_Account_Group__c = :accountGroupId
            AND Storefront__c = :storefront
            //WITH SECURITY_ENFORCED 
            ORDER BY LastModifiedDate DESC]
                 );

            // Get the removed field names - these are the fields they don't have read access to.
            System.debug(securityDecision.getRemovedFields().get('Quick_Theme__c')); // put sobject here
            System.debug(securityDecision.getRemovedFields().get('Quick_Theme_Element__c')); // put sobject here
1

I'd recommend using the stripInaccessible method to figure out exactly what field isn't accessible.

Change your query to not use WITH SECURITY ENFORCED and pass the query into the stripInaccessible method. You will get a SObjectAccessDecision that contains the removed field names. (code below mostly taken from documentation).

Security.SObjectAccessDecision securityDecision = 
         Security.stripInaccessible(AccessType.READABLE,
                 [SELECT Name, BudgetedCost, ActualCost FROM Campaign];
                 );

// Get the removed field names - these are the fields they don't have read access to.
System.debug(securityDecision.getRemovedFields().get('Campaign')); // put sobject here

Edit: In Summer 20 notes, there's a mention that you can use stripInaccessible method to enforce field and object-level security for relationship fields. This seems to imply it didn't work before on relationships (or perhaps was unpredictable) which may explain why it might not have worked for you.

enter image description here

| improve this answer | |
  • I tried this, and I get null back for both of the objects used in the query. I've updated my answer to show the SOQL I'm using. – Michael Sobczak May 1 at 16:54
  • That's interesting. Is the class API 48? I'd also suggest just looping through the results of .getRecords() to confirm you're seeing the object with all its fields. – Kris Goncalves May 1 at 18:30
  • System.debug('records: ' + securityDecision.getRecords()); does show the parent record being returned, but not the children. Maybe that's the issue, since I'm doing a related query? – Michael Sobczak May 4 at 18:12
  • The documentation specifically mentions it should strip the fields that are inaccessible from the query and subquery so it should work. I'm wondering if it's something special with it being a community user. What happens if you split your subquery into a single query just for debugging purposes (Quick_Theme_Elements__c)? Do you get info on any that are inaccessible? – Kris Goncalves May 4 at 19:22
  • 1
    I finally got back to this. I added code that checked the security for the related (or child) records separately. That works fine. No fields were removed. So, I'm guessing WITH SECURITY_ENFORCED does not work with sub-queries. – Michael Sobczak May 11 at 15:38

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.