Эх сурвалжийг харах

HUE-3997 [core] Add useradmin feature that resets axes lockouts

Jenny Kim 9 жил өмнө
parent
commit
0d492db

+ 7 - 1
apps/useradmin/src/useradmin/forms.py

@@ -109,6 +109,10 @@ class UserChangeForm(django.contrib.auth.forms.UserChangeForm):
   language = forms.ChoiceField(label=_t("Language Preference"),
                                choices=LANGUAGES,
                                required=False)
+  unlock_account = forms.BooleanField(label=_t("Unlock Account"),
+                                      help_text=_t("Unlock user's account for login."),
+                                      initial=False,
+                                      required=False)
 
   class Meta(django.contrib.auth.forms.UserChangeForm.Meta):
     fields = ["username", "first_name", "last_name", "email", "ensure_home_directory"]
@@ -132,6 +136,8 @@ class UserChangeForm(django.contrib.auth.forms.UserChangeForm):
         self.fields['is_active'].widget.attrs['readonly'] = True
       if 'is_superuser' in self.fields:
         self.fields['is_superuser'].widget.attrs['readonly'] = True
+      if 'unlock_account' in self.fields:
+        self.fields['unlock_account'].widget.attrs['readonly'] = True
       if 'groups' in self.fields:
         self.fields['groups'].widget.attrs['readonly'] = True
 
@@ -198,7 +204,7 @@ class PasswordChangeForm(UserChangeForm):
 
 class SuperUserChangeForm(UserChangeForm):
   class Meta(UserChangeForm.Meta):
-    fields = ["username", "is_active"] + UserChangeForm.Meta.fields + ["is_superuser", "groups"]
+    fields = ["username", "is_active"] + UserChangeForm.Meta.fields + ["is_superuser", "unlock_account", "groups"]
 
   def __init__(self, *args, **kwargs):
     super(SuperUserChangeForm, self).__init__(*args, **kwargs)

+ 6 - 2
apps/useradmin/src/useradmin/templates/edit_user.mako

@@ -17,6 +17,7 @@
 from desktop.views import commonheader, commonfooter
 from django.utils.translation import ugettext as _
 from useradmin.password_policy import is_password_policy_enabled, get_password_hint
+from useradmin.views import is_user_locked_out
 %>
 
 <%namespace name="layout" file="layout.mako" />
@@ -86,8 +87,11 @@ ${ layout.menubar(section='users') }
         </div>
       % if user.is_superuser:
         <div id="step3" class="stepDetails hide">
-        ${layout.render_field(form["is_active"])}
-                ${'is_superuser' in form.fields and layout.render_field(form["is_superuser"])}
+          ${layout.render_field(form["is_active"])}
+          ${'is_superuser' in form.fields and layout.render_field(form["is_superuser"])}
+          % if is_user_locked_out(username):
+            ${layout.render_field(form["unlock_account"])}
+          % endif
         </div>
       % endif
       </div>

+ 1 - 1
apps/useradmin/src/useradmin/templates/list_users.mako

@@ -163,7 +163,7 @@ ${layout.menubar(section='users')}
         null,
         null,
         null,
-        { "sType": "date" }
+        { "sType": "date" },
       ],
       "oLanguage": {
         "sEmptyTable": "${_('No data available')}",

+ 20 - 0
apps/useradmin/src/useradmin/views.py

@@ -22,6 +22,10 @@ import threading
 import subprocess
 import json
 
+from axes.decorators import FAILURE_LIMIT, LOCK_OUT_AT_FAILURE
+from axes.models import AccessAttempt
+from axes.utils import reset
+
 import ldap
 import ldap_access
 from ldap_access import LdapBindException, LdapSearchException
@@ -129,6 +133,11 @@ def massage_groups_for_json(groups):
   return simple_groups
 
 
+def is_user_locked_out(username):
+  attempts = AccessAttempt.objects.filter(username=username)
+  return any(attempt.failures_since_start >= FAILURE_LIMIT and LOCK_OUT_AT_FAILURE for attempt in attempts)
+
+
 def delete_user(request):
   if not request.user.is_superuser:
     request.audit = {
@@ -263,6 +272,17 @@ def edit_user(request, username=None):
           # All ok
           form.save()
           request.info(_('User information updated'))
+
+          # Unlock account if selected
+          if form.cleaned_data.get('unlock_account'):
+            if not request.user.is_superuser:
+              raise PopupException(_('You must be a superuser to reset users.'), error_code=401)
+
+            try:
+              reset(username=username)
+              request.info(_('Successfully unlocked account for user: %s') % username)
+            except Exception, e:
+              raise PopupException(_('Failed to reset login attempts for %s: %s') % (username, str(e)))
         finally:
           __users_lock.release()