Skip to content

Commit

Permalink
Updated Bitbucket backend to use newer 2.0 APIs instead of 1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
mark-adams committed Jun 21, 2015
1 parent 4ab28ad commit 6c59ceb
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 58 deletions.
54 changes: 22 additions & 32 deletions social/backends/bitbucket.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,51 +9,41 @@
class BitbucketOAuth(BaseOAuth1):
"""Bitbucket OAuth authentication backend"""
name = 'bitbucket'
ID_KEY = 'username'
AUTHORIZATION_URL = 'https://bitbucket.org/api/1.0/oauth/authenticate'
REQUEST_TOKEN_URL = 'https://bitbucket.org/api/1.0/oauth/request_token'
ACCESS_TOKEN_URL = 'https://bitbucket.org/api/1.0/oauth/access_token'
EXTRA_DATA = [
('username', 'username'),
('expires', 'expires'),
('email', 'email'),
('first_name', 'first_name'),
('last_name', 'last_name')
]

def get_user_details(self, response):
"""Return user details from Bitbucket account"""
fullname, first_name, last_name = self.get_user_names(
first_name=response.get('first_name', ''),
last_name=response.get('last_name', '')
)
return {'username': response.get('username') or '',
'email': response.get('email') or '',
fullname, first_name, last_name = self.get_user_names(response['display_name'])

return {'username': response.get('username', ''),
'email': response.get('email', ''),
'fullname': fullname,
'first_name': first_name,
'last_name': last_name}

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, then retrieve the user's primary email address or
# the top email
emails = self.get_json('https://bitbucket.org/api/1.0/emails/',
emails = self.get_json('https://api.bitbucket.org/2.0/user/emails',
auth=self.oauth_auth(access_token))

email = None
for address in reversed(emails):
if address['active']:
email = address['email']
if address['primary']:
break

for address in reversed(emails['values']):
email = address['email']
if address['is_primary']:
break

if self.setting('VERIFIED_EMAILS_ONLY', False) and not address['is_confirmed']:
raise AuthForbidden(
self, 'Bitbucket account has no verified email'
)

user = self.get_json('https://api.bitbucket.org/2.0/user',
auth=self.oauth_auth(access_token))

if email:
return dict(self.get_json('https://bitbucket.org/api/1.0/users/' +
email)['user'],
email=email)
elif self.setting('VERIFIED_EMAILS_ONLY', False):
raise AuthForbidden(self,
'Bitbucket account has any verified email')
else:
return {}
user['email'] = email

return user
79 changes: 53 additions & 26 deletions social/tests/backends/test_bitbucket.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

class BitbucketOAuth1Test(OAuth1Test):
backend_path = 'social.backends.bitbucket.BitbucketOAuth'
user_data_url = 'https://bitbucket.org/api/1.0/users/foo@bar.com'
user_data_url = 'https://api.bitbucket.org/2.0/user'
expected_username = 'foobar'
access_token_body = json.dumps({
'access_token': 'foobar',
Expand All @@ -20,46 +20,73 @@ class BitbucketOAuth1Test(OAuth1Test):
'oauth_token': 'foobar',
'oauth_callback_confirmed': 'true'
})
emails_body = json.dumps([{
'active': True,
'email': 'foo@bar.com',
'primary': True
}])
emails_body = json.dumps({
u'page': 1,
u'pagelen': 10,
u'size': 2,
u'values': [
{
u'email': u'foo@bar.com',
u'is_confirmed': True,
u'is_primary': True,
u'links': { u'self': {u'href': u'https://api.bitbucket.org/2.0/user/emails/foo@bar.com'}},
u'type': u'email'
},
{
u'email': u'not@confirme.com',
u'is_confirmed': False,
u'is_primary': False,
u'links': {u'self': {u'href': u'https://api.bitbucket.org/2.0/user/emails/not@confirmed.com'}},
u'type': u'email'
}
]
})
user_data_body = json.dumps({
'user': {
'username': 'foobar',
'first_name': 'Foo',
'last_name': 'Bar',
'display_name': 'Foo Bar',
'is_team': False,
'avatar': 'https://secure.gravatar.com/avatar/'
'5280f15cedf540b544eecc30fcf3027c?'
'd=https%3A%2F%2Fd3oaxc4q5k2d6q.cloudfront.net%2Fm%2F'
'9e262ba34f96%2Fimg%2Fdefault_avatar%2F32%2F'
'user_blue.png&s=32',
'resource_uri': '/1.0/users/foobar'
}
u'created_on': u'2012-03-29T18:07:38+00:00',
u'display_name': u'Foo Bar',
u'links': {
u'avatar': {u'href': u'https://bitbucket.org/account/foobar/avatar/32/'},
u'followers': {u'href': u'https://api.bitbucket.org/2.0/users/foobar/followers'},
u'following': {u'href': u'https://api.bitbucket.org/2.0/users/foobar/following'},
u'hooks': {u'href': u'https://api.bitbucket.org/2.0/users/foobar/hooks'},
u'html': {u'href': u'https://bitbucket.org/foobar'},
u'repositories': {u'href': u'https://api.bitbucket.org/2.0/repositories/foobar'},
u'self': {u'href': u'https://api.bitbucket.org/2.0/users/foobar'}},
u'location': u'Fooville, Bar',
u'type': u'user',
u'username': u'foobar',
u'uuid': u'{397621dc-0f78-329f-8d6d-727396248e3f}',
u'website': u'http://foobar.com'
})

def test_login(self):
HTTPretty.register_uri(HTTPretty.GET,
'https://bitbucket.org/api/1.0/emails/',
'https://api.bitbucket.org/2.0/user/emails',
status=200, body=self.emails_body)
self.do_login()

def test_partial_pipeline(self):
HTTPretty.register_uri(HTTPretty.GET,
'https://bitbucket.org/api/1.0/emails/',
'https://api.bitbucket.org/2.0/user/emails',
status=200, body=self.emails_body)
self.do_partial_pipeline()


class BitbucketOAuth1FailTest(BitbucketOAuth1Test):
emails_body = json.dumps([{
'active': False,
'email': 'foo@bar.com',
'primary': True
}])
emails_body = json.dumps({
u'page': 1,
u'pagelen': 10,
u'size': 1,
u'values': [
{
u'email': u'foo@bar.com',
u'is_confirmed': False,
u'is_primary': True,
u'links': { u'self': {u'href': u'https://api.bitbucket.org/2.0/user/emails/foo@bar.com'}},
u'type': u'email'
}
]
})

def test_login(self):
self.strategy.set_settings({
Expand Down

0 comments on commit 6c59ceb

Please sign in to comment.