Language agnostic Salesforce Apex unit test

I was doing some work with packaging on Salesforce and used the dreamhouse-lwc repo as a foundation. When I was building package versions the Apex unit tests were failing as the SOQL queries is using WITH SECURITY_ENFORCED and the user running the queries did not have the right access. The solution was to update the unit test to create a user and assign the dreamhouse Permission Set but to create a user you need to set a Profile. Which one to pick? Easy – use the “Standard User” Profile which is easily accessible by SOQL:

SELECT Id FROM Profile WHERE Name='Standard User' LIMIT 1

This code failed however as the Profile couldn’t be found. It turned out to be because the scratch org created was in Danish so the Profile is called “Standard Bruger” instead. This could be solved by setting the language of the scratch org by using the language key in config/project-scratch-def.json but the repo maintainers didn’t want that. A more flexible and still language agnostic way was to query more intelligently for the Profile. The below SOQL query achieves the same result as above but without setting the org language.

SELECT Name, Id
FROM Profile
WHERE UserType = 'Standard' AND PermissionsPrivacyDataAccess = false AND PermissionsSubmitMacrosAllowed = true AND PermissionsMassInlineEdit = true LIMIT 1

Custom Salesforce Auth. Provider for Microsoft Azure client_credentials flow

When doing integrations from Salesforce you sometimes need to do this using single identity instead as in the context of the current user. Salesforce supports both through Named Credentials i.e. both working as the current user or as a Named Principal. Through the Named Credentials and Auth. Provider concepts from Salesforce you can setup a connection between Salesforce and an OAuth 2.0 enabled endpoint such as Microsoft Azure i.e. if needing the access the Microsoft Graph API. This can however be an issue as the target system (i.e. Microsoft Azure in this case) may not use a user that is able to login or you may not want to use a user license in the target system.

In this case you might want to use the client_credentials OAuth flow as that identifies the caller using a client_id and a client_secret instead of a user id. Unfortunately that OAuth flow type is not supported out-of-the-box with Salesforce. The reason is that the Auth. Providers in Salesforce usually deals with a user behind the keyboard. Due to this the OAuth 2.0 Auth. Provider flows was designed for a access_token / refresh_token World. This makes it impossible to use the built in capabilities for the client_credentials flow.

The solution is to write a custom Auth. Provider in Apex and use that from your Named Credential. To make this easier I’ve already implemented this for you. The code is available on Github in my salesforce-azure-clientcredentials-authprovider repo. This implementation just plays along with the access_token / refresh_token requirements and just requests a new access_token using the client_credentials flow whenever a (new) access_token is needed and hence do not need a user behind the keyboard.

The README.md in the repo has instructions for installing and configuring the code in the org. Once deployed you can create an Auth. Provider and a Named Credential. Please note you also need to create an App Registration in Azure Active Directory with the required Application Permissions.

Turning on trace debugging with the Salesforce CLI

When using the Salesforce CLI as the primary way to interact with a scratch org turning on Apex trace debugging can be a tiresome-I-have-to-click-into-the-org situation. Usually you are not able to use force:apex:log:list and force:apex:log:get commands to work with Apex logs without first opening the Web Developer in the org or setting up trace logging.

But it turns out there is a better way using a simple script.

The below script does the trick for you can easily be added to your process for creating new scratch orgs. The script sets up some timestamps and then queries for the scratch org user userId. Then we get the Id of the trace log configuration for the user and then updates the record to enable trace logging for 24 hours.

NOW=`date -u +"%Y-%m-%dT%H:%M:%SZ"`
EXP=`date -v+24H -u +"%Y-%m-%dT%H:%M:%SZ"`

USERID=`sfdx force:data:soql:query -q "select id,name from user where name='User User'" --json | jq ".result.records[0].Id" -r`

TRACEID=`sfdx force:data:soql:query --query "SELECT Id, DebugLevel.DeveloperName, ExpirationDate, TracedEntityId FROM Traceflag WHERE TracedEntityId IN (SELECT ID from USER WHERE ID = '${USERID}')" --usetoolingapi --json | jq ".result.records[0].Id" -r`

sfdx force:data:record:update --sobjecttype TraceFlag --sobjectid $TRACEID -v "StartDate=$NOW ExpirationDate=$EXP" --usetoolingapi --json --loglevel fatal

The above script uses jq (https://stedolan.github.io/jq/) for JSON parsing and works on Mac (date command switches is slightly different on Linux) so YMMV.

Generating JWT’s for Azure in Apex

Lately I’ve been playing around with Azure and integrating Salesforce and Azure. One of the integration patterns calls for using Json Web Tokens (JWT) that you can the exchange for an access token in Azure. There is a catch however…

Since Azure requires that the thumbprint of the certificate be added to the header of the JWT (using the key “x5t”) we cannot use the built in support for JWT in Named Credentials as there are no provisions for custom header key/values. The JTW/JWS classes in Apex cannot be used either as we cannot customize the header there either. Building upon https://github.com/salesforceidentity/jwt I’ve created https://github.com/lekkimworld/azurejwt-apex that bridges the gap.

This allows you to build and sign a JWT that you may exchange for an access token using your tenants OAuth token endpoint v.2 in Azure. Example Apex code is like this:

// declarations (because I'm old school)
final String azureClientId = '88d888a5-0cf4-473a-b9a0-7c88e6fc888e';
final String azureTenantId = 'b34feb2b-132f-4322-af1d-c888f5d888d0';
final String azureCertThumbprint = '4rElsDFTysrbKhB0zTsrRNSxT6s=';
final String azureScopes = '5384888d-868f-442b-b1b3-8688807de914/.default';

// create JWT with certificate from keys mgmt and set the x5t in the header to the 
// thumbprint of the cert as expected by Azure
AzureJWT jwt = new AzureJWT();
jwt.cert = 'JWT_Callout_Certificate';
jwt.iss = azureClientId;
jwt.sub = azureClientId;
jwt.aud = 'https://login.microsoftonline.com/' + azureTenantId + '/oauth2/v2.0/token';
jwt.x5t = azureCertThumbprint;

// invoke the flow and obtain an access_token
final String access_token = AzureJWTBearerFlow.getAccessToken(azureClientId, azureTenantId, azureScopes, jwt);

// use the access token against a Function App in Azure
HttpRequest req = new HttpRequest();
req.setEndpoint('https://foo-functions-demo.azurewebsites.net/api/MyFunction?name=Salesforce');
req.setMethod('GET');
req.setHeader('Authorization', 'Bearer ' + access_token);
Http http = new Http();
HTTPResponse res = http.send(req);
System.debug(res.getBody());

In the https://github.com/lekkimworld/azurejwt-apex Github repo you will find the two Apex classes from the above example together with the example code.

The certificate thumbprint (bold above) isn’t the regular SHA-1 thumbprint but is a special hexdump/base64 encoded edition. To make it even more interesting the thumbprint displayed in Azure Portal is not the thumbprint we need. The thumbprint/hash may be computed this like (gleaned from https://stackoverflow.com/a/52625165):

echo $(openssl x509 -in yourcert.pem -fingerprint -noout) | sed 's/SHA1 Fingerprint=//g' | sed 's/://g' | xxd -r -ps | base64

Using an Auth. Provider and Named Credentials in Salesforce with Azure OAuth

Please note: When I refer to “Azure” below I’m referring to Microsoft Azure, the cloud product from Microsoft.

Please note: If you know all about why Auth. Providers and Named Credentials are great and simply wanna know about how to use them with Microsoft Azure feel free to skip down to “How does it apply to Azure”.

All this started some time back when I was at a customer showing how to integrate with Salesforce and call other API’s from Salesforce. In Salesforce we have a great concept called Authentication Providers (“Auth. Provider”) that handles the underlying authentication protocol such as OAuth 2.0. Auth. Providers may be used to provide Single-Sign-On in Communities (our portals) or with Named Credentials. The latter is a way to externalize authentication from a piece of code or functionality. So if I need to call an external API from Apex (our Java-like programming language) I can simply do something like the code below:

HttpRequest req = new HttpRequest();
req.setEndpoint('callout:My_NamedCredential/accounts/list');
req.setMethod('GET');
Http http = new Http();
HTTPResponse res = http.send(req);
System.debug(res.getBody());

As you can see there is nothing here about authentication. Nor is there anything around the actual URL being called. That information is externalized into a Named Credential called My_NamedCredential in this case. The only part I specify is the specific path of the API I’m referring to (here “/accounts/list”). This is great for development as it makes it easier for me the developer but it’s also easier to admins moving changes between environments as the endpoint and credential management is externalized as setup for the org. It means it’s easy to change credentials and endpoints between development, test, QA and production. Awesome!

Setting this up is pretty easy as well and is done in 3 steps:

  1. Start by setting up the Auth. Provider by specifying your client_id (we call it the “Consumer Key”), the client_secret (we call it the “Consumer Secret”), the Authorization endpoint and the token endpoint. The last two you get from your provider – in this case Azure. For now with version 2 of their identity platform they will be https://login.microsoftonline.com/<tenant>/oauth2/v2.0/authorize and https://login.microsoftonline.com/<tenant>/oauth2/v2.0/token respectively (replace <tenant> with your tenant id).
  2. Now create a Named Credential specifying the root URL you would like to call against in the “URL” field. For “Identity Type” select “Named Principal” to use the same credentials across the org or “Per User” to use user specific credentials and set “Authentication Protocol” to “OAuth 2.0”. In “Authentication Provider” select the provider we created above set the scope to use.
  3. Now use the Named Credential as discussed above.

Now let’s discuss what’s special about Azure.

How does it apply to Azure?

Above I was intentionally pretty loose when discussing the scope to set in the Named Credentials. The reason is that this is quite specific when dealing with Azure.

In Azure an access token is actually a Json Web Token (JWT, https://jwt.io) which is a standardized token format containing signed claims that may be verified by the recipient. The payload in a JWT access token from Azure could look like this:

{
  "aud": "2dd1b05d-8b45-4aba-9181-c24a6f568955",
  "iss": "https://sts.windows.net/e84c365f-2f35-8c7d-01b4-c3412514f42b/",
  "iat": 1573811923,
  "nbf": 1573811923,
  "exp": 1573815823,
  "aio": "42VgYJj0Zt3RXQIblViYGkuiHs9dAQA=",
  "appid": "32c0ba71-04f4-4b3a-a317-1f1febd5fc22",
  "appidacr": "1",
  "idp": "https://sts.windows.net/e84c365f-2f35-8c7d-01b4-c3412514f42b/",
  "oid": "394e0c1a-0992-42e7-9875-3b04786147ca",
  "sub": "394e0c1a-0992-42e7-9875-3b04786147ca",
  "tid": "e84c365f-2f35-8c7d-01b4-c3412514f42b",
  "uti": "ESAOZDPFeEydSYxohgsRAA",
  "ver": "1.0"
}

Here the important piece is the “aud” claim as it contains the ID of the application or API on Azure the token is valid for. In this case it’s for an App Registration in Azure.

When we deal with OAuth providers we might be used to deal with standard OpenID Connect scopes like openid, email, profile and offline_access. For Azure which is much more of a generic platform the scope we specify is used to indicate what application we are requesting access to. In Azure the issued access token is specific to the application we request access to and we can only request access for a single application at a time which have some implications:

  1. If you request an access token for an application (App Registration in Azure) the access token is valid for that application only
  2. The access token is not valid for other API’s like the Microsoft Graph
  3. If you do not request an access token for a specific application Azure issues you an access token for the Microsoft Graph API

This may be obvious but it caused me quite some troubleshooting.

OAuth scopes in Azure

When you request an access token from Azure you must specify what API you intend to use it for. There are two versions of the OAuth endpoints (v1 and v2) – in version 1 you use a resource-parameter to indicate the target application to Azure. In version 2 this has been standardized and is now using the standard scope-parameter. It also means that scope is now not simply the OpenID Connect standard scopes (such as openid, offline_access) or the application specific scopes i.e. from Microsoft Graph but is also used to indicate the API you are requesting access to i.e. an App Registration.

Now to the fun, the stuff you just need to know and the stuff which is easy enough to find if you know what to Google for…

Specifying the URI of an App Registration is the scope is not enough. You have to add a scope to the Application URI and unless you’ve defined a custom scope for your app you should use “.default”. So if your App Registration has an URI of “api://2dd1b05d-8b45-4aba-9181-c24a6f568955” use “2dd1b05d-8b45-4aba-9181-c24a6f568955/.default” as the scope. If you’ve registed custom scopes for an application those may be used in place of .default but you cannot combine .default with more specific scopes. Also using specific scopes are also restricted in use for certain OAuth flows due to the way delegated permissions work in Azure. But that’s for another time.

Using the client_credentials grant type (works somewhat like the Salesforce username/password OAuth flow) this becomes a POST like the one below. Please note that the Azure tenant_id is both in the URL and a parameter in the POST body:

POST /f84c375f-3f35-4d9d-93b3-c4216511f87a/oauth2/v2.0/token HTTP/1.1
 Host: login.microsoftonline.com
 Content-Type: application/x-www-form-urlencoded
 Content-Length: XYZ
 Connection: close
client_id=32c0ba71-04a4-4b3a-a317-1b1febd5fc22
&client_secret=shhhhh...
&grant_type=client_credentials
&tenant=f84c375f-3f35-4d9d-93b3-c4216511f87a
&scope=2dd1b95d-8b45-4aba-9181-c24f6f5e8955/.default

The response is a JSON document with an access_token (a JWT which may then be used as a Bearer token):

{
   "token_type":"Bearer",
   "expires_in":3599,
   "ext_expires_in":3599,
   "access_token":"eyJ0eXAiOiJKV1QiLCJhbGciO..."
}

When using Azure with Salesforce I would recommend using version 2 of the OAuth endpoints as Salesforce Auth. Providers and Named Credentials do not have a way to send custom parameters without resorting to writing a custom Auth. Provider implementation. This means there is no standard way to send the “resource” parameter to the version 1 OAuth endpoint.

What scopes should I specify in Salesforce?

When you create your Auth. Provider or Named Credentials specify the scopes you need from Azure. My personal preference is to specify the scopes on the Auth. Provider when using it for Single-Sign-On and specifying the scopes on the Named Credentials when using it for API access. One thing to note again is that an access token is for one API only and that an access token for a custom application will not work for the Microsoft Graph as well.

Lesson learned: You should not specify the UserInfo endpoint on the Auth. Provider in Salesforce unless it’s used for Single-Sign-On AND you are not specifying an App Registration in the Scopes-field.

If you specify an “App Registration scope” in the Scopes-field and specify the UserInfo endpoint Salesforce will attempt to read from the UserInfo endpoint following successful authentication using the obtained access token which will fail because the access token is only valid for the intended API and not for the Microsoft Graph.

Feel free to add other standard OpenID Connect scopes for Auth. Providers for Single-Sign-On. For most uses you would want to specify the offline_access scope as it ensures your Auth. Provider or Named Credential receives a refresh token.

Calling API’s protected by Azure API Management (APIM)

So far so good. Now you can obtain access tokens and use them with Azure Function Apps or read from the Microsoft Graph. But what if you need to access API’s hosed in Azure API Management (APIM)? Well read on…

In Azure API Management API’s are governed by subscriptions and you need to specify a subscription ID when calling into the API. The subscriptions map into users which are different from the ones in Azure AD. I’m not really sure why this is the case but I’m sure there are reasons.

The subscription ID you should use would be supplied by the people managing the API and is a GUID like string. When you call the API be sure to supply it using the “Ocp-Apim-Subscription-Key”-header. Failing to supply the subscription ID will result in an error like the one below:

{"statusCode": 401,   
"message": "Access denied due to missing subscription key. Make sure to include subscription key when making requests to an API."}

Putting all the above together to POST to an API behind Azure API Management using Apex would be something like the below using a Named Credentials called “My_NamedCredential”:

HttpRequest req = new HttpRequest();
req.setEndpoint('callout:My_NamedCredential/echo
req.setMethod('POST');
req.setHeader('Ocp-Apim-Subscription-Key', '7f9ed...1d6e8');
req.setBody('Hello, Salesforce, World!');
Http http = new Http();
HTTPResponse res = http.send(req);
System.debug(res.getBody());

As always… YMMV!

Calling a Swagger service from Apex using openapi-generator

For a demo I needed to make calls to the Petstore API using a Swagger / OpenAPI definition from Apex. Unfortunately the Apex support that External Services in Salesforce provides is only callable from Flows so I needed another approach. Using openapi-generator and installing via Homebrew it went relatively smoothly anyway.

It’s always nice to stand on the shoulder of giants so the examples provided by Rene Winkelmeyer (Connecting to Swagger-backed APIs with Clicks or Code ) came in handy. Unfortunately didn’t work as the prefix for the generated classes was different plus the petId was was 1 and not 100. Anyway again easy to fix.

Below are my steps to get working using Homebrew and Salesforce DX.

$ brew install openapi-generator
$ openapi-generator generate \
-i https://raw.githubusercontent.com/openapitools/openapi-generator/master/modules/openapi-generator/src/test/resources/2_0/petstore.yaml \
-g apex \
-o /tmp/petstore_swagger/
$ cd /tmp/petstore_swagger
$ sfdx force:org:create \
-v my_devhub \
-f config/project-scratch-def.json -a petstore_swagger
$ sfdx force:source:push -u petstore_swagger
$ sfdx force:apex:execute -u petstore_swagger
>> Start typing Apex code. Press the Enter key after each line,
>> then press CTRL+D when finished.
OASClient client = new OASClient();
OASPetApi api = new OASPetApi(client);
Map<String,Object> params = new Map<String, Object>();
Long petId = Long.valueOf('1');
params.put('petId', petId);
OASPet pet = api.getPetById(params);
System.debug(pet);
<Ctrl-D>

Trying to explain Person Accounts in Salesforce

Person Accounts in Salesforce keeps confusing developers not at home on the platform due to their special behaviour. The purpose of the repo (https://github.com/lekkimworld/salesforce-personaccount-field-reference) is to hold some examples on how to work with Person Accounts in an org using Apex and the Bulk API to try and illustrate a few points.

What ARE PersonAccounts

First of knowing WHAT a Person Account is is important. In Salesforce we normally talk about Accounts and Contacts with the Account being the company entity (i.e. Salesforce.com Inc.) and the Contact being the people that we track for that company (i.e. Marc Benioff, Parker Harris etc.). It means that we have to have an Account and a Contact to track a person in Salesforce. But what if that doesn’t make any sense like when tracking individuals for B2C commerce or similar? Meet the PersonAccount.

Please Note: There is no such object as PersonAccount in Salesforce. There are only Account and Contact but in the following I’ll use PersonAccount to reference this special case for Account.

PersonAccount is a special kind of Account that is both an Account AND a Contact giving you the possibility to treat an individual using an Account. The secret to understanding PersonAccount is knowing that using a special record type and specifying it when you create the Account, Salesforce will automatically create both an Account AND a Contact record and automatically link them and thus create the PersonAccount. Salesforce automatically makes the fields that are normally available (including custom fields) on the Contact available on Account. Only thing you need to do is follow a few simple rules that are listed below.

Please Note: When using PersonAccounts you should always access the Account and never the associated Contact.

Referencing Fields

Because there is both an Account and a Contact for a PersonAccount there are some special rules to follow when referencing fields. This goes for any access whether that be using Apex, REST API and the Bulk API. The rules are pretty easy and are as follows:

  1. Always reference the Account object
  2. When creating a PersonAccount create an Account specifying the record type ID of the PersonAccount record type configured in Salesforce. Doing this makes the Account a PersonAccount.
  3. Fields from Account are available on Account (as probably expected):
    1. Standard fields from Account Referenced using their API name as usual (i.e. Site, Website, NumberOfEmployees)
    2. Custom fields from Account Referenced using their API name as usual (i.e. Revenue__c, MyIntegrationId__c)
  4. Fields from Contact are available directly on Account:
    1. Standard fields from Contact The API name of the field is prefixed with “Person” (i.e. Contact.Department becomes Account.PersonDepartment, Contact.MobilePhone becomes Account.PersonMobilePhone) UNLESS we are talking FirstName and LastName as they keep their names (i.e. Contact.FirstName becomes Account.FirstName, Contact.LastName becomes Account.LastName)
    2. Custom fields from Contact The field API name suffix is changed from __c to __pc (i.e. Contact.Shoesize__c becomes Account.Shoesize__pc)

Bash one-liner for Apex test coverage percentage using SalesforceDX

Update 3 May 2018: There are issues with the percentages reported by SalesforceDX plus it doesn’t report coverage on classes with 0% coverage which will shrew the results. The approach outlined above can be used as an indication but cannot as of today be used as a measure for code coverage when it comes to production deployments. As an example I’ve had the above snippet report a coverage of 88% where as a production deploy reported 63% coverage. We – Salesforce – are aware of the issue and are working to resolve it. Stay tuned!

Note to self – quick note on how to run all tests in a connected org (as identified by the -u argument) and use jq and awk to grab the overall test coverage percentage.

$ sfdx force:apex:test:run -u mheisterberg@example.com.appdev -c -w 2 -r json | jq -r ".result.coverage.coverage[].coveredPercent" | awk '{s+=$1;c++} END {print s/c}'
> 88.1108

YMMV!