Search code examples
pythonpython-requestshttp-headershmacsha1

Create a HMAC-SHA1 base 64 signature for API get request


I am trying to get a requests.get to print from a web site and it needs a signature. From what I read on the website it says that it needs to take my secret key and make a signature out of it using HMAC-SHA1 base 64.

I know I need to import hmac into my Python script but other than that I am not sure if my signature will be what the web site is looking for.

This is a link to how the authentication is suppose to be setup: https://www.ninjarmm.com/dev-api/#the_authentication_header

On the web site it gives an example of how the signature should be but I don't know how to apply this in Python:

### How do I apply this in my python script's header?
Signature = Base64( HMAC-SHA1( YourSecretAccessKeyID, Base64( UTF-8- Encoding-Of( StringToSign ) ) ) ); StringToSign = HTTP-Verb + "n" + Content-MD5 + "n" + Content-Type + "n" + Date + "n" + CanonicalizedResource;
### How do I apply this in my python script's header?

Here is my Code:

import requests
import os
import json
from datetime import date
from email.utils import formatdate

ninjaapi = "some data"
ninjasak = "some data"
ninjaurl = "https://api.ninjarmm.com/v1/devices"

ninjaheaders = {"authorization":ninjaapi + ninjasak, "Date":now,}
ninjastatusresponse = requests.get(ninjaurl, headers=ninjaheaders) 
ninja_json = ninjastatusresponse.json()
print(ninja_json)

Here are the results I get so far:

{'error': 'invalid_header', 'error_description': "Invalid 'Authorization' header", 'error_code': 1}

If anyone has any ideas that I can test let me know!


Solution

  • So I found out there was a nice person who made a module package for everything already. I used his code in my program and it worked for building the signature.

    Its called ninjarmm_api; here is the link: https://bitbucket.org/raptus-it/py-ninjarmm-api-client/src/master/ninjarmm_api/

    Here is the link from the ninjadojo community. https://ninjarmm.zendesk.com/hc/en-us/community/posts/360037165831-Python-client-library-for-API

    Specifically, here is the code for the his auth.py which is what I was trying to figure out how to do.

    from requests.auth import AuthBase
    from email.utils import formatdate
    
    import base64
    import hmac
    import hashlib
    
    class auth(AuthBase):
    
        NINJA_HDR_AUTH = "Authorization"
        NINJA_HDR_DATE = "Date"
        NINJA_ENCODING = "utf-8"
    
    
        def __init__(self, accessKeyId, secretAccessKey):
            self.access_key_id = accessKeyId
            self.secret_access_key = secretAccessKey
            self.tstamp = formatdate(timeval=None, localtime=False, usegmt=True)
    
    
        def __call__(self, request):
            sts_clear = request.method + "\n"             # HTTP verb
            sts_clear += "\n"                             # Content MD5
            sts_clear += "\n"                             # Content type
            sts_clear += self.tstamp + "\n"               # Date
            sts_clear += request.path_url                 # Canonicalized resource
    
            sts_base64 = base64.b64encode(sts_clear.encode(self.NINJA_ENCODING))
            sts_digest = hmac.new(self.secret_access_key.encode(self.NINJA_ENCODING), sts_base64, hashlib.sha1)
            signature = base64.b64encode(sts_digest.digest())
    
            request.headers[self.NINJA_HDR_AUTH] = "NJ " + self.access_key_id + ":" + signature.decode(self.NINJA_ENCODING)
            request.headers[self.NINJA_HDR_DATE] = self.tstamp
            return request