From 350cd92dbbaefd12c0df8336c19e5eb39f77640a Mon Sep 17 00:00:00 2001 From: jordan Date: Tue, 17 May 2011 20:36:25 +0000 Subject: [PATCH] adding support for the new Facebook oauth 2.0 authentication model git-svn-id: http://svn.osqa.net/svnroot/osqa/trunk@1044 0cfe37f9-358a-4d5e-be75-b63607b5c754 --- forum/views/auth.py | 10 ++- forum_modules/facebookauth/authentication.py | 65 ++++++------------- .../facebookauth/templates/button.html | 48 ++++++-------- .../facebookauth/templates/xd_receiver.html | 1 - forum_modules/facebookauth/urls.py | 9 --- forum_modules/facebookauth/views.py | 11 ---- 6 files changed, 50 insertions(+), 94 deletions(-) delete mode 100644 forum_modules/facebookauth/templates/xd_receiver.html delete mode 100644 forum_modules/facebookauth/urls.py delete mode 100644 forum_modules/facebookauth/views.py diff --git a/forum/views/auth.py b/forum/views/auth.py index db8cc32..c0fecc1 100644 --- a/forum/views/auth.py +++ b/forum/views/auth.py @@ -7,6 +7,7 @@ from forum.http_responses import HttpResponseUnauthorized from django.utils.safestring import mark_safe from django.utils.translation import ugettext as _ from django.utils.http import urlquote_plus +from django.utils.encoding import smart_unicode from forum.views.decorators import login_required from forum.modules import decorate from django.contrib.auth import login, logout @@ -197,7 +198,12 @@ def external_register(request): return HttpResponseRedirect(reverse('auth_signin')) provider_class = AUTH_PROVIDERS[auth_provider].consumer - user_data = provider_class.get_user_data(request.session['assoc_key']) + + # Pass the cookies to the Facebook authentication class get_user_data method. We need them to take the access token. + if provider_class.__class__.__name__ == 'FacebookAuthConsumer': + user_data = provider_class.get_user_data(request.COOKIES) + else: + user_data = provider_class.get_user_data(request.session['assoc_key']) if not user_data: user_data = request.session.get('auth_consumer_data', {}) @@ -374,7 +380,7 @@ def login_and_forward(request, user, forward=None, message=None): login(request, user) if message is None: - message = _("Welcome back %s, you are now logged in") % user.username + message = _("Welcome back %s, you are now logged in") % smart_unicode(user.username) request.user.message_set.create(message=message) diff --git a/forum_modules/facebookauth/authentication.py b/forum_modules/facebookauth/authentication.py index b19d794..308c18c 100644 --- a/forum_modules/facebookauth/authentication.py +++ b/forum_modules/facebookauth/authentication.py @@ -2,8 +2,10 @@ import hashlib from time import time from datetime import datetime from urllib import urlopen, urlencode +from urlparse import parse_qs from forum.authentication.base import AuthenticationConsumer, ConsumerTemplateContext, InvalidAuthentication from django.utils.translation import ugettext as _ +from django.utils.encoding import smart_unicode import settings @@ -16,64 +18,39 @@ except: decoder = JSONDecoder() return decoder.decode(json.read()) -REST_SERVER = 'http://api.facebook.com/restserver.php' - class FacebookAuthConsumer(AuthenticationConsumer): def process_authentication_request(self, request): API_KEY = str(settings.FB_API_KEY) - if API_KEY in request.COOKIES: - if self.check_cookies_signature(request.COOKIES): - if self.check_session_expiry(request.COOKIES): - return request.COOKIES[API_KEY + '_user'] - else: - raise InvalidAuthentication(_('Sorry, your Facebook session has expired, please try again')) + # Check if the Facebook cookie has been received. + if 'fbs_%s' % API_KEY in request.COOKIES: + fbs_cookie = request.COOKIES['fbs_%s' % API_KEY] + parsed_fbs = parse_qs(smart_unicode(fbs_cookie)) + self.parsed_fbs = parsed_fbs + + # Check if the session hasn't expired. + if self.check_session_expiry(request.COOKIES): + return parsed_fbs['uid'][0] else: - raise InvalidAuthentication(_('The authentication with Facebook connect failed due to an invalid signature')) + raise InvalidAuthentication(_('Sorry, your Facebook session has expired, please try again')) else: raise InvalidAuthentication(_('The authentication with Facebook connect failed, cannot find authentication tokens')) - - def generate_signature(self, values): - keys = [] - - for key in sorted(values.keys()): - keys.append(key) - - signature = ''.join(['%s=%s' % (key, values[key]) for key in keys]) + str(settings.FB_APP_SECRET) - return hashlib.md5(signature).hexdigest() - def check_session_expiry(self, cookies): - return datetime.fromtimestamp(float(cookies[settings.FB_API_KEY+'_expires'])) > datetime.now() + return datetime.fromtimestamp(float(self.parsed_fbs['expires'][0])) > datetime.now() - def check_cookies_signature(self, cookies): + def get_user_data(self, cookies): API_KEY = str(settings.FB_API_KEY) + fbs_cookie = cookies['fbs_%s' % API_KEY] + parsed_fbs = parse_qs(smart_unicode(fbs_cookie)) - values = {} - - for key in cookies.keys(): - if (key.startswith(API_KEY + '_')): - values[key.replace(API_KEY + '_', '')] = cookies[key] - - return self.generate_signature(values) == cookies[API_KEY] - - def get_user_data(self, key): - request_data = { - 'method': 'Users.getInfo', - 'api_key': settings.FB_API_KEY, - 'call_id': time(), - 'v': '1.0', - 'uids': key, - 'fields': 'name,first_name,last_name,email', - 'format': 'json', - } - - request_data['sig'] = self.generate_signature(request_data) - fb_response = load_json(urlopen(REST_SERVER, urlencode(request_data)))[0] + # Communicate with the access token to the Facebook oauth interface. + json = load_json(urlopen('https://graph.facebook.com/me?access_token=%s' % parsed_fbs['access_token'][0])) + # Return the user data. return { - 'username': fb_response['first_name'] + ' ' + fb_response['last_name'], - 'email': fb_response['email'] + 'username': '%s %s' % (smart_unicode(json['first_name']), smart_unicode(json['last_name'])), + 'email': smart_unicode(json['email']), } class FacebookAuthContext(ConsumerTemplateContext): diff --git a/forum_modules/facebookauth/templates/button.html b/forum_modules/facebookauth/templates/button.html index ceae1fc..ba03a30 100644 --- a/forum_modules/facebookauth/templates/button.html +++ b/forum_modules/facebookauth/templates/button.html @@ -1,38 +1,32 @@ - - + -Facebook \ No newline at end of file + diff --git a/forum_modules/facebookauth/templates/xd_receiver.html b/forum_modules/facebookauth/templates/xd_receiver.html deleted file mode 100644 index 9c1664d..0000000 --- a/forum_modules/facebookauth/templates/xd_receiver.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/forum_modules/facebookauth/urls.py b/forum_modules/facebookauth/urls.py deleted file mode 100644 index cbe3b6c..0000000 --- a/forum_modules/facebookauth/urls.py +++ /dev/null @@ -1,9 +0,0 @@ -from django.conf.urls.defaults import * -from django.views.generic.simple import direct_to_template - -from views import user_is_registered - -urlpatterns = patterns('', - url(r'^xd_receiver.htm$', direct_to_template, {'template': 'modules/facebookauth/xd_receiver.html'}, name='xd_receiver'), - url(r'^facebook/user_is_registered/', user_is_registered, name="facebook_user_is_registered"), -) \ No newline at end of file diff --git a/forum_modules/facebookauth/views.py b/forum_modules/facebookauth/views.py deleted file mode 100644 index f77c628..0000000 --- a/forum_modules/facebookauth/views.py +++ /dev/null @@ -1,11 +0,0 @@ -from forum.models import AuthKeyUserAssociation -from django.http import HttpResponse - -def user_is_registered(request): - try: - fb_uid = request.POST['fb_uid'] - #print fb_uid - AuthKeyUserAssociation.objects.get(key=fb_uid) - return HttpResponse('yes') - except: - return HttpResponse('no') \ No newline at end of file -- 2.39.5