Refine shibboleth signup mechanism
[astakos] / snf-astakos-app / astakos / im / target / local.py
index 88c9123..d993fdb 100644 (file)
@@ -37,24 +37,43 @@ from django.template import RequestContext
 from django.contrib.auth import authenticate
 from django.contrib import messages
 from django.utils.translation import ugettext as _
+from django.views.decorators.csrf import csrf_exempt
+from django.views.decorators.http import require_http_methods
+from django.core.urlresolvers import reverse
 
-from astakos.im.util import prepare_response
+from astakos.im.util import prepare_response, get_query
 from astakos.im.views import requires_anonymous
-from astakos.im.models import AstakosUser
+from astakos.im.models import AstakosUser, PendingThirdPartyUser
 from astakos.im.forms import LoginForm
+from astakos.im.settings import RATELIMIT_RETRIES_ALLOWED
+from astakos.im.settings import ENABLE_LOCAL_ACCOUNT_MIGRATION
 
+from ratelimit.decorators import ratelimit
+
+retries = RATELIMIT_RETRIES_ALLOWED-1
+rate = str(retries)+'/m'
+
+@require_http_methods(["GET", "POST"])
+@csrf_exempt
 @requires_anonymous
+@ratelimit(field='username', method='POST', rate=rate)
 def login(request, on_failure='im/login.html'):
     """
     on_failure: the template name to render on login failure
     """
-    form = LoginForm(data=request.POST)
-    next = request.POST.get('next')
+    was_limited = getattr(request, 'limited', False)
+    form = LoginForm(data=request.POST, was_limited=was_limited, request=request)
+    next = get_query(request).get('next', '')
+    username = get_query(request).get('key')
+    
     if not form.is_valid():
-        return render_to_response(on_failure,
-                                  {'form':form,
-                                   'next':next},
-                                  context_instance=RequestContext(request))
+        return render_to_response(
+            on_failure,
+            {'login_form':form,
+             'next':next,
+             'key':username},
+            context_instance=RequestContext(request)
+        )
     # get the user from the cash
     user = form.user_cache
     
@@ -62,11 +81,39 @@ def login(request, on_failure='im/login.html'):
     if not user:
         message = _('Cannot authenticate account')
     elif not user.is_active:
-        message = _('Inactive account')
+        if user.sent_activation:
+            message = _('Your request is pending activation')
+        else:
+            message = _('You have not followed the activation link')
     if message:
-        messages.add_message(request, message.ERROR, message)
+        messages.add_message(request, messages.ERROR, message)
         return render_to_response(on_failure,
                                   {'form':form},
                                   context_instance=RequestContext(request))
     
-    return prepare_response(request, user, next)
+    # hook for switching account to use third party authentication
+    if ENABLE_LOCAL_ACCOUNT_MIGRATION and username:
+        try:
+            new = PendingThirdPartyUser.objects.get(
+                username=username)
+        except:
+            messages.error(
+                request,
+                _('Account failed to switch to %(provider)s' % locals())
+            )
+            return render_to_response(
+                on_failure,
+                {'login_form':form,
+                 'next':next},
+                context_instance=RequestContext(request)
+            )
+        else:
+            user.provider = new.provider
+            user.third_party_identifier = new.third_party_identifier
+            user.save()
+            new.delete()
+            messages.success(
+                request,
+                _('Account successfully switched to %(provider)s' % user.__dict__)
+            )
+    return prepare_response(request, user, next)
\ No newline at end of file