Securing IBM WebSphere Cast Iron Appliance while integrating with Salesforce-Part IV

Introduction

This article series discusses about securing IBM Websphere Cast Iron Appliance when integrating with Salesforce. In the previous articles, we discussed about the security challenges and some of the methods to address those challenges including protecting the enterprise network using Firewall, SSL/Certificate based authentication. In this article, we will see how requests from cross-organization to cross-environment (from Salesforce to on-premise) can be prevented. This method also protects your organization’s web services from being accessed from other enterprises who are co-located along with your organization’s orgs. Implementing this method along with the solutions described in the previous articles is a powerful method that will secure your enterprises web services from almost any type of unauthorized access.

Background

In a typical enterprise, multiple environments are created to promote development to production. The usual model is to have one single environment for DEV, one for QA, one for Staging and another for Production. The number of environments may vary depending on the organization’s needs, but the bottom line is that there will be multiple organizations (Sandboxes) on the Salesforce side and matching environments at on-premise with mapping from Salesforce orgs to these local environments. At on-premise, each of these environments are either physically or logically separated using various technologies such as NAT and firewall rules are implemented to prevent cross environment access such that DEV servers can talk only to other DEV servers, QA servers can talk to other QA servers, etc. The bottom line is that applications from one environment cannot call into the applications/databases/services in another environment. But this type of implementation is not possible with Salesforce, because Salesforce doesn’t have the concept that we just explained above. Further we explained in part-2 about how the requests originates from Salesforce. To recap, Salesforce has a set of IP addresses for each region (such as North America, Asia Pacific, etc…) and the web service callouts made by the Salesforce client applications carry one of this IP address as their source address. Salesforce doesn’t have the concept of different network segments for the web service callouts, hence by default, there is no way for the enterprises to distinguish the requests to identify if it come from sandbox or production org or even from their own orgs. But not all is lost. The solution proposed here will address this problem, by not only, preventing the cross-organization to cross-environment access, but also prevents access from other enterprises orgs.

Solution

The solution to this problem involves some custom coding along with a Salesforce provided feature called ‘Organization Id’. Every Salesforce organization has a unique identifier called ‘Organization Id’. The ‘Organization Id’ can be found under Your Name | Setup | Administration Setup | Company Profile | Company Information.

A2-P4-01-OrganizationId[4]

Figure 1: Getting the Organization Id

The ‘Organization Id’ is unique for each Salesforce org. It is not only unique with your enterprise’s Salesforce orgs, but also unique universally across all orgs of all it’s clients. That means that if your web service client in Salesforce embed this ‘Organization Id’ in the request, then a web service can catch that and can prevent the call from executing if the ‘Organization Id’ is not in their access control list. This is what exactly we are going to do that. Here is a simple flowchart that describes this technique.

OrgValidation-FlowChart[4]

Figure 2: Flow chart that depicts the solution

As shown in the flowchart above, the client (Salesforce) will send the ‘Organization Id’ along with the input payload when it makes a web service callout to the Cast Iron. Apex provides the User API through which the ‘Organization Id’ can be retrieved which suits well for apex code. We get the ‘Organization Id’ from this object and embed it in the HTTP headers. For outbound SOAP messages, the outbound workflow action itself provides the ‘Organization Id’. Cast Iron will retrieve the ‘Organization Id’ from the request and validates against it’s configuration. If the ‘Organization Id’ matches, it continue to process, otherwise, the web service exits immediately, returning an error code. The following sections will provide step by step details along with the necessary code that implements this pattern.

Developing the OrgValidationService Cast Iron Orchestration

Since we want to validate all the incoming requests, it is best to develop the validation as a separate web service, so that all other web services can call this one web service to validate the ‘Organization Id’. We will call this as ‘OrgValidationService’. This web service will be consumed by all other Cast Iron web services that want to validate the organization ids. The following image is extracted from the Cast Iron studio that depicts the flow.

A2-P4-CI-01-OrgValidationService[4]

Figure 3: OrgValidationService

Previously, we saw that the client has to send the ‘Organization Id’ along with the input payload. This can be done with couple of ways. I preferred to embed the ‘Organization Id’ as part of the HTTP headers, because, this is less intrusive. Had we chose to embed this as part of the input request parameters, instead of putting into HTTP headers, then the XML schema for all of these web services need to be updated to include the ‘Organization Id’ parameter. Here is the logic:

  • The web service receives the input parameter and assigns it to input variable named ‘objOrgInfoRequest’. While assigning we filter it for the value ‘Organization Id’. Please note that apart from the HTTP headers, you will also notice another parameter named ‘OrganizationId’, which will be used if web service callout is made by outbound SOAP message. The following screenshot shows how the ‘Organization Id’ is passed through the HTTP headers.

A2-P4-CI-02-OrgInfo-HTTPHeaders-Mapping[4]

Figure 4: Filtering the input headers to get the ‘Organization Id’

  • The valid ‘Organization Id’ for that particular environment is configured in a variable named ‘OrgIdLookup’. This is retrieved and assigned to a variable.
  • The web service checks the ‘Organization Id’ that came as part of the input parameter and checks against this configured value.
  • If it matches, then it assigns the status to ‘true’, otherwise, it assigns the status ‘false’.

The code for this orchestration can be downloaded from here.

Developing the Test Web Service Cast Iron Orchestration

The Test Web Service Cast Iron orchestration will serve as an example of how the regular Cast Iron orchestrations (that will be developed to support your organization’s business requirements) should utilize the OrgValidationService to validate the ‘Organization Id’. The following image is extracted from the Cast Iron studio.

A2-P4-CI-03-TestRequestService[3]

Figure 5: TestRequestService Web Service to be consumed by Apex code.

This orchestration is exposed as a web service which will be consumed by your apex code. It copies the HTTP headers to a local variable and calls the OrgValidationService passing this variable. If the return value from the OrgValidationService is true, then the orchestration proceeds to execute, otherwise, it terminates immediately. The code for this orchestration can be downloaded from here.

Consuming the OrgValidationService in Salesforce

There are couple of ways the Salesforce can be programmed/configured to consume a web service that is hosted elsewhere. The right solution depends on the needs, but they are as follows:

  • Apex code
  • Outbound SOAP message
  • AppExchange App

Consuming the Test Web Service from Salesforce (through Apex code)

With apex code option, the consuming the Test Web Service from Salesforce is done completely by coding in Apex. Developers choose this option when they want to

  • pull data from multiple objects and pass them as input parameters
  • process the data and derive the input parameters for the web service

Here are the steps to consume the test web service from Salesforce using the apex code.

  • Generate the WSDL from the Cast Iron web service and save it to a folder
  • Login into your dev/sandbox org and go to the section ‘Apex Classes’ under Your Name | Setup | App Setup | Develop.
  • Click ‘Generate from WSDL’ and choose the file that you saved from the Cast Iron studio.
  • If you want to rename the default names provided by the import wizard, go ahead and change the file names. I renamed the files as follows:

A2-P4-CI-05-GenerateFromWsdl[4]

Figure 6: Naming the system generated classes in Salesforce

  • Click ‘Generate Apex Code’ button and click ‘Done’.

Now we need to create a wrapper class that utilizes the stub generated by the import wizard. To do this, click ‘New’ under Your Name | Setup | Develop | Apex Classes. Copy the code given below. This code consumes the test web service by utilizing the stub that we just generated.

public class TestRequestServiceClient {
    @future (callout=true)
    public static void Test() {
        Boolean isSuccess = true;
        try {
            TestRequestServiceWsdl.Provide_ServicePort binding = buildService();
            List<TestRequestServiceRequest.TestRequest_element > elementList = new List<TestRequestServiceRequest.TestRequest_element >();
            TestRequestServiceRequest.TestRequest_element element = new TestRequestServiceRequest.TestRequest_element ();
            binding.Provide_Service('1', 'Test');
            isSuccess = true;
        } catch (Exception e) {
            isSuccess = false;
        }
        //return;
    }
    private static TestRequestServiceWsdl.Provide_ServicePort buildService() {
        TestRequestServiceWsdl.Provide_ServicePort updateStatusInstance = new TestRequestServiceWsdl.Provide_ServicePort ();
        updateStatusInstance.endpoint_x         = 'https://yourcastironwebserver:443/TestRequestService';
        updateStatusInstance.inputHttpHeaders_x = new Map<String, String>();
        updateStatusInstance.inputHttpHeaders_x.put('OrganizationId', UserInfo.getOrganizationId());
        updateStatusInstance.inputHttpHeaders_x.put('OrganizationName', UserInfo.getOrganizationName());
        System.debug('\nOrganization Id :' + UserInfo.getOrganizationId());
        updateStatusInstance.timeout_x          = 60000;
        return updateStatusInstance;
    }
}

Click Save.

Consuming the OrgValidationService in Salesforce (outbound SOAP message)

With outbound SOAP message option, the outbound SOAP action sends the ‘Organization Id’ as part of the request payload. This is the reason that we designed our OrgValidationService to accept both HTTP headers and a separate parameter named ‘Organization Id’ to support both scenarios (Apex code and outbound SOAP messages).

Here is the test web service built to be consumed by an outbound SOAP message. The outbound SOAP message definition provides you the WSDL and the following screenshot shows the test web service implmented using this WSDL. The code for this web service can be found here.

A2-P4-CI-04-TestRequestServiceO[3]

Figure 7: ‘TestRequestServiceO’ web service to be consumed by Outbound SOAP message

Now we have completed all the development tasks. Before start testing, you need to perform the following tasks:

  • Deploy all the three Cast Iron orchestrations in your Cast Iron server (preferably in your development environment)
  • In OrgValidationService, configure the ‘OrganizationId’ configuration property to the organization id of the Salesforce org that you are going to test. You can get the organization id from the ‘Company Information’ link under Your Name | Setup | Company Profile‘ as shown in the Figure 1 above. Note that the organization id that is displayed here is 15 digit and you need to use the 18 digit version, as otherwise, your OrgValidationService will fail. [You can get the 18 digit through many ways. One way is to let it run against your cast iron web service and look at the cast iron log and you will find the 18 digit id (set the log level to ‘All’ in your cast iron server).
  • In Salesforce, update the ‘endpoint_x’ variable in the TestRequestServiceWsdl to point to your cast iron server and save it. (I renamed the system generated file to ‘TestRequestServiceWsdl’. If you choose a different name or if you didn’t rename, then the file name will be different in your case.

With this, we are all set to test it. Invoke the developer console from Your Name | Developer Console and execute the following: TestRequestServiceClient.Test(); Now if you open the debug logs, you will see that the call succeeded. If you check your Cast Iron logs, you would see log message titled either ‘Request came from authorized organization’ or ‘Request came from unauthorized organization’ depending on what value you have configured for the ‘Organization Id’ configuration property in the OrgValidationService orchestration.

Summary

This article is the fourth in the five part article series. The first part described the security challenges. The second part explained how the enterprise can use firewall to filter unwanted traffic other than the trusted networks. The third part continued to explain about transport level encryption. The fifth part will now explain about authorizing the trusted users. This scenario is particularly important if you are going to use Cast Iron server to integrate with other systems including other cloud services such as Docusign, Amazon elastic cloud, Windows Azure, etc.

Advertisements

Tagged: , , , , , ,

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: