From: Matías Aguirre Date: Sat, 11 Feb 2012 19:38:16 +0000 (-0200) Subject: BrowserID support. Closes #228 X-Git-Url: https://git.parisson.com/?a=commitdiff_plain;h=4136ea49e53550b81b36d0ed6f45c987aa2318ae;p=django-social-auth.git BrowserID support. Closes #228 --- diff --git a/README.rst b/README.rst index 4e8c69b..9f31fda 100644 --- a/README.rst +++ b/README.rst @@ -112,6 +112,7 @@ Configuration 'social_auth.backends.google.GoogleOAuth2Backend', 'social_auth.backends.google.GoogleBackend', 'social_auth.backends.yahoo.YahooBackend', + 'social_auth.backends.browserid.BrowserIDBackend', 'social_auth.backends.contrib.linkedin.LinkedinBackend', 'social_auth.backends.contrib.livejournal.LiveJournalBackend', 'social_auth.backends.contrib.orkut.OrkutBackend', @@ -773,6 +774,19 @@ Flickr uses OAuth v1.0 for authentication. FLICKR_API_SECRET = '' +--------- +BrowserID +--------- +Support for BrowserID_ is possible by posting the ``assertion`` code to +``/complete/browserid/`` URL. + +The setup doesn't need any setting, just the usual BrowserID_ javascript +include in your document and the needed mechanism to trigger the POST to +`django-social-auth`_. + +Check the second "Use Case" for an implementation example. + + ------- Testing ------- @@ -828,6 +842,40 @@ Some particular use cases are listed below. disconnect, name='socialauth_disconnect_individual'), ) +2. Include a similar snippet in your page to make BrowserID_ work:: + + + + +
+ + BrowserID +
+ + + + + ------------- Miscellaneous ------------- @@ -964,7 +1012,7 @@ Base work is copyrighted by: .. _micrypt: https://github.com/micrypt .. _South: http://south.aeracode.org/ .. _bedspax: https://github.com/bedspax -.. _django-social-auth: https://convore.com/django-social-auth/ +.. _django-social-auth: https://github.com/omab/django-social-auth .. _Convore: https://convore.com/ .. _Selenium: http://seleniumhq.org/ .. _LinkedIn fields selectors: http://developer.linkedin.com/docs/DOC-1014 @@ -979,3 +1027,4 @@ Base work is copyrighted by: .. _Flickr App Garden: http://www.flickr.com/services/apps/create/ .. _danielgtaylor: https://github.com/danielgtaylor .. _example application: https://github.com/omab/django-social-auth/blob/master/example/local_settings.py.template#L23 +.. _BrowserID: https://browserid.org diff --git a/doc/backends/browserid.rst b/doc/backends/browserid.rst new file mode 100644 index 0000000..021ad48 --- /dev/null +++ b/doc/backends/browserid.rst @@ -0,0 +1,14 @@ +--------- +BrowserID +--------- +Support for BrowserID_ is possible by posting the ``assertion`` code to +``/complete/browserid/`` URL. + +The setup doesn't need any setting, just the usual BrowserID_ javascript +include in your document and the needed mechanism to trigger the POST to +`django-social-auth`_. + +Check the second "Use Case" for an implementation example. + +.. _django-social-auth: https://github.com/omab/django-social-auth +.. _BrowserID: https://browserid.org diff --git a/doc/configuration.rst b/doc/configuration.rst index 91b5728..c3cd344 100644 --- a/doc/configuration.rst +++ b/doc/configuration.rst @@ -17,6 +17,7 @@ Configuration 'social_auth.backends.google.GoogleOAuth2Backend', 'social_auth.backends.google.GoogleBackend', 'social_auth.backends.yahoo.YahooBackend', + 'social_auth.backends.browserid.BrowserIDBackend', 'social_auth.backends.contrib.linkedin.LinkedinBackend', 'social_auth.backends.contrib.livejournal.LiveJournalBackend', 'social_auth.backends.contrib.orkut.OrkutBackend', diff --git a/doc/miscellaneous.rst b/doc/miscellaneous.rst index 410e69f..1c1b4ee 100644 --- a/doc/miscellaneous.rst +++ b/doc/miscellaneous.rst @@ -26,6 +26,7 @@ package and link it there. .. _South: http://south.aeracode.org/ -.. _django-social-auth: https://convore.com/django-social-auth/ +.. _django-social-auth: https://github.com/omab/django-social-auth .. _Convore: https://convore.com/ .. _djangopackages.com: http://djangopackages.com/grids/g/social-auth-backends/ + diff --git a/doc/use_cases.rst b/doc/use_cases.rst index daec210..2934b86 100644 --- a/doc/use_cases.rst +++ b/doc/use_cases.rst @@ -15,3 +15,36 @@ Some particular use cases are listed below. url(r'^disconnect/(?P[^/]+)/(?P[^/]+)/$', disconnect, name='socialauth_disconnect_individual'), ) + +2. Include a similar snippet in your page to make BrowserID_ work:: + + + + +
+ + BrowserID +
+ + + diff --git a/example/settings.py b/example/settings.py index 6fc3b9b..5bd8ad3 100644 --- a/example/settings.py +++ b/example/settings.py @@ -78,6 +78,7 @@ AUTHENTICATION_BACKENDS = ( 'social_auth.backends.contrib.flickr.FlickrBackend', 'social_auth.backends.OpenIDBackend', 'social_auth.backends.contrib.livejournal.LiveJournalBackend', + 'social_auth.backends.browserid.BrowserIDBackend', 'django.contrib.auth.backends.ModelBackend', ) diff --git a/example/templates/base.html b/example/templates/base.html index b528e2f..9e1fd71 100644 --- a/example/templates/base.html +++ b/example/templates/base.html @@ -30,6 +30,8 @@ #valid-badges {position: fixed; right: 10px; bottom: 10px;} #valid-badges p {display: inline;} + + {% block script %}{% endblock %}

Django Social Auth (v{{ version }})

diff --git a/example/templates/done.html b/example/templates/done.html index 6b12fd9..2ef4e0d 100644 --- a/example/templates/done.html +++ b/example/templates/done.html @@ -1,5 +1,10 @@ {% extends "base.html" %} +{% block script %} + + +{% endblock %} + {% block heading %}Logged in!{% endblock %} {% block content %} @@ -74,6 +79,32 @@ {% endfor %} + +

Associate new BrowserID:

+
+ + BrowserID + +
diff --git a/example/templates/home.html b/example/templates/home.html index 1a39af4..c90ba1c 100644 --- a/example/templates/home.html +++ b/example/templates/home.html @@ -1,5 +1,10 @@ {% extends "base.html" %} +{% block script %} + + +{% endblock %} + {% block heading %}Login using any of the following methods{% endblock %} {% block content %} @@ -54,4 +59,32 @@ {% endfor %}
+ +
+

Login using BrowserID:

+
+ + BrowserID + +
+
{% endblock %} diff --git a/social_auth/backends/__init__.py b/social_auth/backends/__init__.py index 4a946d2..b52869c 100644 --- a/social_auth/backends/__init__.py +++ b/social_auth/backends/__init__.py @@ -150,7 +150,7 @@ class SocialAuthBackend(ModelBackend): def extra_data(self, user, uid, response, details): """Return default blank user extra data""" - return '' + return {} def get_user_id(self, details, response): """Must return a unique ID from values returned on details""" @@ -634,9 +634,11 @@ if setting('SOCIAL_AUTH_IMPORT_BACKENDS'): from warnings import warn warn("SOCIAL_AUTH_IMPORT_SOURCES is deprecated") + # Cache for discovered backends. BACKENDSCACHE = {} + def get_backends(force_load=False): """ Entry point to the BACKENDS cache. If BACKENDSCACHE hasn't been @@ -685,6 +687,7 @@ def get_backend(name, *args, **kwargs): except KeyError: return None + BACKENDS = { 'openid': OpenIdAuth } diff --git a/social_auth/backends/browserid.py b/social_auth/backends/browserid.py new file mode 100644 index 0000000..a8774b5 --- /dev/null +++ b/social_auth/backends/browserid.py @@ -0,0 +1,90 @@ +""" +BrowserID support +""" +import time +from datetime import datetime +from urllib import urlencode +from urllib2 import urlopen + +from django.contrib.auth import authenticate +from django.utils import simplejson + +from social_auth.backends import SocialAuthBackend, BaseAuth, USERNAME +from social_auth.utils import log, setting + + +# BrowserID verification server +BROWSER_ID_SERVER = 'https://browserid.org/verify' + + +class BrowserIDBackend(SocialAuthBackend): + """BrowserID authentication backend""" + name = 'browserid' + + def get_user_id(self, details, response): + """Use BrowserID email as ID""" + return details['email'] + + def get_user_details(self, response): + """Return user details, BrowserID only provides Email.""" + # {'status': 'okay', + # 'audience': 'localhost:8000', + # 'expires': 1328983575529, + # 'email': 'name@server.com', + # 'issuer': 'browserid.org'} + email = response['email'] + return {USERNAME: email.split('@', 1)[0], + 'email': email, + 'fullname': '', + 'first_name': '', + 'last_name': ''} + + def extra_data(self, user, uid, response, details): + """Return users extra data""" + # BrowserID sends timestamp for expiration date, here we + # comvert it to the remaining seconds + expires = (response['expires'] / 1000) - \ + time.mktime(datetime.now().timetuple()) + return { + 'audience': response['audience'], + 'issuer': response['issuer'], + setting('SOCIAL_AUTH_EXPIRATION', 'expires'): expires + } + + +# Auth classes +class BrowserIDAuth(BaseAuth): + """BrowserID authentication""" + AUTH_BACKEND = BrowserIDBackend + + def auth_complete(self, *args, **kwargs): + """Completes loging process, must return user instance""" + if not 'assertion' in self.data: + raise ValueError('Missing assertion parameter') + + data = urlencode({ + 'assertion': self.data['assertion'], + 'audience': self.request.get_host() + }) + + try: + response = simplejson.load(urlopen(BROWSER_ID_SERVER, data=data)) + except ValueError: + log('error', 'Could not load user data from BrowserID.', + exc_info=True) + else: + if response.get('status') == 'failure': + log('debug', 'Authentication failed.') + raise ValueError('Authentication failed') + + kwargs.update({ + 'response': response, + self.AUTH_BACKEND.name: True + }) + return authenticate(*args, **kwargs) + + +# Backend definition +BACKENDS = { + 'browserid': BrowserIDAuth +}