i am following the canvas app documentation to verify a signed request before using the parameters i am passing in the canvas app request. The canvas app is embedding a third party app in salesforce.
From documentation:
- Receive the POST message that contains the initial signed request from
Salesforce.- Split the signed request on the first period. The result is two strings: the hashed Based64 context signed with the consumer secret
and the Base64 encoded context itself.- Use the HMAC SHA-256 algorithm to hash the Base64 encoded context and sign it using your consumer secret.
- Base64 encode the string created in the previous step.
5.Compare the Base64 encoded string with the hashed Base64 context signed with the consumer secret you received in step 2.
I followed the below instructions
For step 1
Map<String, String> pageParams = ApexPages.currentPage().getParameters();
String sSignedReq = pageParams.get('signed_request');
For step 2:
List<String> outputval = sSignedReq.split('\\.');
For step 3:
Blob encodedEnvelopeHash = Crypto.generateDigest('SHA-256', Blob.valueOf(outputval[1]));
String Privatekey = 'XXX';
blob signedvalue = Crypto.sign('RSA-SHA256', encodedEnvelopeHash, encodingutil.base64Decode(Privatekey));
I used open ssl to generate private key(PKCS8 format) for using it in crypto sign function
Link here:
Relevant code:
// Generate your own certificate - subject information is redacted
openssl req -x509 -nodes -subj "/C=XX/ST=XXX/L=XXX/CN=www.xxx.com" -days 365 -newkey rsa:1024 -keyout key.pem -out cert.pem
// Output the private key onto the terminal in PKCS#8 format
openssl pkcs8 -topk8 -nocrypt -in key.pem -outform PEM
For step 4:
String finalouput = EncodingUtil.base64Encode(signedvalue);
In step 5 i am doing a comparison and the 2 strings are never the same.
if(outputval[0] == finalouput)
system.debug('datamatchingok');
else
system.debug('datanotmatchingok');
What am i doing wrong? and how do i use consumer secret for verifying the signed request. Step 3 of documentation says we need to use that but i wasn't able to wrap my head around the documentation to understand where to use it?
Best Answer
Here is a step-by-step click path to create a Salesforce Canvas App that uses a POSTed Signed Request to a Visualforce Page with an Apex Controller (and the Apex Controller successfully validates the Signed Request).
Note that in practice, I have always had Canvas Apps pointing to external platforms such as Heroku Express/Node, Java or Ruby. So I typically do the signed request validation in another language (e.g. javascript in Node.js). But to answer your specific question, I have included sample code for Visualforce and Apex and we will be validating the signed request using pure Apex. Also note that you do NOT need your own self-signed certificate or any use of openssl.
Here you go... this exercise will take about 15-30 minutes to complete. Let me know if you have any issue or questions and I'll see if I can assist further.
Step 1 (use Classic)
Step 2 (create and configure a new Canvas Connected App) -
Create -> Apps -> New Connected App
Connected App Details for "Canvas Test"
Create -> Apps -> Connected Apps
Step 3 (create an Apex controller)
Apex
Step 4 (create a Visualforce page) - File -> New -> Visualforce Page - Name: canvas_page - Code:
Visualforce
Step 5 (preview the Canvas App and the parameters) - Setup -> App Setup -> Canvas App Previewer - Click on "Canvas Test" - You should see the Canvas App delivering a successfully verfied signed request in this format:
JSON context data structure sent with Canvas Signed Request
Cheers,
Bryan Isbell
Salesforce Certified Technical Architect, CISSP