aboutsummaryrefslogtreecommitdiffstats
path: root/gitrefinery/auth_views.py
blob: 33edd62329d3f17f92fca5c50c0977cffb9bec66 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
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)