Azure Service Bus through APIM and generating a SAS Token

On one of my recent projects, a client application was required to place a message onto an Azure Service Bus using an HTTP endpoint rather than the Service Bus SDK and with the following constraints.

  • The client is unable to generate the Service Bus SAS token.
  • Service Bus Session Id needs to be set to the customer number found in the message to ensure ordered delivery by the consumer.
  • Custom HTTP Request Headers may be used.

I decided upon a solution that uses Azure APIM to expose the Service Bus endpoint.

  1. The first step of this solution is to create an Azure Service Bus with a queue called 'apimqueue'.

Please refer below screenshot.

Azure Service Bus through APIM and generating a SAS Token

Azure Service Bus through APIM and generating a SAS Token

2. Next, click on created queue, navigate to Shared access policy, and add' apimqueuesend' with only Send claim.

Azure Service Bus through APIM and generating a SAS Token

Azure Service Bus through APIM and generating a SAS Token

3. Click on created shared access policies and copy the primary key for further use.

Azure Service Bus through APIM and generating a SAS Token

4. Next is to create an API using the 'Blank API' template, similar to what I have done below. Note the 'Web service URL' value is the base address of the Service Bus topic URL.

Azure Service Bus through APIM and generating a SAS Token

5. Enter the Name, give your service bus's web service URL, and click on create.

Azure Service Bus through APIM and generating a SAS Token

6. Add operation based on your request, like Post, and Get Methods.

Azure Service Bus through APIM and generating a SAS Token

Refer below screen after the created operation.

Azure Service Bus through APIM and generating a SAS Token

7. Next step is to add policies to added operation.

Azure Service Bus through APIM and generating a SAS Token

8. Add the below policy as shown in the above screen.

<policies>
    <inbound>
        <base />
        <cache-lookup-value key="apimqueuesend" variable-name="apimqueuesend" />
        <choose>
            <when condition="@(context.Variables.GetValueOrDefault&lt;string>("apimqueuesend") == null)">
                <cache-store-value key="crmsbsas" value="@{
                        string resourceUri = "https://dwproject.servicebus.windows.net/apimqueue";
                        string keyName = "apimqueuesend";
                        string key = "saskey";
                        TimeSpan sinceEpoch = DateTime.UtcNow - new DateTime(1970, 1, 1);
                        var expiry = Convert.ToString((int)sinceEpoch.TotalSeconds + 120);
                        string stringToSign = System.Uri.EscapeDataString(resourceUri) + "\n" + expiry;
                        HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes(key));
                        var signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
                        var sasToken = String.Format("SharedAccessSignature sr={0}&amp;sig={1}&amp;se={2}&amp;skn={3}",
                                        System.Uri.EscapeDataString(resourceUri),
                                        System.Uri.EscapeDataString(signature), expiry, keyName);
                        return sasToken;
                    }" duration="10" />
                <cache-lookup-value key="apimqueuesend" variable-name="apimqueuesend" />
            </when>
        </choose>
        <set-backend-service base-url="https://dwproject.servicebus.windows.net" />
        <rewrite-uri template="apimqueue/messages" />
        <set-header name="Content-Type" exists-action="override">
            <value>vnd.microsoft.servicebus.yml</value>
        </set-header>
        <set-header name="Authorization" exists-action="override">
            <value>{{apimqueuesend}}</value>
        </set-header>
        <set-header name="BrokerProperties" exists-action="override">
            <value>@{
                    var json = new JObject();
                    json.Add("MessageId", context.RequestId);
                    return json.ToString(Newtonsoft.Json.Formatting.None);
                }</value>
        </set-header>
        <set-body>@{
                JObject json = context.Request.Body.As<JObject>(preserveContent: true);
                return JsonConvert.SerializeObject(json);
            }</set-body>
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <base />
    </outbound>
    <on-error>
        <base />
        <return-response>
            <set-status code="200" reason="OK" />
        </return-response>
    </on-error>
</policies>

9. To test added policy, please navigate to test in the APIM section. Please give the required headers and JSON data and click on send.

Azure Service Bus through APIM and generating a SAS Token

Azure Service Bus through APIM and generating a SAS Token

​​​​​​​10. Finally, Navigate to our queue and check whether the message has been received.

Azure Service Bus through APIM and generating a SAS Token