13

I was watching an old Dev 501 video today (#4 Classes & Objects) in which the instructor said profile based sharing rules were only checked at the entry point where apex code begins it's execution. He said profile based sharing of any classes called beyond the entry point wasn't checked by SF to determine whether it should run.

The video is quite old and may no longer apply. SF was at API 15 at the time this was recorded. When I looked at the docs, it was unclear to me on whether sharing is checked following initial entry. Is the video correct or is sharing checked again and respected with each call that follows to another class?

Edit

Before posting this, some of the articles I looked at included Without Sharing: Best practices when bypassing Apex sharing rules and object security by Dan Appleman in which he says "CRUD and FLS security is largely part of the user interface infrastructure. Sharing is largely implemented in the database query system." He then goes on to discuss what he refers to as "A Matter of Intent".

One of the questions that had occurred to me was the situation where at the entry point, "without sharing" was specified, a query returned the data to be operated on and a subsequent class to process the data "with sharing" was called. Because of FLS, the user who initiated the transaction might have read only access to some of the fields, yet the 2nd class called might operate on the fields, then perform DML to commit them.

If sharing rules are propagated from the initial User who initiated the transaction, the DML would presumably fail. If they're not propagated, the DML would succeed. I'd like to understand which would be the case and whether it's because of the class's sharing being propagated in the one situation or the user's sharing in the other possible outcome.

Appleman's article didn't discuss propagation of Role based sharing as additional classes are called from the entry point or subsequent classes. It wasn't clear to me whether the calling class's sharing model would be what was respected by subsequent classes, the the User's sharing model who initiated the execution of Apex code or neither of them.

In a single class execution, the answer is clear, but its less obvious in other situations, especially when SOQL or DML isn't involved. For example, if the above mentioned user doesn't have FLS permissions to edit a particular field in Opportunity named myOppField__c, I wouldn't expect an Apex Class "with sharing" to prevent code from allowing opp.myOppField__c[i] = opp2[i+1].myOppField__c; from running.

Instead, what I'd hope to be able to expect, would be a problem when an attempt was made to commit the database changes via DML when the revised data was returned to a calling class defined "with sharing" from the subsequent class which had been defined "without sharing" that made the changes to the read only field (for that User).

You could say, that this suggests to me that permissions and security involve more than just DML and SOQL queries, but coding to take those permissions into account as well. I hope this helps clarify the nature of my question. I greatly appreciate the answers I've received thus far.

8

The "with sharing" and "without sharing" keywords deal with if sharing is enforced within the confines of that class. This affects DML statements and queries that are performed within the bounds of that class.

See my answer on this question for an explaination of how "with sharing" and "without sharing" affect queries and DML operations.

It does indeed apply every time you come into or out of a class. The current class' execution context is affected by "with sharing" or "without sharing."

Only the entry point determines if the user can run through the entire logic. For example, if a user has access to a Visualforce page, they do not need to have access to the page's extensions/controller classes. This may be what the instructor was attempting to explain when they stated that only the first entry point determines if access is granted to an execution context.


Edit:

First, FLS is never applied to Apex Code. You must manually choose to enforce FLS. This is true regardless of the current sharing mode. Conversely, universally required/unique indexes/etc are always enforced in Apex Code, regardless of the sharing model.

However, in regards to queries and DML, it is entirely possible to query records in a "without sharing" context, and pass those records to a "with sharing" context, in which case, the DML will fail if the user does not have read or edit access on the record in question. The difference is how sharing is enforced in the various contexts. For example, here's a trivial case:

// Without sharing util class
public without sharing class accountUtil {
    public static Account[] getAccounts() {
        return [SELECT Name, OwnerId, Industry FROM Account];
    }
}

// With sharing controller
public with sharing class accountEdit {
    public account[] accounts { get; set; }
    public accountEdit() {
        accounts = accountUtil.getAccounts();
    }
    public void save() {
        try {
            update accounts;
        } catch(Exception e) {
            ApexPages.addMessages(e);
        }
    }
}

<!-- trivial mass edit page -->
<apex:page controller="accountEdit">
    <apex:form>
        <apex:pageBlock>
            <apex:pageMessages />
            <apex:pageBlockButtons>
                <apex:commandButton action="{!save}" value="Save"/>
            </apex:pageBlockButtons>
            <apex:pageBlockTable value="{!accounts}" var="account">
                <apex:column>
                    <apex:inputField value="{!account.name}" />
                </apex:column>
                <apex:column>
                    <apex:inputField value="{!account.Industry}" />
                </apex:column>
            </apex:pageBlockTable>
        </apex:pageBlock>
    </apex:form>
</apex:page>

Given this code, an administrator would be able to edit every account in the system. However, if you turn sharing to private or read-only on accounts, and then log in as a normal user, they'll get "Insufficient privileges" error when this DML attempts to operate. Sharing is enforced at the moment the DML occurs, if done so in a "with sharing" context. You can try it out in a dev org to see what I'm demonstrating.

However, this only applies at the record level. Field level security is always compromised when using code, so if you intend to prevent an edit on a field, you need to check the field's access before you write to it. You can always see a user's field permissions using describes, even in a "without sharing" context (the context doesn't affect the describes a user would receive).

  • No, he was referring to code entering subsequent classes that might be called. – crmprogdev Apr 25 '15 at 22:34
  • Please see the update to my question. – crmprogdev Apr 28 '15 at 14:57
  • @crmprogdev See my edit. Does this help? – sfdcfox Apr 28 '15 at 16:03
  • Thank you. If permissions weren't propagated from class to class, some of these measures at times would be bypassed and I wanted to thoroughly understand the security implications of what could happen when "without sharing" classes are called in a sequence containing "with sharing" classes and vice versa. There's obviously more involved than just DML and SOQL that needs to be considered when reusing code. – crmprogdev Apr 28 '15 at 17:50
7

The way I understand it, is that you must specify with or without otherwise the class being called will respect the calling classes sharing. This blog post from around the same time period explains it well.

It's best practices to use these keywords with declaring new classes as if they are not used, the current sharing rules remain in effect. For example, if a class without sharing keywords specified is called by another class, then the sharing is enforced by the first class.

  • Please see the update to my question. – crmprogdev Apr 28 '15 at 14:57
-1

Yes, Sharing rules are checked at every point when a method or class is being called. Consider the below scenario.

public without sharing ClassA
    { 
    ClassB b = new ClassB();
    }

    public with sharing ClassB
    {
    //some code
    }

The constructor call of ClassB will fail if current user doesn't have sharing access to ClassB.

Check the last points in this Link.

  • No, the code won't fail. We're talking about two different things here: "with sharing" and "without sharing", and "security permissions on classes." ClassB doesn't need to have access granted to it when called from ClassA. The security permissions are only checked on the initial entry point, but "without sharing" and "with sharing" apply every time a class is entered. – sfdcfox Apr 25 '15 at 22:06
  • 1
    Oh Okay. I got the question wrong. I've read your answer. If ClassB had a SOQL query in the constructor, to fetch some restricted records, then the code would fail in the constructor. Thanks for correcting me! – Santanu Halder Apr 26 '15 at 11:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.