0

If I am creating a new Contact record in apex, will the following code be sufficient for FLS/CRUD requirements in a security review, or will I need to check .isCreateable() for each field individually before setting them as well.

Contact con = new Contact();
con.FirstName = 'Joe';
con.LastName = 'Smith';
con.Phone = '01234 56789';
con.Email = '[email protected]';

if (Schema.sObjectType.Contact.isCreateable()) {
    insert con;
}

1 Answer 1

4

In a word: yes.

You should decide if you can categorise the fields as essential or optional (based on both how the field is set as required at the database level, and your app's logic needs) and then ensure that you either throw an exception when an essential field cannot be set, or ensure that optional fields are omitted from the insert.

E.g. (and I'm not suggesting you use this approach), you could laboriously do:

if (!SObjectType.Contact.isCreateable()) {
    throw new SomeException('need to be able to create contact message');
} else if (SObjectType.Contact.fields.LastName.isCreateable()) {
    throw new SomeException('need to be able to set LastName message');
}

Contact con = new Contact(LastName = 'Smith');

if (SObjectType.Contact.fields.FirstName.isCreateable()) {
    con.FirstName = 'Joe';
}

if (SObjectType.Contact.fields.Phone.isCreateable()) {
    con.Phone = '01234 56789';
}

if (SObjectType.Contact.fields.Email.isCreateable()) {
    con.Email = '[email protected]';
}

insert con;

In this example, only LastName is deemed "essential".

There are other ways to deal with this, such as via the use of Security.stripInaccessible.

In that case you can reduce your code to something more like:

if (!SObjectType.Contact.isCreateable()) {
    throw new SomeException('need to be able to create contact message');
} else if (SObjectType.Contact.fields.LastName.isCreateable()) {
    throw new SomeException('need to be able to set LastName message');
}

Contact con = new Contact(FirstName = 'Joe',
                          LastName = 'Smith',
                          Phone = '01234 56789',
                          Email = '[email protected]');

SObjectAccessDecision securityDecision = Security.stripInaccessible(AccessType.CREATABLE, new Contact[] { con });
con = securityDecision.getRecords()[0];

insert con;

Taking @sfdcfox's comment on user mode into consideration, we can re-write the above to be even shorter:

Contact con = new Contact(FirstName = 'Joe',
                          LastName = 'Smith',
                          Phone = '01234 56789',
                          Email = '[email protected]');

SObjectAccessDecision securityDecision = Security.stripInaccessible(AccessType.CREATABLE, new Contact[] { con });
con = securityDecision.getRecords()[0];

insert as user con;

In this case, since the insert is done "as user", all CRUD/FLS permissions will be enforced. Thus, if the user doesn't have create permission for Contact, or for LastName, then we'll get a DML exception raised.

2
  • 4
    Don't forget about user mode. These methods will also pass a security review.
    – sfdcfox
    Sep 1, 2023 at 11:21
  • 1
    @sfdcfox I didn't mention user mode because that currently doesn't allow for "optional" fields in the way that stripInaccessible does. But I guess it would deal with the removal of the first two checks/throwing exceptions...
    – Phil W
    Sep 1, 2023 at 11:48

You must log in to answer this question.

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