Visualforce Security - El Toro - Find articles about Visualforce, Apex, Force.com and Salesforce in general

Print Preview

Visualforce Security

As you already know, Salesforce uses a security based on three things:

  • CRED: Permissions on the object to Read, Cread, Edit and Delete records
  • FLS: Permissions on the object to Read/Write fields.
  • Record Access: Permissions on the record to Read/Write records (defined in OWD, Sharing, Role Hierarchy, ...)
Standard behavior (Page Layouts), Visualforce, and the API respect all these settings, but you have to be careful when working with Apex, because it will assume full CRED, FLS and possibly Record Access. You may be thinking about defining classes using the With Sharing keywords, but remember that it only controls Record Access (see my other article titled "Dynamic Apex to check CRUD and FLS")

But what about a Visualforce page that has an Apex controller (Custom Controller or Controller Extension), does it work as Visualforce or does it work as Apex with regards to security? Very good question, I am glad you asked!! It depends on how the data is accessed.

Let's take a look at this Visualforce and Apex code

<apex:page standardController="Contact" extensions="validateSecurity">
    <apex:pageblock >
        <apex:pageBlockSection columns="1" >
            <apex:pageBlockSectionItem >
                <apex:outputLabel >Contact.Phone</apex:outputLabel>
                <apex:outputText value="{!Contact.Phone}" />
            </apex:pageBlockSectionItem>
            <apex:pageBlockSectionItem >
                <apex:outputLabel >cVF.Phone</apex:outputLabel>
                <apex:outputText value="{!cVF.Phone}" />
            </apex:pageBlockSectionItem>
            <apex:pageBlockSectionItem >
                <apex:outputLabel >cApex.Phone</apex:outputLabel>
                <apex:outputText value="{!cApex.Phone}" />
            </apex:pageBlockSectionItem>
            <apex:pageBlockSectionItem >
                <apex:outputLabel >priority</apex:outputLabel>
                <apex:outputText value="{!Phone}" />
            </apex:pageBlockSectionItem>
        </apex:pageBlockSection>
    </apex:pageblock>
</apex:page>

This is the Apex code

public with sharing class validateSecurity {
    public Contact cVF { get; set; }
    public String Phone { get; set; }
    public Contact cApex { get; set; }
 
    public validateSecurity(ApexPages.StandardController controller) {
        String id = controller.getID();
        cVF = (Contact) controller.getRecord();
        
        cApex = [SELECT ID, Phone FROM Contact WHERE ID = :id];
        Phone = cApex.Phone;
    }
}

A user who has CRUD on Contacts, FLS on Phone and Record Access on a contact record, will see this screen when the page is accessed:

If we remove FLS for the Phone Field (but keep CRUD and Record Access), the user will see this screen:

Whenever Visualforce fetches the values ({!Contact.Phone}, {!cVF.Phone} or {!cApex.Priority__c}) the field is not shown, but if the field is fetched by Apex {!Phone} then the user will see the value because Apex, which runs on user mode, is accessing the database.

If we remove CRUD or Record Access, then the user will get an error message (Data Not Available) when displayng this page. But if we change the Visualforce code to this:

<apex:page standardController="Contact" extensions="validateSecurity">
    <apex:pageblock >
        <apex:pageBlockSection columns="1" >
            <apex:pageBlockSectionItem >
                <apex:outputLabel >cApex.Phone</apex:outputLabel>
                <apex:outputText value="{!cApex.Phone}" />
            </apex:pageBlockSectionItem>
            <apex:pageBlockSectionItem >
                <apex:outputLabel >Phone</apex:outputLabel>
                <apex:outputText value="{!Phone}" />
            </apex:pageBlockSectionItem>
        </apex:pageBlockSection>
    </apex:pageblock>
</apex:page>

And the controller to this:

public class validateSecurity {
    public String Phone { get; set; }
    public Contact cApex { get; set; }
 
    public validateSecurity(ApexPages.StandardController controller) {
        String id = controller.getID();
        
        cApex = [SELECT ID, Phone FROM Contact WHERE ID = :id];
        Phone = cApex.Phone;
    }
}

Then the user who does have no CRUD, no FLS  and no Record Access, then the user will see this:

So far, we have seen how FLS and CRUD works, but what about record access. Does it follow User Security or System Security? That's also a great question... thanks again for asking. Let's take a look at the new Visualforce page...

<apex:page standardController="Contact" extensions="validateSecurity">
    <apex:pageblock >
        <apex:pageBlockSection columns="1" >
            <apex:pageBlockSectionItem >
                <apex:outputLabel >cApex.Phone</apex:outputLabel>
                <apex:outputText value="{!cApex.Phone}" />
            </apex:pageBlockSectionItem>
            <apex:pageBlockSectionItem >
                <apex:outputLabel >Phone</apex:outputLabel>
                <apex:outputText value="{!Phone}" />
            </apex:pageBlockSectionItem>
            <apex:pageBlockTable value="{!cApex.Cases}" var="Case" >
                <apex:column value="{!Case.CaseNumber}"/>
            </apex:pageBlockTable>
        </apex:pageBlockSection>
    </apex:pageblock>
</apex:page>

And the updated Apex controller extension looks like this:

public with sharing class validateSecurity {
    public String Phone { get; set; }
    public Contact cApex { get; set; }
    
    public validateSecurity(ApexPages.StandardController controller) {
        String id = controller.getID();
        
        cApex = [SELECT ID, Phone, (SELECT ID, CaseNumber FROM Cases) FROM Contact WHERE ID = :id];
        Phone = cApex.Phone;
    }
}

Here the records will be shown or protected based on the With(out) Sharing settings of the Apex controller.

So in conclusion: If you pass a reference to the object and Visualforce fetches the field values, then the FLS and the CRUD will be protected (running on User Mode), and the record access will follow Apex With(out) Sharing settings.

Be very careful when making strings in Apex that concatenate fields that should be hidden to users.

comments powered by Disqus

© El Toro . IT @ 2013
Andrés Pérez