Add event to track failed logins, password reset starts, and password reset completions. Signed-off-by: Roberto Rosario <roberto.rosario@mayan-edms.com>
224 lines
7.6 KiB
Python
224 lines
7.6 KiB
Python
from __future__ import absolute_import, unicode_literals
|
|
|
|
from django.contrib import messages
|
|
from django.contrib.auth import get_user_model
|
|
from django.contrib.auth.forms import SetPasswordForm
|
|
from django.contrib.auth.views import (
|
|
LoginView, LogoutView, PasswordChangeDoneView, PasswordChangeView,
|
|
PasswordResetCompleteView, PasswordResetConfirmView, PasswordResetDoneView,
|
|
PasswordResetView
|
|
)
|
|
from django.core.exceptions import PermissionDenied
|
|
from django.http import HttpResponseRedirect
|
|
from django.shortcuts import redirect
|
|
from django.urls import reverse, reverse_lazy
|
|
from django.utils.translation import ungettext, ugettext_lazy as _
|
|
|
|
from stronghold.views import StrongholdPublicMixin
|
|
|
|
import mayan
|
|
from mayan.apps.common.generics import MultipleObjectFormActionView
|
|
from mayan.apps.common.settings import (
|
|
setting_home_view, setting_project_title, setting_project_url
|
|
)
|
|
from mayan.apps.events.utils import get_system_user
|
|
from mayan.apps.user_management.permissions import permission_user_edit
|
|
|
|
from .events import (
|
|
event_user_authentication_error, event_user_password_reset_complete,
|
|
event_user_password_reset_started
|
|
)
|
|
from .forms import EmailAuthenticationForm, UsernameAuthenticationForm
|
|
from .settings import setting_login_method, setting_maximum_session_length
|
|
|
|
|
|
class MayanLoginView(StrongholdPublicMixin, LoginView):
|
|
"""
|
|
Control how the use is to be authenticated, options are 'email' and
|
|
'username'
|
|
"""
|
|
extra_context = {
|
|
'appearance_type': 'plain'
|
|
}
|
|
template_name = 'authentication/login.html'
|
|
redirect_authenticated_user = True
|
|
|
|
def form_valid(self, form):
|
|
result = super(MayanLoginView, self).form_valid(form=form)
|
|
remember_me = form.cleaned_data.get('remember_me')
|
|
|
|
# remember_me values:
|
|
# True - long session
|
|
# False - short session
|
|
# None - Form has no remember_me value and we let the session
|
|
# expiration default.
|
|
|
|
if remember_me is True:
|
|
self.request.session.set_expiry(
|
|
setting_maximum_session_length.value
|
|
)
|
|
elif remember_me is False:
|
|
self.request.session.set_expiry(0)
|
|
|
|
return result
|
|
|
|
def form_invalid(self, form):
|
|
event_user_authentication_error.commit(actor=get_system_user())
|
|
return super(MayanLoginView, self).form_invalid(form=form)
|
|
|
|
def get_form_class(self):
|
|
if setting_login_method.value == 'email':
|
|
return EmailAuthenticationForm
|
|
else:
|
|
return UsernameAuthenticationForm
|
|
|
|
|
|
class MayanLogoutView(LogoutView):
|
|
"""No current change or overrides, left here for future expansion"""
|
|
|
|
|
|
class MayanPasswordChangeDoneView(PasswordChangeDoneView):
|
|
def dispatch(self, *args, **kwargs):
|
|
messages.success(
|
|
message=_('Your password has been successfully changed.'),
|
|
request=self.request
|
|
)
|
|
return redirect(to='user_management:current_user_details')
|
|
|
|
|
|
class MayanPasswordChangeView(PasswordChangeView):
|
|
extra_context = {'title': _('Current user password change')}
|
|
success_url = reverse_lazy(viewname='authentication:password_change_done')
|
|
template_name = 'appearance/generic_form.html'
|
|
|
|
def dispatch(self, *args, **kwargs):
|
|
if self.request.user.user_options.block_password_change:
|
|
messages.error(
|
|
message=_(
|
|
'Changing the password is not allowed for this account.'
|
|
), request=self.request
|
|
)
|
|
return HttpResponseRedirect(
|
|
redirect_to=reverse(viewname=setting_home_view.view)
|
|
)
|
|
|
|
return super(MayanPasswordChangeView, self).dispatch(*args, **kwargs)
|
|
|
|
|
|
class MayanPasswordResetCompleteView(StrongholdPublicMixin, PasswordResetCompleteView):
|
|
extra_context = {
|
|
'appearance_type': 'plain'
|
|
}
|
|
template_name = 'authentication/password_reset_complete.html'
|
|
|
|
|
|
class MayanPasswordResetConfirmView(StrongholdPublicMixin, PasswordResetConfirmView):
|
|
extra_context = {
|
|
'appearance_type': 'plain'
|
|
}
|
|
success_url = reverse_lazy(
|
|
viewname='authentication:password_reset_complete_view'
|
|
)
|
|
template_name = 'authentication/password_reset_confirm.html'
|
|
|
|
def post(self, *args, **kwargs):
|
|
event_user_password_reset_complete.commit(actor=get_system_user())
|
|
return super(MayanPasswordResetConfirmView, self).post(*args, **kwargs)
|
|
|
|
|
|
class MayanPasswordResetDoneView(StrongholdPublicMixin, PasswordResetDoneView):
|
|
extra_context = {
|
|
'appearance_type': 'plain'
|
|
}
|
|
template_name = 'authentication/password_reset_done.html'
|
|
|
|
|
|
class MayanPasswordResetView(StrongholdPublicMixin, PasswordResetView):
|
|
email_template_name = 'authentication/password_reset_email.html'
|
|
extra_context = {
|
|
'appearance_type': 'plain'
|
|
}
|
|
extra_email_context = {
|
|
'project_copyright': mayan.__copyright__,
|
|
'project_license': mayan.__license__,
|
|
'project_title': setting_project_title.value,
|
|
'project_website': setting_project_url.value
|
|
}
|
|
subject_template_name = 'authentication/password_reset_subject.txt'
|
|
success_url = reverse_lazy(
|
|
viewname='authentication:password_reset_done_view'
|
|
)
|
|
template_name = 'authentication/password_reset_form.html'
|
|
|
|
def post(self, *args, **kwargs):
|
|
event_user_password_reset_started.commit(actor=get_system_user())
|
|
return super(MayanPasswordResetView, self).post(*args, **kwargs)
|
|
|
|
|
|
class UserSetPasswordView(MultipleObjectFormActionView):
|
|
form_class = SetPasswordForm
|
|
model = get_user_model()
|
|
object_permission = permission_user_edit
|
|
success_message = _('Password change request performed on %(count)d user')
|
|
success_message_plural = _(
|
|
'Password change request performed on %(count)d users'
|
|
)
|
|
|
|
def get_extra_context(self):
|
|
queryset = self.object_list
|
|
|
|
result = {
|
|
'submit_label': _('Submit'),
|
|
'title': ungettext(
|
|
singular='Change user password',
|
|
plural='Change users passwords',
|
|
number=queryset.count()
|
|
)
|
|
}
|
|
|
|
if queryset.count() == 1:
|
|
result.update(
|
|
{
|
|
'object': queryset.first(),
|
|
'title': _('Change password for user: %s') % queryset.first()
|
|
}
|
|
)
|
|
|
|
return result
|
|
|
|
def get_form_extra_kwargs(self):
|
|
queryset = self.object_list
|
|
result = {}
|
|
if queryset:
|
|
result['user'] = queryset.first()
|
|
return result
|
|
else:
|
|
raise PermissionDenied
|
|
|
|
def object_action(self, form, instance):
|
|
try:
|
|
if instance.is_superuser or instance.is_staff:
|
|
messages.error(
|
|
message=_(
|
|
'Super user and staff user password '
|
|
'reseting is not allowed, use the admin '
|
|
'interface for these cases.'
|
|
), request=self.request
|
|
)
|
|
else:
|
|
instance.set_password(form.cleaned_data['new_password1'])
|
|
instance.save()
|
|
messages.success(
|
|
message=_(
|
|
'Successful password reset for user: %s.'
|
|
) % instance, request=self.request
|
|
)
|
|
except Exception as exception:
|
|
messages.error(
|
|
message=_(
|
|
'Error reseting password for user "%(user)s": %(error)s'
|
|
) % {
|
|
'user': instance, 'error': exception
|
|
}, request=self.request
|
|
)
|