summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEvgeny Fadeev <evgeny.fadeev@gmail.com>2012-12-23 01:52:07 -0300
committerEvgeny Fadeev <evgeny.fadeev@gmail.com>2012-12-23 01:52:07 -0300
commit661460d593d32cbc91382b30dbb2a4034701114f (patch)
tree9276e0d1b4aadff50c8723d7e73837b2dbed1293
parent1819a86eeed5dd3978a7f66ac168410bb20f7c53 (diff)
downloadaskbot-661460d593d32cbc91382b30dbb2a4034701114f.tar.gz
askbot-661460d593d32cbc91382b30dbb2a4034701114f.tar.bz2
askbot-661460d593d32cbc91382b30dbb2a4034701114f.zip
first pass on fixing facebook login, "approve" path works
-rw-r--r--askbot/__init__.py1
-rw-r--r--askbot/deps/django_authopenid/backends.py2
-rw-r--r--askbot/deps/django_authopenid/forms.py3
-rw-r--r--askbot/deps/django_authopenid/urls.py5
-rw-r--r--askbot/deps/django_authopenid/util.py88
-rw-r--r--askbot/deps/django_authopenid/views.py88
-rw-r--r--askbot/media/jquery-openid/jquery.openid.js7
-rw-r--r--askbot/templates/authopenid/logout.html21
-rw-r--r--askbot/templates/authopenid/providers_javascript.html16
-rw-r--r--askbot_requirements.txt1
-rw-r--r--askbot_requirements_dev.txt4
11 files changed, 108 insertions, 128 deletions
diff --git a/askbot/__init__.py b/askbot/__init__.py
index 72d9c240..d64c4068 100644
--- a/askbot/__init__.py
+++ b/askbot/__init__.py
@@ -23,6 +23,7 @@ REQUIREMENTS = {
'keyedcache': 'django-keyedcache',
'threaded_multihost': 'django-threaded-multihost',
'robots': 'django-robots',
+ 'sanction': 'sanction',
'unidecode': 'unidecode',
'django_countries': 'django-countries==1.0.5',
'djcelery': 'django-celery==2.2.7',
diff --git a/askbot/deps/django_authopenid/backends.py b/askbot/deps/django_authopenid/backends.py
index 1e8626ac..f719e811 100644
--- a/askbot/deps/django_authopenid/backends.py
+++ b/askbot/deps/django_authopenid/backends.py
@@ -145,7 +145,7 @@ class AuthBackend(object):
return None
elif method == 'oauth':
- if login_providers[provider_name]['type'] == 'oauth':
+ if login_providers[provider_name]['type'] in ('oauth', 'oauth2'):
try:
assoc = UserAssociation.objects.get(
openid_url = oauth_user_id,
diff --git a/askbot/deps/django_authopenid/forms.py b/askbot/deps/django_authopenid/forms.py
index 3c0e8e7f..f8822877 100644
--- a/askbot/deps/django_authopenid/forms.py
+++ b/askbot/deps/django_authopenid/forms.py
@@ -212,7 +212,8 @@ class LoginForm(forms.Form):
self.cleaned_data['login_type'] = 'openid'
elif provider_type == 'oauth':
self.cleaned_data['login_type'] = 'oauth'
- pass
+ elif provider_type == 'oauth2':
+ self.cleaned_data['login_type'] = 'oauth2'
elif provider_type == 'facebook':
self.cleaned_data['login_type'] = 'facebook'
#self.do_clean_oauth_fields()
diff --git a/askbot/deps/django_authopenid/urls.py b/askbot/deps/django_authopenid/urls.py
index 1b7d0b01..1d07aa94 100644
--- a/askbot/deps/django_authopenid/urls.py
+++ b/askbot/deps/django_authopenid/urls.py
@@ -19,6 +19,11 @@ urlpatterns = patterns('askbot.deps.django_authopenid.views',
'complete_oauth_signin',
name='user_complete_oauth_signin'
),
+ url(
+ r'^signin/complete-oauth2/',
+ 'complete_oauth2_signin',
+ name='user_complete_oauth2_signin'
+ ),
url(r'^%s$' % _('register/'), 'register', name='user_register'),
url(
r'^%s$' % _('signup/'),
diff --git a/askbot/deps/django_authopenid/util.py b/askbot/deps/django_authopenid/util.py
index e003c493..72ee09df 100644
--- a/askbot/deps/django_authopenid/util.py
+++ b/askbot/deps/django_authopenid/util.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
import cgi
import urllib
-import urllib2
+import urlparse
import functools
import re
import random
@@ -9,10 +9,11 @@ from openid.store.interface import OpenIDStore
from openid.association import Association as OIDAssociation
from openid.extensions import sreg
from openid import store as openid_store
-import oauth2 as oauth
+import oauth2 as oauth # OAuth1 protocol
from django.db.models.query import Q
from django.conf import settings
+from django.core.urlresolvers import reverse
from django.utils import simplejson
from django.utils.datastructures import SortedDict
from django.utils.translation import ugettext as _
@@ -386,12 +387,23 @@ def get_enabled_major_login_providers():
'password_changeable': True
}
+ def get_facebook_user_id(client):
+ """returns facebook user id given the access token"""
+ profile = client.request('me')
+ return profile['id']
+
if askbot_settings.FACEBOOK_KEY and askbot_settings.FACEBOOK_SECRET:
data['facebook'] = {
'name': 'facebook',
'display_name': 'Facebook',
- 'type': 'facebook',
+ 'type': 'oauth2',
+ 'auth_endpoint': 'https://www.facebook.com/dialog/oauth/',
+ 'token_endpoint': 'https://graph.facebook.com/oauth/access_token',
+ 'resource_endpoint': 'https://graph.facebook.com/',
'icon_media_path': '/jquery-openid/images/facebook.gif',
+ 'get_user_id_function': get_facebook_user_id,
+ 'response_parser': lambda data: dict(urlparse.parse_qsl(data))
+
}
if askbot_settings.TWITTER_KEY and askbot_settings.TWITTER_SECRET:
data['twitter'] = {
@@ -666,8 +678,11 @@ def get_oauth_parameters(provider_name):
elif provider_name == 'identi.ca':
consumer_key = askbot_settings.IDENTICA_KEY
consumer_secret = askbot_settings.IDENTICA_SECRET
+ elif provider_name == 'facebook':
+ consumer_key = askbot_settings.FACEBOOK_KEY
+ consumer_secret = askbot_settings.FACEBOOK_SECRET
else:
- raise ValueError('sorry, only linkedin and twitter oauth for now')
+ raise ValueError('unexpected oauth provider %s' % provider_name)
data['consumer_key'] = consumer_key
data['consumer_secret'] = consumer_secret
@@ -781,62 +796,21 @@ class OAuthConnection(object):
return auth_url
-class FacebookError(Exception):
- """Raised when there's something not right
- with FacebookConnect
- """
- pass
+def get_oauth2_starter_url(provider_name):
+ """returns redirect url for the oauth2 protocol for a given provider"""
+ from sanction.client import Client
-def urlsafe_b64decode(input):
- length = len(input)
- return base64.urlsafe_b64decode(
- input.ljust(length + length % 4, '=')
+ providers = get_enabled_login_providers()
+ params = providers[provider_name]
+ client_id = getattr(askbot_settings, provider_name.upper() + '_KEY')
+ redirect_uri = askbot_settings.APP_URL + reverse('user_complete_oauth2_signin')
+ client = Client(
+ auth_endpoint=params['auth_endpoint'],
+ client_id=client_id,
+ redirect_uri=redirect_uri
)
+ return client.auth_uri()
-def parse_signed_facebook_request(signed_request, secret):
- """
- Parse signed_request given by Facebook (usually via POST),
- decrypt with app secret.
-
- Arguments:
- signed_request -- Facebook's signed request given through POST
- secret -- Application's app_secret required to decrpyt signed_request
-
- slightly edited copy from https://gist.github.com/1190267
- """
-
- if "." in signed_request:
- esig, payload = signed_request.split(".")
- else:
- return {}
-
- sig = urlsafe_b64decode(str(esig))
- data = simplejson.loads(urlsafe_b64decode(str(payload)))
-
- if not isinstance(data, dict):
- raise ValueError("Pyload is not a json string!")
- return {}
-
- if data["algorithm"].upper() == "HMAC-SHA256":
- if hmac.new(str(secret), str(payload), hashlib.sha256).digest() == sig:
- return data
- else:
- raise ValueError("Not HMAC-SHA256 encrypted!")
-
- return {}
-
-def get_facebook_user_id(request):
- try:
- key = askbot_settings.FACEBOOK_KEY
- fb_cookie = request.COOKIES['fbsr_%s' % key]
- if not fb_cookie:
- raise ValueError('cannot access facebook cookie')
-
- secret = askbot_settings.FACEBOOK_SECRET
- response = parse_signed_facebook_request(fb_cookie, secret)
- return response['user_id']
- except Exception, e:
- raise FacebookError(e)
def ldap_check_password(username, password):
import ldap
diff --git a/askbot/deps/django_authopenid/views.py b/askbot/deps/django_authopenid/views.py
index 1d1a9a57..a7dcabb8 100644
--- a/askbot/deps/django_authopenid/views.py
+++ b/askbot/deps/django_authopenid/views.py
@@ -54,6 +54,7 @@ from recaptcha_works.decorators import fix_recaptcha_remote_ip
from askbot.deps.django_authopenid.ldap_auth import ldap_create_user
from askbot.deps.django_authopenid.ldap_auth import ldap_authenticate
from askbot.utils.loading import load_module
+from sanction.client import Client as OAuth2Client
from urlparse import urlparse
from openid.consumer.consumer import Consumer, \
@@ -265,6 +266,58 @@ def not_authenticated(func):
return func(request, *args, **kwargs)
return decorated
+def complete_oauth2_signin(request):
+ if 'next_url' in request.session:
+ next_url = request.session['next_url']
+ del request.session['next_url']
+ else:
+ next_url = reverse('index')
+
+ providers = util.get_enabled_login_providers()
+ try:
+ provider_name = request.session['provider_name']
+ params = providers[provider_name]
+ assert(params['type'] == 'oauth2')
+ except Exception:
+ return HttpResponseBadRequest()
+
+ client_id = getattr(askbot_settings, provider_name.upper() + '_KEY')
+ client_secret = getattr(askbot_settings, provider_name.upper() + '_SECRET')
+
+ client = OAuth2Client(
+ token_endpoint=params['token_endpoint'],
+ resource_endpoint=params['resource_endpoint'],
+ redirect_uri=askbot_settings.APP_URL + reverse('user_complete_oauth2_signin'),
+ client_id=client_id,
+ client_secret=client_secret
+ )
+
+ client.request_token(code=request.GET['code'], parser=params['response_parser'])
+
+ #todo: possibly set additional parameters here
+ user_id = params['get_user_id_function'](client)
+
+ user = authenticate(
+ oauth_user_id = user_id,
+ provider_name = provider_name,
+ method = 'oauth'
+ )
+
+ logging.debug('finalizing oauth signin')
+
+ request.session['email'] = ''#todo: pull from profile
+ request.session['username'] = ''#todo: pull from profile
+
+ return finalize_generic_signin(
+ request = request,
+ user = user,
+ user_identifier = user_id,
+ login_provider_name = provider_name,
+ redirect_url = next_url
+ )
+
+
+
def complete_oauth_signin(request):
if 'next_url' in request.session:
next_url = request.session['next_url']
@@ -480,12 +533,10 @@ def signin(request, template_name='authopenid/signin.html'):
elif login_form.cleaned_data['login_type'] == 'oauth':
try:
#this url may need to have "next" piggibacked onto
- callback_url = reverse('user_complete_oauth_signin')
-
connection = util.OAuthConnection(
- provider_name,
- callback_url = callback_url
- )
+ provider_name,
+ callback_url=reverse('user_complete_oauth_signin')
+ )
connection.start()
@@ -504,32 +555,17 @@ def signin(request, template_name='authopenid/signin.html'):
) % {'provider': provider_name}
request.user.message_set.create(message = msg)
- elif login_form.cleaned_data['login_type'] == 'facebook':
- #have to redirect for consistency
- #there is a requirement that 'complete_signin'
+ elif login_form.cleaned_data['login_type'] == 'oauth2':
try:
- #this call may raise FacebookError
- user_id = util.get_facebook_user_id(request)
-
- user = authenticate(
- method = 'facebook',
- facebook_user_id = user_id
- )
-
- return finalize_generic_signin(
- request = request,
- user = user,
- user_identifier = user_id,
- login_provider_name = provider_name,
- redirect_url = next_url
- )
-
- except util.FacebookError, e:
+ redirect_url = util.get_oauth2_starter_url(provider_name)
+ request.session['provider_name'] = provider_name
+ return HttpResponseRedirect(redirect_url)
+ except util.OAuthError, e:
logging.critical(unicode(e))
msg = _('Unfortunately, there was some problem when '
'connecting to %(provider)s, please try again '
'or use another provider'
- ) % {'provider': 'Facebook'}
+ ) % {'provider': provider_name}
request.user.message_set.create(message = msg)
elif login_form.cleaned_data['login_type'] == 'wordpress_site':
diff --git a/askbot/media/jquery-openid/jquery.openid.js b/askbot/media/jquery-openid/jquery.openid.js
index 249413b9..881b2098 100644
--- a/askbot/media/jquery-openid/jquery.openid.js
+++ b/askbot/media/jquery-openid/jquery.openid.js
@@ -405,12 +405,7 @@ $.fn.authenticator = function() {
);
setup_event_handlers(
- signin_page.find('input.facebook'),
- start_facebook_login
- );
-
- setup_event_handlers(
- signin_page.find('input.oauth'),
+ signin_page.find('input.oauth,input.oauth2'),
start_simple_login
);
diff --git a/askbot/templates/authopenid/logout.html b/askbot/templates/authopenid/logout.html
index e3e1363f..47579679 100644
--- a/askbot/templates/authopenid/logout.html
+++ b/askbot/templates/authopenid/logout.html
@@ -5,27 +5,6 @@
<h1 class="section-title">{% trans %}You have successfully logged out{% endtrans %}</h1>
{% if have_federated_login_methods %}
<p>{% trans %}However, you still may be logged in to your OpenID provider. Please logout of your provider if you wish to do so.{% endtrans %}</p>
- {% if settings.FACEBOOK_KEY and settings.FACEBOOK_SECRET %}
- <div id="fb-root"></div>
- <script src="//connect.facebook.net/en_US/all.js"></script>
- <script>
- FB.init({appId: '{{settings.FACEBOOK_KEY}}', status: true, cookie: true, xfbml: true});
- </script>
- {% endif %}
{% endif %}
{% endblock %}
-{% block endjs %}
- <script type="text/javascript">
- $(document).ready(function(){
- //logout user from facebook
- if (typeof FB != 'undefined'){
- FB.getLoginStatus(function(response){
- if (response.session){
- FB.logout();
- }
- });
- }
- });
- </script>
-{% endblock %}
<!-- end logout.html -->
diff --git a/askbot/templates/authopenid/providers_javascript.html b/askbot/templates/authopenid/providers_javascript.html
index b0ee0ae2..bf9f2542 100644
--- a/askbot/templates/authopenid/providers_javascript.html
+++ b/askbot/templates/authopenid/providers_javascript.html
@@ -37,19 +37,3 @@
askbot['settings']['signin_always_show_local_login'] = {% if settings.SIGNIN_ALWAYS_SHOW_LOCAL_LOGIN %}true{% else %}false{% endif %};
$("body").authenticator();
</script>
-{% if settings.FACEBOOK_KEY and settings.FACEBOOK_SECRET %}
-<div id="fb-root"></div>
-<script src="//connect.facebook.net/en_US/all.js"></script>
-<script>
- $(document).ready(function(){
- if (typeof FB != 'undefined'){
- var ret = FB.init({appId: '{{settings.FACEBOOK_KEY}}', status: true, cookie: true, xfbml: true, oauth: true});
- FB.Event.subscribe('auth.authResponseChange', function(response){
- if (response.authResponse) {
- $('#signin-form').submit();
- }
- });
- };
- });
-</script>
-{% endif %}
diff --git a/askbot_requirements.txt b/askbot_requirements.txt
index 60f76d52..a9a939b4 100644
--- a/askbot_requirements.txt
+++ b/askbot_requirements.txt
@@ -19,6 +19,7 @@ django-recaptcha-works
python-openid
pystache==0.3.1
pytz
+sanction
django-tinymce
longerusername
beautifulsoup4
diff --git a/askbot_requirements_dev.txt b/askbot_requirements_dev.txt
index 4a90315f..1fbd064c 100644
--- a/askbot_requirements_dev.txt
+++ b/askbot_requirements_dev.txt
@@ -21,3 +21,7 @@ python-openid
pystache==0.3.1
pylint
pytz
+sanction
+django-tinymce
+longerusername
+beautifulsoup4