ApexSensei

Drills › Ship it safely

Build a secure Account service

Ship it safely · Advanced · 25 min · Runs in your Salesforce Developer org · Apex Path

Scenario. A reusable service must not rely on system-mode defaults when it reads or prepares Account data.

Deploy a with-sharing Account service that blocks users without access and strips fields they cannot create.

What you will learn

Saved Apex runs in system mode and ignores user access unless you check. with sharing applies record sharing. WITH USER_MODE makes a query respect user access.

if (!Account.SObjectType.getDescribe().isAccessible()) {
    throw new AccessDeniedException('…');
}
SObjectAccessDecision d = Security.stripInaccessible(
    AccessType.CREATABLE, candidates
);

Cast each record in d.getRecords() to Account.

Gotcha. stripInaccessible never removes Id — clear it on copies.

The task

Finish the Account service so reads respect the user's access and create copies lose fields the user can't set.

Examples:

  • two Account Ids → their names, sorted: Secure Alpha, Secure Zeta
  • a user with no Account access calls readableNames → AccessDeniedException
  • a queried Account passed to sanitizeForCreate → a copy with no SystemModstamp and a null Id

Requirements:

  1. Keep with sharing. Return an empty list for null or empty input, with no query.
  2. Throw AccessDeniedException when Account or its Name field is not readable. Otherwise query the Ids WITH USER_MODE, sorted by Name.
  3. Throw AccessDeniedException when Account is not creatable.
  4. Use Security.stripInaccessible(AccessType.CREATABLE, ...), clear Id on the returned copies, and leave the caller's records unchanged.
  5. The checks also run your class with System.runAs as a user who can read but not create Accounts, and as a user with no Account access.

Starter code

public with sharing class AS_AD7A552FF932_SecureAccountService {
    public class AccessDeniedException extends Exception {}

    public static List<String> readableNames(Set<Id> accountIds) {
        return new List<String>();
    }

    public static List<Account> sanitizeForCreate(List<Account> candidates) {
        if (candidates == null) {
            return new List<Account>();
        }
        return candidates;
    }
}

When it passes

The saved class uses with sharing, reads in user mode, blocks users without access, strips SystemModstamp and clears Id on copies, and leaves the original records alone.

Try this drill free

You write the Apex yourself. ApexSensei runs it and tells you what passed and what did not.

‹ Gate a release with test evidence