-1

I have a short CURL script that I'm trying to convert to Python, but I'm having a decent amount of trouble doing so. I'm targeting an API that requires an auth string that is formatted <public_key>.<sha256 hmac of url and body>.

My legacy setup is a simple PHP script that generates the hmac and runs a CURL command with the output. I'm trying to port this over to Python for a separate project.


Legacy code:

hmac.php

<?php

$public = 'PUBLIC_KEY';
$private = 'PRIVATE_KEY';

$url = $argv[1];
$body = $argv[2];

$hmac = hash_hmac('sha256', $url . $body, $private, true);

print($public . '.' . base64_encode($hmac));

Example command:

$ DATA='{"command": "say Just testing the API, ignore this..."}'
$ URL='https://website.url/api/user/<UUID>/command'
$ curl -X POST -d $DATA -H "Content-Type: application/json" -H "Authorization: Bearer $(php hmac.php $URL $DATA)" --url $URL

The Python Port

So far, I've figured out how to create the correct hmac digest for GET requests, but I'm having trouble with the POST requests I detailed above.

send_command.py:

def generate_bearer(pubkey, privkey, url, body):
    h = hmac.new(privkey.encode('utf8'), (url + body).encode('utf8'), sha256)
    encoded = b64encode(h.digest())
    return pubkey + '.' + encoded.decode('utf-8')

def send_command(server, command):
    target = '{}/server/{}/command'.format(url, server)
    data = {'command': command}

    bearer = generate_bearer(public, private, target, str(data))
    headers = {'Authorization': 'Bearer {}'.format(bearer),
               'content-type': 'application/json'}

    r = requests.post(target, headers=headers, data=data)

if __name__ == '__main__':
    print(send_command('<UUID>', 'say Just testing the API, ignore this...'))

As far as I can tell, I need to pass the full JSON string both to generate_bearer() and as the data I'm POSTing in the request. However, with this current code, I get the error "The HMAC for the request was invalid." What am I doing wrong here?

3 Answers 3

1

It's very hard to tell from what you're describing what the problem might be. Is this API publicly available so others can test and be of better help?

I was comparing the PHP vs Python code and noticed that the URL you do not follow the same pattern:

but again is very hard to tell since the examples are incomplete or out of context.

Sign up to request clarification or add additional context in comments.

1 Comment

The API is publicly available, but not very well documented here. The output of that formatted python string is identical to the PHP script, i.e. https://website.url/api/user/<UUID>/command, just using function parameters.
0

After a little bit of experimentation, I figured it out. When passing my data dict to the hashing function, I was using str(data). I switched to json.dumps(data) for both the hash and the request, and everything now works properly.

The new code looks like this:

def send_command(server, command):
    target = '{}/server/{}/command'.format(url, server)
    d = {'command': command}

    bearer = generate_bearer(public, private, target, json.dumps(d))
    h = {'Authorization': 'Bearer {}'.format(bearer),
         'content-type': 'application/json'}

    r = requests.post(target, headers=h, data=json.dumps(d))

    return r.text

Comments

0

I took the example here and converted it to Python like this:

import hmac
import hashlib
import base64

public = 'JkAFq7M47kLN0xVD';
private = 'E6X9FyZvMFeJbqtq.IwjlTuR.MKDoicB';

url = 'http://pterodactyl.app/api/admin/users';
body = '';

dig = hmac.new(private, msg='{}{}'.format(url, body), digestmod=hashlib.sha256).digest()

print '{}.{}'.format(public,  base64.b64encode(dig).decode()),

which returns the same output as the PHP code: JkAFq7M47kLN0xVD.wgIxj+V8RHgIetcQg2lRM0PRSH/y5M21cPz9zVhfFaQ

1 Comment

The Python code is coming from this: stackoverflow.com/questions/1306550/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.