This article is the fourth in the five part article series on making authenticated web service callouts from Salesforce to IBM WebSphere Cast Iron using SSL/certificates. Web Service callouts is a powerful feature and the IBM WebSphere Cast Iron provides great integration capabilities. We discussed the basics of the authenticated callouts and the problem scenario in the first part and implemented a solution without the SSL/certificates in the second part. We also discussed about securing the web service with one-way SSL/certificate authentication in the third part. In this part, we will continue to add two-way SSL/certificates that demonstrates the concept of both the parties proving their identities.
Understanding the two-way SSL
As explained in the third part, the one-way SSL/certificates based authentication allows one of the parties (read ‘server’) to prove its identity to the client(s) based on the PKI mechanism such that the client and the server can exchange communication on a secure medium. This is the most commonly found scenario which is widely implemented by most web sites such as amazon.com, ebay.com, etc. Sometimes, this arrangement is not enough and the server needs to know whom it is talking to. This is particularly relevant when you integrate cloud based services with on-premise or other cloud based systems.
Let’s consider a real scenario. You want to integrate the information from your salesforce platform to your on-premise system – assume you have infrastructure as described in the architecture diagram in Part-2. You can secure your IBM WebSphere Cast Iron server with certificates signed by public CA. You may even put firewall rules to restrict access that allows inbound calls only from salesforce.com servers. (adding *.salesforce.com to firewall will not work. Salesforce has a set of IP ranges and the request may arrive from any of these IP addresses. There is no distinction on the requests to indicate the salesforce organization from where the request originated [the salesforce does send the organization name if it is outbound SOAP message based web service callout]. These IP address ranges has to be added to your firewall to restrict the access to salesforce.com servers). But still there is a gaping hole. If someone knows your endpoint who also is a salesforce user (from a different company; for that matter, it can be an individual from salesforce DE user), then he can very well invoke your web services, provided, you do not have other forms of authentication, built into your orchestration. You can always build such other forms of authentication into your orchestrations, but it may not be versatile.
There’s a better solution available which is the two-way SSL/certificates based authentication. In this method, the client, as well, provides its identity to the server to prove it’s identity. This is much better, because, in most cases, this is just a configuration task, especially on the IBM WebSphere Cast Iron side. On the client side, it depends on the platform you use – Salesforce does provide both configuration only and code based approaches. This is definitely better than user name/password based authentication, because, if the user name/password is compromised somehow, then the attacker can easily gain access to your systems. Sure, if the attacker gain access to your client’s public key, then it is still a high risk with two-way SSL/certificates approach as well; but for all practical scenarios, this is highly difficult, if not impossible. But the same is not true with user name/password based approach, for e.g. if the attacker uses brute force method and your password is not strong enough to resist it. There’s much more to this and it is out of scope for this article to discuss elaborately and I’ll write more about the security in a future article series.
To summarize, in two-way SSL/certificates based authentication, both the server and the client(s) prove their identities respectively using SSL certificates. As explained in the Part-3, Salesforce will accept only certificates signed by public CA, when it acts as a client and makes a callout to the server. On the contrary, you can use either self-signed certificates, provided you import this certificate into the Key Store of your IBM WebSphere Cast Iron runtime appliance, or you can use certificates signed by public CA (you don’t need to do any thing special on IBM WebSphere Cast Iron side for this). We are going to see this in action in the remainder of this article.
Tutorial-3: Setting up two-way SSL/certificate authentication
The basic concept here is to add the SSL/certificate authentication to the client side. The concept of two-way SSL/certificate authentication is generic to all platforms and technologies, though the implementation could slightly differ. From Salesforce perspective, there are two ways to accomplish this. They are as follows:
In both the scenarios, we can either use self-signed certificates or certificates signed by public CA. This article will explain both these approaches for the above two scenarios.
Certificate generated from non-Salesforce
This is also called the ‘Legacy’ method by Salesforce. In this scenario, we generate the CSR from non-Salesforce system, such as Windows Active Directory Services or Open SSL. This involves some coding work on the Salesforce side which will be explained later.
With the self-signed certificates, we can have our own CA installed in our infrastructure and can generate the CSR and sign it. Self-signed certificates may not work in all occasions; for e.g. if the other end can accept only certificate signed by public CA. Usually, this may happen with SaaS vendors or with any third-party services. For our tutorial, we will use the Open SSL to get the self-signed certificates.
Step # 1: Setting up Open SSL and generating root certificate
Download the Open SSL from www.openssl.org for linux. This tutorial uses the windows distribution of Open SSL. Open a command prompt, and execute the following commands:
In my workstation, I have installed it under E:\OpenSSL-Win32\. Please replace the drive where you have installed in your workstation.
Now that we have setup the Open SSL, let’s generate the root certificate that will be used to sign the certificate that we will generate in the next step. Before proceeding, let’s cover some basics. A digital certificate is verified using a chain of trust. It is formed as a tree structure and the first node of this tree structure is issued by the Root Certificate Authority and may contain intermediate certificates in the tree structure. The private key of the root certificate is used to sign the other certificates. Each certificate in the certificate chain inherits the trust worthiness of it’s parent certificate which goes all the way up to the root certificate. This is why we need a root certificate before creating the actual certificate, since the private key of the root certificate will be used to sign our certificate. IBM WebSphere Cast Iron normally (like most servers) doesn’t allow a certificate to be imported if the chain of trust is not present, though it does provide an option to bypass it, but this is not a recommended practice.
To generate the root certificate, execute the following command:
openssl req -new -x509 -extensions v3_ca -keyout keys\cakey.pem -out certs\cacert.pem -days 730 -newkey rsa:2048
This command generates a new root certificate with new key which is 2048 bits long.
Figure 4a. Generate root certificate
Step # 2: Creating the CSR for client
The Certificate Signing Request (CSR) contains the information about your organization and the public key which the CA validates it before signing it. In this case, we have our own CA which will be used to sign this certificate.
Here is the command to generate the CSR.
openssl req -new -nodes -out certs\contoso.csr -key keys\cakey.pem
Figure 4b. Create CSR using Open SSL (for self-signed certificate)
This will generate the CSR file under certs\contoso.csr. An important thing to note is that the common name should either exactly match your domain name or should match your domain name with wild card. Wild card is used if you want to use the same certificate for the sub domains. For e.g. the same certificate can be used for the URLs secure.contoso.com, docs.contoso.com, contoso.com, if you use ‘*.contoso.com’ in the common name. If you use IP address, then note that your clients can access the web service only by IP address, the exception being, if your subjectAlternateName has your DNS name in it (same as common name).
Step # 3: Sign the certificate
Now that we have the CSR generated, it needs to be signed which can be done by the following command.
openssl ca -policy policy_anything -cert certs/cacert.pem -in certs/contoso.csr -keyfile keys/cakey.pem -days 730 -out certs/contoso.cer
Figure 4c. Sign the certificate using Open SSL
The above command instructs to sign the CSR using the root certificate that we generated in step # 1 using the private key and set the certificate to expire in 2 years.
IBM WebSphere Cast Iron can accept only PKCS#12 formatted certificates and hence we need to convert our PEM formatted certificate to PKCS#12 format. This can be accomplished by the following command:
openssl pkcs12 -export -out certs/contoso.p12 -in certs/contoso.cer -inkey keys/cakey.pem
Figure 4d. Convert the PEM encoded certificate to PKCS#12 format
Step # 4: Import the root certificate and self-signed certificate into IBM WebSphere Cast Iron runtime appliance
Most servers including IBM WebSphere Cast Iron ships with root certificates for most of the vendors such as Verisign, Thawte, etc. But since we are using the self signed certificates which is signed by our own CA that we setup in the step # 1, we first need to import the root certificate into the Trust Store.
To do this, click ‘Import’ under the ‘Trust Store’ section of Security->Certificates. This will open up a dialog box. You can either select the file or paste the content from the certificate file. Click ‘Browse’ and select the file and click ‘Open’. Click ‘Import’ and the certificate should be imported into your Trust Store now.
To import the self signed certificate, click ‘Import’ under the ‘Key Store’ section of Security->Certificates. This will open up a dialog box. You can either select the file or paste the content from the certificate file. Click ‘Browse’ and select the file and click ‘Open’. Enter the password that you used to generate the self signed certificate. Click ‘Import’ and the certificate should be imported into your Key Store now.
Step # 5: Update the code to embed the certificate in the web service callout
The web service callout code needs to be updated to include the certificate in the call for the two-way authentication. The certificate that we have now is in PKCS12 format which is a binary format and we need the text version (PEM) of it to embed it into the code. To get this, execute the following command:
openssl base64 -in certs/contoso.p12 -out certs/contoso.pem
Open the contoso.pem file in a text editor and copy the content. Now, update the UserStatusClient file on the Salesforce side by clicking ‘Edit’ against ‘UserStatusClient’ under Setup->Develop->Apex Classes.
string key = ''; // paste the content that you copied from the contoso.pem file.
updateStatusInstance.clientCert_x = key;
updateStatusInstance.clientCertPasswd_x = 'xxxxxx'; // enter the password that you put when you generated the certificate.
Test it by updating the test user’s status and you should see that it has made a web service callout with two-way authentication.
Public CA Signed Certificates
The biggest advantage of getting the certificate signed by public CA is that you there is no need to import the certificate in the target server, as in the case of self-signed certificates, as the web/application server(s) trust the certificates signed by public CA’s. This will really helpful where the user doesn’t have control or a way to import the self-signed certificates into the target server’s Trust/Key Store.
In this scenario, we will see how to get the certificate signed by public CA using CSR generated from Open SSL.
Step # 1: Creating the CSR for client
To create the CSR, you can follow the same steps as described in the step # 2 of the previous section.
Step # 2: Get the certificate signed from public CA
Submit the CSR to your preferred public CA (should be supported by Salesforce) and get it signed.
Step # 3: Update the code to embed the certificate in the web service callout
Follow the same steps as described in the step # 5 of the previous section to update the wrapper class in Salesforce to include the certificate when making the web service callout.
Test it by updating the user’s status and you should see that it has made a web service callout with two-way authentication. And as described above, you don’t need to import the certificate into IBM WebSphere Cast Iron runtime appliance as the server can accept the certificate passed by the salesforce since it is signed by public CA.
Certificate generated from Salesforce
Salesforce provides the option to generate the Certificate from its platform and this is the suggested method by Salesforce. The biggest advantage is that the private key is not shared outside of the Salesforce and the caveat is that you will not be able to use this certificate from any other system, other than the Salesforce, since you cannot get the private key when you download the certificate from Salesforce. This section will also cover both the scenarios; self-signed certificates and certificate signed by public CA, but this time the Certificate is generated from the Salesforce.
Step # 1: Creating self-signed certificate the CSR for client
To generate the certificate from Salesforce, login into your Salesforce organization and click ‘Create Self-Signed Certificate’ under Setup->Security Controls (under Administration Setup)->Certificate and Key Management. Enter the information as below.
Figure 4e. Create self-signed certificate from Salesforce.
Click ‘Save’ and it should show you the screen as below.
Figure 4f. Self-signed certificate generated in Salesforce.
Step # 2: Update the code to reference the certificate in the web service callout
Since the certificate is now residing within Salesforce, we don’t need to embed the certificate in the web service callout; instead, we can just reference the certificate name in the code and Salesforce runtime automatically embeds the certificate in the callout. Update the UserStatusClient file on the Salesforce side by clicking ‘Edit’ against ‘UserStatusClient’ under Setup->Develop->Apex Classes
updateStatusInstance.clientCertName_x = 'Contoso_SF';
updateStatusInstance.clientCertPasswd_x = 'test';
Public CA Signed Certificates
Step # 1: Creating the CSR for client
To get the certificate signed by public CA that is generated from Salesforce, click ‘Create CA-Signed Certificate’ under Setup->Security Controls-> (under Administration Setup)->Certificate and Key Management. Enter the information as below.
Figure 4g. Create CSR from Salesforce.
Step # 2: Get the certificate signed from public CA and Upload to Salesforce
Download the CSR by clicking ‘Download Certificate Signing Request’ button and submit this CSR to your preferred public CA and get it signed. Once you receive the signed certificate, upload it by clicking ‘Upload Signed Certificate’ button.
Step # 3: Update the code to reference the certificate in the web service callout
This is similar as described in the previous section; i.e., since the certificate is residing within Salesforce, we don’t need to embed the certificate in the web service callout; instead, we can just reference the certificate name in the code and Salesforce runtime automatically embeds the certificate in the callout. Update the UserStatusClient file on the Salesforce side by clicking ‘Edit’ against ‘UserStatusClient’ under Setup->Develop->Apex Classes
updateStatusInstance.clientCertName_x = 'Contoso_SF_PCA';
updateStatusInstance.clientCertPasswd_x = 'test';
In this article, we saw how to make two-way authenticated calls using SSL/certificates including some of the fundamentals about the certificates and how they work. In Part-5, which is also the final piece of this article series, we will see some common issues and how to fix them.