'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',
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
-------
disconnect, name='socialauth_disconnect_individual'),
)
+2. Include a similar snippet in your page to make BrowserID_ work::
+ <!-- Include BrowserID JavaScript -->
+ <script src="https://browserid.org/include.js" type="text/javascript"></script>
+
+ <!-- Define a form to send the POST data -->
+ <form method="post" action="{% url socialauth_complete "browserid" %}">
+ <input type="hidden" name="assertion" value="" />
+ <a rel="nofollow" id="browserid" href="#">BrowserID</a>
+ </form>
+
+ <!-- Setup click handler that retieves BrowserID assertion code and sends
+ POST data -->
+ <script type="text/javascript">
+ $(function () {
+ $('#browserid').click(function (e) {
+ e.preventDefault();
+ var self = $(this);
+
+ navigator.id.get(function (assertion) {
+ if (assertion) {
+ self.parent('form')
+ .find('input[type=hidden]')
+ .attr('value', assertion)
+ .end()
+ .submit();
+ } else {
+ alert('Some error occurred');
+ }
+ });
+ });
+ });
+ </script>
+
+
-------------
Miscellaneous
-------------
.. _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
.. _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
--- /dev/null
+---------
+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
'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',
.. _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/
+
url(r'^disconnect/(?P<backend>[^/]+)/(?P<association_id>[^/]+)/$',
disconnect, name='socialauth_disconnect_individual'),
)
+
+2. Include a similar snippet in your page to make BrowserID_ work::
+ <!-- Include BrowserID JavaScript -->
+ <script src="https://browserid.org/include.js" type="text/javascript"></script>
+
+ <!-- Define a form to send the POST data -->
+ <form method="post" action="{% url socialauth_complete "browserid" %}">
+ <input type="hidden" name="assertion" value="" />
+ <a rel="nofollow" id="browserid" href="#">BrowserID</a>
+ </form>
+
+ <!-- Setup click handler that retieves BrowserID assertion code and sends
+ POST data -->
+ <script type="text/javascript">
+ $(function () {
+ $('#browserid').click(function (e) {
+ e.preventDefault();
+ var self = $(this);
+
+ navigator.id.get(function (assertion) {
+ if (assertion) {
+ self.parent('form')
+ .find('input[type=hidden]')
+ .attr('value', assertion)
+ .end()
+ .submit();
+ } else {
+ alert('Some error occurred');
+ }
+ });
+ });
+ });
+ </script>
'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',
)
#valid-badges {position: fixed; right: 10px; bottom: 10px;}
#valid-badges p {display: inline;}
</style>
+
+ {% block script %}{% endblock %}
</head>
<body>
<h1>Django Social Auth (v{{ version }})</h1>
{% extends "base.html" %}
+{% block script %}
+<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>
+<script src="https://browserid.org/include.js" type="text/javascript"></script>
+{% endblock %}
+
{% block heading %}Logged in!{% endblock %}
{% block content %}
</li>
{% endfor %}
</ul>
+
+ <h3>Associate new <a href="https://browserid.org/" title="BrowserID">BrowserID</a>:</h3>
+ <form method="post" action="{% url socialauth_complete "browserid" %}">
+ <input type="hidden" name="assertion" value="" />
+ <a rel="nofollow" id="browserid" href="#">BrowserID</a>
+ <script type="text/javascript">
+ $(function () {
+ $('#browserid').click(function (e) {
+ e.preventDefault();
+ var self = $(this);
+
+ navigator.id.get(function (assertion) {
+ if (assertion) {
+ self.parent('form')
+ .find('input[type=hidden]')
+ .attr('value', assertion)
+ .end()
+ .submit();
+ } else {
+ alert('Some error occurred');
+ }
+ });
+ });
+ });
+ </script>
+ </form>
</div>
<div>
{% extends "base.html" %}
+{% block script %}
+<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>
+<script src="https://browserid.org/include.js" type="text/javascript"></script>
+{% endblock %}
+
{% block heading %}Login using any of the following methods{% endblock %}
{% block content %}
{% endfor %}
</ul>
</div>
+
+<div>
+ <h3>Login using <a href="https://browserid.org/" title="BrowserID">BrowserID</a>:</h3>
+ <form method="post" action="{% url socialauth_complete "browserid" %}">
+ <input type="hidden" name="assertion" value="" />
+ <a rel="nofollow" id="browserid" href="#">BrowserID</a>
+ <script type="text/javascript">
+ $(function () {
+ $('#browserid').click(function (e) {
+ e.preventDefault();
+ var self = $(this);
+
+ navigator.id.get(function (assertion) {
+ if (assertion) {
+ self.parent('form')
+ .find('input[type=hidden]')
+ .attr('value', assertion)
+ .end()
+ .submit();
+ } else {
+ alert('Some error occurred');
+ }
+ });
+ });
+ });
+ </script>
+ </form>
+</div>
{% endblock %}
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"""
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
except KeyError:
return None
+
BACKENDS = {
'openid': OpenIdAuth
}
--- /dev/null
+"""
+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
+}