The Force.com Platform allows for multiple ways to access data and to control that access on different levels. The different ways you can access the Objects are:

1. Object Level
2. Record Level
3. Field Level

In this article I’m going to talk about Object and Field Level security and the different techniques you can use to work with them when creating custom code.

So what exactly is CRUD? CRUD stands for Create-Read-Update-Delete access. CRUD settings are applied at the profile level in Salesforce.com. To see an example, just go to Setup->Profiles and select a profile (in my case I used the default “Standard User” and cloned it, then named it “Sample CRUD”), and select the Object Settings. This brings up a List of all the Objects in your organization and the permissions for each one. If I select “Accounts” I will be present with the Object Permissions and the Field Permissions.

CRUD - Figure 1.PNG

I can edit or change the permissions for this user by clicking on the “Edit” button.

CRUD - Figure 2.PNG

For my Custom Sample CRUD profile I can change the Object access by turning on or off the Read, Create, Edit, and Delete. On the same screen you’ll see Field Level Security (FLS) for every field in the Object. I can turn the access off for each individual field as well.

CRUD is automatically supported when the developer references an object (like the Account) and the objects fields directly in a VisualForce page. For example, if a user without FLS visibility to the Phone field of the Accounts object was to view the below page, phone numbers would be automatically removed from the table.


<apex:page standardcontroller="Account" recordsetVar="Acct" sidebar="false">

<apex:form >
   <apex:sectionHeader title="CRUD Example One" />
   <apex:pageBlock title="Accounts">
      <apex:pageBlockTable value="{!Acct}" var="item">
          <apex:column value="{!item.Name}"/>
          <apex:column value="{!item.BillingState}"/>
          <apex:column value="{!item.Phone}"/>
          <apex:column value="{!item.WebSite}"/>
      </apex:pageBlockTable>
   </apex:pageBlock>
</apex:form>
</apex:page>

The same thing will happen in VisualForce if you are rendering an Edit page for an object. For example if we have a custom VisualForce edit page for Account and the user does not have access to the Phone Number it will not appear in the edit form. Along that same line, apex:inputField tags will be rendered as read-only elements for fields that are set to read-only through FLS.

However using other input tags such as apex:inputText or apex:inputTextArea with SObject fields indicate to VisualForce that the fields should not be treated as SObject fields and prevent the platform to automatically enforcing FLS.

There are often cases where developers use VisualForce pages to display data derived from an Object field in an indirect or processed form. For instance, a page controller may use internal logic to determine the appropriate value to display. A simple example of this would be a page that displays a random Contact Name from a list of Contacts:


<apex:page controller="RandomContactController">
   <apex:outputText value="{!getRandomName}" />
</apex:page>

public with sharing class RandomContactController 
{
    public String getGetRandomName() 
    {
        // Check if the user has read access on the Contact.Name field
        if (!Schema.sObjectType.Contact.fields.Name.isAccessible())
        {
          return '';
        }
         
        Contact [] myList = [SELECT Name FROM Contact LIMIT 1000];
        
        // Pick a list entry at random
        Integer index = Math.mod(Math.abs(Crypto.getRandomInteger()),myList.size());
        Contact selected = myList.get(index);
        return selected.Name;
    }
}


This example indirectly displays the Name field of the Contact object by using a custom get method that returns a string (the name) value. Because VisualForce only sees the return value as a string and not as an SObject field, CRUD and FLS is not automatically enforced and it is necessary to call the isAccessible() method on the appropriate Describe Field Result in order to manually check the user’s CRUD and FLS access. The isAccessible() method automatically checks that the user has the corresponding CRUD access to the object type.

By the same approach we now have a mechanism for checking all CRUD access on any Objects fields. First we need to find the SObject in question (say it’s the Contact) and then we need to check for priveledges. So for handling the Create option we can create a Utility Class (CRUD_Checker) which can check the status of any field on any Object.



public Class CRUD_Checker
{
    public Boolean IsUpdateAllowed(String obj, String fld)
    {
	Boolean bResult = true;

	// First get the Object		
	SObjectType objType = Schema.getGlobalDescribe().get(obj);
	Map m = objType.getDescribe().fields.getMap();

        // Check if the user has create access on the each field
        if (!m.get(fld.toLowerCase()).getDescribe().isUpdateable()) 
        {
   	    system.debug('Insufficient access for field : ' + fld + ' in ' + obj);  
   	    bResult = false; 			
        }
		
	return(bResult);
    }

    public Boolean IsCreateAllowed(String obj, String fld)
    {
	Boolean bResult = true;

	// First get the Object		
	SObjectType objType = Schema.getGlobalDescribe().get(obj);
	Map m = objType.getDescribe().fields.getMap();

        // Check if the user has create access on the each field
        if (!m.get(fld.toLowerCase()).getDescribe().isCreateable()) 
        {
   	    system.debug('Insufficient access for field : ' + fld + ' in ' + obj);  
   	    bResult = false; 			
        }
		
	return(bResult);
    }
}


Finally we look at the case of Delete. You do not have applications that delete fields (generally speaking). That’s a method applied to the Object record. Which means the CRUD access is at the Object (Table) level as opposed to the field level. So for handling our Delete we check against the CRUD utility for delete permissions.


public Boolean IsDeleteAllowed(String obj)
{
    Boolean bResult = true;
    
    // First get the Object     
    SObjectType objType = Schema.getGlobalDescribe().get(obj);
    if(! objType.getDescribe().isDeletable())
    	bResult = false;
        
    return(bResult);	
}

NOTE : If you are using controller extensions and intend to delete the active record, another option is to call the standard controller’s delete() function instead of deleting the object within the controller extension. The standard controller will automatically check CRUD access before performing the operation.

So there you have it, the basics of handling CRUD in your Apex and Visual Force classes.

[contact-form]
Filed under: Salesforce.com Programming