Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@st4lk
Created May 15, 2015 20:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save st4lk/314e181faaea7d671d0e to your computer and use it in GitHub Desktop.
Save st4lk/314e181faaea7d671d0e to your computer and use it in GitHub Desktop.
"""
Example of OAuth 1.0a 3-legged standard process from the client side.
API of bitbucket is used: https://confluence.atlassian.com/display/BITBUCKET/OAuth+on+Bitbucket
"""
import random
import time
from urlparse import parse_qsl, urlparse
from urllib import quote, urlencode
import urllib2
import binascii
import hashlib
import hmac
import webbrowser
# Constants given by service provider
CONSUMER_KEY = 'your_app_key'
CONSUMER_SECRET = 'your_app_secret'
REQUEST_TOKEN_URL = 'https://bitbucket.org/api/1.0/oauth/request_token'
AUTHORIZE_URL = 'https://bitbucket.org/api/1.0/oauth/authenticate'
ACCESS_TOKEN_URL = 'https://bitbucket.org/api/1.0/oauth/access_token'
# Values that choose client application
CALL_BACK = 'http://127.0.0.1/oauth1_callback'
API_RESOURCE_URL = 'https://api.bitbucket.org/1.0/repositories/st4lk/django-articles-transmeta/branches'
# Helpful functions
q = lambda x: quote(x, safe="~")
get_timestamp = lambda: int(time.time())
get_nonce = lambda: str(str(random.getrandbits(64)) + str(get_timestamp()))
def get_sign(params, url, http_method, oauth_token_secret=""):
"""returns HMAC-SHA1 sign"""
params.sort()
normalized_params = urlencode(params)
base_string = "&".join((http_method, q(url), q(normalized_params)))
sig = hmac.new("&".join([CONSUMER_SECRET, oauth_token_secret]), base_string, hashlib.sha1)
return binascii.b2a_base64(sig.digest())[:-1]
# Start oauth 1.0 3-legged process
#######################
# STEP 1: request token
#######################
# oauth_signature_method choices: ("HMAC-SHA1", "RSA-SHA1", "PLAINTEXT")
# we use "HMAC-SHA1"
params_request_token = [
('oauth_consumer_key', CONSUMER_KEY),
('oauth_nonce', get_nonce()),
('oauth_signature_method', "HMAC-SHA1"),
('oauth_timestamp', get_timestamp()),
('oauth_callback', CALL_BACK),
('oauth_version', '1.0'),
]
# signature
signature = get_sign(params_request_token, REQUEST_TOKEN_URL, "POST")
params_request_token.append(('oauth_signature', signature))
# params can be included in ("HTTP headers", "HTTP body", "HTTP query")
# we use query
# POST https://bitbucket.org/api/1.0/oauth/request_token?
# oauth_callback=http%3A%2F%2F127.0.0.1%2Foauth1_callback&
# oauth_consumer_key=your_app_key&
# oauth_nonce=27718007815082439851427366369&
# oauth_signature_method=HMAC-SHA1&
# oauth_timestamp=1427366369&
# oauth_version=1.0&
# oauth_signature=KbLt0XDVjljXhMJHmmpWxHkFnfs%3D
url = "?".join((REQUEST_TOKEN_URL, urlencode(params_request_token)))
resp = urllib2.urlopen(urllib2.Request(url, data=[]))
assert resp.code == 200
resp_content = dict(parse_qsl(resp.read()))
request_token, request_token_secret = resp_content['oauth_token'], resp_content['oauth_token_secret']
###########################
# STEP 2: user confirmation
###########################
user_confirm_url = "{0}?oauth_token={1}".format(AUTHORIZE_URL, request_token)
webbrowser.open_new_tab(user_confirm_url)
redirected_url = raw_input("Paste here url you were redirected:\n")
# we get back something like
# http://127.0.0.1/oauth1_callback?oauth_verifier=9994919128&oauth_token=PQYAJCBVtzSpWjc9fH
verifier = dict(parse_qsl(urlparse(redirected_url).query))['oauth_verifier']
######################
# STEP 3: access token
######################
# Note a verifier here
params_access_token = [
('oauth_consumer_key', CONSUMER_KEY),
('oauth_token', request_token),
('oauth_nonce', get_nonce()),
('oauth_signature_method', "HMAC-SHA1"),
('oauth_timestamp', get_timestamp()),
('oauth_verifier', verifier),
('oauth_version', '1.0'),
]
# signature
# Note, that signature now includes request_token_secret
signature = get_sign(params_access_token, ACCESS_TOKEN_URL, "POST", request_token_secret)
params_access_token.append(('oauth_signature', signature))
# POST https://bitbucket.org/api/1.0/oauth/access_token?
# oauth_consumer_key=your_app_key&
# oauth_nonce=79726261759143643421427366924&
# oauth_signature_method=HMAC-SHA1&
# oauth_timestamp=1427366924&
# oauth_token=buEh26qBrMPfC4n8ta&
# oauth_verifier=7577782189&
# oauth_version=1.0&
# oauth_signature=3ehn%2B0AEyZ1xdnmVnOaWyx9X5m4%3D
url = "?".join((ACCESS_TOKEN_URL, urlencode(params_access_token)))
resp = urllib2.urlopen(urllib2.Request(url, data=[]))
assert resp.code == 200
resp_content = dict(parse_qsl(resp.read()))
access_token, access_token_secret = resp_content['oauth_token'], resp_content['oauth_token_secret']
####################################
# STEP 4: request to server resource
####################################
params_confirmed_access_token = [
('oauth_consumer_key', CONSUMER_KEY),
('oauth_token', access_token),
('oauth_nonce', get_nonce()),
('oauth_signature_method', "HMAC-SHA1"),
('oauth_timestamp', get_timestamp()),
('oauth_version', '1.0'),
]
# signature
# Note, that signature now includes access_token_secret
signature = get_sign(params_confirmed_access_token, API_RESOURCE_URL, "GET", access_token_secret)
params_confirmed_access_token.append(('oauth_signature', signature))
# GET https://api.bitbucket.org/1.0/repositories/st4lk/django-articles-transmeta/branches?
# oauth_consumer_key=your_app_key&
# oauth_nonce=19465031069998501171427367108&
# oauth_signature_method=HMAC-SHA1&
# oauth_timestamp=1427367108&
# oauth_token=dXcGkeza39yhMEKqRy&
# oauth_version=1.0&
# oauth_signature=iH%2FDy2jj6C7rdWfmgDq2zJlGzao%3D
url = "?".join((API_RESOURCE_URL, urlencode(params_confirmed_access_token)))
resp = urllib2.urlopen(url)
assert resp.code == 200
print resp.read()
@d3v-null
Copy link

Thanks for this! Really helped me put everything together.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment