Search code examples
pythondatabrickshmac

Databricks Model Registry Webhook HMAC verification not working


Databricks Model Registry lets you create webhooks to react to events. You can use HMAC to verify the message sent by the webhook. This is the Python example code from the Databricks documentation.

import hmac
import hashlib
import json

secret = shared_secret.encode('utf-8')
signature_key = 'X-Databricks-Signature'

def validate_signature(request):
    if not request.headers.has_key(signature_key):
        raise Exception('No X-Signature. Webhook not be trusted.')

    x_sig = request.headers.get(signature_key)
    body = request.body.encode('utf-8')
    h = hmac.new(secret, body, hashlib.sha256)
    computed_sig = h.hexdigest()

    if not hmac.compare_digest(computed_sig, x_sig.encode()):
        raise Exception('X-Signature mismatch. Webhook not be trusted.')

I tried changing computed_sig = h.hexdigest() for computed_sig = h.digest() but it still doesn't work.


Solution

  • Well, after some struggling I've figured it out. It turns out that the HMAC signature that is received is in hexadecimal format (I should have realized it at once as :)) and we need to convert it to bytes like this bytes.fromhex(x_sig). We also need to use digest() instead of hexdigest(). And now it works. This is the updated version:

    import hmac
    import hashlib
    
    
    secret = shared_secret.encode('utf-8')
    signature_key = 'X-Databricks-Signature'
    
    
    def validate_signature_1(request):
        if signature_key not in request['headers']:
            raise Exception('No X-Signature. Webhook not be trusted.')
    
        x_sig = request['headers'].get(signature_key)
        body = request['body'].encode('utf-8')
        h = hmac.new(secret, body, hashlib.sha256)
        computed_sig = h.digest()
    
        if not hmac.compare_digest(computed_sig, bytes.fromhex(x_sig)):
            raise Exception('X-Signature mismatch. Webhook not be trusted.')
    

    Note that I've made some minor arrangements to other parts of the code.

    I'm not going to delete this question just in case some one come across the same problem.