2

I had been under the impression that omitting a sharing declaration was equivalent to using "without sharing", but that appears to not always be true.

For example, if I have legacy code like this...

// No sharing declaration here
global class MyWebservice {
    webservice static List<Account> getAccount(String accountName) {
        return new List<Account>([SELECT Id FROM Account WHERE Name = :accountName]);
    }
    webservice static void updateAccount(Account acc) {
        update acc;
    }
}

... if I try to test in the following way, I get failures:

private class MyWebserviceTest {
    @TestSetup
    static void makeData() {
        insert new Account(Name = 'Test Account');
        TestUtil.insertPartnerUser();
    }

    @isTest
    static void testGetAccount() {
        User partner = TestUtil.getPartnerUser();
        System.runAs(partner) {
            List<Account> result = MyWebservice.getAccount('Test Account');
            // AssertException: expected 1, actual 0
            // The partner user doesn't have visibility to the Account, even
            // though we aren't explicitly using "with sharing"
            System.assertEquals(1, result.size()); 
        }
    }

    @isTest
    static void testUpdateAccount() {
        User partner = TestUtil.getPartnerUser();
        User systemAdmin = [
            SELECT Id FROM User 
            WHERE Profile.Name = 'System Administrator' 
            AND IsActive = TRUE
            LIMIT 1
        ];
        Account acc = MyWebservice.getAccount('Test Account')[0];
        acc.OwnerId = systemAdmin.Id;
        System.runAs(partner) {
            // INSUFFICIENT_ACCESS_ON_CROSS_REFERENCE_ENTITY
            // i.e. the partner doesn't have visibility to the system admin user
            // and isn't allowed to assign that user as the record owner
            MyWebservice.updateAccount(acc);
        }
    }
}

Adding "without sharing" at the top of the MyWebservice class resolves the failures. But I'm a little leery of making these types of changes because I don't have a comprehensive view of what additional access this grants.

What does adding "without sharing" to a class that previously had no sharing declaration do in terms of user-based restrictions, beyond the differences I've stumbled on above?

1 Answer 1

3

You're definitely incorrect. without sharing specifies that the code runs in System Mode, while omitting sharing entirely is "do whatever the calling method uses, or without sharing in some top-level contexts, or with sharing in other top-level contexts." I go in to more detail in SFDC: Understanding With Sharing, Without Sharing & Unspecified Sharing Classes.

The documentation isn't clear as to what happens in the case of System.runAs or even in the case of unit tests that don't specify a sharing model (though historically, it's been omitted frequently in such classes by most developers). The point is, if you don't specify a sharing mode, you get whatever the system feels like giving you, and it's nearly impossible to determine all the edge cases in this scenario.

If I recall correctly, webservice enabled methods and Chatter methods use an implied with sharing if no sharing mode is specified, although the documentation has apparently been updated to make it impossible to find that trivia. You have just managed to stumble across one of those situations where omitted sharing isn't the same as without sharing.

You should always specify inherited sharing, with sharing, or without sharing in order to avoid these edge cases. It is strongly recommended that you use inherited sharing if you're unsure about which mode you want to use, it will typically be the "right" one. If you specifically want to ignore sharing, you should specify without sharing.

2
  • I agree that new code should always specify the intended sharing behavior. Right now I'm dealing mostly with legacy code with inadequate unit tests, so there's a real risk of regression if I add these types of specifications without a complete understanding of how the code has been behaving to date. The fact that there may or may not be random behavior differences associated with webservice methods, System.runAs(), etc certainly doesn't improve my confidence level. I really wish there were better information available in this area. Commented Mar 24, 2021 at 15:51
  • @MatthewSouther Unfortunately, the only "real" way forward is to test each unit and/or consult any documentation, if any, and then fix the code as you go.
    – sfdcfox
    Commented Mar 24, 2021 at 16:22

You must log in to answer this question.

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