Connecting Force.com to on Premises Resources, Part 2

by Richard Seroter

As noted in Part 1 of this series, Force.com recognizes several integration patterns, and provides SOAP and REST-based APIs for Data Integration, business Logic Integration, as well as APIs to connect with presentation, and security layers. Part 1 introduced the options for outbound integration and showed how you can call the Service Bus Relay service from Apex Code using REST. This installment continues by showing how to call SOAP- and REST-based relay endpoints, then presents an example that sends Force.com outbound messages to the Service Bus Relay service.

Calling a SOAP-based Relay Endpoint

For this scenario, you would ideally use Apex generated classes based on the WCF WSDL. However, the Service Bus looks for the relay token in the SOAP header, NOT the HTTP header. Therefore, you need a higher degree of control over the payload than what the generated classes can offer. Instead, use the Http and HttpRequest classes to send messages to the Service Bus endpoint. The first thing to do is acquire the Access Control credentials needed to authenticate to Service Bus. These credentials are found in the Windows Azure Management Portal and Service Bus namespace view. Click the Access Key button to view the default, administrator credentials. It’s recommended to create non-administrator credentials to share with other applications.

Figure 1: Management Portal and Service Bus namespace view.

With those credentials in hand, create the new operation in a Visualforce controller. Instantiate the Http and HttpRequest objects and create variables to hold the Access Control URL and URL encoded password. Set the HttpRequest’s endpoint, HTTP method (POST), content-type, and body. Invoke the Access Control service by calling the send operation of the Http object and retrieve the response.

Http h = new Http();
HttpRequest req = new HttpRequest();
       
// ** Getting Security Token from STS
String Url = 'https://[namespace]-sb.accesscontrol.windows.net/WRAPv0.9/';
String encodedPW = EncodingUtil.urlEncode([password]', 'UTF-8');
       
req.setEndpoint(Url);
req.setMethod('POST');
req.setBody('wrap_name=[issuer name]&wrap_password=' + encodedPW + '&wrap_scope=http://[namespace].servicebus.windows.net/MenuService');
req.setHeader('Content-Type','application/x-www-form-urlencoded');
HttpResponse res = h.send(req);
String result = res.getBody();

The token returned by Access Control looks something like this. Notice that allowed actions are included (available options are send, listen, and manage), the identity provider is called out, the valid service endpoint is specified, the token expiration is identifed, and the secure SHA256 hash is listed.

wrap_access_token='''net.windows.servicebus.action'''%3dSend%26http%253a%252f%252fschemas.microsoft.com%252faccesscontrolservice%252f2010%252f07%252fclaims%252fidentityprovider%3dhttps%253a%252f%252fseroter-sb.accesscontrol.windows.net%252f%26Audience%3dhttp%253a%252f%252fseroter.servicebus.windows.net%252fMenuService%26ExpiresOn%3d1362757818%26Issuer%3dhttps%253a%252f%252fseroter-sb.accesscontrol.windows.net%252f%26HMACSHA256[hash]&wrap_access_token_expires_in=599

This token cannot be immediately used in the calls to the Service Bus. You first must reformat it. This includes stripping out the “wrap_access_token_expires_in” value at the end, eliminating the “wrap_access_token” prefix, URL decoding the remaining string, and finally creating a base64 encoded string of the token.

// clean up result
String suffixRemoved = result.split('&')[0];
String prefixRemoved = suffixRemoved.split('=')[1];
String decodedToken = EncodingUtil.urlDecode(prefixRemoved, 'UTF-8');
       
Blob byteArray = Blob.valueof(decodedToken);
String baseToken = EncodingUtil.base64Encode(byteArray);

You are now ready to invoke the SOAP relay endpoint. In the code below, see that the Service Bus endpoint (as listed in the WCF service configuration) is specified and a GUID is created. The GUID is used within the SOAP message to identify the token.

//set service bus endpoint URL
String sbUrl = 'https://[namespace].servicebus.windows.net/MenuService/';
//generate guid
Blob guidb = Crypto.GenerateAESKey(128);
String guidh = EncodingUtil.ConvertTohex(guidb);
String guid = guidh.SubString(0,8)+ '-' + guidh.SubString(8,12) + '-' + 
		guidh.SubString(12,16) + '-' + guidh.SubString(16,20) + '-' + 
		guidh.substring(20);  

The final major step is to build up the SOAP message payload. There are the usual SOAP envelope, head and body nodes, but notice (in red) the access token included in the header. The SOAP body, colored blue, includes the details from the Visualforce page.

//build up request
String requestBody = '<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">'+
       '<s:Header>' +
         '<RelayAccessToken xmlns=\"http://schemas.microsoft.com/netservices/2009/05/servicebus/connect\">' +  
         '<wsse:BinarySecurityToken wsu:Id=\"uuid:'+ guid +'\" ValueType=\"http://schemas.xmlsoap.org/ws/2009/11/swt-token-profile-1.0\"' +
         'EncodingType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary\" ' + 
         'xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\" ' + 
         'xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">' +
            baseToken +
         '</wsse:BinarySecurityToken></RelayAccessToken>'+
       '</s:Header>' +  
       '<s:Body>' + 
       '<GetMenu xmlns=\"http://tempuri.org/\"><menudate> '+ this.VisitDate +'T00:00:00</menudate>' +
       '<siteid>'+ this.Cafeteria +'</siteid></GetMenu>' +
       '</s:Body></s:Envelope>';        

Dom.Document requestDoc = new Dom.Document();
requestDoc.load(requestBody);

Next, build up the HTTP request by specifying the URL, HTTP verb (POST), content-type, SOAPAction, and body text.

HttpRequest sbReq = new HttpRequest();
sbReq.setEndpoint(sbUrl);
sbReq.setMethod('POST');
sbReq.setHeader('SOAPAction', 'http://tempuri.org/IMenuService/GetMenu');
sbReq.setHeader('Content-Type', 'text/xml; charset=utf-8');
sbReq.setBodyDocument(requestDoc);

Send the message, receive the response, and load it into an XML document. Then perform the necessary XPath to extract the values from the response message.

HttpResponse sbResult = h.send(sbReq);
Dom.Document responseDoc = sbResult.getBodyDocument();   
 
//namespace of XML nodes in response body      
String menuNS = 'http://schemas.datacontract.org/2004/07/RelayHost';  

Dom.XMLNode envelope = responseDoc.getRootElement();
Dom.XMLNode menuNode = 
  envelope.getChildElement('Body', 'http://schemas.xmlsoap.org/soap/envelope/').
     getChildElement('GetMenuResponse', 'http://tempuri.org/').
       getChildElement('GetMenuResult', 'http://tempuri.org/');
       
String salad = menuNode.getChildElement('SaladSpecial', menuNS).getText();
String grill = menuNode.getChildElement('GrillSpecial', menuNS).getText();
String sandwich = menuNode.getChildElement('SandwichSpecial', menuNS).getText();
 
MenuResult = '<b>Salad Station:</b> ' + salad+ '<br/><b>Grill Station:</b> ' + grill + '<br/><b>Sandwich Station:</b> ' + sandwich;

The code is now complete! Return to Visual Studio, start the relay host application (ensuring that that SOAP relay endpoint is added) and wait for the connection with Windows Azure to be made. Then, visit your Visualforce page and invoke the controller operation. See that the on-premises WCF service is called and menu details are returned.

Figure 2: Invoking the controller operation from Visualforce.

Calling a REST-based Relay Endpoint

Invoking the REST endpoint of your on-premises WCF service is very similar to calling the SOAP endpoint. However, there are a few subtle differences. The Apex code necessary to acquire the Access Control token is identical. The post-processing of that token is slightly different. Specifically, the token is not base64 encoded, and a prefix (“WRAP access_token=”) is added to the final result.

Http h= new Http();
HttpRequest acReq = new HttpRequest();
HttpRequest sbReq = new HttpRequest();
        
// ** Getting Security Token from STS
String acUrl = 'https://[namespace]-sb.accesscontrol.windows.net/WRAPV0.9/';
String encodedPW = EncodingUtil.urlEncode('[password', 'UTF-8');
        
acReq.setEndpoint(acUrl);
acReq.setMethod('POST');
acReq.setBody('wrap_name=[issuer name]&wrap_password=' + encodedPW + '&wrap_scope=http://[namepace].servicebus.windows.net/');
acReq.setHeader('Content-Type','application/x-www-form-urlencoded');
   
HttpResponse acRes = h.send(acReq);
String acResult = acRes.getBody();
            
// clean up result
String suffixRemoved = acResult.split('&')[0];
String prefixRemoved = suffixRemoved.split('=')[1];
String decodedToken = EncodingUtil.urlDecode(prefixRemoved, 'UTF-8');
String finalToken = 'WRAP access_token=\"' + decodedToken + '\"';

With a token properly formatted, you next build up the HTTP request to the Service Bus Relay. Recall that RESTful services rely on resource URIs, and there is no payload for a GET request. Instead, build up the URL string to point to the desired resource. Your WCF service expects the site ID (cafeteria identifier) and visit date, so build up the corresponding URL. Set the HTTP verb to “GET”, specify the content-type, and add an HTTP header that holds the Service Bus authorization token.

// setup service bus call
String sbUrl = 'https://[namespace].servicebus.windows.net/MenuREST/Menu/' + this.Cafeteria + '/' + this.VisitDate;
sbReq.setEndpoint(sbUrl);
sbReq.setMethod('GET');
sbReq.setHeader('Content-Type', 'text/xml');
sbReq.setHeader('Authorization', finalToken);
Finallly, send the request to the service endpoint using the HTTP object. Load the response into an XML object and perform the necessary XPath to extract the desire node values.

HttpResponse sbResult = h.send(sbReq);
Dom.Document responseDoc = sbResult.getBodyDocument();   

//set namespace of XML payload    
String menuNS = 'http://schemas.datacontract.org/2004/07/RelayHost';  
       
Dom.XMLNode rootNode = responseDoc.getRootElement();
       
String salad = rootNode.getChildElement('SaladSpecial', menuNS).getText();
String grill = rootNode.getChildElement('GrillSpecial', menuNS).getText();
String sandwich = rootNode.getChildElement('SandwichSpecial', menuNS).getText();
       
MenuResult = '<b>Salad Station:</b> ' + salad+ '<br/><b>Grill Station:</b> ' + grill + '<br/><b>Sandwich Station:</b> ' + sandwich;

Back in Visual Studio, ensure that the REST endpoint of the service is configured in the application configuration file before starting up the console project. Once started, call the REST endpoint from the Force.com controller and observe that data is returned by the service.

Figure 3: Calling the REST endpoint.

The Service Bus allows you to communicate with both SOAP and REST web services that reside inside private networks.

Sending Force.com Outbound Messages to Windows Azure Service Bus Relay Service

Outbound Messaging is a unique and powerful feature of the Force.com platform. If you want to use it, one of the biggest hurdles to overcome is exposing a public-internet facing endpoint for Force.com to send messages to. In this example, you will build a Windows Azure Service Bus Relay endpoint that can accept Force.com Outbound Messages and forward them to a service behind the corporate firewall.

One wrinkle in this solution revolves around security. Force.com developers cannot intercept Outbound Messages and append additional HTTP headers, so there’s no way to attach a Service Bus ACS token. Therefore, the Service Bus endpoint must be configured to accept requests with no authorization token. You may consider trying to validate users through the client certificate that Force.com sends with each Outbound Message, except that the Service Bus strips off any client certificates before relaying the message to the web service listener! So how do you validate the user? While you could rely on “security through obscurity” and hope that no one uncovers your Service Bus endpoint, a better solution is to inject a token into the object payload before sending through the Force.com Outbound Messaging service. That token can then be checked by the Service Bus listener before proceeding. While there are flaws in this approach, it does provide one viable solution.

In your Force.com application, navigate to the list of Account object fields by going to Setup –> App Setup –> Customize –> Accounts –> Fields. Add a new string field called AzureValidationToken. This field will be set on Outbound Messages and sent to the Service Bus listener.

Figure 4: Adding a new validation token.

Next, create a new Outbound Message configuration. Go to App Setup –> Create –> Workflows & Approvals –> Outbound Messages and click the New Outbound Message button. Choose the Account object as the one that you’ll be sending.

Figure 5: Creating a new outbound message.

The next screen asks you to configure the Outbound Message endpoint and data structure. Provide a unique name and useful description. Note that you don’t have a receiving endpoint configured yet, so enter http://localhost as a placeholder. Choose which fields to send as part of the Outbound Message and don’t forget to include the new custom AzureValidationToken field. It’s also possible to include a session ID in the Outbound Message if you want the receiving service to be able to call back into Force.com to get the latest information (instead of relying on data included in the message itself).

Figure 6: Configuring the outbound message.

Save the configuration and see that now you have the option to retrieve a WSDL corresponding to the Outbound Message. This is the WSDL for the service that *consumes* the Outbound Message and thus must be implemented by the custom WCF service that you’re about to build. Save the WSDL locally to your machine.

Create a new console project in Visual Studio. This will host the service listener that Outbound Messages will be routed to. Like with the previous console project, add the NuGet package for the Service Bus in order to get the required assemblies and configuration settings.

Figure 7: Setting up a service listener in Visual Studio.

In order to create a WCF service that matches the Outbound Messaging WSDL from Force.com, use the ServiceModel Metadata Utility Tool (svcutil.exe) that comes with the .NET Framework. This tools is primarily used for consuming existing services, but it can also be used to generate WCF service contracts for new services. Open the .NET Command Prompt on your machine and navigate to the folder where the Outbound Messaging WSDL is stored.

Execute the following command in order to generate a proxy class (without a configuration file) for the WSDL.

svcutil outboundmsg.wsdl -noconfig /language:C# /out:INotificationService.cs

This produces a C# class file that you will add to your existing console project. This class has the service interface definition and data types needed to build a service that implements this contract. Comment out the notificationAsync operation that exists in the NotificationsPort contract and just leave the single operation called notifications. Also, at the bottom of the generated class, comment out the two operations that reference the async endpoints.

Figure 8: Selecting the object for the outbound message.

Add a new class (named NotificationService) that will serve as the service implementation. This service implements the NotificationPort interface and the single notifications operation. This operation returns a boolean acknowledgement that Force.com expects to receive before considering the message transmission a success. Before returning a successful acknowledgement, look for the AzureValidationToken property and compare it to a randomly generated GUID (that you will use again in a few moments).

public class NotificationService : NotificationPort {

  public notificationsResponse1 notifications(notificationsRequest request)
  {
     notificationsResponse response = new notificationsResponse();
     notificationsResponse1 responseWrapper = new notificationsResponse1();
     //look for token in first object (of many, possibly)
     string token = request.notifications.Notification[0].sObject.AzureValidationToken__c;
     if (token == "4B0CC553-5C82-4413-9B4C-525C280F7BD7")
     {
       response.Ack = true;
       Console.WriteLine("Message received for account " + request.notifications.Notification[0].sObject.Name);
     }
     else
     {
       response.Ack = false;
       Console.WriteLine("Unauthorized message received");
     }
     responseWrapper.notificationsResponse = response;
           
     //return ack
     return responseWrapper;
   }
}

Open the application configuration file and set up the service, endpoint and behaviors needed to connect this WCF service to the Service Bus. Note that this service’s relayClientAuthenticationType is set to “None” because we cannot inject an Access Control token into the Outbound Message and need an alternate way to validate the incoming request.

<behaviors>

     <endpointBehaviors>
       <behavior name="RelayBehavior">
         <transportClientEndpointBehavior>
           <tokenProvider>
             <sharedSecret issuerName="[issuer]" issuerSecret="[password]" />
           </tokenProvider>
         </transportClientEndpointBehavior>
         <serviceRegistrySettings />
       </behavior>
     </endpointBehaviors>
   </behaviors>
   <bindings>
     <basicHttpRelayBinding>
       <binding name="RelayBinding">
         <security relayClientAuthenticationType="None" />
       </binding>
     </basicHttpRelayBinding>
   </bindings>
   <services>
     <service name="OutboundMessagingRelayHost.NotificationService">
       <endpoint address="https://[namespace].servicebus.windows.net/AccountService"
         behaviorConfiguration="RelayBehavior" binding="basicHttpRelayBinding"
         bindingConfiguration="RelayBinding" name="RelayEndpoint" contract="NotificationPort" />
     </service>

The service is now complete! You have a WCF service that implements the Outbound Messaging WSDL and can receive messages sent by Force.com.

The final step is to finish configuring the Outbound Messaging settings and specify a workflow rule that will kick off the process. Return to the Force.com setup screens and go to back to the Outbound Messaging configuration. Locate your previous-created entry and edit it. Plug in the Service Bus URL (“https://[namespace].servicebus.windows.net/AccountService”) into the Endpoint URL field. Then go to App Setup –> Create –> Workflow & Approvals –> Workflow Rules and create a new rule to trigger this Outbound Message.

In the New Workflow Rule wizard, select Account as the object to execute the rule against. Set the rule to evaluate whenever new accounts are created and ensure that it only fires when the Account Name field is not empty.

Figure 9:Creating a new workflow rule in the wizard.

After saving the rule, specify which actions will occur when this rule criteria is met. In this case, you want to do two things: (1) create a Field Update action to set the AzureValidationToken field, and (2) reference the Outbound Messaging entry you created earlier.

First, create a New Field Update workflow action by selecting it from the list of available actions.

Figure 10: Creating a new workflow action.


Set a name for this action and choose which field to update. In this case, select the custom field called AzureValidationToken. Choose the option to “use a formula to set the new value” and enter a GUID value. This randomly generated value represents the unique key for this Force.com organization that will be matched in the on-premises service listening in on the Service Bus.

Figure 11: Specifying the field to be updated.

Save the workflow action. You are returned to the “New Account Rule” page and will now reference your previously-created Outbound Messaging configuration. From the drop-down list for Add Workflow Action, choose Select Existing Action.

Figure 12: New Account Rule page.

Set the Search value to Outbound Messages and choose the configuration you created earlier.

Figure 13: Setting the Search value.

Save the rule, and activate it by clicking the Activate button at the top of the Rule Details page. The new workflow rule now has two workflow actions that are invoked when the rule criteria is met.

Return to Visual Studio and start the WCF service. It will connect to the Service Bus Relay service and be ready for new requests. Back in your Force.com application, create a brand new account record and save it.

Figure 14: Creating a new account in Force.com.

Within a matter of seconds, there should be a new message in the .NET console host application.

Figure 15: The .Net response to the outbound message.

If the outbound message fails for any reason (e.g. bad security token, listening service offline), then the message is queued up for retry. You can view these queued messages by going to Administration Setup –> Monitoring –> Outbound Messages where you will see each failed message and a reason for failure. From here, messages can be immediately retried (instead of waiting for the engine to automatically retry later) or deleted.

Figure 16: Reporting back on the result.

Outbound Messaging is an extremely useful way to quickly send Force.com data to interested systems. Using this method you can easily create an internet endpoint that forwards traffic to business systems behind the corporate firewall.

Summary

Many developers focus solely on integration scenarios where you are pushing data into Force.com. However, the Salesforce Platform also offers a number of ways to reach out from Force.com into other systems, making it possible to tap into valuable services that exist deep within corporate networks. Whether issuing remote commands through Apex code, or using Outbound Messaging, you can utilize these methods to create a more dynamic Force.com application.

About the Author

Richard Seroter is a product manager for cloud computing provider Tier 3, a Microsoft MVP, Pluralsight trainer, speaker, and author of multiple books on application integration strategies. Richard maintains a regularly updated blog on topics of architecture and solution design and can be found on Twitter as @rseroter.

This article was originally published March, 2013