Newer Version Available
PolicyCondition Interface
Namespace
Usage
The evaluate method is called upon the occurrence of an event monitored by a transaction security policy. A typical implementation first selects the item of interest from the event. Then the item is tested to see if it meets the condition being monitored. If the condition is met, the method returns true.
For example, imagine a transaction security policy that checks for the same user logging in more than once. For each login event, the method would check if the user logging in already has a login session in progress, and if so, true is returned.
PolicyCondition Methods
The following is the method for PolicyCondition.
evaluate(event)
Signature
public Boolean evaluate(TxnSecurity.Event event)
Parameters
- event
- Type: TxnSecurity.Event
- The event to check against the transaction security policy.
Return Value
Type: Boolean
When the policy is triggered, True is returned. For example, let’s suppose the policy is to limit users to a single login session. If anyone tries to log in a second time, the policy’s action requires that they end their current session. The policy also sends an email notification to the Salesforce admin. The evaluate() method only checks the login event, and returns True if it’s the user’s second login. The Transaction Security system performs the action and notification, and not the evaluate() method.
PolicyCondition Example Implementations
PolicyCondition Example: Block Localhost Login
1global class BlockLocalhostCondition implements TxnSecurity.PolicyCondition {
2
3 public boolean evaluate(TxnSecurity.Event e) {
4 // Get the IP address.
5 String sourceIp = e.data.get('SourceIp');
6 // If it’s localhost the policy is triggered and true is returned.
7 if(sourceIp != null && sourceIp.equals('127.0.0.1')){
8 return true;
9 } else {
10 return false;
11 }
12 }
13}Here’s the test class for the implementation:
1@isTest
2public class TestLogin {
3 public static testMethod void testLocalhostLogin() {
4 Map<String, String> eventData = new Map<String, String>();
5
6 /* Insert localhost IP address into the event data map */
7 eventData.put('SourceIp', '127.0.0.1');
8
9 TxnSecurity.Event e = new TxnSecurity.Event(
10 '00Dxxx123123123', /* organizationId */
11 '005xxx123123123', /* userId */
12 'AuthSession', /* entityName */
13 'Login', /* action */
14 'LoginHistory', /* resourceType */
15 '01pR00000009D2H', /* entityId */
16 Datetime.newInstance(2015, 9, 15), /* timeStamp */
17 eventData; /* data - Map containing information about the event */ )
18
19 /* We are unit testing a PolicyCondition that triggers
20 when an event is generated from localhost */
21 BlockLocalhostCondition condition = new BlockLocalhostCondition();
22
23 /* Assert that the condition is triggered */
24 System.assertEquals(true, condition.evaluate(e));
25 }
26
27 public static testMethod void testNonLocalhostLogin() {
28 Map<String, String> eventData = new Map<String, String>();
29
30 /* Insert non-localhost IP address into the event data map */
31 eventData.put('SourceIp', '1.1.1.1');
32
33 TxnSecurity.Event e = new TxnSecurity.Event(
34 '00Dxxx123123123', /* organizationId */
35 '005xxx123123123', /* userId */
36 'AuthSession', /* entityName */
37 'Login', /* action */
38 'LoginHistory', /* resourceName */
39 '01pR00000009D2H', /* entityId */
40 Datetime.newInstance(2015, 9, 15), /* timeStamp */
41 eventData; /* data - Map containing information about the event */ )
42
43 /* We are unit testing a PolicyCondition that triggers
44 when an event is generated from localhost */
45 BlockLocalhostCondition condition = new BlockLocalhostCondition();
46
47 /* Assert that the condition is NOT triggered */
48 System.assertEquals(false, condition.evaluate(e));
49 }
50}PolicyCondition Example: Block Large Data Export
An admin or other customer with API privileges can download all customer data in bulk using SOAP API, REST API, or the Bulk API. This security policy restricts API-based data downloads to 2,000 records and alerts the admin with a real-time notification if the policy is triggered.
1public global class DataLoaderExportGt2KRecords implements TxnSecurity.PolicyCondition
2{
3 public boolean evaluate(TxnSecurity.Event event){
4 if(Boolean.valueOf(event.data.get('IsApi'))){ // For any API request
5 Integer numberOfRecords = Integer.valueOf(event.data.get('NumberOfRecords'));
6 if (numberOfRecords >= 2000){
7 return true;
8 }
9 return false;
10 }
11 }
12}Continuing the example, you can add specific criteria to include Lexi Loader and Data Loader Partner Client IDs:
1if('LexiLoader/'.equals(clientId)||'DataLoaderPartnerUI/'.equals(clientId) && numberOfRecords >= 2000){
2 return true;
3 }PolicyCondition Example: High-Assurance Session
You can have sensitive, confidential data in your quarterly Salesforce reports. You also want to ensure that teams accessing those reports use two-factor authentication (2FA) for high assurance before viewing this data. The policy makes 2FA a requirement, but you can’t provide high-assurance sessions until your teams have a way to meet the 2FA requirements. As a prerequisite, first set up 2FA in your Salesforce environment.
This example highlights the capability of a policy to enforce 2FA for a specific report and specific roles accessing the report. The report defined here is any report with “Quarterly Report FY 2016” in its name. We use the role hierarchy to define everybody reporting to the CEO. Those people are required to have a high-assurance session using 2FA before accessing the reports.
1global class ConfidentialDataCondition implements TxnSecurity.PolicyCondition {
2 public boolean evaluate(TxnSecurity.Event event) {
3 if(event.resourceType == 'Reports'){ // If the event is about reports...
4 List<Report> reports = [SELECT Name FROM Report WHERE Id = :event.entityId];
5 if(reports.size() > 0){ // and if there’s a report...
6 String name = (String) reports.get(0).get('Name');
7 if(!String.isBlank(name) && name.containsIgnoreCase('Quarterly Report FY 2016')){
8 return true; // and if the name meets our criteria, trigger the policy.
9 }
10 }
11 }
12 return false; // Otherwise the policy is not triggered.
13 }
14}PolicyCondition Example: Restricting Platform Browser
Here’s a policy example for restricting access. Many organizations have standard hardware and support specific versions of different browsers. You can use this standard to reduce the security risk for high impact individuals by acting when logins take place from unusual devices. For example, your CEO typically logs in from San Francisco using a Macbook or Salesforce1 mobile application on an iPhone to Salesforce. When a login occurs from elsewhere using a Chromebook, it’s highly suspicious. Since hackers do not necessarily know which platforms corporate executives use, this policy makes a security breach less likely.
In this example, the customer organization knows that their CEO is using a Macbook running OS X with the Safari browser. Any attempt to log in using the CEO’s credentials with anything else is automatically blocked.
1global class CeoBrowserAccessPolicyCondition implements TxnSecurity.PolicyCondition {
2 public boolean evaluate(TxnSecurity.Event event) {
3 if (event.resourceType == 'LoginHistory') { // If it’s a login history event
4 LoginHistory lHistoryObj =[SELECT Platform, Browser FROM LoginHistory WHERE Id =:
5 event.data.get('LoginHistoryId')]; // Get the platform & browser from login history
6 String platform = lHistoryObj.Platform;
7 String browser = lHistoryObj.Browser;
8 if (platform == 'Mac OSX' && browser.startsWith('Safari')) {
9 return false; // Safari on the Mac OSX is OK, so the policy isn’t triggered
10 }
11 return true; // Not Safari or Mac OSX, so the policy is triggered
12 }
13 return false; // Not a login history event, so the policy isn’t triggered
14 }
15}PolicyCondition Example: Block Access by Geography
Your organization could have remote offices and a global presence but, due to international law, wants to restrict access to their Salesforce org. The restrictions would be from specific countries, or obtain alerts when unusual login activity occurs.
This example builds a policy that blocks users logging in from North Korea. If users are in North Korea but using a corporate VPN, their VPN gateway would be in Singapore or the United States. The VPN gateway would make their login successful because Salesforce would see the internal US-based company IP address.
1global class BlockAccessFromNKPolicyCondition implements TxnSecurity.PolicyCondition {
2 public boolean evaluate(TxnSecurity.Event e) {
3 List<LoginHistory> loginHistoryObj = // Get the login history
4 [SELECT LoginGeoId FROM LoginHistory WHERE Id = :e.data.get('LoginHistoryId')];
5 String loginGeoId = (String) loginHistoryObj.get(0).get('LoginGeoId'); // Get the geo info
6 List<LoginGeo> loginGeoObj = [SELECT Country FROM LoginGeo WHERE Id = :loginGeoId];
7 String country = (String) loginGeoObj.get(0).get('Country'); // Get the country name
8 if(country == 'North Korea') {
9 return true; // The policy is triggered for North Korea
10 }
11 return false;
12 }
13}You can also restrict access to other specific values, like postal code or city.
PolicyCondition Example: Block Access by OS
You’re concerned with a specific mobile platform’s vulnerabilities and its ability to capture screen shots and read data while accessing Salesforce. If the device is not running a security client, you could restrict access from device platforms using operating systems with known and well-identified vulnerabilities. In this example, we create a policy to block devices using Android 5.0 or earlier.
1global class BlockAndroidDevicesPolicyPolicyCondition implements TxnSecurity.PolicyCondition {
2 public boolean evaluate(TxnSecurity.Event e) {
3 LoginHistory lHistoryObj = [SELECT Platform FROM LoginHistory WHERE Id = :e.data.get('LoginHistoryId')];
4 if (lHistoryObj != null) { // If this was a login event...
5 String platform = lHistoryObj.Platform;
6 if (platform.contains('Android') && platform.compareTo('Android 5') < 0) {
7 return true; // check for the platform name and then the version.
8 }
9 }
10 return false; // Not Android 5.0 or less.
11 }
12}PolicyCondition Example: Using Apex API Callouts
Advertisers and spammers often post messages to successful communities at high rates to increase their chances of people clicking their links. The links can include unwanted content. You can use technologies outside of Salesforce to scan or filter content based on these different services.
In this example, we have unwanted text in communities posts and the policy executes an API callout to see if the content is compliant. This example uses a simple Google search API at WDYL.com.
1global class ChatterMessageLangFilter implements TxnSecurity.PolicyCondition {
2 public boolean evaluate(TxnSecurity.Event e) {
3 String body = e.data.get('Body');
4 HttpRequest req = new HttpRequest();
5 req.setMethod('GET'); // Set HTTPRequest Method
6
7 //Set HTTPRequest header properties
8 req.setHeader('content-type', 'text');
9 req.setHeader('Connection','keep-alive');
10 req.setEndpoint('http://www.wdyl.com/profanity?q=' + EncodingUtil.urlEncode(body,'UTF-8'));
11 Boolean isProfanity;
12 Http http = new Http();
13 HTTPResponse response = http.send(req);
14 if(response.getStatusCode() != 200 /* Failure */){
15 isProfanity = false; // If we can’t call out successfully, don’t trigger the policy.
16 } else {
17 JSONParser parser = JSON.createParser(response.getBody());
18 while (parser.nextToken() != null) {
19 if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) &&
20 (parser.getText() == 'response')) {
21 parser.nextToken(); // Get the value.
22 isProfanity = Boolean.valueOf(parser.getText());
23 }
24 }
25 }
26 return isProfanity;
27 }
28}PolicyCondition Example: Block Connected App Access
Sometimes connected apps have API privileges to access data system (org) wide due to sharing or account access settings definitions. However, the end user of the connected app is restricted to only a specific data set. This conflict can result in an increased security risk by identifying the API key and performing command-line searches directly in the database to look for leads. The following policy avoids this situation and data loss around your company’s lead information.
1global class DataLoaderLeadExportCondition implements TxnSecurity.PolicyCondition {
2 public boolean evaluate(TxnSecurity.Event e){
3 if(Boolean.valueOf(e.data.get('IsApi'))){
4
5 // The event data is a Map<String, String>. We need to call the valueOf()
6 // method on appropriate data types to use them in our logic.
7 String entityName = e.data.get('EntityName');
8 String connectedAppId = e.data.get(‘ConnectedAppId’);
9 Integer numberOfRecords = Integer.valueOf(e.data.get('NumberOfRecords'));
10 Integer executionTimeMillis = Integer.valueOf(e.data.get('ExecutionTime'));
11
12 // We're looking for leads accessed by a specific connected app that is
13 // transferring more than 2,000 records in more than a second - a large transfer.
14 if ('Lead'.equals(entityName) &&
15 connectedAppId == '0CiD00000004Cce' &&
16 numberOfRecords > 2000 && executionTimeMillis > 1000 ){
17 return true;
18 }
19 }
20 return false;
21 }
22}