HMAC Examples in API Connect
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