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
Best Answer
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).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.