4

I'm trying to work with Duo's python client (https://github.com/duosecurity/duo_client_python) and I believe I'm simply missing something with my novice python eyes. I somehow need to authenticate my requests to the API using an HMAC signature -- which I've not worked with before but seems trivial to generate (they even provide a python function). Doc here https://duo.com/docs/adminapi#authentication

I'm at a loss as to HOW to craft this signature for authentication, prior to passing my request to the API. From https://duo.com/docs/adminapi#authentication:

The API uses HTTP Basic Authentication to authenticate requests. Use your >Duo application’s integration key as the HTTP Username.

Generate the HTTP Password as an HMAC signature of the request. This will >be different for each request and must be re-generated each time.

It then goes into which parameters are added and necessary for the HMAC signature to be generated properly. I understand this part. My issue is how and when to pass the HMAC signature that I generate. As the Duo doc doesn't specifically go into that, I'm thinking that this is something I should already know [were I not such a python novice].

For example, simple auth calls work fine (as they need no authentication):

root@box:~# python -m duo_client.client --ikey XXXXXXXX --skey XXXXXXXX --host XXXXXXXX.duosecurity.com --method GET --path /auth/v2/check 200 OK
{
"response":
{ "time": 1496437236 }
,
"stat": "OK"
}

However, calls using admin require authentication, and thus fail with:

root@box:~# python -m duo_client.client --ikey XXXXXXXX --skey XXXXXXXX --host XXXXXXXX.duosecurity.com --method GET --path /admin/v1/users signature=XXXXXXXX
401 Unauthorized
{
    "code": 40103,
    "message": "Invalid signature in request credentials",
    "stat": "FAIL"
}

Thanks in advance for any insight!

==EDIT==

So I thought I'd post the function that Duo provide for creating the signature, which appears similar to what is happening in the StackOverflow question I found that I thought might help (Python, HTTPS GET with basic authentication). From https://duo.com/docs/adminapi#authentication:

def sign(method, host, path, params, skey, ikey):
    """
    Return HTTP Basic Authentication ("Authorization" and "Date") headers.
    method, host, path: strings from request
    params: dict of request parameters
    skey: secret key
    ikey: integration key
    """

    # create canonical string
    now = email.Utils.formatdate()
    canon = [now, method.upper(), host.lower(), path]
    args = []
    for key in sorted(params.keys()):
        val = params[key]
        if isinstance(val, unicode):
            val = val.encode("utf-8")
        args.append(
            '%s=%s' % (urllib.quote(key, '~'), urllib.quote(val, '~')))
    canon.append('&'.join(args))
    canon = '\n'.join(canon)

    # sign canonical string
    sig = hmac.new(skey, canon, hashlib.sha1)
    auth = '%s:%s' % (ikey, sig.hexdigest())

    # return headers
    return {'Date': now, 'Authorization': 'Basic %s' % base64.b64encode(auth)}

I've used the above function in a simple script to print out (just so I can visualize) what should be getting passed within the script I'll create to server our needs -- I added the function to a script and used print by adding the following:

# Printing Signature Headers ### TESTING ###
print sign('GET', 'XXXhostXXX', '/admin/v1/users', 'XXXparamXXX', 'XXXskeyXXX', 'XXXXikeyXXXX')

However, I'm getting this error:

root@box:~# ./duo.py
Traceback (most recent call last):
  File "./duo.py", line 39, in 
    print sign('GET', 'XXXhostXXX', '/admin/v1/users', 'XXXparamXXX', 'XXXskeyXXX', 'XXXikeyXXX')
  File "./duo.py", line 18, in sign
    for key in sorted(params.keys()):
AttributeError: 'str' object has no attribute 'keys'

Am I just missing something here? I've been looking for what could cause that error but I thought I'd ask here as well.

Andre Goree
  • 73
  • 1
  • 6
  • Found some things that should help me along the way -- namely, the second answer here: https://stackoverflow.com/questions/6999565/python-https-get-with-basic-authentication – Andre Goree Jun 05 '17 at 18:22

1 Answers1

1

This was an "issue" on Duo's side...wrong skey was being used and my user did not have the proper access.

Andre Goree
  • 73
  • 1
  • 6