From 96309f5934b90fcceedb73eed9487832e0c0bee0 Mon Sep 17 00:00:00 2001 From: Caio Ariede Date: Tue, 23 Nov 2010 11:11:17 -0200 Subject: [PATCH] orkut support --- README.rst | 23 +++++++- example/local_settings.py.template | 2 + social_auth/auth.py | 94 +++++++++++++++++++++++++++++- social_auth/backends.py | 18 ++++++ social_auth/conf.py | 10 ++++ social_auth/views.py | 3 +- 6 files changed, 145 insertions(+), 5 deletions(-) diff --git a/README.rst b/README.rst index 59ba498..0603029 100644 --- a/README.rst +++ b/README.rst @@ -40,6 +40,7 @@ Installation AUTHENTICATION_BACKENDS = ( 'social_auth.backends.TwitterOAuthBackend', 'social_auth.backends.FacebookOAuthBackend', + 'social_auth.backends.OrkutOAuthBackend', 'social_auth.backends.OpenIDBackend', 'django.contrib.auth.backends.ModelBackend', ) @@ -50,6 +51,8 @@ Installation TWITTER_CONSUMER_SECRET = '' FACEBOOK_APP_ID = '' FACEBOOK_API_SECRET = '' + ORKUT_CONSUMER_KEY = '' + ORKUT_CONSUMER_SECRET = '' - Setup login urls:: @@ -130,9 +133,8 @@ providing endpoint Url. OAuth ----- OAuth communication demands a set of keys exchange to validate the client -authenticity prior to user approbation, Twitter and Facebook facilitates these -keys by application registration, see `Twitter`_ and `Facebook`_ sections for -details. +authenticity prior to user approbation, Twitter, Facebook and Orkut facilitates +these keys by application registration, see next sections for details. ------- @@ -167,6 +169,21 @@ Further documentation at `Facebook development resources`_: FACEBOOK_APP_ID FACEBOOK_API_SECRET +------- +Orkut +------- +Orkut offers per application keys named "Consumer Key" and +"Consumer Secret". To enable Orkut these two keys are needed. + +For getting your consumer_key and consumer_secret, you may look +the following link for more information: + +http://www.google.com/support/a/bin/answer.py?hl=en&answer=162105 + +- fill "Consumer Key" and "Consumer Secret" settings:: + + ORKUT_CONSUMER_KEY + ORKUT_CONSUMER_SECRET ---- Bugs diff --git a/example/local_settings.py.template b/example/local_settings.py.template index f6726fa..e43eba8 100644 --- a/example/local_settings.py.template +++ b/example/local_settings.py.template @@ -2,6 +2,8 @@ TWITTER_CONSUMER_KEY = '' TWITTER_CONSUMER_SECRET = '' FACEBOOK_APP_ID = '' FACEBOOK_API_SECRET = '' +ORKUT_CONSUMER_KEY = '' +ORKUT_CONSUMER_SECRET = '' SOCIAL_AUTH_CREATE_USERS = True SOCIAL_AUTH_FORCE_RANDOM_USERNAME = False SOCIAL_AUTH_DEFAULT_USERNAME = 'socialauth_user' diff --git a/social_auth/auth.py b/social_auth/auth.py index 35a02c8..61a5ef9 100644 --- a/social_auth/auth.py +++ b/social_auth/auth.py @@ -20,7 +20,10 @@ from .conf import AX_ATTRS, SREG_ATTR, OPENID_ID_FIELD, SESSION_NAME, \ TWITTER_REQUEST_TOKEN_URL, TWITTER_ACCESS_TOKEN_URL, \ TWITTER_AUTHORIZATION_URL, TWITTER_CHECK_AUTH, \ TWITTER_UNAUTHORIZED_TOKEN_NAME, FACEBOOK_CHECK_AUTH, \ - FACEBOOK_AUTHORIZATION_URL, FACEBOOK_ACCESS_TOKEN_URL + FACEBOOK_AUTHORIZATION_URL, FACEBOOK_ACCESS_TOKEN_URL, \ + ORKUT_SERVER, ORKUT_SCOPE, ORKUT_UNAUTHORIZED_TOKEN_NAME, \ + ORKUT_REQUEST_TOKEN_URL, ORKUT_ACCESS_TOKEN_URL, \ + ORKUT_AUTHORIZATION_URL, ORKUT_REST_ENDPOINT, ORKUT_EXTRA_DATA class OpenIdAuth(BaseAuth): @@ -129,6 +132,95 @@ class BaseOAuth(BaseAuth): self.redirect_uri = self.request.build_absolute_uri(self.redirect) +class OrkutAuth(BaseOAuth): + """Orkut OAuth authentication mechanism""" + def auth_url(self): + """Returns redirect url""" + token = self.unauthorized_token() + self.request.session[ORKUT_UNAUTHORIZED_TOKEN_NAME] = token.to_string() + return self.oauth_request(token, ORKUT_AUTHORIZATION_URL).to_url() + + def auth_complete(self): + """Returns user, might be logged in""" + unauthed_token = self.request.session.get(ORKUT_UNAUTHORIZED_TOKEN_NAME) + if not unauthed_token: + raise ValueError, 'Missing unauthorized token' + + token = OAuthToken.from_string(unauthed_token) + if token.key != self.request.GET.get('oauth_token', 'no-token'): + raise ValueError, 'Incorrect tokens' + access_token = self.access_token(token) + data = self.user_data(access_token) + if data is not None: + data['access_token'] = access_token.to_string() + return authenticate(response=data, orkut=True) + + def unauthorized_token(self): + """Return request for unauthorized token (first stage)""" + request = self.oauth_request(token=None, url=ORKUT_REQUEST_TOKEN_URL) + response = self.fetch_response(request) + return OAuthToken.from_string(response) + + def oauth_request(self, token, url, params={}): + """Generate OAuth request, setups callback url""" + params.update({'oauth_callback': self.redirect_uri, \ + 'scope': ORKUT_SCOPE}) + if 'oauth_verifier' in self.request.GET: + params['oauth_verifier'] = self.request.GET['oauth_verifier'] + request = OAuthRequest.from_consumer_and_token(self.consumer, + token=token, + http_url=url, + parameters=params) + request.sign_request(OAuthSignatureMethod_HMAC_SHA1(), self.consumer, + token) + return request + + def fetch_response(self, request): + """Executes request and fetchs service response""" + self.connection.request(request.http_method, request.to_url()) + response = self.connection.getresponse() + return response.read() + + def access_token(self, token): + """Return request for access token value""" + request = self.oauth_request(token, ORKUT_ACCESS_TOKEN_URL) + return OAuthToken.from_string(self.fetch_response(request)) + + def user_data(self, access_token): + """Loads user data from service""" + params = {'method': 'people.get', \ + 'id': 'myself', \ + 'userId': '@me', \ + 'groupId': '@self', \ + 'fields': 'name,displayName,emails,%s' % ORKUT_EXTRA_DATA} + request = self.oauth_request(access_token, ORKUT_REST_ENDPOINT, params) + response = urllib.urlopen(request.to_url()).read() + try: + json = simplejson.loads(response) + return json['data'] + except simplejson.JSONDecodeError: + return None + + @property + def connection(self): + """Setups connection""" + conn = getattr(self, '_connection', None) + if conn is None: + conn = httplib.HTTPSConnection(ORKUT_SERVER) + setattr(self, '_connection', conn) + return conn + + @property + def consumer(self): + """Setups consumer""" + cons = getattr(self, '_consumer', None) + if cons is None: + cons = OAuthConsumer(settings.ORKUT_CONSUMER_KEY, + settings.ORKUT_CONSUMER_SECRET) + setattr(self, '_consumer', cons) + return cons + + class TwitterAuth(BaseOAuth): """Twitter OAuth authentication mechanism""" def auth_url(self): diff --git a/social_auth/backends.py b/social_auth/backends.py index c73e70c..f6640ce 100644 --- a/social_auth/backends.py +++ b/social_auth/backends.py @@ -36,6 +36,24 @@ class TwitterBackend(OAuthBackend): 'last_name': ''} +class OrkutBackend(OAuthBackend): + """Orkut OAuth authentication backend""" + name = 'orkut' + + def authenticate(self, **kwargs): + """Authenticate user only if this was a Orkut request""" + if kwargs.pop('orkut', False): + return super(OrkutBackend, self).authenticate(**kwargs) + + def get_user_details(self, response): + """Return user details from Orkut account""" + return {'email': response['emails'][0]['value'], + 'username': response['displayName'], + 'fullname': response['displayName'], + 'firstname': response['name']['givenName'], + 'lastname': response['name']['familyName']} + + class FacebookBackend(OAuthBackend): """Facebook OAuth authentication backend""" name = 'facebook' diff --git a/social_auth/conf.py b/social_auth/conf.py index 91604f5..86b8f1a 100644 --- a/social_auth/conf.py +++ b/social_auth/conf.py @@ -13,6 +13,16 @@ FACEBOOK_AUTHORIZATION_URL = 'https://%s/oauth/authorize' % FACEBOOK_SERVER FACEBOOK_ACCESS_TOKEN_URL = 'https://%s/oauth/access_token' % FACEBOOK_SERVER FACEBOOK_CHECK_AUTH = 'https://%s/me' % FACEBOOK_SERVER +# Orkut configuration +ORKUT_SERVER = 'www.google.com' +ORKUT_REQUEST_TOKEN_URL = 'https://%s/accounts/OAuthGetRequestToken' % ORKUT_SERVER +ORKUT_ACCESS_TOKEN_URL = 'https://%s/accounts/OAuthGetAccessToken' % ORKUT_SERVER +ORKUT_AUTHORIZATION_URL = 'https://%s/accounts/OAuthAuthorizeToken' % ORKUT_SERVER +ORKUT_SCOPE = 'http://orkut.gmodules.com/social/' +ORKUT_REST_ENDPOINT = 'http://www.orkut.com/social/rpc' +ORKUT_UNAUTHORIZED_TOKEN_NAME = 'orkut_unauthorized_token' +ORKUT_EXTRA_DATA = 'age,gender,currentLocation' + # OpenID configuration OLD_AX_ATTRS = [ ('http://schema.openid.net/contact/email', 'old_email'), diff --git a/social_auth/views.py b/social_auth/views.py index f76b98f..c791ede 100644 --- a/social_auth/views.py +++ b/social_auth/views.py @@ -5,7 +5,7 @@ from django.http import HttpResponseRedirect, HttpResponse, \ from django.core.urlresolvers import reverse from django.contrib.auth import login, REDIRECT_FIELD_NAME -from .auth import TwitterAuth, FacebookAuth, OpenIdAuth, GoogleAuth, YahooAuth +from .auth import TwitterAuth, FacebookAuth, OpenIdAuth, GoogleAuth, YahooAuth, OrkutAuth # Authenticatin backends @@ -15,6 +15,7 @@ BACKENDS = { 'google': GoogleAuth, 'yahoo': YahooAuth, 'openid': OpenIdAuth, + 'orkut': OrkutAuth, } def auth(request, backend): -- 2.39.5