Commit 9bd227f4 authored by Kostas Papadimitriou's avatar Kostas Papadimitriou
Browse files

Several auth providers fixes/improvements

- Allow third party signup if existing account with the same third party
  identifier is not yet verified. Subsequent registrations will replace
  previous ones (pending/unverified accounts will be removed).
- Merge common third party code in target/__init__.py
- Be able to identify if third party signup comes from login page (or
  user explicitly requested to signup)
parent d1940892
......@@ -99,8 +99,25 @@ class AuthProvider(object):
def add_url(self):
return reverse(self.login_view)
def __init__(self, user=None):
@property
def provider_details(self):
if self.user:
if self.identifier:
self._provider_details = \
self.user.get_auth_providers().get(module=self.module,
identifier=self.identifier).__dict__
else:
self._provider_details = self.user.get(module=self.module).__dict__
return self._provider_details
def __init__(self, user=None, identifier=None, provider_details=None):
self.user = user
self.identifier = identifier
self._provider_details = None
if provider_details:
self._provider_details = provider_details
for tpl in ['login_prompt', 'login', 'signup_prompt']:
tpl_name = '%s_%s' % (tpl, 'template')
override = self.get_setting(tpl_name)
......@@ -254,12 +271,12 @@ class LinkedInAuthProvider(AuthProvider):
login_prompt_template = 'im/auth/third_party_provider_generic_login_prompt.html'
def get_provider(id, user_obj=None, default=None):
def get_provider(id, user_obj=None, default=None, identifier=None, provider_details={}):
"""
Return a provider instance from the auth providers registry.
"""
if not id in PROVIDERS:
raise Exception('Invalid auth provider requested "%s"' % id)
return PROVIDERS.get(id, default)(user_obj)
return PROVIDERS.get(id, default)(user_obj, identifier, provider_details)
......@@ -207,6 +207,7 @@ AUTH_PROVIDER_LOGIN_TO_ADD = "The new login method will be a
AUTH_PROVIDER_INVALID_LOGIN = "No account exists."
AUTH_PROVIDER_REQUIRED = "%(provider)s login method is required. Add one from your profile page."
AUTH_PROVIDER_CANNOT_CHANGE_PASSWORD = "Changing password is not supported."
AUTH_PROVIDER_SIGNUP_FROM_LOGIN = None
EXISTING_EMAIL_THIRD_PARTY_NOTIFICATION = "You can add '%s' login method to your existing account from your " \
" <a href='%s'>profile page</a>"
......
......@@ -601,6 +601,7 @@ class AstakosUser(User):
if 'identifier' in kwargs:
try:
# provider with specified params already exist
print "LALALALA", include_unverified
if not include_unverified:
kwargs['user__email_verified'] = True
existing_user = AstakosUser.objects.get_auth_provider_user(provider,
......
......@@ -46,6 +46,19 @@ from astakos.im.util import prepare_response, get_context
from astakos.im.views import requires_anonymous, render_response
def init_third_party_session(request):
params = dict(request.GET.items())
request.session['third_party_request_params'] = params
def get_third_party_session_params(request):
if 'third_party_request_params' in request.session:
params = request.session['third_party_request_params']
del request.session['third_party_request_params']
return params
return {}
def add_pending_auth_provider(request, third_party_token):
if third_party_token:
# use requests to assign the account he just authenticated with with
......@@ -58,11 +71,9 @@ def add_pending_auth_provider(request, third_party_token):
def get_pending_key(request):
third_party_token = get_query(request).get('key', False)
if not third_party_token:
third_party_token = request.session.get('pending_key', None)
if third_party_token:
del request.session['pending_key']
third_party_token = get_query(request).get('key', request.session.get('pending_key', False))
if 'pending_key' in request.session:
del request.session['pending_key']
return third_party_token
......@@ -115,8 +126,8 @@ def handle_third_party_signup(request, userid, provider_module, third_party_key,
def handle_third_party_login(request, provider_module, identifier,
third_party_key=None, provider_info=None,
affiliation=None):
provider_info=None, affiliation=None,
third_party_key=None):
if not provider_info:
provider_info = {}
......@@ -124,13 +135,13 @@ def handle_third_party_login(request, provider_module, identifier,
if not affiliation:
affiliation = provider_module.title()
if not third_party_key:
third_party_key = get_pending_key(request)
next_redirect = request.GET.get('next', request.session.get('next_url', None))
if 'next_url' in request.session:
del request.session['next_url']
third_party_request_params = get_third_party_session_params(request)
from_login = third_party_request_params.get('from_login', False)
# an existing user accessed the view
if request.user.is_authenticated():
......@@ -153,10 +164,22 @@ def handle_third_party_login(request, provider_module, identifier,
return HttpResponseRedirect(reverse('edit_profile'))
# astakos user exists ?
user = AstakosUser.objects.get_auth_provider_user(
provider_module,
identifier=identifier
)
try:
user = AstakosUser.objects.get_auth_provider_user(
provider_module,
identifier=identifier,
user__email_verified=True,
)
except AstakosUser.DoesNotExist:
# TODO: add a message ? redirec to login ?
if astakos_messages.AUTH_PROVIDER_SIGNUP_FROM_LOGIN:
messages.warning(request,
astakos_messages.AUTH_PROVIDER_SIGNUP_FROM_LOGIN)
raise
if not third_party_key:
third_party_key = get_pending_key(request)
if user.is_active:
# authenticate user
response = prepare_response(request,
......
......@@ -55,7 +55,7 @@ from astakos.im.activation_backends import get_backend, SimpleBackend
from astakos.im import settings
from astakos.im import auth_providers
from astakos.im.target import add_pending_auth_provider, get_pending_key, \
handle_third_party_signup, handle_third_party_login
handle_third_party_signup, handle_third_party_login, init_third_party_session
import logging
import time
......@@ -89,6 +89,7 @@ def get_redirect_uri():
@requires_auth_provider('google', login=True)
@require_http_methods(["GET", "POST"])
def login(request):
init_third_party_session(request)
params = {
'scope': token_scope,
'response_type': 'code',
......
......@@ -55,7 +55,7 @@ from astakos.im.activation_backends import get_backend, SimpleBackend
from astakos.im import settings
from astakos.im import auth_providers
from astakos.im.target import add_pending_auth_provider, get_pending_key, \
handle_third_party_signup, handle_third_party_login
handle_third_party_signup, handle_third_party_login, init_third_party_session
import astakos.im.messages as astakos_messages
......@@ -77,6 +77,7 @@ authenticate_url = 'https://www.linkedin.com/uas/oauth/authorize'
@requires_auth_provider('linkedin', login=True)
@require_http_methods(["GET", "POST"])
def login(request):
init_third_party_session(request)
resp, content = client.request(request_token_url, "GET")
if resp['status'] != '200':
messages.error(request, 'Invalid linkedin response')
......
......@@ -55,7 +55,7 @@ from astakos.im.activation_backends import get_backend, SimpleBackend
from astakos.im import auth_providers
from astakos.im import settings
from astakos.im.target import add_pending_auth_provider, get_pending_key, \
handle_third_party_signup, handle_third_party_login
handle_third_party_signup, handle_third_party_login, init_third_party_session
import astakos.im.messages as astakos_messages
import logging
......@@ -82,6 +82,7 @@ def login(
template='im/third_party_check_local.html',
extra_context=None):
init_third_party_session(request)
extra_context = extra_context or {}
tokens = request.META
......
......@@ -56,7 +56,7 @@ from astakos.im.activation_backends import get_backend, SimpleBackend
from astakos.im import settings
from astakos.im import auth_providers
from astakos.im.target import add_pending_auth_provider, get_pending_key, \
handle_third_party_signup, handle_third_party_login
handle_third_party_signup, handle_third_party_login, init_third_party_session
import astakos.im.messages as astakos_messages
......@@ -77,6 +77,7 @@ authenticate_url = 'http://twitter.com/oauth/authenticate'
@requires_auth_provider('twitter', login=True)
@require_http_methods(["GET", "POST"])
def login(request):
init_third_party_session(request)
force_login = request.GET.get('force_login',
settings.TWITTER_AUTH_FORCE_LOGIN)
resp, content = client.request(request_token_url, "GET")
......@@ -142,7 +143,7 @@ def authenticated(
try:
return handle_third_party_login(request, 'google', userid,
return handle_third_party_login(request, 'twitter', userid,
provider_info, affiliation)
except AstakosUser.DoesNotExist, e:
third_party_key = get_pending_key(request)
......
{% load astakos_tags %}
<h2><a href="{% provider_login_url provider %}">
<h2><a href="{% provider_login_url provider 1 %}">
{{ provider.get_primary_login_prompt_display|safe }} {{ provider.get_title_display }}
</a></h2>
{% load astakos_tags %}
<a href="{% provider_login_url provider %}" alt="{{ provider.get_title_display }}" class="icons"><img src="{{ provider.get_icon_url_display }}" alt="{{ provider.get_title_display }}" /></a>
<a href="{% provider_login_url provider 1 %}" alt="{{ provider.get_title_display }}" class="icons">
<img src="{{ provider.get_icon_url_display }}" alt="{{ provider.get_title_display }}" /></a>
......@@ -183,7 +183,7 @@ def get_grant_value(rname, form):
@register.tag(name="provider_login_url")
@basictag(takes_context=True)
def provider_login_url(context, provider):
def provider_login_url(context, provider, from_login=False):
request = context['request'].REQUEST
next = request.get('next', None)
code = request.get('code', None)
......@@ -196,6 +196,8 @@ def provider_login_url(context, provider):
attrs['code'] = code
if key:
attrs['key'] = key
if from_login:
attrs['from_login'] = 1
url = provider.add_url
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment