Friday, June 26, 2020

Salesforce Apex: Tips and Tricks

Generate a set of Ids from a List of SObject
List<Account> accounts = [SELECT Id, Name FROM Account];
Set<Id> selectedIds = new Map<Id, SObject>(accounts).keySet();
System.debug(selectedIds);

Division of 2 numbers
public static Decimal divide(Integer numerator, Integer denominator) {
    Decimal result;
    if (denominator != 0) {
        result = Decimal.valueOf(Double.valueOf(numerator) / Double.valueOf(denominator));
        return result.setScale(2);
    }
    return 0;
}


Formatting time in Apex
https://paulforce.wordpress.com/2009/08/27/formatting-time-in-apex/
Share This:    Facebook Twitter

Sunday, March 8, 2020

Monday, February 17, 2020

Accepting third Party Identity in Salesforce

Single Sign-On (SSO)

A process that allows the network to access all authorized networks without having to separately log in to each resource - one password fits all.
  • Federated Authentication: uses SAML and industry standards protocols. It is the default form of single sign-on. When enabled:
    • Salesforce doesn't validate the user's password
    • The platform receives an assertion in an HTTP POST
  • Delegated Authentication: a Salesforce-specific technology. When enabled:
    • Salesforce will make a Web service call to an external client to validate credentials. The web service must be SOAP and accessible over the internet.
NOTE:
  • While setting up SSO, you need to set up My Domain to allow redirection of users to an identity provider and allow access to Salesforce through deep links.
  • When you have an external identity provider and configure SSO for your Salesforce org, Salesforce is then acting as a service provider. You can also enable Salesforce as an identity provider and use SSO to connect to a different service provider. Only the service provider needs to configure SSO.

SAML

  • An OASIS standard for single sign-on
  • Security Assertion Markup Language (XML-based)
  • Designed to exchange authorization and authentication data
  • Trust is established during SAML configuration
    • The IdP's public key certificate is stored on the service provider's system
    • The IdP includes its public key certificate with the service provider in its assertions while making those HTTP POST requests.
    • The service provider uses the certificate to validate that the digital signature originated from the IdP, thereby validating the integrity of assertion.
  • Assertions can be encrypted optionally.

SAML Components

In a SAML SSO scenario, there are 3 key parties involved:
  1. A user or principal, who requires access to a resource (like Salesforce), which is provided by the Service Provider.  
  2. The Identity provider authenticates the user on behalf of the service provider. The Identity Provider is typically an Identity Management platform such as Ping Federate or Active Directory Federation Services (ADFS) and issues a SAML assertion token which is consumed by the service provider to authenticate the user.
  3. Service Provider – the website containing the resources the user wants to access. Eg Salesforce if federated identity used
So whatever authenticates you, that is the identity provider, while the service provider is whatever you are trying to get to. To understand the difference in layman's terms, check out this post.

Types of SAML Flow

  1. IdP Initiated: IdP sends an unsolicited SAML assertion to Salesforce
  2. SP Initiated: Starts with Salesforce, which solicits a SAML assertion from the IdP



SP Initiated Flow is the recommended Salesforce best practice.
  • Has the best user experience
  • Is required for using SSO with Salesforce mobile and desktop applications
  • Supports deep links
Check this video to see how to implement SSO in Salesforce: https://www.youtube.com/watch?v=ucmyYJ3iQoA

Delegated Authentication



  • Enable delegated authentication for a specific organization by contacting salesforce.com support
  • Download the AuthenticationService WSDL
    • Generate server-side stub and add specific implementation details
  • Specify SSO gateway
  • Modify profiles (specify which profiles will be enabled)
  • User credentials are encrypted and passed from Salesforce to DAS
NOTE: Do not enable SSO for the System Administrator profile. If the identity provider is unavailable, administrators will not be able to access the org.

Considerations
  • Activated at the profile level
  • Requires a proxy server that Salesforce can access
    • More cost for infrastructure and maintenance
  • Requires a valid certificate if an SSL or HTTPS connection is used with the authentication service

Which method to use?

  • User ID/password when basic configuration is required
  • SAML to provide single sign-on for the Web and applications
  • Delegated authentication with older infrastructures
  • OAuth when building an API client or mobile application

SAML with Multiple ORGs & Considerations

  • Adding additional orgs to single sign-on with SAML is just configuration
  • Many possible topologies are available:
    • Single enterprise identity provider, multiple service provider orgs
    • One org as identity provider, others as service provider
  • Check this link for more information: "Configure SSO Across Multiple Salesforce Orgs"

External Authentication Providers

  • External Authentication Providers allow ‘Social Sign-on’ using OAuth 2.0 and can be used to provision accounts, thereby letting your users log in to your Salesforce org using their login credentials from a third-party service.
  • Salesforce provides external authentication providers for apps that support the OpenID Connect protocol, such as Apple, Facebook, Google, Facebook, LinkedIn, and Twitter.
  • For apps that don’t support the OpenID Connect protocol but support OAuth or other authentication protocols, Salesforce provides an Apex Auth.AuthProviderPluginClass abstract class. With this class, you can create a custom authentication provider. This repo demonstrates the use of a Salesforce Custom External Authentication.
  • Salesforce can also be used as an authorisation provider for other orgs

To set up an external authentication provider,
  • Set up the Authorization Provider (e.g. Facebook)
  • Create an Apex Registration Handler class. Check this link for sample code.
  • Define the Authentication Provider in the Org
  • Add the button (e.g. Facebook) to the Login Page

EXAMPLE: How to set up Google as an external authentication provider?

  • Create an OAuth Client ID of type of web application in Google.
  • Set up an authorization provider like below, and provide the consumer key and secret.
  • Update the redirect URI in the OAuth client ID with the callback URL generated after creating the auth provider.
  • Add the Google sign-in button by updating the Authentication Configuration in My Domain.

Just-in-Time Provisioning for SAML

  • With Just-in-Time provisioning, you can use a SAML assertion to create regular and portal users on the fly the first time they try to log in. This eliminates the need to create user accounts in advance. 
  • For example, if you recently added an employee to your organization, you don't need to manually create the user in Salesforce. When they log in with single sign-on, their account is automatically created for them, eliminating the time and effort with on-boarding the account. 
  • Just-in-Time provisioning works with your SAML identity provider to pass the correct user information to Salesforce in a SAML 2.0 assertion. You can both create and modify accounts this way. 
  • Because Just-in-Time provisioning uses SAML to communicate, your organization must have SAML-based single sign-on enabled.
  • JIT provisioning uses attributes in the SAML assertion to create and update user records in Salesforce.
  • The SAML assertion must provide (at least):
    • Email
    • LastName
    • UserName
    • ProfileId - 15 character ID or profile name
  • It can also include any other optional attributes, such as
    • FirstName
    • Phone
    • Manager

Troubleshooting SAML

  • In Salesforce, from Setup, enter Single Sign-On Settings in the Quick Find box, then select Single Sign-On Settings.
  • Click SAML Assertion Validator. The SAML Validator shows the last recorded SAML login failure with some details as to why it failed.
  • To test the SAML assertion from the Axiom app, copy the Formatted SAML Response from the Axiom app.
  • In the Salesforce SAML Validator, paste the SAML assertion in the SAML Response box at the bottom of the page.
  • Click Validate. The page displays some results to help you troubleshoot the assertion. For example, if the assertion was generated a while before it was used to log in, the timestamp expires and the login isn’t valid. In that case, regenerate the SAML assertion and try again.
Share This:    Facebook Twitter

Thursday, February 6, 2020

Salesforce Platform Events

Platform events are part of Salesforce’s enterprise messaging platform, providing an event-driven messaging architecture to enable apps to communicate inside and outside of Salesforce. An event-driven (or message-driven) software architecture consists of event producers, event consumers, and channels. The architecture is suitable for large distributed systems because it decouples event producers from event consumers, thereby simplifying the communication model in connected systems. One or more subscribers can listen to the same event and carry out actions.

Systems in request-response communication models make a request to a web service or database to obtain information about a certain state. The sender of the request establishes a connection to the service and depends on the availability of the service. Also, the external system pushing data into Salesforce is dependent on the completion of the transaction, i.e. if data is being pushed into an sobject and if there are triggers running on the data being pushed, then the external system must wait until all the business logic in the trigger completes its execution. 
In comparison, systems in an event-based model obtain information and can react to it in near real-time when the event occurs. Event producers don’t know the consumers that receive the events. Any number of consumers can receive and react to the same events. Both parties are also not dependent on each other.
The only dependency between producers and consumers is the semantic of the message content.

A platform event is a special kind of Salesforce entity, similar in many ways to an sObject. But
  1. Unlike custom or standard objects, you can’t update or delete event records. All platform event fields are read-only by default.
  2. You can set read and create permissions for platform events. Grant permissions to users in profiles or in permission sets. 
  3. You can’t restrict access to a particular field. Field-level security permissions don’t apply and the event message contains all fields.
  4. Because event publishing is equivalent to a DML insert operation, DML limits and other Apex governor limits apply.

Publish Immediately vs Publish After Commit

Platform event messages are published either immediately or after a transaction is committed, depending on the publish behavior you set in the platform event definition.
  1. Publish Immediately: The event message is published when the publish call executes. Select this option if you want the event message to be published regardless of whether the transaction succeeds. Also choose this option if the publisher and subscribers are independent, and subscribers don't rely on data committed by the publisher. For example, the immediate publishing behavior is suitable for an event used for logging purposes. With this option, a subscriber might receive the event message before data is committed by the publisher transaction. The allOrNone header is ignored when publishing through the APIs. Some events can be published even when others fail in the same call.
  2. Publish After Commit: The event message is published only after a transaction commits successfully. Select this option if subscribers rely on data that the publishing transaction commits. For example, a process publishes an event message and creates a task record. A second process that is subscribed to the event is fired and expects to find the task record. Another reason for choosing this behavior is when you don't want the event message to be published if the transaction fails. The allOrNone header value takes effect. If allOrNone is set to true, no events are published if at least one event fails in the same call.

High-Volume Platform Events

In API version 45.0 and later, your new custom event definitions are high volume by default. High-volume platform events offer better scalability than standard-volume platform events.
High-volume platform events are published asynchronously. After the publishing call returns with a successful result, the publish request is queued in Salesforce. The event message might not be published immediately.
High-volume platform event messages are stored for 72 hours. You can retrieve past event messages when using CometD clients to subscribe to a channel.
To know about high-volume platform event default allocations, check the documentation.

Publishing Platform Events

  • To publish event messages with Process Builder, add a Create a Record action to the appropriate process. Where you'd usually pick an object to create, select the custom platform event.

  • To publish event messages with flows, add a Create Records element to the appropriate flow. Where you'd usually pick an object to create, select the custom platform event.

  • To publish event messages with Apex, call the EventBus.publish method. Each EventBus.publish method call is considered a DML statement, and DML limits apply. The below code is taken from the documentation to show how to publish platform events with Apex.
    List<Low_Ink__e> inkEvents = new List<Low_Ink__e>(); 
    inkEvents.add(new Low_Ink__e(Printer_Model__c='XZO-5', Serial_Number__c='12345', Ink_Percentage__c=0.2)); 
    List<Database.SaveResult> results = EventBus.publish(inkEvents); 
    for (Database.SaveResult sr : results) { 
        if (sr.isSuccess()) { 
            System.debug('Successfully published event.'); 
        } else { 
            for(Database.Error err : sr.getErrors()) { 
                System.debug('Error returned: ' + err.getStatusCode() + ' - ' + err.getMessage()); 
            } 
        } 
    }

  • Publish events with Salesforce APIs such as SOAP API, REST API, or Bulk API. To publish a platform event message using REST API, send a POST request to the following endpoint: /services/data/v48.0/sobjects/Event_Name__e/

When publishing an event message, the result that the API returns contains information about whether the operation was successful and the errors encountered. If the success field is true, the event was published for a standard-volume event. For a high-volume event, the publish request is queued in Salesforce and the event message might not be published immediately. If the success field is false, the event publish operation resulted in errors, which are returned in the errors field.
The returned result also contains the Id system field. The Id field value is not included in the event message delivered to subscribers. It is not used to identify an event message, and is not always unique. Subscribers can use the ReplayId system field, which is included in the delivered message, to identify the position of the event in the stream.

Subscribing to Platform Events

  • Both processes and flows can subscribe to platform events and receive event messages published through Apex, APIs, flows, or other processes. Both of them provide an auto subscription mechanism.

  • To subscribe to event notifications with Apex Triggers, write an after insert trigger on the event object type. Only after insert triggers are supported for platform events because event notifications can’t be updated. They’re only inserted (published).
    trigger LowInkTrigger on Low_Ink__e (after insert) {    
        for (Low_Ink__e event : Trigger.New) {
         ...
         ...
        }
    }

    NOTE: In platform event triggers, if you create a Salesforce record that contains an ownerId field, set the ownerId field explicitly to the appropriate user. Platform event triggers run under the Automated Process entity. If you don’t set the ownerId field on records that contain this field, the system sets the default value of Automated Process.

  • Subscribe to platform events with the empApi component in your Lightning web component or Aura component.

  • Use CometD to subscribe to platform events in an external client. The process of subscribing to platform event notifications through CometD is similar to subscribing to PushTopics or generic events. The only difference is the channel name. The platform event channel name is case-sensitive and is in the following format: /event/Event_Name__e. Use this CometD endpoint with the API version appended to it: /cometd/48.0. You can refer the below code to subscribe to a platform event in a Node application.
  • const jsforce = require("jsforce");
    const dotenv = require("dotenv");
    const express = require("express");
    const session = require("express-session");
    
    dotenv.config({
        path: "./config/config.env"
    });
    
    const app = express();
    
    // Configure express-session to store Session Id and Instance URL
    app.use(
        session({ secret: "keyboard cat", resave: true, saveUninitialized: true })
    );
    
    const oauth2 = new jsforce.OAuth2({
        loginUrl: process.env.SF_LOGIN_URL,
        clientId: process.env.SF_CLIENT_ID,
        clientSecret: process.env.SF_CLIENT_SECRET,
        redirectUri: process.env.SF_REDIRECT_URI
    });
    
    app.get("/oauth2/auth", function(req, res) {
        res.redirect(
            oauth2.getAuthorizationUrl({ scope: "api id web refresh_token" })
        );
    });
    
    app.get("/oauth2/callback", function(req, res) {
        var conn = new jsforce.Connection({ oauth2: oauth2 });
        conn.authorize(req.query.code, function(err, userInfo) {
            if (err) {
                return console.error(err);
            }
            console.log(userInfo);
            console.log(conn.accessToken, conn.refreshToken, conn.instanceUrl);
    
            req.session.accessToken = conn.accessToken;
            req.session.instanceUrl = conn.instanceUrl;
    
            res.redirect("/");
        });
    });
    
    app.get("/", function(req, res) {
        if (!req.session.accessToken || !req.session.instanceUrl) {
            res.redirect("/oauth2/auth");
            return;
        }
        // Connect and output query results
        const conn = new jsforce.Connection({
            accessToken: req.session.accessToken,
            instanceUrl: req.session.instanceUrl
        });
        res.send(req.session.instanceUrl);
        subscribeToEvents(conn, res);
    });
    
    function subscribeToEvents(conn, res) {
        conn.streaming.topic("/event/DemoEvent__e").subscribe(function(message) {
            console.log(message);
        });
    }
    
    const PORT = process.env.PORT || 3000;
    
    app.listen(PORT, console.log(`Server running on ${PORT}`));

ReplayId System Field

Each event message is assigned an opaque ID contained in the ReplayId field. The ReplayId field value, which is populated by the system when the event is delivered to subscribers, refers to the position of the event in the event stream. Replay ID values are not guaranteed to be contiguous for consecutive events. A subscriber can store a replay ID value and use it on resubscription to retrieve events that are within the retention window.
You can replay platform events that were sent in the past 24 hours. You can replay platform events through the API (CometD) but not Apex. The process of replaying platform events is the same as for other Streaming API events. You can use workbench to replay the platform events.


Standard Platform Events

Salesforce provides events with predefined fields, called standard platform events. An example of a standard platform event is AssetTokenEvent, which monitors OAuth 2.0 authentication activity. Another example is BatchApexErrorEvent, which reports errors encountered in batch Apex jobs (check the code for force-brf - a batch retry framework, to understand how to handle such event). You can subscribe to a standard platform event stream using the subscription mechanism that the event supports. Check the documentation to go through all the standard platform events.

Limits

Check the documentation to learn about the allocations available for platform event definitions, publishing and subscribing to platform events, and event delivery in CometD clients. The below table provides information about the default allocation for the high-volume events.
Please note the following points:
  1. The maximum event message size that you can publish is 1 MB. If your event object has hundreds of custom fields or many long text area fields, you could hit this limit. In this case, the publishing call gets an error.
  2. Non-CometD clients, including Apex triggers, processes, and flows, don’t count against the event delivery limit.
  3. The empApi Lightning component is a CometD client. As a result, the event delivery allocation applies to the component and it is per channel per unique browser session.
  4. Platform events ARE quite capable when only used “on-platform”. Read this blog to understand in detail.

Some important StackExchange links

Other important links



Share This:    Facebook Twitter

Total Pageviews

My Social Profiles

View Sonal's profile on LinkedIn

Tags

__proto__ $Browser Access Grants Accessor properties Admin Ajax AllowsCallouts Apex Apex Map Apex Sharing AssignmentRuleHeader AsyncApexJob Asynchronous Auth Provider AWS Callbacks Connected app constructor Cookie CPU Time CSP Trusted Sites CSS Custom settings CustomLabels Data properties Database.Batchable Database.BatchableContext Database.query Describe Result Destructuring Dynamic Apex Dynamic SOQL Einstein Analytics enqueueJob Enterprise Territory Management Enumeration escapeSingleQuotes featured Flows geolocation getGlobalDescribe getOrgDefaults() getPicklistValues getRecordTypeId() getRecordTypeInfosByName() getURLParameters Google Maps Governor Limits hasOwnProperty() Heap Heap Size IIFE Immediately Invoked Function Expression Interview questions isCustom() Javascript Javascript Array jsForce Lightning Lightning Components Lightning Events lightning-record-edit-form lightning:combobox lightning:icon lightning:input lightning:select LockerService Lookup LWC Manual Sharing Map Modal Module Pattern Named Credentials NodeJS OAuth Object.freeze() Object.keys() Object.preventExtensions() Object.seal() Organization Wide Defaults Override PDF Reader Performance performance.now() Permission Sets Picklist Platform events Popup Postman Primitive Types Profiles Promise propertyIsEnumerable() prototype Query Selectivity Queueable Record types Reference Types Regex Regular Expressions Relationships Rest API Rest Operator Revealing Module Pattern Role Hierarchy Salesforce Salesforce Security Schema.DescribeFieldResult Schema.DescribeSObjectResult Schema.PicklistEntry Schema.SObjectField Schema.SObjectType Security Service Components Shadow DOM Sharing Sharing Rules Singleton Slots SOAP API SOAP Web Services SOQL SOQL injection Spread Operator Star Rating stripInaccessible svg svgIcon Synchronous this Token Triggers uiObjectInfoApi Upload Files VSCode Web Services XHR
Scroll To Top