Recently when visiting a customer, they were wanting a custom policy that could be used to do HMAC validation of payloads.

In brief HMAC is a tool to verify a payload programmatically. When the payload is passed it a signature is attached, in this case in a header. The HMAC algorithm then uses a secret key to generate the digest and that is compared against the signature passed.

For more information please see [HMAC on Wikipedia](https://en.wikipedia.org/wiki/HMAC#:~:text=In%20cryptography%2C%20an%20HMAC%20(sometimes,and%20a%20secret%20cryptographic%20key.)

The following global policy can be attached to a prehook rule. If the verb is a Put Post Patch it will get the signature and run a check over the payload being passed in. They key is hard coded into the policy.  

global-policy: 1.0.0

info:
  title: HMAC-Validate
  name: hmac
  version: 1.0.0
  description: HMAC Validate on incoming request
  contact:
    name: Chris Phillips
    url: 'https://github.com/ibm-datapower/'
    email: chris.phillips@uk.ibm.com
gateways:
  - datapower-api-gateway
assembly:
  execute:
  - switch:
      version: 2.0.0
      title: switch
      case:
        - condition: >-
            ($httpVerb() = 'PUT' or $httpVerb() = 'POST' or $httpVerb() =
            'PATCH')
          execute:
            - parse:
                version: 2.1.0
                title: parse
                parse-settings-reference:
                  default: apic-default-parsesettings
            - gatewayscript:
                version: 2.0.0
                title: gatewayscript
                source: >-
                  var crypto = require("crypto");


                  var key =
                  "gyvgjwoyvzlurvzbpxjtipuolxxbozwaaxohgalsxmygdbjwdbquoviwylekmehojktolimcvaxddfiwgwkpphochqzgzjqvxtkqbznnkwadcrjrqqhmhdmuvzzicisvlahgkxotpqkwadlizbsneqnytkzgutxd"


                  var hmac = crypto.createHmac("hmac-sha1", new Buffer(key)
                  );

                  var result = hmac.update(new
                  Buffer(context.get('message.body'))).digest('base64');


                  if (result != context.get("message.headers.X-Signature"))
                  {
                      console.error('HMAC mismatch got ',result,'expected',context.get("message.headers.X-Signature"))
                      throw new Error()
                  }

This can be applied with the following shell commands

  apic global-policies:create --catalog sandbox --configured-gateway-service fwd --org demo --server small-mgmt-api-manager-apic-v10.mycluster-lon02-m3c-8x64-420eb34f056ae68f3969289d61f61851-0000.eu-gb.containers.appdomain.cloud  --scope catalog gpolicy.yaml
  apic global-policies:get --catalog sandbox --configured-gateway-service fwd --org demo --server small-mgmt-api-manager-apic-v10.mycluster-lon02-m3c-8x64-420eb34f056ae68f3969289d61f61851-0000.eu-gb.containers.appdomain.cloud  --scope catalog hmac:1.0.0 --fields url
  sed -i'e' s/url\:/global_policy_url\:/ GlobalPolicy.yaml
  apic global-policy-prehooks:create --catalog sandbox --configured-gateway-service fwd --org demo --server small-mgmt-api-manager-apic-v10.mycluster-lon02-m3c-8x64-420eb34f056ae68f3969289d61f61851-0000.eu-gb.containers.appdomain.cloud  --scope catalog GlobalPolicy.yaml

Of course it may not be suitable to do this for all APIs. The custom policy below has the same function and it can be dragged onto the API Canvas only where desired.

policy: 1.0.0
info:
  title: HMAC-Validation
  name: hmac-policy
  version: 1.0.0
  description: Validate the payload if its a put post or patch request.
  contact:
    name: Chris Phillips
    url: 'https://github.com/ibm-datapower/'
    email: chris.phillips@uk.ibm.com
attach:
  - rest
  - soap
gateways:
  - datapower-api-gateway
assembly:
  execute:
  - switch:
      version: 2.0.0
      title: switch
      case:
        - condition: >-
            ($httpVerb() = 'PUT' or $httpVerb() = 'POST' or $httpVerb() =
            'PATCH')
          execute:
            - parse:
                version: 2.1.0
                title: parse
                parse-settings-reference:
                  default: apic-default-parsesettings
            - gatewayscript:
                version: 2.0.0
                title: gatewayscript
                source: >-
                  var crypto = require("crypto");


                  var key =
                  "gyvgjwoyvzlurvzbpxjtipuolxxbozwaaxohgalsxmygdbjwdbquoviwylekmehojktolimcvaxddfiwgwkpphochqzgzjqvxtkqbznnkwadcrjrqqhmhdmuvzzicisvlahgkxotpqkwadlizbsneqnytkzgutxd"


                  var hmac = crypto.createHmac("hmac-sha1", new Buffer(key)
                  );

                  var result = hmac.update(new
                  Buffer(context.get('message.body'))).digest('base64');


                  if (result != context.get("message.headers.X-Signature"))
                  {
                      console.error('HMAC mismatch got ',result,'expected',context.get("message.headers.X-Signature"))
                      throw new Error()
                  }

This can be applied by the following script

zip hmac-policy.zip policy.yaml
apic policies:create -s small-mgmt-api-manager-apic-v10.mycluster-lon02-m3c-8x64-420eb34f056ae68f3969289d61f61851-0000.eu-gb.containers.appdomain.cloud  --scope catalog -c sandbox -o demo ./hmac-policy.zip --configured-gateway-service fwd