Created
December 10, 2016 22:24
-
-
Save nderkach/663532a8ffc83b02b022b9672ecdc0fd to your computer and use it in GitHub Desktop.
MAC Access Authentication example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
from binascii import b2a_base64 | |
import hashlib | |
import hmac | |
try: | |
from urlparse import urlparse | |
except ImportError: | |
from urllib.parse import urlparse | |
from oauthlib.common import add_params_to_uri, add_params_to_qs, unicode_type | |
from oauthlib import common | |
from oauthlib.oauth2.rfc6749 import utils | |
def prepare_mac_header(token, uri, key, http_method, | |
nonce=None, | |
headers=None, | |
body=None, | |
ext='', | |
hash_algorithm='hmac-sha-1', | |
issue_time=None, | |
draft=0): | |
"""Add an `MAC Access Authentication`_ signature to headers. | |
Unlike OAuth 1, this HMAC signature does not require inclusion of the | |
request payload/body, neither does it use a combination of client_secret | |
and token_secret but rather a mac_key provided together with the access | |
token. | |
Currently two algorithms are supported, "hmac-sha-1" and "hmac-sha-256", | |
`extension algorithms`_ are not supported. | |
Example MAC Authorization header, linebreaks added for clarity | |
Authorization: MAC id="h480djs93hd8", | |
nonce="1336363200:dj83hs9s", | |
mac="bhCQXTVyfj5cmA9uKkPFx1zeOXM=" | |
.. _`MAC Access Authentication`: http://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01 | |
.. _`extension algorithms`: http://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01#section-7.1 | |
:param uri: Request URI. | |
:param headers: Request headers as a dictionary. | |
:param http_method: HTTP Request method. | |
:param key: MAC given provided by token endpoint. | |
:param hash_algorithm: HMAC algorithm provided by token endpoint. | |
:param issue_time: Time when the MAC credentials were issued (datetime). | |
:param draft: MAC authentication specification version. | |
:return: headers dictionary with the authorization field added. | |
""" | |
http_method = http_method.upper() | |
host, port = utils.host_from_uri(uri) | |
if hash_algorithm.lower() == 'hmac-sha-1': | |
h = hashlib.sha1 | |
elif hash_algorithm.lower() == 'hmac-sha-256': | |
h = hashlib.sha256 | |
else: | |
raise ValueError('unknown hash algorithm') | |
if draft == 0: | |
nonce = nonce or '{0}:{1}'.format(utils.generate_age(issue_time), | |
common.generate_nonce()) | |
else: | |
pass | |
# ts = common.generate_timestamp() | |
# nonce = common.generate_nonce() | |
sch, net, path, par, query, fra = urlparse(uri) | |
if query: | |
request_uri = path + '?' + query | |
else: | |
request_uri = path | |
# Hash the body/payload | |
if body is not None and draft == 0: | |
body = body.encode('utf-8') | |
bodyhash = b2a_base64(h(body).digest())[:-1].decode('utf-8') | |
else: | |
bodyhash = '' | |
# Create the normalized base string | |
base = [] | |
if draft == 0: | |
base.append(nonce) | |
else: | |
base.append(ts) | |
base.append(nonce) | |
base.append(http_method.upper()) | |
base.append(request_uri) | |
base.append(host) | |
base.append(port) | |
if draft == 0: | |
base.append(bodyhash) | |
base.append(ext or '') | |
base_string = '\n'.join(base) + '\n' | |
print(base_string) | |
# hmac struggles with unicode strings - http://bugs.python.org/issue5285 | |
if isinstance(key, unicode_type): | |
key = key.encode('utf-8') | |
sign = hmac.new(key, base_string.encode('utf-8'), h) | |
sign = b2a_base64(sign.digest())[:-1].decode('utf-8') | |
header = [] | |
header.append('MAC id="%s"' % token) | |
if draft != 0: | |
header.append('ts="%s"' % ts) | |
header.append('nonce="%s"' % nonce) | |
if bodyhash: | |
header.append('bodyhash="%s"' % bodyhash) | |
if ext: | |
header.append('ext="%s"' % ext) | |
header.append('mac="%s"' % sign) | |
headers = headers or {} | |
headers['Authorization'] = ', '.join(header) | |
return headers | |
token = "h480djs93hd8" | |
key = "489dks293j39" | |
alg = "hmac-sha-1" | |
ts = "1336363200" | |
nonce = "dj83hs9s" | |
uri = "http://example.com/resource/1?b=1&a=2" | |
h = prepare_mac_header(key=key, uri=uri, nonce=nonce, issue_time=ts, token=token, http_method="GET", draft=1, hash_algorithm=alg) | |
print(h) | |
# Result: mac="6T3zZzy2Emppni6bzL7kdRxUWL4=" | |
# Expected: mac="bhCQXTVyfj5cmA9uKkPFx1zeOXM=" (https://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01#section-1.1) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment