4

I'm am trying to drop messages into an Azure message queue from Salesforce with apex. I started with a basic c# console app to understand the REST API in Azure and was able to get it to work as expected. As I began reproducing the same thing in Salesforce, I have come across an issue that I can't seem to get figured out. I am producing the HttpRequest object and contacting Azure successfully but receiving a 403 error. I have verified that the signed signature is being created exactly as it is in the console app (verified the results return from both) but still getting the same issue. Can anyone put another set of eyes against this anonymous block and see if I am doing something horribly wrong? (names have been changed to protect the innocents)

    string storageKey = 'removedforprivacy';

    Datetime dt = Datetime.now();
    string formattedDate = dt.formatGMT('EEE, dd MMM yyyy HH:mm:ss') + ' UTC';
    string stringToSign = 'POST\n\napplication/xml\n\nx-ms-date:' + formattedDate + '\n' +
                                      '/myqueue/testqueue/messages';

    // Sign the request
    Blob temp = EncodingUtil.base64Decode(storageKey);
    Blob hmac = Crypto.generateMac('HMacSHA256', Blob.valueOf(stringToSign), temp);
    string signature = EncodingUtil.base64Encode(hmac);
    Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign))));

    // This ends up being the exact same as the console app
    system.debug('SIGNATURE==>SharedKey myqueue:' + signature);

    HttpRequest req = new HttpRequest();
    req.setMethod('POST');
    req.setHeader('content-type', 'application/xml');
    req.setHeader('x-ms-date', formattedDate);
    string authHeader = 'SharedKey myqueue:' + signature;
    req.setHeader('Authorization', authHeader);

    req.setEndpoint('https://myqueue.queue.core.windows.net/testqueue/messages');

    req.setBody('<QueueMessage><MessageText>' + EncodingUtil.base64Encode(Blob.valueOf('This is a test from salesforce')) + '</MessageText></QueueMessage>');

    system.debug(req);

    Http http = new Http();

    try
    {
        HTTPResponse res = http.send(req);

        system.debug(res.toString());
        system.debug(res.getStatus());
        system.debug(res.getStatusCode());

    }
    catch (system.CalloutException ce)
    {
        system.debug(ce);
    }
4
  • The 403 error suggests "that the server can be reached and understood the request, but refuses to take any further action. Status code 403 responses are the result of the web server being configured to deny access, for some reason, to the requested resource by the client.". The body of the request may provide more information as to why it gave the error.
    – BarCotter
    Oct 7 '14 at 15:43
  • Is there a way to get the request in Salesforce? Oct 7 '14 at 19:31
  • I assume you mean the response rather than the request. System.debug(res.getBody()); will print out the body of the response.
    – BarCotter
    Oct 8 '14 at 8:55
  • actually I was talking about the request. I think that if I could see the request that is being sent (like is visible in fiddler on the local pc) I could debug this more successfully. I already know what the response is as the call out exception is actually printing out that information. which by the way is 'Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.' This is the part I am having issues with as the authorization header is exactly the same as the console app that works. Oct 8 '14 at 14:15
2

So I finally figured out the issue after manually building the request outside of Salesforce. The datetime needs to be GMT not UTC. After fixing that slight oversight, this pumps messages onto the queue as expected.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.