SOCIAL_AUTH_DEFAULT_USERNAME
SOCIAL_AUTH_UUID_LENGTH
SOCIAL_AUTH_USERNAME_FIXER
+ SOCIAL_AUTH_ASSOCIATE_URL_NAME
- User creation setting should be avoided and remove the entry ``create_user``
from pipeline instead::
SOCIAL_AUTH_ASSOCIATE_BY_MAIL
+- Associate URLs are deprecated since the login ones can handle the case, this
+ avoids issues where providers check the redirect URI and redirects to the
+ configured value in the application. So, from now on a single entry point is
+ recommended being::
+
+ /<social auth path>/login/<backend>/
+
+ And to complete the process::
+
+ /<social auth path>/complete/<backend>/
+
+
Usage example
-------------
SOCIAL_AUTH_DEFAULT_USERNAME
SOCIAL_AUTH_UUID_LENGTH
SOCIAL_AUTH_USERNAME_FIXER
+ SOCIAL_AUTH_ASSOCIATE_URL_NAME
- User creation setting should be avoided and remove the entry ``create_user``
from pipeline instead::
``associate_by_email`` pipeline entry instead of using this setting::
SOCIAL_AUTH_ASSOCIATE_BY_MAIL
+
+- Associate URLs are deprecated since the login ones can handle the case, this
+ avoids issues where providers check the redirect URI and redirects to the
+ configured value in the application. So, from now on a single entry point is
+ recommended being::
+
+ /<social auth path>/login/<backend>/
+
+ And to complete the process::
+
+ /<social auth path>/complete/<backend>/
<h3>Associate new <a href="http://oauth.net/" title="OAuth">OAuth</a> credentials:</h3>
<ul>
{% for name in social_auth.backends.oauth %}
- <li><a rel="nofollow" href="{% url socialauth_associate_begin name %}">{{ name|title }}</a></li>
+ <li><a rel="nofollow" href="{% url socialauth_begin name %}">{{ name|title }}</a></li>
{% endfor %}
</ul>
<h3>Associate new <a href="http://tools.ietf.org/html/draft-ietf-oauth-v2-10" title="OAuth2">OAuth2</a> credentials:</h3>
<ul>
{% for name in social_auth.backends.oauth2 %}
- <li><a rel="nofollow" href="{% url socialauth_associate_begin name %}">{{ name|title }}</a></li>
+ <li><a rel="nofollow" href="{% url socialauth_begin name %}">{{ name|title }}</a></li>
{% endfor %}
</ul>
{% for name in social_auth.backends.openid %}
<li>
{% if name != "livejournal" and name != "openid" %}
- <a rel="nofollow" href="{% url socialauth_associate_begin name %}">{{ name|title }}</a>
+ <a rel="nofollow" href="{% url socialauth_begin name %}">{{ name|title }}</a>
{% else %}
{% if name == "livejournal" %}
- <form action="{% url socialauth_associate_begin "livejournal" %}" method="post">{% csrf_token %}
+ <form action="{% url socialauth_begin "livejournal" %}" method="post">{% csrf_token %}
<div>
<label for="openid_lj_user">LiveJournal user:</label>
<input id="openid_lj_user" type="text" value="" name="openid_lj_user" />
</form>
{% else %}
{% if name == "openid" %}
- <form action="{% url socialauth_associate_begin "openid" %}" method="post">{% csrf_token %}
+ <form action="{% url socialauth_begin "openid" %}" method="post">{% csrf_token %}
<div>
<label for="openid_identifier">Other provider</label>
<input id="openid_identifier" type="text" value="" name="openid_identifier" />
--- /dev/null
+from functools import wraps
+
+from django.core.urlresolvers import reverse
+from django.http import HttpResponseRedirect, HttpResponseServerError
+from django.utils.importlib import import_module
+
+from social_auth.backends import get_backend
+from social_auth.utils import setting, log, backend_setting
+
+
+LOGIN_ERROR_URL = setting('LOGIN_ERROR_URL', setting('LOGIN_URL'))
+RAISE_EXCEPTIONS = setting('SOCIAL_AUTH_RAISE_EXCEPTIONS', setting('DEBUG'))
+PROCESS_EXCEPTIONS = setting('SOCIAL_AUTH_PROCESS_EXCEPTIONS',
+ 'social_auth.utils.log_exceptions_to_messages')
+
+
+def dsa_view(redirect_name=None):
+ """Decorate djangos-social-auth views. Will check and retrieve backend
+ or return HttpResponseServerError if backend is not found.
+
+ redirect_name parameter is used to build redirect URL used by backend.
+ """
+ def dec(func):
+ @wraps(func)
+ def wrapper(request, backend, *args, **kwargs):
+ if redirect_name:
+ redirect = reverse(redirect_name, args=(backend,))
+ else:
+ redirect = request.path
+ backend = get_backend(backend, request, redirect)
+
+ if not backend:
+ return HttpResponseServerError('Incorrect authentication ' + \
+ 'service')
+
+ try:
+ return func(request, backend, *args, **kwargs)
+ except Exception, e: # some error ocurred
+ if RAISE_EXCEPTIONS:
+ raise
+ log('error', unicode(e), exc_info=True, extra={
+ 'request': request
+ })
+
+ mod, func_name = PROCESS_EXCEPTIONS.rsplit('.', 1)
+ try:
+ process = getattr(import_module(mod), func_name,
+ lambda *args: None)
+ except ImportError:
+ pass
+ else:
+ process(request, backend, e)
+
+ url = backend_setting(backend, 'SOCIAL_AUTH_BACKEND_ERROR_URL',
+ LOGIN_ERROR_URL)
+ return HttpResponseRedirect(url)
+ return wrapper
+ return dec
"""URLs module"""
from django.conf.urls.defaults import patterns, url
-from social_auth.views import auth, complete, associate, associate_complete, \
- disconnect
+from social_auth.views import auth, complete, disconnect
urlpatterns = patterns('',
url(r'^complete/(?P<backend>[^/]+)/$', complete,
name='socialauth_complete'),
- # association
- url(r'^associate/(?P<backend>[^/]+)/$', associate,
+ # XXX: Deprecated, this URLs are deprecated, instead use the login and
+ # complete ones directly, they will differentiate the user intention
+ # by checking it's authenticated status association.
+ url(r'^associate/(?P<backend>[^/]+)/$', auth,
name='socialauth_associate_begin'),
- url(r'^associate/complete/(?P<backend>[^/]+)/$', associate_complete,
+ url(r'^associate/complete/(?P<backend>[^/]+)/$', complete,
name='socialauth_associate_complete'),
# disconnection
on third party providers that (if using POST) won't be sending csrf
token back.
"""
-from functools import wraps
-
-from django.http import HttpResponseRedirect, HttpResponse, \
- HttpResponseServerError
-from django.core.urlresolvers import reverse
+from django.http import HttpResponseRedirect, HttpResponse
from django.contrib.auth import login, REDIRECT_FIELD_NAME
from django.contrib.auth.decorators import login_required
from django.contrib import messages
-from django.utils.importlib import import_module
from django.views.decorators.csrf import csrf_exempt
-from social_auth.backends import get_backend
-from social_auth.utils import sanitize_redirect, setting, log, \
+from social_auth.utils import sanitize_redirect, setting, \
backend_setting, clean_partial_pipeline
+from social_auth.decorators import dsa_view
DEFAULT_REDIRECT = setting('SOCIAL_AUTH_LOGIN_REDIRECT_URL') or \
setting('LOGIN_REDIRECT_URL')
LOGIN_ERROR_URL = setting('LOGIN_ERROR_URL', setting('LOGIN_URL'))
-RAISE_EXCEPTIONS = setting('SOCIAL_AUTH_RAISE_EXCEPTIONS', setting('DEBUG'))
-PROCESS_EXCEPTIONS = setting('SOCIAL_AUTH_PROCESS_EXCEPTIONS',
- 'social_auth.utils.log_exceptions_to_messages')
-
-
-def dsa_view(redirect_name=None):
- """Decorate djangos-social-auth views. Will check and retrieve backend
- or return HttpResponseServerError if backend is not found.
-
- redirect_name parameter is used to build redirect URL used by backend.
- """
- def dec(func):
- @wraps(func)
- def wrapper(request, backend, *args, **kwargs):
- if redirect_name:
- redirect = reverse(redirect_name, args=(backend,))
- else:
- redirect = request.path
- backend = get_backend(backend, request, redirect)
-
- if not backend:
- return HttpResponseServerError('Incorrect authentication ' + \
- 'service')
-
- try:
- return func(request, backend, *args, **kwargs)
- except Exception, e: # some error ocurred
- if RAISE_EXCEPTIONS:
- raise
- log('error', unicode(e), exc_info=True, extra={
- 'request': request
- })
-
- mod, func_name = PROCESS_EXCEPTIONS.rsplit('.', 1)
- try:
- process = getattr(import_module(mod), func_name,
- lambda *args: None)
- except ImportError:
- pass
- else:
- process(request, backend, e)
-
- url = backend_setting(backend, 'SOCIAL_AUTH_BACKEND_ERROR_URL',
- LOGIN_ERROR_URL)
- return HttpResponseRedirect(url)
- return wrapper
- return dec
@dsa_view(setting('SOCIAL_AUTH_COMPLETE_URL_NAME', 'socialauth_complete'))
def complete(request, backend, *args, **kwargs):
"""Authentication complete view, override this view if transaction
management doesn't suit your needs."""
- return complete_process(request, backend, *args, **kwargs)
-
-
-@login_required
-@dsa_view(setting('SOCIAL_AUTH_ASSOCIATE_URL_NAME',
- 'socialauth_associate_complete'))
-def associate(request, backend):
- """Authentication starting process"""
- return auth_process(request, backend)
+ if request.user.is_authenticated():
+ return associate_complete(request, backend, *args, **kwargs)
+ else:
+ return complete_process(request, backend, *args, **kwargs)
-@csrf_exempt
@login_required
-@dsa_view()
def associate_complete(request, backend, *args, **kwargs):
"""Authentication complete process"""
# pop redirect value before the session is trashed on login()