aboutsummaryrefslogtreecommitdiffstats
path: root/gitrefinery/auth_views.py
diff options
context:
space:
mode:
Diffstat (limited to 'gitrefinery/auth_views.py')
-rw-r--r--gitrefinery/auth_views.py141
1 files changed, 141 insertions, 0 deletions
diff --git a/gitrefinery/auth_views.py b/gitrefinery/auth_views.py
new file mode 100644
index 0000000..33edd62
--- /dev/null
+++ b/gitrefinery/auth_views.py
@@ -0,0 +1,141 @@
+# gitrefinery-web - extended authentication views
+#
+# Copyright (C) 2018 Intel Corporation
+#
+# Licensed under the MIT license, see COPYING.MIT for details
+
+from django.contrib import messages
+from django.contrib.auth import logout
+from django.contrib.auth.hashers import make_password
+from django.contrib.auth.views import (PasswordResetConfirmView,
+ PasswordResetView)
+from django.contrib.sites.shortcuts import get_current_site
+
+from django.core.exceptions import PermissionDenied
+from django.urls import reverse
+from django.http import HttpResponseRedirect, HttpResponse
+from django.shortcuts import render
+from django.utils.decorators import method_decorator
+from django.views.decorators.cache import never_cache
+from django_registration import signals
+from django_registration.backends.activation.views import RegistrationView
+
+from gitrefinery.auth_forms import (CaptchaPasswordResetForm,
+ CaptchaRegistrationForm, DeleteAccountForm,
+ SecurityQuestionPasswordResetForm)
+
+from .models import SecurityQuestion, SecurityQuestionAnswer, UserProfile
+#from . import tasks
+import settings
+
+@method_decorator(never_cache, name='dispatch')
+class CaptchaRegistrationView(RegistrationView):
+ form_class = CaptchaRegistrationForm
+
+ def register(self, form):
+ new_user = self.create_inactive_user(form)
+ signals.user_registered.send(
+ sender=self.__class__,
+ user=new_user,
+ request=self.request
+ )
+
+ # Add security question answers to the database
+ security_question_1 = SecurityQuestion.objects.get(question=form.cleaned_data.get("security_question_1"))
+ security_question_2 = SecurityQuestion.objects.get(question=form.cleaned_data.get("security_question_2"))
+ security_question_3 = SecurityQuestion.objects.get(question=form.cleaned_data.get("security_question_3"))
+ answer_1 = form.cleaned_data.get("answer_1").replace(" ", "").lower()
+ answer_2 = form.cleaned_data.get("answer_2").replace(" ", "").lower()
+ answer_3 = form.cleaned_data.get("answer_3").replace(" ", "").lower()
+
+ user = UserProfile.objects.create(user=new_user)
+ # Answers are hashed using Django's password hashing function make_password()
+ SecurityQuestionAnswer.objects.create(user=user, security_question=security_question_1,
+ answer=make_password(answer_1))
+ SecurityQuestionAnswer.objects.create(user=user, security_question=security_question_2,
+ answer=make_password(answer_2))
+ SecurityQuestionAnswer.objects.create(user=user, security_question=security_question_3,
+ answer=make_password(answer_3))
+
+ def get_context_data(self, **kwargs):
+ context = super(CaptchaRegistrationView, self).get_context_data(**kwargs)
+ form = context['form']
+ # Prepare a list of fields with errors
+ # We do this so that if there's a problem with the captcha, that's the only error shown
+ # (since we have a username field, we want to make user enumeration difficult)
+ if 'captcha' in form.errors:
+ error_fields = ['captcha']
+ else:
+ error_fields = form.errors.keys()
+ context['error_fields'] = error_fields
+ return context
+
+
+@method_decorator(never_cache, name='dispatch')
+class CaptchaPasswordResetView(PasswordResetView):
+ form_class = CaptchaPasswordResetForm
+
+
+def delete_account_view(request, template_name):
+ if not request.user.is_authenticated:
+ raise PermissionDenied
+ if request.user.is_superuser:
+ # It's not really appropriate for the superuser to be deleted this way
+ raise PermissionDenied
+ if request.method == 'POST':
+ form = DeleteAccountForm(request.POST, instance=request.user)
+ if form.is_valid():
+ # Naturally we don't call form.save() here !
+ # Take a copy of request.user as it is about to be invalidated by logout()
+ user = request.user
+ logout(request)
+ user.delete()
+ messages.add_message(request, messages.SUCCESS,
+ 'Your user account has been successfully deleted')
+ return HttpResponseRedirect(reverse('frontpage'))
+ else:
+ form = DeleteAccountForm(instance=request.user)
+
+ return render(request, template_name, {
+ 'user': request.user,
+ 'form': form,
+ })
+
+
+class PasswordResetSecurityQuestions(PasswordResetConfirmView):
+ form_class = SecurityQuestionPasswordResetForm
+
+ def get(self, request, *args, **kwargs):
+ try:
+ self.user.userprofile
+ except UserProfile.DoesNotExist:
+ return HttpResponseRedirect(reverse('password_reset_fail'))
+ if not self.user.is_active:
+ return HttpResponseRedirect(reverse('account_lockout'))
+
+ return super().get(request, *args, **kwargs)
+
+ def post(self, request, *args, **kwargs):
+ form = self.form_class(data=request.POST, user=self.user)
+ form.is_valid()
+ for error in form.non_field_errors().as_data():
+ if error.code == "account_locked":
+ # Deactivate user's account.
+ self.user.is_active = False
+ self.user.save()
+ # Send admin an email that user is locked out.
+ site_name = get_current_site(request).name
+ subject = "User account locked on " + site_name
+ text_content = "User " + self.user.username + " has been locked out on " + site_name + "."
+ admins = settings.ADMINS
+ from_email = settings.DEFAULT_FROM_EMAIL
+ msg = EmailMessage(subject, text_content, from_email, [a[1] for a in admins])
+ msg.send()
+ #tasks.send_email.apply_async((subject, text_content, from_email, [a[1] for a in admins]))
+ return HttpResponseRedirect(reverse('account_lockout'))
+
+ if error.code == "incorrect_answers":
+ # User has failed first attempt at answering questions, give them another try.
+ return self.form_invalid(form)
+
+ return super().post(request, *args, **kwargs)