/
bitbucket.py
109 lines (94 loc) · 4.1 KB
/
bitbucket.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
"""
Bitbucket OAuth support.
This adds support for Bitbucket OAuth service. An application must
be registered first on Bitbucket and the settings BITBUCKET_CONSUMER_KEY
and BITBUCKET_CONSUMER_SECRET must be defined with the corresponding
values.
By default username, email, token expiration time, first name and last name are
stored in extra_data field, check OAuthBackend class for details on how to
extend it.
"""
from django.utils import simplejson
from social_auth.backends import ConsumerBasedOAuth, OAuthBackend, USERNAME
from urllib import urlopen
from social_auth.utils import setting
# Bitbucket configuration
BITBUCKET_SERVER = 'bitbucket.org/api/1.0'
BITBUCKET_REQUEST_TOKEN_URL = 'https://%s/oauth/request_token' % \
BITBUCKET_SERVER
BITBUCKET_ACCESS_TOKEN_URL = 'https://%s/oauth/access_token' % BITBUCKET_SERVER
BITBUCKET_AUTHORIZATION_URL = 'https://%s/oauth/authenticate' % \
BITBUCKET_SERVER
BITBUCKET_EMAIL_DATA_URL = 'https://%s/emails/' % BITBUCKET_SERVER
BITBUCKET_USER_DATA_URL = 'https://%s/users/' % BITBUCKET_SERVER
class BitbucketBackend(OAuthBackend):
"""Bitbucket OAuth authentication backend"""
name = 'bitbucket'
EXTRA_DATA = [
('username', 'username'),
('expires', setting('SOCIAL_AUTH_EXPIRATION', 'expires')),
('email', 'email'),
('first_name', 'first_name'),
('last_name', 'last_name')
]
def get_user_details(self, response):
"""Return user details from Bitbucket account"""
return {USERNAME: response.get('username'),
'email': response.get('email'),
'fullname': ' '.join((response.get('first_name'),
response.get('last_name'))),
'first_name': response.get('first_name'),
'last_name': response.get('last_name')}
def get_user_id(self, details, response):
"""Return the user id, Bitbucket only provides username as a unique
identifier"""
return response['username']
@classmethod
def tokens(cls, instance):
"""Return the tokens needed to authenticate the access to any API the
service might provide. Bitbucket uses a pair of OAuthToken consisting
on a oauth_token and oauth_token_secret.
instance must be a UserSocialAuth instance.
"""
token = super(BitbucketBackend, cls).tokens(instance)
if token and 'access_token' in token:
token = dict(tok.split('=')
for tok in token['access_token'].split('&'))
return token
class BitbucketAuth(ConsumerBasedOAuth):
"""Bitbucket OAuth authentication mechanism"""
AUTHORIZATION_URL = BITBUCKET_AUTHORIZATION_URL
REQUEST_TOKEN_URL = BITBUCKET_REQUEST_TOKEN_URL
ACCESS_TOKEN_URL = BITBUCKET_ACCESS_TOKEN_URL
SERVER_URL = BITBUCKET_SERVER
AUTH_BACKEND = BitbucketBackend
SETTINGS_KEY_NAME = 'BITBUCKET_CONSUMER_KEY'
SETTINGS_SECRET_NAME = 'BITBUCKET_CONSUMER_SECRET'
def user_data(self, access_token):
"""Return user data provided"""
# Bitbucket has a bit of an indirect route to obtain user data from an
# authenticated query: First obtain the user's email via an
# authenticated GET
url = BITBUCKET_EMAIL_DATA_URL
request = self.oauth_request(access_token, url)
response = self.fetch_response(request)
try:
email = simplejson.loads(response)[0]['email']
# Then return the user data using a normal GET with the
# BITBUCKET_USER_DATA_URL and the user's email
response = urlopen(BITBUCKET_USER_DATA_URL + email)
user_details = simplejson.load(response)['user']
user_details['email'] = email
return user_details
except ValueError:
return None
return None
@classmethod
def enabled(cls):
"""Return backend enabled status by checking basic settings"""
return setting('BITBUCKET_CONSUMER_KEY') and \
setting('BITBUCKET_CONSUMER_SECRET')
# Backend definition
BACKENDS = {
'bitbucket': BitbucketAuth,
}