Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge remote-tracking branch 'upstream/master'

Conflicts:
	example/settings.py
	social_auth/backends/__init__.py
	social_auth/backends/contrib/vkontakte.py
	social_auth/backends/contrib/yandex.py
  • Loading branch information...
commit bb864506d87e69aaed35ce00175ec20c700f05dc 2 parents a8a1539 + bdd23b5
@krvss krvss authored
View
1  .gitignore
@@ -13,3 +13,4 @@ contrib/tests/test_settings.py
*.ipr
*.iws
Django-social-auth.iml
+tags
View
23 README.rst
@@ -51,6 +51,7 @@ credentials, some features are:
* `MSN Live Connect OAuth2`_
* `Skyrock OAuth`_
* `Yahoo OAuth`_
+ * `Evernote OAuth`_
- Basic user data population and signaling, to allows custom fields values
from providers response
@@ -946,7 +947,7 @@ Vkontakte uses OAuth v2 for Authentication
- Define VK_EXTRA_DATA to pass extra fields when gathering the user profile data, like::
- VK_EXTRA_DATA = 'photo,country'
+ VK_EXTRA_DATA = ['photo','country']
- Also it's possible to define extra permissions with::
@@ -999,6 +1000,19 @@ OAuth 1.0 workflow, useful if you are planning to use Yahoo's API.
YAHOO_CONSUMER_KEY = ''
YAHOO_CONSUMER_SECRET = ''
+Evernote OAuth
+^^^^^^^^^^^^^^
+
+Evernote OAuth 1.0 workflow.
+
+- Register a new application at `Evernote API Key form`_.
+
+- Fill ``Consumer Key`` and ``Consumer Secret`` values in the settings::
+
+ EVERNOTE_CONSUMER_KEY = ''
+ EVERNOTE_CONSUMER_SECRET = ''
+
+
Testing
-------
@@ -1192,6 +1206,11 @@ Attributions to whom deserves:
- Skyrock.com support
+- hassek_ (Tomas Henriquez)
+
+ - Evernote support
+
+
Copyrights
----------
@@ -1290,3 +1309,5 @@ Base work is copyrighted by:
.. _Skyrock API Documentation: http://www.skyrock.com/developer/documentation/
.. _Yahoo OAuth: http://developer.yahoo.com/oauth/guide/oauth-auth-flow.html
.. _Yahoo Developer Center: https://developer.apps.yahoo.com/projects/
+.. _Evernote API Key form: http://dev.evernote.com/support/api_key.php
+.. _hassek: https://github.com/hassek
View
13 doc/backends/evernote.rst
@@ -0,0 +1,13 @@
+Evernote OAuth
+==============
+
+Evernote OAuth 1.0 workflow.
+
+- Register a new application at `Evernote API Key form`_.
+
+- Fill ``Consumer Key`` and ``Consumer Secret`` values in the settings::
+
+ EVERNOTE_CONSUMER_KEY = ''
+ EVERNOTE_CONSUMER_SECRET = ''
+
+.. _Evernote API Key form: http://dev.evernote.com/support/api_key.php
View
3  doc/backends/index.rst
@@ -21,4 +21,5 @@ Contents:
vkontakte
live
skyrock
- yahoo
+ yahoo
+ evernote
View
8 doc/contributions.rst
@@ -40,6 +40,12 @@ andrusha_ (Andrew Korzhuev)
* MSN Live Connect support
* Yahoo OAuth 1.0 support
+niQo_ (Nicolas Quiénot)
+ * Skyrock.com support
+
+hassek_ (Tomas Henriquez)
+ * Evernote support
+
.. _caioariede: https://github.com/caioariede
.. _krvss: https://github.com/krvss
.. _jezdez: https://github.com/jezdez
@@ -53,3 +59,5 @@ andrusha_ (Andrew Korzhuev)
.. _maraujop: https://github.com/maraujop
.. _bedspax: https://github.com/bedspax
.. _python-oauth2: https://github.com/simplegeo/python-oauth2
+.. _niQo: https://github.com/niQo
+.. _hassek: https://github.com/hassek
View
1  example/settings.py
@@ -80,6 +80,7 @@
'social_auth.backends.contrib.instagram.InstagramBackend',
'social_auth.backends.contrib.github.GithubBackend',
'social_auth.backends.contrib.yandex.YandexBackend',
+ 'social_auth.backends.contrib.yahoo.YahooOAuthBackend',
'social_auth.backends.OpenIDBackend',
'social_auth.backends.contrib.livejournal.LiveJournalBackend',
'social_auth.backends.browserid.BrowserIDBackend',
View
107 social_auth/backends/__init__.py
@@ -17,8 +17,8 @@
from openid.consumer.discover import DiscoveryFailure
from openid.extensions import sreg, ax
-from oauth2 import Consumer as OAuthConsumer, Token, Request as OAuthRequest,\
- SignatureMethod_HMAC_SHA1
+from oauth2 import Consumer as OAuthConsumer, Token, Request as OAuthRequest, \
+ SignatureMethod_HMAC_SHA1
from django.db import models
from django.contrib.auth import authenticate
@@ -26,13 +26,14 @@
from django.utils import simplejson
from django.utils.importlib import import_module
-from social_auth.utils import setting, log, model_to_ctype, ctype_to_model,\
- clean_partial_pipeline
+from social_auth.utils import setting, log, model_to_ctype, ctype_to_model, \
+ clean_partial_pipeline
from social_auth.store import DjangoOpenIDStore
-from social_auth.backends.exceptions import StopPipeline, AuthException,\
- AuthFailed, AuthCanceled,\
- AuthUnknownError, AuthTokenError,\
- AuthMissingParameter
+from social_auth.backends.exceptions import StopPipeline, AuthException, \
+ AuthFailed, AuthCanceled, \
+ AuthUnknownError, AuthTokenError, \
+ AuthMissingParameter
+from social_auth.backends.utils import build_consumer_oauth_request
if setting('SOCIAL_AUTH_USER_MODEL'):
@@ -55,7 +56,7 @@
('http://axschema.org/namePerson/first', 'first_name'),
('http://axschema.org/namePerson/last', 'last_name'),
('http://axschema.org/namePerson/friendly', 'nickname'),
- ]
+]
SREG_ATTR = [
('email', 'email'),
('fullname', 'fullname'),
@@ -69,14 +70,14 @@
USERNAME = 'username'
PIPELINE = setting('SOCIAL_AUTH_PIPELINE', (
- 'social_auth.backends.pipeline.social.social_auth_user',
- 'social_auth.backends.pipeline.associate.associate_by_email',
- 'social_auth.backends.pipeline.user.get_username',
- 'social_auth.backends.pipeline.user.create_user',
- 'social_auth.backends.pipeline.social.associate_user',
- 'social_auth.backends.pipeline.social.load_extra_data',
- 'social_auth.backends.pipeline.user.update_user_details',
- ))
+ 'social_auth.backends.pipeline.social.social_auth_user',
+ 'social_auth.backends.pipeline.associate.associate_by_email',
+ 'social_auth.backends.pipeline.user.get_username',
+ 'social_auth.backends.pipeline.user.create_user',
+ 'social_auth.backends.pipeline.social.associate_user',
+ 'social_auth.backends.pipeline.social.load_extra_data',
+ 'social_auth.backends.pipeline.user.update_user_details',
+ ))
class SocialAuthBackend(ModelBackend):
@@ -258,7 +259,7 @@ def values_from_response(self, response, sreg_names=None, ax_names=None):
resp = sreg.SRegResponse.fromSuccessResponse(response)
if resp:
values.update((alias, resp.get(name) or '')
- for name, alias in sreg_names)
+ for name, alias in sreg_names)
# Use Attribute Exchange attributes if provided
if ax_names:
@@ -276,9 +277,9 @@ def get_user_details(self, response):
# update values using SimpleRegistration or AttributeExchange
# values
values.update(self.values_from_response(response,
- SREG_ATTR,
- OLD_AX_ATTRS +\
- AX_SCHEMA_ATTRS))
+ SREG_ATTR,
+ OLD_AX_ATTRS + \
+ AX_SCHEMA_ATTRS))
fullname = values.get('fullname') or ''
first_name = values.get('first_name') or ''
@@ -294,8 +295,8 @@ def get_user_details(self, response):
values.update({'fullname': fullname, 'first_name': first_name,
'last_name': last_name,
- USERNAME: values.get(USERNAME) or\
- (first_name.title() + last_name.title())})
+ USERNAME: values.get(USERNAME) or \
+ (first_name.title() + last_name.title())})
return values
def extra_data(self, user, uid, response, details):
@@ -351,7 +352,7 @@ def to_session_dict(self, next_idx, *args, **kwargs):
'backend': self.AUTH_BACKEND.name,
'args': tuple(map(model_to_ctype, args)),
'kwargs': dict((key, model_to_ctype(val))
- for key, val in kwargs.iteritems())
+ for key, val in kwargs.iteritems())
}
def from_session_dict(self, entry, *args, **kwargs):
@@ -363,7 +364,7 @@ def from_session_dict(self, entry, *args, **kwargs):
kwargs = kwargs.copy()
kwargs.update((key, ctype_to_model(val))
- for key, val in entry['kwargs'].iteritems())
+ for key, val in entry['kwargs'].iteritems())
return (entry['next'], args, kwargs)
def continue_pipeline(self, *args, **kwargs):
@@ -437,7 +438,7 @@ def auth_html(self):
return_to = self.build_absolute_uri(self.redirect)
form_tag = {'id': 'openid_message'}
return openid_request.htmlMarkup(self.trust_root(), return_to,
- form_tag_attrs=form_tag)
+ form_tag_attrs=form_tag)
def trust_root(self):
"""Return trust-root option"""
@@ -446,7 +447,7 @@ def trust_root(self):
def continue_pipeline(self, *args, **kwargs):
"""Continue previous halted pipeline"""
response = self.consumer().complete(dict(self.data.items()),
- self.build_absolute_uri())
+ self.build_absolute_uri())
kwargs.update({
'auth': self,
'response': response,
@@ -457,7 +458,7 @@ def continue_pipeline(self, *args, **kwargs):
def auth_complete(self, *args, **kwargs):
"""Complete auth process"""
response = self.consumer().complete(dict(self.data.items()),
- self.build_absolute_uri())
+ self.build_absolute_uri())
if not response:
raise AuthException(self, 'OpenID relying party endpoint')
elif response.status == SUCCESS:
@@ -484,7 +485,7 @@ def setup_request(self, extra_params=None):
# Mark all attributes as required, Google ignores optional ones
for attr, alias in (AX_SCHEMA_ATTRS + OLD_AX_ATTRS):
fetch_request.add(ax.AttrInfo(attr, alias=alias,
- required=True))
+ required=True))
else:
fetch_request = sreg.SRegRequest(optional=dict(SREG_ATTR).keys())
openid_request.addExtension(fetch_request)
@@ -494,7 +495,7 @@ def setup_request(self, extra_params=None):
def consumer(self):
"""Create an OpenID Consumer object for the given Django request."""
return Consumer(self.request.session.setdefault(SESSION_NAME, {}),
- DjangoOpenIDStore())
+ DjangoOpenIDStore())
@property
def uses_redirect(self):
@@ -534,17 +535,18 @@ def __init__(self, request, redirect):
super(BaseOAuth, self).__init__(request, redirect)
self.redirect_uri = self.build_absolute_uri(self.redirect)
- def get_key_and_secret(self):
+ @classmethod
+ def get_key_and_secret(cls):
"""Return tuple with Consumer Key and Consumer Secret for current
service provider. Must return (key, secret), order *must* be respected.
"""
- return setting(self.SETTINGS_KEY_NAME),\
- setting(self.SETTINGS_SECRET_NAME)
+ return setting(cls.SETTINGS_KEY_NAME), \
+ setting(cls.SETTINGS_SECRET_NAME)
@classmethod
def enabled(cls):
"""Return backend enabled status by checking basic settings"""
- return setting(cls.SETTINGS_KEY_NAME) and\
+ return setting(cls.SETTINGS_KEY_NAME) and \
setting(cls.SETTINGS_SECRET_NAME)
@@ -602,31 +604,23 @@ def auth_complete(self, *args, **kwargs):
def unauthorized_token(self):
"""Return request for unauthorized token (first stage)"""
request = self.oauth_request(token=None, url=self.REQUEST_TOKEN_URL,
- extra_params=self.request_token_extra_arguments())
+ extra_params=self.request_token_extra_arguments())
response = self.fetch_response(request)
return Token.from_string(response)
def oauth_authorization_request(self, token):
"""Generate OAuth request to authorize token."""
return OAuthRequest.from_token_and_callback(token=token,
- callback=self.redirect_uri,
- http_url=self.AUTHORIZATION_URL,
- parameters=self.auth_extra_arguments())
+ callback=self.redirect_uri,
+ http_url=self.AUTHORIZATION_URL,
+ parameters=self.auth_extra_arguments())
def oauth_request(self, token, url, extra_params=None):
"""Generate OAuth request, setups callback url"""
- params = {'oauth_callback': self.redirect_uri}
- if extra_params:
- params.update(extra_params)
-
- if 'oauth_verifier' in self.data:
- params['oauth_verifier'] = self.data['oauth_verifier']
- request = OAuthRequest.from_consumer_and_token(self.consumer,
- token=token,
- http_url=url,
- parameters=params)
- request.sign_request(SignatureMethod_HMAC_SHA1(), self.consumer, token)
- return request
+ return build_consumer_oauth_request(self, token, url,
+ self.redirect_uri,
+ self.data.get('oauth_verifier'),
+ extra_params)
def fetch_response(self, request):
"""Executes request and fetchs service response"""
@@ -662,6 +656,8 @@ class BaseOAuth2(BaseOAuth):
ACCESS_TOKEN_URL = None
SCOPE_SEPARATOR = ' '
RESPONSE_TYPE = 'code'
+ SCOPE_VAR_NAME = None
+ DEFAULT_SCOPE = None
def auth_url(self):
"""Return redirect url"""
@@ -690,9 +686,9 @@ def auth_complete(self, *args, **kwargs):
'client_secret': client_secret,
'redirect_uri': self.redirect_uri}
headers = {'Content-Type': 'application/x-www-form-urlencoded',
- 'Accept': 'application/json'}
+ 'Accept': 'application/json'}
request = Request(self.ACCESS_TOKEN_URL, data=urlencode(params),
- headers=headers)
+ headers=headers)
try:
response = simplejson.loads(urlopen(request).read())
@@ -719,7 +715,10 @@ def auth_complete(self, *args, **kwargs):
def get_scope(self):
"""Return list with needed access scope"""
- return []
+ scope = self.DEFAULT_SCOPE or []
+ if self.SCOPE_VAR_NAME:
+ scope = scope + setting(self.SCOPE_VAR_NAME, [])
+ return scope
# Backend loading was previously performed via the
@@ -789,4 +788,4 @@ def get_backend(name, *args, **kwargs):
BACKENDS = {
'openid': OpenIdAuth
-}
+}
View
95 social_auth/backends/contrib/evernote.py
@@ -0,0 +1,95 @@
+"""
+EverNote OAuth support
+
+No extra configurations are needed to make this work.
+"""
+try:
+ from urlparse import parse_qs
+ parse_qs # placate pyflakes
+except ImportError:
+ # fall back for Python 2.5
+ from cgi import parse_qs
+
+from oauth2 import Token
+from social_auth.utils import setting
+from social_auth.backends import ConsumerBasedOAuth, OAuthBackend, USERNAME
+
+
+if setting('EVERNOTE_DEBUG', False):
+ EVERNOTE_SERVER = 'sandbox.evernote.com'
+else:
+ EVERNOTE_SERVER = 'www.evernote.com'
+
+EVERNOTE_REQUEST_TOKEN_URL = 'https://%s/oauth' % EVERNOTE_SERVER
+EVERNOTE_ACCESS_TOKEN_URL = 'https://%s/oauth' % EVERNOTE_SERVER
+EVERNOTE_AUTHORIZATION_URL = 'https://%s/OAuth.action' % EVERNOTE_SERVER
+
+
+class EvernoteBackend(OAuthBackend):
+ """
+ Evernote OAuth authentication backend.
+
+ Possible Values:
+ {'edam_expires': ['1367525289541'],
+ 'edam_noteStoreUrl': ['https://sandbox.evernote.com/shard/s1/notestore'],
+ 'edam_shard': ['s1'],
+ 'edam_userId': ['123841'],
+ 'edam_webApiUrlPrefix': ['https://sandbox.evernote.com/shard/s1/'],
+ 'oauth_token': ['S=s1:U=1e3c1:E=13e66dbee45:C=1370f2ac245:P=185:A=my_user:H=411443c5e8b20f8718ed382a19d4ae38']}
+ """
+ name = 'evernote'
+
+ EXTRA_DATA = [
+ ('access_token', 'access_token'),
+ ('oauth_token', 'oauth_token'),
+ ('edam_noteStoreUrl', 'store_url'),
+ ('edam_expires', setting('SOCIAL_AUTH_EXPIRATION', 'expires'))
+ ]
+
+ def get_user_details(self, response):
+ """Return user details from Evernote account"""
+ return {
+ USERNAME: response['edam_userId'],
+ 'email': '',
+ }
+
+ def get_user_id(self, details, response):
+ return response['edam_userId'][0]
+
+
+class EvernoteAuth(ConsumerBasedOAuth):
+ """Evernote OAuth authentication mechanism"""
+ AUTHORIZATION_URL = EVERNOTE_AUTHORIZATION_URL
+ REQUEST_TOKEN_URL = EVERNOTE_REQUEST_TOKEN_URL
+ ACCESS_TOKEN_URL = EVERNOTE_ACCESS_TOKEN_URL
+ SERVER_URL = '%s' % EVERNOTE_SERVER
+ AUTH_BACKEND = EvernoteBackend
+ SETTINGS_KEY_NAME = 'EVERNOTE_CONSUMER_KEY'
+ SETTINGS_SECRET_NAME = 'EVERNOTE_CONSUMER_SECRET'
+
+ def access_token(self, token):
+ """Return request for access token value"""
+ request = self.oauth_request(token, self.ACCESS_TOKEN_URL)
+ response = self.fetch_response(request)
+ params = parse_qs(response)
+
+ # evernote sents a empty secret token, this way it doesn't fires up the
+ # exception
+ response = response.replace('oauth_token_secret=',
+ 'oauth_token_secret=None')
+ token = Token.from_string(response)
+
+ token.user_info = params
+ return token
+
+ def user_data(self, access_token, *args, **kwargs):
+ """Return user data provided"""
+ # drop lists
+ return dict([(key, val[0]) for key, val in
+ access_token.user_info.items()])
+
+
+# Backend definition
+BACKENDS = {
+ 'evernote': EvernoteAuth,
+}
View
7 social_auth/backends/contrib/github.py
@@ -51,11 +51,8 @@ class GithubAuth(BaseOAuth2):
SETTINGS_KEY_NAME = 'GITHUB_APP_ID'
SETTINGS_SECRET_NAME = 'GITHUB_API_SECRET'
SCOPE_SEPARATOR = ','
-
- def get_scope(self):
- """Return list with needed access scope"""
- # Look at http://developer.github.com/v3/oauth/
- return setting('GITHUB_EXTENDED_PERMISSIONS', [])
+ # Look at http://developer.github.com/v3/oauth/
+ SCOPE_VAR_NAME = 'GITHUB_EXTENDED_PERMISSIONS'
def user_data(self, access_token, *args, **kwargs):
"""Loads user data from service"""
View
18 social_auth/backends/contrib/live.py
@@ -4,12 +4,15 @@
Settings:
LIVE_CLIENT_ID
LIVE_CLIENT_SECRET
-LIVE_EXTENDED_PERMISSIONS (default: wl.basic, wl.emails)
+LIVE_EXTENDED_PERMISSIONS (defaults are: wl.basic, wl.emails)
References:
* oAuth http://msdn.microsoft.com/en-us/library/live/hh243649.aspx
* Scopes http://msdn.microsoft.com/en-us/library/live/hh243646.aspx
* REST http://msdn.microsoft.com/en-us/library/live/hh243648.aspx
+
+Throws:
+AuthUnknownError - if user data retrieval fails
"""
from urllib import urlencode, urlopen
@@ -17,6 +20,7 @@
from social_auth.utils import setting
from social_auth.backends import BaseOAuth2, OAuthBackend, USERNAME
+from social_auth.backends.exceptions import AuthUnknownError
# Live Connect configuration
@@ -24,7 +28,7 @@
LIVE_ACCESS_TOKEN_URL = 'https://login.live.com/oauth20_token.srf'
LIVE_USER_DATA_URL = 'https://apis.live.net/v5.0/me'
LIVE_SERVER = 'live.com'
-LIVE_EXTENDED_PERMISSIONS = ['wl.basic', 'wl.emails']
+LIVE_DEFAULT_PERMISSIONS = ['wl.basic', 'wl.emails']
class LiveBackend(OAuthBackend):
@@ -64,10 +68,8 @@ class LiveAuth(BaseOAuth2):
SETTINGS_KEY_NAME = 'LIVE_CLIENT_ID'
SETTINGS_SECRET_NAME = 'LIVE_CLIENT_SECRET'
SCOPE_SEPARATOR = ','
-
- def get_scope(self):
- """Return list with needed access scope"""
- return setting('LIVE_EXTENDED_PERMISSIONS', LIVE_EXTENDED_PERMISSIONS)
+ SCOPE_VAR_NAME = 'LIVE_EXTENDED_PERMISSIONS'
+ DEFAULT_SCOPE = LIVE_DEFAULT_PERMISSIONS
def user_data(self, access_token, *args, **kwargs):
"""Loads user data from service"""
@@ -76,8 +78,8 @@ def user_data(self, access_token, *args, **kwargs):
})
try:
return simplejson.load(urlopen(url))
- except ValueError:
- return None
+ except (ValueError, IOError):
+ raise AuthUnknownError("Error during profile retrieval, please, try again later")
# Backend definition
View
24 social_auth/backends/contrib/yahoo.py
@@ -9,12 +9,20 @@
* http://developer.yahoo.com/oauth/guide/oauth-auth-flow.html
* http://developer.yahoo.com/social/rest_api_guide/introspective-guid-resource.html
* http://developer.yahoo.com/social/rest_api_guide/extended-profile-resource.html
+
+Scopes:
+To make this extension works correctly you have to have at least
+Yahoo Profile scope with Read permission
+
+Throws:
+AuthUnknownError - if user data retrieval fails (guid or profile)
"""
from django.utils import simplejson
from social_auth.utils import setting
from social_auth.backends import ConsumerBasedOAuth, OAuthBackend, USERNAME
+from social_auth.backends.exceptions import AuthUnknownError
# Google OAuth base configuration
@@ -38,11 +46,15 @@ def get_user_id(self, details, response):
return response['guid']
def get_user_details(self, response):
- """Return user details from Orkut account"""
+ """Return user details from Yahoo Profile"""
fname = response.get('givenName')
lname = response.get('familyName')
+ if 'emails' in response:
+ email = response.get('emails')[0]['handle']
+ else:
+ email = ''
return {USERNAME: response.get('nickname'),
- 'email': response.get('emails')[0]['handle'],
+ 'email': email,
'fullname': '%s %s' % (fname, lname),
'first_name': fname,
'last_name': lname}
@@ -66,9 +78,13 @@ def user_data(self, access_token, *args, **kwargs):
try:
return simplejson.loads(response)['profile']
except ValueError:
- return None
+ raise AuthUnknownError("Error during profile retrieval, please, try again later")
def _get_guid(self, access_token):
+ """
+ Beause you have to provide GUID for every API request
+ it's also returned during one of OAuth calls
+ """
url = 'http://social.yahooapis.com/v1/me/guid?format=json'
request = self.oauth_request(access_token, url)
response = self.fetch_response(request)
@@ -76,7 +92,7 @@ def _get_guid(self, access_token):
json = simplejson.loads(response)
return json['guid']['value']
except ValueError:
- return 'me'
+ raise AuthUnknownError("Error during user id retrieval, please, try again later")
# Backend definition
BACKENDS = {
View
4 social_auth/backends/facebook.py
@@ -60,9 +60,7 @@ class FacebookAuth(BaseOAuth2):
AUTHORIZATION_URL = 'https://www.facebook.com/dialog/oauth'
SETTINGS_KEY_NAME = 'FACEBOOK_APP_ID'
SETTINGS_SECRET_NAME = 'FACEBOOK_API_SECRET'
-
- def get_scope(self):
- return setting('FACEBOOK_EXTENDED_PERMISSIONS', [])
+ SCOPE_VAR_NAME = 'FACEBOOK_EXTENDED_PERMISSIONS'
def user_data(self, access_token, *args, **kwargs):
"""Loads user data from service"""
View
10 social_auth/backends/google.py
@@ -150,14 +150,15 @@ def oauth_request(self, token, url, extra_params=None):
extra_params['xoauth_displayname'] = xoauth_displayname
return super(GoogleOAuth, self).oauth_request(token, url, extra_params)
- def get_key_and_secret(self):
+ @classmethod
+ def get_key_and_secret(cls):
"""Return Google OAuth Consumer Key and Consumer Secret pair, uses
anonymous by default, beware that this marks the application as not
registered and a security badge is displayed on authorization page.
http://code.google.com/apis/accounts/docs/OAuth_ref.html#SigningOAuth
"""
try:
- return super(GoogleOAuth, self).get_key_and_secret()
+ return super(GoogleOAuth, cls).get_key_and_secret()
except AttributeError:
return 'anonymous', 'anonymous'
@@ -184,9 +185,8 @@ class GoogleOAuth2(BaseOAuth2):
ACCESS_TOKEN_URL = 'https://accounts.google.com/o/oauth2/token'
SETTINGS_KEY_NAME = _OAUTH2_KEY_NAME
SETTINGS_SECRET_NAME = 'GOOGLE_OAUTH2_CLIENT_SECRET'
-
- def get_scope(self):
- return GOOGLE_OAUTH2_SCOPE + setting('GOOGLE_OAUTH_EXTRA_SCOPE', [])
+ SCOPE_VAR_NAME = 'GOOGLE_OAUTH_EXTRA_SCOPE'
+ DEFAULT_SCOPE = GOOGLE_OAUTH2_SCOPE
def user_data(self, access_token, *args, **kwargs):
"""Return user data from Google API"""
View
44 social_auth/backends/utils.py
@@ -0,0 +1,44 @@
+from urllib2 import urlopen
+from oauth2 import Consumer as OAuthConsumer, Token, Request as OAuthRequest, \
+ SignatureMethod_HMAC_SHA1
+
+from django.utils import simplejson
+
+from social_auth.models import User
+
+
+def consumer_oauth_url_request(backend, url, user_or_id, redirect_uri='/',
+ json=True):
+ """Builds and retrieves an OAuth signed response."""
+ if isinstance(user_or_id, User):
+ user = user_or_id
+ else:
+ user = User.objects.get(pk=user_or_id)
+
+ oauth_info = user.social_auth.filter(provider=backend.AUTH_BACKEND.name)[0]
+ token = Token.from_string(oauth_info.tokens['access_token'])
+ request = build_consumer_oauth_request(backend, token, url, redirect_uri)
+ response = '\n'.join(urlopen(request.to_url()).readlines())
+
+ if json:
+ response = simplejson.loads(response)
+ return response
+
+
+def build_consumer_oauth_request(backend, token, url, redirect_uri='/',
+ oauth_verifier=None, extra_params=None):
+ """Builds a Consumer OAuth request."""
+ params = {'oauth_callback': redirect_uri}
+ if extra_params:
+ params.update(extra_params)
+
+ if oauth_verifier:
+ params['oauth_verifier'] = oauth_verifier
+
+ consumer = OAuthConsumer(*backend.get_key_and_secret())
+ request = OAuthRequest.from_consumer_and_token(consumer,
+ token=token,
+ http_url=url,
+ parameters=params)
+ request.sign_request(SignatureMethod_HMAC_SHA1(), consumer, token)
+ return request
Please sign in to comment.
Something went wrong with that request. Please try again.