Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,5 @@ local_settings.py
sessions/
_build/
fabfile.py

.DS_Store
2 changes: 2 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ or extend current one):
* Angel_ OAuth2
* Behance_ OAuth2
* Bitbucket_ OAuth1
* Box_ OAuth2
* Dailymotion_ OAuth2
* Disqus_ OAuth2
* Douban_ OAuth1 and OAuth2
Expand Down Expand Up @@ -179,6 +180,7 @@ check `django-social-auth LICENCE`_ for details:
.. _Angel: https://angel.co
.. _Behance: https://www.behance.net
.. _Bitbucket: https://bitbucket.org
.. _Box: https://www.box.com
.. _Dailymotion: https://dailymotion.com
.. _Disqus: https://disqus.com
.. _Douban: http://www.douban.com
Expand Down
24 changes: 24 additions & 0 deletions docs/backends/box.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
Box.net
======

Box works similar to Facebook (OAuth2).

- Register an application at `Manage Box Applications`_

- Fill the **Consumer Key** and **Consumer Secret** values in your settings::

SOCIAL_AUTH_BOX_KEY = ''
SOCIAL_AUTH_BOX_SECRET = ''

- By default the token is not permanent, it will last an hour::

To refresh the access token just do::

from social.apps.django_app.utils import load_strategy

strategy = load_strategy(backend='box')
user = User.objects.get(pk=foo)
social = user.social_auth.filter(provider='box')[0]
social.refresh_token(strategy=strategy)

.. _Manage Box Applications: https://app.box.com/developers/services
2 changes: 2 additions & 0 deletions docs/intro.rst
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ or extend current one):
* Angel_ OAuth2
* Behance_ OAuth2
* Bitbucket_ OAuth1
* Box_ OAuth2
* Dailymotion_ OAuth2
* Disqus_ OAuth2
* Douban_ OAuth1 and OAuth2
Expand Down Expand Up @@ -105,6 +106,7 @@ suits your project. Check `Authentication Pipeline`_ section.
.. _Angel: https://angel.co
.. _Behance: https://www.behance.net
.. _Bitbucket: https://bitbucket.org
.. _Box: https://www.box.com
.. _Dailymotion: https://dailymotion.com
.. _Disqus: https://disqus.com
.. _Douban: http://www.douban.com
Expand Down
1 change: 1 addition & 0 deletions examples/django_example/dj/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@
'social.backends.angel.AngelOAuth2',
'social.backends.behance.BehanceOAuth2',
'social.backends.bitbucket.BitbucketOAuth',
'social.backends.box.BoxOAuth2',
'social.backends.linkedin.LinkedinOAuth',
'social.backends.linkedin.LinkedinOAuth2',
'social.backends.github.GithubOAuth2',
Expand Down
1 change: 1 addition & 0 deletions examples/django_example/dj/templates/home.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
<a href="{% url 'social:begin' "angel" %}">Angel OAuth2</a> <br />
<a href="{% url 'social:begin' "behance" %}">Behance OAuth2</a> <br />
<a href="{% url 'social:begin' "bitbucket" %}">Bitbucket OAuth</a> <br />
<a href="{% url 'social:begin' "box" %}">Box.net OAuth2</a> <br />
<a href="{% url 'social:begin' "linkedin" %}">LinkedIn OAuth</a> <br />
<a href="{% url 'social:begin' "github" %}">Github OAuth2</a> <br />
<a href="{% url 'social:begin' "foursquare" %}">Foursquare OAuth2</a> <br />
Expand Down
1 change: 1 addition & 0 deletions examples/flask_example/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
'social.backends.angel.AngelOAuth2',
'social.backends.behance.BehanceOAuth2',
'social.backends.bitbucket.BitbucketOAuth',
'social.backends.box.BoxOAuth2',
'social.backends.linkedin.LinkedinOAuth',
'social.backends.github.GithubOAuth2',
'social.backends.foursquare.FoursquareOAuth2',
Expand Down
1 change: 1 addition & 0 deletions examples/flask_example/templates/home.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<a href="{{ url_for("social.auth", backend="angel") }}">Angel OAuth2</a> <br />
<a href="{{ url_for("social.auth", backend="behance") }}">Behance OAuth2</a> <br />
<a href="{{ url_for("social.auth", backend="bitbucket") }}">Bitbucket OAuth</a> <br />
<a href="{{ url_for("social.auth", backend="box") }}">Box OAuth2</a> <br />
<a href="{{ url_for("social.auth", backend="linkedin") }}">LinkedIn OAuth</a> <br />
<a href="{{ url_for("social.auth", backend="github") }}">Github OAuth2</a> <br />
<a href="{{ url_for("social.auth", backend="foursquare") }}">Foursquare OAuth2</a> <br />
Expand Down
1 change: 1 addition & 0 deletions examples/webpy_example/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
'social.backends.angel.AngelOAuth2',
'social.backends.behance.BehanceOAuth2',
'social.backends.bitbucket.BitbucketOAuth',
'social.backends.box.BoxOAuth2',
'social.backends.linkedin.LinkedinOAuth',
'social.backends.github.GithubOAuth2',
'social.backends.foursquare.FoursquareOAuth2',
Expand Down
1 change: 1 addition & 0 deletions examples/webpy_example/templates/home.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<a href="/login/angel/">Angel OAuth2</a> <br />
<a href="/login/behance/">Behance OAuth2</a> <br />
<a href="/login/bitbucket/">Bitbucket OAuth</a> <br />
<a href="/login/box/">Box OAuth2</a> <br />
<a href="/login/linkedin/">LinkedIn OAuth</a> <br />
<a href="/login/github/">Github OAuth2</a> <br />
<a href="/login/foursquare/">Foursquare OAuth2</a> <br />
Expand Down
59 changes: 59 additions & 0 deletions social/backends/box.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
"""
Box.net OAuth support.

This contribution adds support for GitHub OAuth service. The settings
SOCIAL_AUTH_BOX_KEY and SOCIAL_AUTH_BOX_SECRET must be defined with the values
given by Box.net application registration process.

Extended permissions are supported by defining BOX_EXTENDED_PERMISSIONS
setting, it must be a list of values to request.

By default account id and token expiration time are stored in extra_data
field, check OAuthBackend class for details on how to extend it.
"""
from social.backends.oauth import BaseOAuth2


class BoxOAuth2(BaseOAuth2):
"""Box.net OAuth authentication backend"""
name = 'box'
AUTHORIZATION_URL = 'https://www.box.com/api/oauth2/authorize'
ACCESS_TOKEN_METHOD = 'POST'
ACCESS_TOKEN_URL = 'https://www.box.com/api/oauth2/token'
REVOKE_TOKEN_URL = 'https://www.box.com/api/oauth2/revoke'
SCOPE_SEPARATOR = ','
EXTRA_DATA = [
('refresh_token', 'refresh_token', True),
('id', 'id'),
('expires', 'expires'),
]

def do_auth(self, access_token, response=None, *args, **kwargs):
response = response or {}
data = self.user_data(access_token)

data['access_token'] = response.get('access_token')
data['refresh_token'] = response.get('refresh_token')
data['expires'] = response.get('expires_in')
kwargs.update({'backend': self, 'response': data})
return self.strategy.authenticate(*args, **kwargs)

def get_user_details(self, response):
"""Return user details Box.net account"""
return {'username': response.get('login'),
'email': response.get('login') or '',
'first_name': response.get('name')}

def user_data(self, access_token, *args, **kwargs):
"""Loads user data from service"""
params = self.setting('PROFILE_EXTRA_PARAMS', {})
params['access_token'] = access_token
return self.get_json('https://api.box.com/2.0/users/me',
params=params)

def refresh_token(self, token, *args, **kwargs):
params = self.refresh_token_params(token, *args, **kwargs)
request = self.request(self.REFRESH_TOKEN_URL or self.ACCESS_TOKEN_URL,
data=params, headers=self.auth_headers(),
method='POST')
return self.process_refresh_token_response(request, *args, **kwargs)
66 changes: 66 additions & 0 deletions tests/backends/box_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
from sure import expect
from tests.oauth import OAuth2Test
import json


class BoxOAuth2Test(OAuth2Test):
backend_path = 'social.backends.box.BoxOAuth2'
user_data_url = 'https://api.box.com/2.0/users/me'
expected_username = 'sean+awesome@box.com'
access_token_body = json.dumps({
"access_token": "T9cE5asGnuyYCCqIZFoWjFHvNbvVqHjl",
"expires_in": 3600,
"restricted_to": [],
"token_type": "bearer",
"refresh_token": "J7rxTiWOHMoSC1isKZKBZWizoRXjkQzig5C6jFgCVJ9bUnsUfGMinKBDLZWP9BgR"
})
user_data_body = json.dumps({
"type": "user",
"id": "181216415",
"name": "sean rose",
"login": "sean+awesome@box.com",
"created_at": "2012-05-03T21:39:11-07:00",
"modified_at": "2012-11-14T11:21:32-08:00",
"role": "admin",
"language": "en",
"space_amount": 11345156112,
"space_used": 1237009912,
"max_upload_size": 2147483648,
"tracking_codes": [],
"can_see_managed_users": True,
"is_sync_enabled": True,
"status": "active",
"job_title": "",
"phone": "6509241374",
"address": "",
"avatar_url": "https://www.box.com/api/avatar/large/181216415",
"is_exempt_from_device_limits": False,
"is_exempt_from_login_verification": False,
"enterprise": {
"type": "enterprise",
"id": "17077211",
"name": "seanrose enterprise"
}
})
refresh_token_body = json.dumps({
"access_token": "T9cE5asGnuyYCCqIZFoWjFHvNbvVqHjl",
"expires_in": 3600,
"restricted_to": [],
"token_type": "bearer",
"refresh_token": "J7rxTiWOHMoSC1isKZKBZWizoRXjkQzig5C6jFgCVJ9bUnsUfGMinKBDLZWP9BgR"
})

def test_login(self):
self.do_login()

def test_partial_pipeline(self):
self.do_partial_pipeline()

def refresh_token_arguments(self):
uri = self.strategy.build_absolute_uri('/complete/box/')
return {'redirect_uri': uri}

def test_refresh_token(self):
user, social = self.do_refresh_token()
expect(social.extra_data['access_token']).to.equal('T9cE5asGnuyYCCqIZFoWjFHvNbvVqHjl')