Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Apex: Object and Field Security Made Easy

Apex: Object and Field Security Made Easy

Chris Peterson

May 29, 2019
Tweet

More Decks by Chris Peterson

Other Decks in Programming

Transcript

  1. Apex Security
    Object and Field Security Made Easy
    @TedLF
    Ted Freeman, Lead Software Engineer
    @ca_peterson
    Chris Peterson, Director of Product Management

    View Slide

  2. Forward-Looking Statement
    This presentation may contain forward-looking statements that involve risks, uncertainties, and assumptions. If any such uncertainties materialize or if any of the
    assumptions proves incorrect, the results of salesforce.com, inc. could differ materially from the results expressed or implied by the forward-looking statements
    we make. All statements other than statements of historical fact could be deemed forward-looking, including any projections of product or service availability,
    subscriber growth, earnings, revenues, or other financial items and any statements regarding strategies or plans of management for future operations,
    statements of belief, any statements concerning new, planned, or upgraded services or technology developments and customer contracts or use of our services.
    The risks and uncertainties referred to above include – but are not limited to – risks associated with developing and delivering new functionality for our service,
    new products and services, our new business model, our past operating losses, possible fluctuations in our operating results and rate of growth, interruptions or
    delays in our Web hosting, breach of our security measures, the outcome of any litigation, risks associated with completed and any possible mergers and
    acquisitions, the immature market in which we operate, our relatively limited operating history, our ability to expand, retain, and motivate our employees and
    manage our growth, new releases of our service and successful customer deployment, our limited history reselling non-salesforce.com products, and utilization
    and selling to larger enterprise customers. Further information on potential factors that could affect the financial results of salesforce.com, inc. is included in our
    annual report on Form 10-K for the most recent fiscal year and in our quarterly report on Form 10-Q for the most recent fiscal quarter. These documents and
    others containing important disclosures are available on the SEC Filings section of the Investor Information section of our Web site.
    Any unreleased services or features referenced in this or other presentations, press releases or public statements are not currently available and may not be
    delivered on time or at all. Customers who purchase our services should make the purchase decisions based upon features that are currently available.
    Salesforce.com, inc. assumes no obligation and does not intend to update these forward-looking statements.
    Statement under the Private Securities Litigation Reform Act of 1995

    View Slide

  3. Current State of Field Level Security in Apex
    Returning a simple query
    return [SELECT Name, Owner.Name FROM Account];

    View Slide

  4. Current State of Field Level Security in Apex
    Becomes a complex, error prone task
    if (Schema.SObjectType.Account.isAccessible() &&
    Schema.SObjectType.Account.fields.Name.isAccessible() &&
    Schema.SObjectType.Account.fields.OwnerId.isAccessible() &&
    Schema.SObjectType.Account.fields.OwnerId.getReferenceTo()[0].getDescribe().isAccessible()) {
    return [SELECT Name, Owner.Name FROM Account];
    } else {
    throw new AuraHandledException('Access Denied');
    }

    View Slide

  5. Current State of Field Level Security in Apex
    Returning a slightly less simple query
    return [SELECT Name, Account.Owner FROM Account WITH SECURITY_ENFORCED];
    Pros:
    ● Fully automated FLS and CRUD checks on the query
    ● Dead simple
    Cons:
    ● Can't gracefully degrade
    ● Doesn't cover DML
    ● No good tools for sanitizing SObjects from untrusted sources
    ● Beta (GA planned for Winter '20)
    ○ Not blessed for Security Review until GA

    View Slide

  6. Introducing The Security.stripInaccessible() Method
    SObjectAccessDecision Security.stripInaccessible(
    AccessType accessCheckType,
    List sourceRecords,
    [Boolean enforceRootObjectCRUD])
    AccessType Enum DescribeFieldResult method
    AccessType.READABLE isAccessible()
    AccessType.CREATABLE isCreatable()
    AccessType.UPDATABLE isUpdateable()
    Open Pilot!
    Summer '19

    View Slide

  7. The SObjectAccessDecision Object
    Contains results of stripInaccessble
    Methods
    • global List getRecords()
    A clone of the input records with inaccessible fields removed
    • global Set getModifiedIndexes()
    All indexes of the input list that had fields stripped
    • global Map getRemovedFields()
    Contains details on all the fields that were removed from one or more records.
    Nested collection so that cross-object relationship fields can also be included

    View Slide

  8. Example Use Cases
    1. Removing Fields Prior to DML
    2. Removing Fields for Presentation
    3. Removing Fields from a Heterogeneous List
    4. Live Demo: Stopping injection in LWC

    View Slide

  9. Example 1 - Removing Fields Prior to DML
    List accounts = new List{
    new Account(Name='Account1', AnnualRevenue=1000),
    new Account(Name='Account2')
    };
    // Strip fields that are not creatable
    SObjectAccessDecision decision = Security.stripInaccessible(
    AccessType.CREATABLE,
    accounts);
    User does not have permission to create Annual Revenue

    View Slide

  10. // Safe insert - does not create AnnualRevenue
    insert decision.getRecords();
    // Print results
    for (SObject strippedAccount : decision.getRecords()) {
    System.debug('Inserted account: ' + strippedAccount);
    }
    System.debug('Modified records: ' + decision.getModifiedIndexes());
    System.debug('Removed fields: ' + decision.getRemovedFields());
    Debuggable feedback on what was changed
    Example 1 - Removing Fields Prior to DML

    View Slide

  11. Execution Log: Details
    Inserted account: Account:{Name=Account1, Id=00130000001nFfpIAE}
    Inserted account: Account:{Name=Account2, Id=00130000001nFfqIAE}
    Modified records: {0}
    Removed fields: {Account={AnnualRevenue}}
    User does not have permission to create Annual Revenue
    Example 1 - Removing Fields Prior to DML

    View Slide

  12. Example 2 - Removing Fields for Presentation
    User does not have permission to read Social Security Number
    Id Name Amount Business Unit User
    a0030000000iZbYIAU Expense_Report1 1000 Marketing 00530000000HgGwIAK
    a0030000000iZbZIAU Expense_Report2 4000 Sales 00530000000HgGxIAK
    Id Social Security
    00530000000HgGwIAK 555-44-3333
    00530000000HgGxIAK 777-88-9999
    Expense Report Table
    User Table

    View Slide

  13. Example 2 - Removing Fields for Presentation
    // Strip fields that are not readable
    SObjectAccessDecision decision = Security.stripInaccessible(
    AccessType.READABLE,
    [SELECT Name, Amount__c, Business_Unit__c, User__r.Social_Security__c
    FROM Expense_Report__c]
    );
    User does not have permission to read Social Security Number

    View Slide

  14. Example 2 - Removing Fields for Presentation
    // Print results - does not display Social Number
    for (SObject obj : decision.getRecords()) {
    Expense_Report__c rpt = (Expense_Report__c)obj;
    System.debug('Expense Report: ' + rpt);
    User usr = (User)rpt.getSobject('User__r');
    System.debug('User: ' + usr);
    }
    System.debug('Modified records: ' + decision.getModifiedIndexes());
    System.debug('Removed fields: ' + decision.getRemovedFields());
    User does not have permission to read Social Security Number

    View Slide

  15. Example 2 - Removing Fields for Presentation
    User does not have permission to read Social Security Number
    Execution Log: Details
    Expense Report: Expense_Report__c:{Name=Expense_Report1, Amount__c=1000,
    Business_Unit__c=Marketing, User__c=00530000000HgGwIAK, Id=a0030000000iZbYIAU}
    User:{Id=00530000000HgGwIAK}
    Expense Report: Expense_Report__c:{Name=Expense_Report2, Amount__c=4000,
    Business_Unit__c=Sales, User__c=00530000000HgGxIAK, Id=a0030000000iZbZIAU}
    User:{Id=00530000000HgGxIAK}
    Modified records: {0, 1}
    Removed fields: {User={Social_Security__c}}

    View Slide

  16. Example 3 - Removing Fields from a Heterogeneous List
    List project = new List{
    new Account(Name='Account1', Flag1__c=1),
    new Opportunity(Name='Opportunity1')
    };
    SObjectAccessDecision decision = Security.stripInaccessible(
    AccessType.UPDATABLE,
    project);
    The sourceRecords argument can contain different types of SObjects

    View Slide

  17. Example 3 - Removing Fields from a Heterogeneous List
    // Verify stripped records
    for (SObject strippedRecord : decision.getRecords()) {
    switch on strippedRecord {
    when Account a {
    System.assertEquals(true, a.isSet('Name'));
    System.assertEquals(false, a.isSet('Flag1__c'));
    }
    when Opportunity o {
    System.assertEquals(true, o.isSet('Name'));
    }
    }
    }
    The sourceRecords argument can contain different types of SObjects

    View Slide

  18. LWC Demo

    View Slide

  19. We want your feedback!
    The only reason it's a pilot is so we can change things.
    https://sfdc.co/stripinacessible-feedback
    @ca_peterson
    or

    View Slide

  20. View Slide