Order of Execution in Salesforce

  • Loads the original record from DB.
  • Loads the new record field values and overwrite the old values.
  • If you are using Standard UI, system validation rules will be execute.
  • Executes all before triggers.
  • Executes all user defined validation rules.
  • Saves the record to the database, but does not commit yet.
  • Executes all After trigger.
  • Executes Assignment Rules.
  • Executes Auto-Response Rules.
  • Executes Workflow Rules.
  • If there are any workflow updates, update the record again.
  • If the record was updated with workflow field updates, fires before update triggers and after update triggers one more time, in addition to standard validations. Custom validation rules and duplicate rules are not run again.
  • Executes Processes.
  • Executes Escalation Rules.
  • Executes Entitlement Rules.
  • If the record contains a roll-up summary field or is part of a cross-object workflow, performs calculations and updates the roll-up summary field in the parent record.
  • If the parent record is updated, and a grandparent record contains a roll-up summary field or is part of a cross-object workflow, performs calculations and updates the roll-up summary field in the grandparent record.
  • Executes Criteria Based Sharing evaluation.
  • Commits all DML operations.
  • Executes post-commit logic, like sending emails.
Order of Execution in Salesforce

Order of Execution in Salesforce

Global Variables In Salesforce

We use global variables to reference general information about the current user and your organization on a page. Global variables must be referenced using Visualforce expression syntax to be evaluated, for example, {!$User.FirstName}.

  • $Action
    A global merge field type to use when referencing standard Salesforce actions such as displaying the Accounts tab home page, creating new accounts, editing accounts, and deleting accounts.
  • $Api
    A global merge field type to use when referencing API URLs.
  • $Asset
    A global merge field to use when referencing images and other assets that are part of the Lightning Design System.
  • $Cache.Org
    A global merge field to access an org cache from a Visualforce page. Retrieve cached values from a specified partition’s org cache in the referenced org.
  • $Cache.Session
    A global merge field to access an org’s session cache from a Visualforce page. Retrieve cached values from a specified partition’s session cache in the referenced org.
  • $Component
    A global merge field type to use when referencing a Visualforce component.
  • $ComponentLabel
    A global merge field to use when referencing the label of an inputField component on a Visualforce page that is associated with a message.
  • $CurrentPage
    A global merge field type to use when referencing the current Visualforce page or page request.
  • $FieldSet
    Provides access to a field set defined in your organization.
  • $Label
    A global merge field type to use when referencing a custom label.
  • $Label.Site
    A global merge field type to use when referencing a standard Sites label in a Visualforce page. Like all standard labels, the text will display based on the user’s language and locale.
  • $Network
    A global merge field type to use when referencing community details in a Visualforce email template.
  • $ObjectType
    A global merge field type to use when referencing standard or custom objects (such as Accounts, Cases, or Opportunities) and the values of their fields.
  • $Organization
    A global merge field type to use when referencing information about your company profile. Use organization merge fields to reference your organization’s city, fax, ID, or other details.
  • $Page
    A global merge field type to use when referencing a Visualforce page.
  • $Permission
    A global merge field type to use when referencing information about the current user’s custom permission access. Use permission merge fields to reference information about the user’s current access to any of your organization’s custom permissions.
  • $Profile
    A global merge field type to use when referencing information about the current user’s profile. Use profile merge fields to reference information about the user’s profile such as license type or name.
  • $Resource
    A global merge field type to use when referencing an existing static resource by name in a Visualforce page. You can also use resource merge fields in URLFOR functions to reference a particular file in a static resource archive.
  • $SControl
    A global merge field type to use when referencing an existing custom s-control by name. This merge field type results in a URL to a page where the s-control executes.
  • $Setup
    A global merge field type to use when referencing a custom setting of type “hierarchy.”
  • $Site
    A global merge field type to use when referencing information about the current Force.com site.
  • $System.OriginDateTime
    A global merge field that represents the literal value of 1900-01-01 00:00:00.
  • $User
    A global merge field type to use when referencing information about the current user. User merge fields can reference information about the user such as alias, title, and ID. Most of the fields available on the User standard object are also available on $User.
  • $User.UITheme and $User.UIThemeDisplayed
    These global merge fields identify the Salesforce look and feel a user sees on a given Web page.
  • $UserRole
    A global merge field type to use when referencing information about the current user’s role. Role merge fields can reference information such as role name, description, and ID.

Salesforce Single Sign-On Implementation

What is Single Sign-On?
Single Sign-On is a process that allows network users to access all authorized network resources without having to separately log in to each resource. Single Sign-On also enables your organization to integrate with an external identity management system or perform web-based single sign-on to Force.com. Single Sign-On enables multiple types of authentication integration, but the most common are:

  • Use an existing directory of user names and passwords, such as Active Directory or LDAP, for Salesforce users.
  • Allow seamless sign-on to Force.com applications, eliminating the need for explicit user log on actions

Advantage of Single Sign-On
Single Sign-On produces benefits in three main areas – reduction in administrative costs, increased ease of use and better implementation of security schemes.

  • Reduced Administrative Costs: With Single Sign-On, all user authentication information resides in a central directory, which reduces the need to maintain, monitor and potentially synchronized multiple stores, as well as reducing user support requests around passwords.
  • Increased ease of use: Each user only has a single username and password which grants them access to corporate resources and Salesforce. Reduced complexity means an easier to use environment that provides seamless access to all resources. Single Sign-On also saves users time, since each individual sign-on process can take 5 to 20 seconds to complete. And removing the extra step of logging into Salesforce can increase user adoption of your Salesforce applications by lowering the barrier to use.
  • Increased Security: Any password policies that you have established for your corporate network will also be in effect for Salesforce. In addition, sending an authentication credential that is only valid for a single use can increase security for users who have access to sensitive data.

How Single Sign-On Works?
The high-level process for authenticating users via Single Sign-On is as follows:

  • When a user tries to log in—either online or using the API—Salesforce validates the username and checks the user’s profile settings.
  • If the user’s profile has the “Uses Single Sign-on” user permission, then Salesforce does not authenticate the username with the password. Instead, a Web Services call is made to the user’s single sign-on service, asking it to validate the username and password.
  • The Web Services call passes the username, password, and sourceIp to a Web Service defined for your organization. (sourceIp is the IP address that originated the login request). You must create and deploy an implementation of the Web Service that can be accessed by Salesforce.com servers.
  • Your implementation of the Web Service validates the passed information and returns either “true” or “false.”
  • If the response is “true,” then the login process continues, a new session is generated, and the user proceeds to the application. If “false” is returned, then the user is informed that his or her username and password combination was invalid.

Single Sign-On Configuration

Step 1:

  • From Setup, click “Security Controls | Single Sign-On Settings”, then click Federated Single Sign-On Using SAML Edit.
  • Select the SAML Enabled check box.

Step 2:

  • Click ‘New’ to fill out Single Sign On settings.
  • Use the following settings:
    1. Name: Put the name of SSO
    2. SAML Version: 2.0
    3. API Name: Will auto populate as per the Name field
    4. Issuer: (The issuer can be found in SSO form provided by External System team) Issuer is nothing but domain URL of Identity provider Org.
    5. Entity Id: It would be the URL of the target org.
    6. Identity Provider Certificate: Upload the Identity provider certificate from the Auth. Single Sign On server.
    7. Request Signing Certificate: Default Certificate
    8. Request Signature Method: RSA-SHA1
    9. SAML Identity Type: Select – Assertion contains the Federation ID from the User object.
    10. SAML Identity Location: Identity is in the NameIdentifier element of the Subject statement.
    11. Service Provider Initiated Request Binding: HTTP Redirect
    12. Identity Provider Login URL: (External system login page) Parameter of your application)
    13. Identity Provider Logout URL: (External system site logout page) Parameter of your application.

The input fields in the image should be entered as described in above.

SSO1

Step 3:

  • From Setup, click Domain Management | My Domain – Enter a new subdomain name, and click Check Availability. If the name is available, click the Terms and Conditions check box, then click Register Domain.

SSO2

Step 4:

  • Test App sign on option should be visible on the login page of the target org. So, we need to enable it in Authentication configuration. From Setup, click Domain Management | My Domain | Edit – Authentication Configuration | Enable Test App. After enable it we can see the Test App link in Salesforce Login page. Click it and once Test App portal shows up, login using Test App Credentials.

SSO3

Step 5:

  • To tie External System to SFDC User account, the system admin needs to know the unique id associated with External System ID that gets passed by SAML assertion. As of now, only way to get this is via reading SAML assertion as noted above and this can cause a bad user experience. The best way to approach this issue is via creating new SFDC user account whenever a use wants to setup sync between his or her External System ID and SFDC account. On the context of on-boarding, this means that the user would need to get External System ID first prior to getting SFDC account. Once the user creates External System ID, the user can use login using External System ID feature to create a new SFDC account. If the user go through this route, the federation ID field of newly created user will be auto-populated with the entity from SAML message that is specified in SAML single sign on setting. SFDC provides such option under SAML Single Sign-On Settings. It can be found at the bottom of the page.

SSO4

  • To automate sync the External System user to Salesforce we need to write an apex class. And that class must be executed by a user, which user has the permission to create/edit of users.

Sample JIT Handler Class

//This class provides logic for inbound just-in-time provisioning of single sign-on users in your Salesforce organization.
global class SSOUserHandler implements Auth.SamlJitHandler {
    private class JitException extends Exception{}
    
    private void handleUser(boolean create, User u, Map<String, String> attributes,
        String federationIdentifier, boolean isStandard) {
        
        if(create && attributes.containsKey('User.Username')) {
            u.Username = attributes.get('User.Username');
        }
        if(create) {
            if(attributes.containsKey('User.FederationIdentifier')) {
                u.FederationIdentifier = attributes.get('User.FederationIdentifier');
            } else {
                u.FederationIdentifier = federationIdentifier;
            }
        }
        if(attributes.containsKey('User.ProfileId')) {
            String profileId = attributes.get('User.ProfileId');
            Profile p = [SELECT Id FROM Profile WHERE Id=:profileId];
            u.ProfileId = p.Id;
        }
        if(attributes.containsKey('User.UserRoleId')) {
            String userRole = attributes.get('User.UserRoleId');
            UserRole r = [SELECT Id FROM UserRole WHERE Id=:userRole];
            u.UserRoleId = r.Id;
        }
        if(attributes.containsKey('User.Phone')) {
            u.Phone = attributes.get('User.Phone');
        }
        if(attributes.containsKey('User.Email')) {
          u.Email = attributes.get('User.Email');            
        }
        if(attributes.containsKey('User.FirstName')) {
            u.FirstName = attributes.get('User.FirstName');
        }
        if(attributes.containsKey('FirstName')) {
            u.FirstName = attributes.get('FirstName');
        }
        if(attributes.containsKey('User.LastName')) {
            u.LastName = attributes.get('User.LastName');
        }
        if(attributes.containsKey('User.Title')) {
            u.Title = attributes.get('User.Title');
        }
        if(attributes.containsKey('User.CompanyName')) {
            u.CompanyName = attributes.get('User.CompanyName');
        }
        if(attributes.containsKey('User.AboutMe')) {
            u.AboutMe = attributes.get('User.AboutMe');
        }
        if(attributes.containsKey('User.Street')) {
            u.Street = attributes.get('User.Street');
        }
        if(attributes.containsKey('User.State')) {
            u.State = attributes.get('User.State');
        }
        if(attributes.containsKey('User.City')) {
            u.City = attributes.get('User.City');
        }
        if(attributes.containsKey('User.Zip')) {
            u.PostalCode = attributes.get('User.Zip');
        }
        if(attributes.containsKey('User.Country')) {
            u.Country = attributes.get('User.Country');
        }
        if(attributes.containsKey('User.CallCenter')) {
            u.CallCenterId = attributes.get('User.CallCenter');
        }
        if(attributes.containsKey('User.Manager')) {
            u.ManagerId = attributes.get('User.Manager');
        }
        if(attributes.containsKey('User.MobilePhone')) {
            u.MobilePhone = attributes.get('User.MobilePhone');
        }
        if(attributes.containsKey('User.DelegatedApproverId')) {
            u.DelegatedApproverId = attributes.get('User.DelegatedApproverId');
        }
        if(attributes.containsKey('User.Department')) {
            u.Department = attributes.get('User.Department');
        }
        if(attributes.containsKey('User.Division')) {
            u.Division = attributes.get('User.Division');
        }
        if(attributes.containsKey('User.EmployeeNumber')) {
            u.EmployeeNumber = attributes.get('User.EmployeeNumber');
        }
        if(attributes.containsKey('User.Extension')) {
            u.Extension = attributes.get('User.Extension');
        }
        if(attributes.containsKey('User.Fax')) {
            u.Fax = attributes.get('User.Fax');
        }
        if(attributes.containsKey('User.CommunityNickname')) {
            u.CommunityNickname = attributes.get('User.CommunityNickname');
        }
        if(attributes.containsKey('User.IsActive')) {
            String IsActiveVal = attributes.get('User.IsActive');
            u.IsActive = '1'.equals(IsActiveVal) || Boolean.valueOf(IsActiveVal);
        }
        if(attributes.containsKey('User.ReceivesAdminInfoEmails')) {
            String ReceivesAdminInfoEmailsVal = attributes.get('User.ReceivesAdminInfoEmails');
            u.ReceivesAdminInfoEmails = '1'.equals(ReceivesAdminInfoEmailsVal) || Boolean.valueOf(ReceivesAdminInfoEmailsVal);
        }
        if(attributes.containsKey('User.ReceivesInfoEmails')) {
            String ReceivesInfoEmailsVal = attributes.get('User.ReceivesInfoEmails');
            u.ReceivesInfoEmails = '1'.equals(ReceivesInfoEmailsVal) || Boolean.valueOf(ReceivesInfoEmailsVal);
        }
        if(attributes.containsKey('User.ForecastEnabled')) {
            String ForecastEnabledVal = attributes.get('User.ForecastEnabled');
            u.ForecastEnabled = '1'.equals(ForecastEnabledVal) || Boolean.valueOf(ForecastEnabledVal);
        }
        String uid = UserInfo.getUserId();
        User currentUser = 
            [SELECT LocaleSidKey, LanguageLocaleKey, TimeZoneSidKey, EmailEncodingKey FROM User WHERE Id=:uid];
        if(attributes.containsKey('User.LocaleSidKey')) {
            u.LocaleSidKey = attributes.get('User.LocaleSidKey');
        } else if(create) {
            u.LocaleSidKey = currentUser.LocaleSidKey;
        }
        if(attributes.containsKey('User.LanguageLocaleKey')) {
            u.LanguageLocaleKey = attributes.get('User.LanguageLocaleKey');
        } else if(create) {
            u.LanguageLocaleKey = currentUser.LanguageLocaleKey;
        }
        if(attributes.containsKey('User.Alias')) {
            u.Alias = attributes.get('User.Alias');
        } else if(create) {
            String alias = '';
            if(u.FirstName == null) {
                alias = u.LastName;
            } else {
                alias = u.FirstName.charAt(0) + u.LastName;
            }
            if(alias.length() > 5) {
                alias = alias.substring(0, 5);
            }
            u.Alias = alias;
        }
        if(attributes.containsKey('User.TimeZoneSidKey')) {
            u.TimeZoneSidKey = attributes.get('User.TimeZoneSidKey');
        } else if(create) {
            u.TimeZoneSidKey = currentUser.TimeZoneSidKey;
        }
        if(attributes.containsKey('User.EmailEncodingKey')) {
            u.EmailEncodingKey = attributes.get('User.EmailEncodingKey');
        } else if(create) {
            u.EmailEncodingKey = currentUser.EmailEncodingKey;
        }
		
		if(!create) {
            update(u);
        }
        else{
            Insert u;
        }
    }
    
    private void handleJit(boolean create, User u, Id samlSsoProviderId, Id communityId, Id portalId, String federationIdentifier, Map<String, String> attributes, String assertion) {
        handleUser(create, u, attributes, federationIdentifier);
    }
    
    global User createUser(Id samlSsoProviderId, Id communityId, Id portalId,
        String federationIdentifier, Map<String, String> attributes, String assertion) {
        User u = new User();
        handleJit(true, u, samlSsoProviderId, communityId, portalId, federationIdentifier, attributes, assertion);
        return u;
    }

    global void updateUser(Id userId, Id samlSsoProviderId, Id communityId, Id portalId,
        String federationIdentifier, Map<String, String> attributes, String assertion) {
        User u = [SELECT Id, FirstName, ContactId FROM User WHERE Id=:userId];
		handleJit(false, u, samlSsoProviderId, communityId, portalId, federationIdentifier, attributes, assertion);
    }
}

Sample SOAP Message
As part of the Single Sign-On process, a Salesforce.com server makes a SOAP 1.1 request to authenticate the user who is passing in the credentials. Below is an example of this type of request. Your Single Sign-On service needs to accept this request, process it, and return a “true” or “false” response.

Sample Request

<?xml version="1.0" encoding="UTF-8" ?> 
<soapenv:Envelope 
xmlns:soapenv="<a rel="nofollow" class="external free" href="http://schemas.xmlsoap.org/soap/envelope/">http://schemas.xmlsoap.org/soap/envelope/</a>"> 
 <soapenv:Body> 
   <Authenticate xmlns="urn:authentication.soap.sforce.com"> 
     <username>testuser@testorg.com</username>  
     <password>test12345</password>  
     <sourceIp>1.2.3.4</sourceIp>  
   </Authenticate> 
 </soapenv:Body> 
</soapenv:Envelope> 

Sample Response Message

<?xml version="1.0" encoding="UTF-8"?> 
<soapenv:Envelope 
xmlns:soapenv="<a rel="nofollow" class="external free" href="http://schemas.xmlsoap.org/soap/envelope/">http://schemas.xmlsoap.org/soap/envelope/</a>"> 
<soapenv:Body> 
 <AuthenticateResponse 
xmlns="urn:authentication.soap.sforce.com"> 
  <Authenticated>true</Authenticated> 
 </AuthenticateResponse> 
</soapenv:Body> 
</soapenv:Envelope>

Sample SAML Assertion for Just-In-Time Provisioning

<saml:AttributeStatement>

   <saml:Attribute Name="User.Username" 
      NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
      <saml:AttributeValue xsi:type="xs:anyType">testuser@testorg.com
      </saml:AttributeValue>
   </saml:Attribute>

   <saml:Attribute Name="User.Phone" 
      NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
      <saml:AttributeValue xsi:type="xs:anyType">123-456-7890
      </saml:AttributeValue>
   </saml:Attribute>

   <saml:Attribute Name="User.FirstName"
      NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
      <saml:AttributeValue xsi:type="xs:anyType">Biswajeet
      </saml:AttributeValue>
   </saml:Attribute>

   <saml:Attribute Name="User.LanguageLocaleKey"
      NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
      <saml:AttributeValue xsi:type="xs:anyType">en_US
      </saml:AttributeValue>
   </saml:Attribute>

   <saml:Attribute Name="User.CompanyName"
      NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
      <saml:AttributeValue xsi:type="xs:anyType">ABC 
      </saml:AttributeValue>
   </saml:Attribute>

   <saml:Attribute Name="User.Alias"
      NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
      <saml:AttributeValue xsi:type="xs:anyType">Kunal
      </saml:AttributeValue>
   </saml:Attribute>

   <saml:Attribute Name="User.CommunityNickname"
      NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
      <saml:AttributeValue xsi:type="xs:anyType">Kunal
      </saml:AttributeValue>
   </saml:Attribute>

   <saml:Attribute Name="User.UserRoleId"
      NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
      <saml:AttributeValue xsi:type="xs:anyType">000000000000000
      </saml:AttributeValue>
   </saml:Attribute>

   <saml:Attribute Name="User.Title"
      NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
      <saml:AttributeValue xsi:type="xs:anyType">Mr.
      </saml:AttributeValue>
   </saml:Attribute>

   <saml:Attribute Name="User.LocaleSidKey"
      NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
      <saml:AttributeValue xsi:type="xs:anyType">en_CA
      </saml:AttributeValue>
   </saml:Attribute>

   <saml:Attribute Name="User.Email"
      NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
      <saml:AttributeValue xsi:type="xs:anyType">testuser@testorg.com
      </saml:AttributeValue>
   </saml:Attribute>

   <saml:Attribute Name=" User.FederationIdentifier"
      NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
      <saml:AttributeValue xsi:type="xs:anyType">123542
      </saml:AttributeValue>
   </saml:Attribute>

   <saml:Attribute Name="User.TimeZoneSidKey"
      NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
      <saml:AttributeValue xsi:type="xs:anyType">America/Los_Angeles
      </saml:AttributeValue>
   </saml:Attribute>

   <saml:Attribute Name="User.LastName"
      NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
      <saml:AttributeValue xsi:type="xs:anyType">Samal
      </saml:AttributeValue>
   </saml:Attribute>

   <saml:Attribute Name="User.ProfileId"
      NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
      <saml:AttributeValue xsi:type="xs:anyType">00ex0000001pDNP
      </saml:AttributeValue>
   </saml:Attribute>

   <saml:Attribute Name="User.IsActive"
      NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
      <saml:AttributeValue xsi:type="xs:anyType">1
      </saml:AttributeValue>
   </saml:Attribute>

   <saml:Attribute Name="User.EmailEncodingKey"
      NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
      <saml:AttributeValue xsi:type="xs:anyType">UTF-8
      </saml:AttributeValue>
   </saml:Attribute>

</saml:AttributeStatement>

How to add a list of records to a map in Salesforce?

Normally we used to do something like this:

Map<Id,Contact> mapContact =  new Map<Id,Contact>();
public static void addListToMap(List<Contact> conList){
	for(Contact con:conList){
		mapContact.put(con.id,con);
	}
}

Here the processing time will be more(CPU execution time will be more), because we are iterating over a for loop to construct a map.

The best way to construct the map where we can avoid iteration like this:

public static void addListToMap(List<Contact> conList){
	Map<Id,Contact> mapContact =  new Map<Id,Contact>(conList);
}

Here the processing time will be very less.