-
Notifications
You must be signed in to change notification settings - Fork 17
Expand file tree
/
Copy pathadmin_form.py
More file actions
179 lines (153 loc) · 6.28 KB
/
Copy pathadmin_form.py
File metadata and controls
179 lines (153 loc) · 6.28 KB
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# coding: utf-8
from django import forms as django_forms
from django.contrib.auth import forms
from django.utils.translation import ngettext_lazy, gettext_lazy as _
from django.contrib.auth.models import User
from django_otp.forms import OTPAuthenticationFormMixin
from django.contrib.auth import get_user_model
from concrete_datastore.concrete.constants import MFA_EMAIL
class MyAuthForm(forms.AuthenticationForm):
username = django_forms.EmailField(
label=_("Email Address"), max_length=254
)
class OTPAuthenticationForm(MyAuthForm, OTPAuthenticationFormMixin):
otp_error_messages = {
'token_required': _('Please enter your OTP token.'),
'challenge_exception': _('Error generating challenge: {0}'),
'challenge_message_email': _(
'Enter the two authentication code you received by email'
),
'challenge_message_otp': _(
'Enter the two-factor authentication code from a configured OTP application'
),
'invalid_token': _(
'Invalid token. Please make sure you have entered it correctly.'
),
'n_failed_attempts': ngettext_lazy(
"Verification temporarily disabled because of %(failure_count)d failed attempt, please try again soon.",
"Verification temporarily disabled because of %(failure_count)d failed attempts, please try again soon.",
"failure_count",
),
'verification_not_allowed': _(
"Verification of the token is currently disabled"
),
}
otp_token = django_forms.CharField(
required=False,
widget=django_forms.TextInput(attrs={'autocomplete': 'off'}),
)
# This is a placeholder field that allows us to detect when the user clicks
# the otp_challenge submit button.
otp_challenge = django_forms.CharField(required=False)
def clean(self):
self.cleaned_data = super().clean()
self.clean_otp(self.get_user())
return self.cleaned_data
def _handle_challenge(self, device):
challenge_message_name = 'challenge_message_otp'
if device.mfa_mode == MFA_EMAIL:
challenge_message_name = 'challenge_message_email'
try:
device.generate_challenge()
except Exception as e:
raise django_forms.ValidationError(
self.otp_error_messages['challenge_exception'].format(e),
code='challenge_exception',
)
#: If the challenge is successfully generated and in order to show
#: the appropriate message, a `ValidationError` must be raised.
#: *NB* This validation error does not mean that an error occured
raise django_forms.ValidationError(
self.otp_error_messages[challenge_message_name],
code=challenge_message_name,
)
def clean_otp(self, user):
if user is None:
return
device = self._chosen_device(user)
token = self.cleaned_data.get('otp_token')
username = self.cleaned_data.get('username')
password = self.cleaned_data.get('password')
user.otp_device = None
try:
if token:
user.otp_device = self._verify_token(user, token, device)
user._is_verified = True
user.save()
elif username and password:
self._handle_challenge(device)
else:
#: If no username or no password are given, the user
#: would be None, so this case should never occur,
#: but we keep it in case it happens
raise django_forms.ValidationError( # pragma: no cover
self.otp_error_messages['token_required'],
code='token_required',
)
finally:
if user.otp_device is None:
self._update_form(user)
def _chosen_device(self, user):
device = user.totp_device
if device is None:
device = user.emaildevice_set.filter(confirmed=True).first()
if device is None:
device = user.emaildevice_set.create(
email=user.email, name='User default email', confirmed=True
)
user.emaildevice_set.exclude(pk=device.pk).delete()
return device
@staticmethod
def device_choices(user):
user_divices = user.emaildevice_set.filter(confirmed=True)
if not user_divices:
user_divices = [
user.emaildevice_set.create(
email=user.email, name='User default email', confirmed=True
)
]
return list((d.persistent_id, d.name) for d in user_divices)
class MyCreationUserForm(forms.UserCreationForm):
email = django_forms.EmailField(required=True)
class Meta:
model = User
fields = ("email", "password1", "password2")
def clean_email(self):
email = self.cleaned_data.get("email").lower()
Concreteuser = get_user_model()
if Concreteuser.objects.filter(email=email).count() > 0:
raise django_forms.ValidationError(
_("A user with this email already exists.")
)
return email
def save(self, commit=True):
user = super(MyCreationUserForm, self).save(commit=False)
user.email = self.cleaned_data['email'].lower()
if commit:
user.save()
return user
class MyChangeUserForm(forms.UserChangeForm):
MY_CHOICES = (
('SuperUser', 'Super User'),
('Admin', 'Admin'),
('Manager', 'Manager'),
('SimpleUser', 'Simple User'),
('Blocked', 'Blocked'),
)
user_level = django_forms.ChoiceField(choices=MY_CHOICES)
def __init__(self, *args, **kwargs):
obj = kwargs.get('instance')
if obj is not None:
user_level = ""
if obj.is_superuser:
user_level = 'SuperUser'
elif obj.admin:
user_level = 'Admin'
elif obj.is_staff:
user_level = 'Manager'
elif obj.is_active:
user_level = 'SimpleUser'
else:
user_level = 'Blocked'
kwargs['initial'] = {'user_level': user_level}
super(MyChangeUserForm, self).__init__(*args, **kwargs)