mirror of
https://github.com/haiwen/seahub.git
synced 2025-08-01 07:10:55 +00:00
[sysadmin] Force passwd change when add/reset user
This commit is contained in:
parent
808a5e186d
commit
054ef03687
@ -23,6 +23,7 @@ from seahub.auth.forms import AuthenticationForm, CaptchaAuthenticationForm
|
||||
from seahub.auth.forms import PasswordResetForm, SetPasswordForm, PasswordChangeForm
|
||||
from seahub.auth.tokens import default_token_generator
|
||||
from seahub.base.accounts import User
|
||||
from seahub.options.models import UserOptions
|
||||
from seahub.utils import is_ldap_user
|
||||
from seahub.utils.http import is_safe_url
|
||||
from seahub.utils.ip import get_remote_ip
|
||||
@ -134,6 +135,11 @@ def login(request, template_name='registration/login.html',
|
||||
# have captcha
|
||||
form = CaptchaAuthenticationForm(data=request.POST)
|
||||
if form.is_valid():
|
||||
if UserOptions.objects.passwd_change_required(
|
||||
form.get_user().username):
|
||||
redirect_to = reverse('auth_password_change')
|
||||
request.session['force_passwd_change'] = True
|
||||
|
||||
# captcha & passwod is valid, log user in
|
||||
request.session['remember_me'] = remember_me
|
||||
return log_user_in(request, form.get_user(), redirect_to)
|
||||
@ -143,6 +149,11 @@ def login(request, template_name='registration/login.html',
|
||||
else:
|
||||
form = authentication_form(data=request.POST)
|
||||
if form.is_valid():
|
||||
if UserOptions.objects.passwd_change_required(
|
||||
form.get_user().username):
|
||||
redirect_to = reverse('auth_password_change')
|
||||
request.session['force_passwd_change'] = True
|
||||
|
||||
# password is valid, log user in
|
||||
request.session['remember_me'] = remember_me
|
||||
return log_user_in(request, form.get_user(), redirect_to)
|
||||
@ -365,6 +376,12 @@ def password_change(request, template_name='registration/password_change_form.ht
|
||||
form = password_change_form(user=request.user, data=request.POST)
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
|
||||
if request.session.get('force_passwd_change', False):
|
||||
del request.session['force_passwd_change']
|
||||
UserOptions.objects.unset_force_passwd_change(
|
||||
request.user.username)
|
||||
|
||||
update_session_auth_hash(request, request.user)
|
||||
return HttpResponseRedirect(post_change_redirect)
|
||||
else:
|
||||
@ -375,6 +392,7 @@ def password_change(request, template_name='registration/password_change_form.ht
|
||||
'min_len': config.USER_PASSWORD_MIN_LENGTH,
|
||||
'strong_pwd_required': config.USER_STRONG_PASSWORD_REQUIRED,
|
||||
'level': config.USER_PASSWORD_STRENGTH_LEVEL,
|
||||
'force_passwd_change': request.session.get('force_passwd_change', False),
|
||||
}, context_instance=RequestContext(request))
|
||||
|
||||
def password_change_done(request, template_name='registration/password_change_done.html'):
|
||||
|
@ -1,4 +1,8 @@
|
||||
import re
|
||||
|
||||
from django.core.cache import cache
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.http import HttpResponseRedirect
|
||||
|
||||
import seaserv
|
||||
|
||||
@ -12,6 +16,7 @@ try:
|
||||
from seahub.settings import MULTI_TENANCY
|
||||
except ImportError:
|
||||
MULTI_TENANCY = False
|
||||
from seahub.settings import SITE_ROOT
|
||||
|
||||
class BaseMiddleware(object):
|
||||
"""
|
||||
@ -70,3 +75,21 @@ class InfobarMiddleware(object):
|
||||
|
||||
def process_response(self, request, response):
|
||||
return response
|
||||
|
||||
|
||||
class ForcePasswdChangeMiddleware(object):
|
||||
def _request_in_black_list(self, request):
|
||||
path = request.path
|
||||
black_list = (r'^%s$' % SITE_ROOT, r'home/.+', r'repo/.+',
|
||||
r'[f|d]/[a-f][0-9]{10}', r'group/\d+', r'groups/',
|
||||
r'share/', r'profile/', r'notification/list/')
|
||||
|
||||
for patt in black_list:
|
||||
if re.search(patt, path) is not None:
|
||||
return True
|
||||
return False
|
||||
|
||||
def process_request(self, request):
|
||||
if request.session.get('force_passwd_change', False):
|
||||
if self._request_in_black_list(request):
|
||||
return HttpResponseRedirect(reverse('auth_password_change'))
|
||||
|
@ -18,6 +18,9 @@ KEY_SUB_LIB = "sub_lib"
|
||||
VAL_SUB_LIB_ENABLED = "1"
|
||||
VAL_SUB_LIB_DISABLED = "0"
|
||||
|
||||
KEY_FORCE_PASSWD_CHANGE = "force_passwd_change"
|
||||
VAL_FORCE_PASSWD_CHANGE = "1"
|
||||
|
||||
KEY_DEFAULT_REPO = "default_repo"
|
||||
|
||||
class CryptoOptionNotSetError(Exception):
|
||||
@ -43,6 +46,11 @@ class UserOptionsManager(models.Manager):
|
||||
|
||||
return user_option
|
||||
|
||||
def unset_user_option(self, username, k):
|
||||
"""Remove user's option.
|
||||
"""
|
||||
super(UserOptionsManager, self).filter(email=username, option_key=k).delete()
|
||||
|
||||
def enable_server_crypto(self, username):
|
||||
"""
|
||||
|
||||
@ -185,7 +193,24 @@ class UserOptionsManager(models.Manager):
|
||||
return user_option.option_val
|
||||
except UserOptions.DoesNotExist:
|
||||
return None
|
||||
|
||||
|
||||
def passwd_change_required(self, username):
|
||||
"""Check whether user need to change password.
|
||||
"""
|
||||
try:
|
||||
r = super(UserOptionsManager, self).get(
|
||||
email=username, option_key=KEY_FORCE_PASSWD_CHANGE)
|
||||
return r.option_val == VAL_FORCE_PASSWD_CHANGE
|
||||
except UserOptions.DoesNotExist:
|
||||
return False
|
||||
|
||||
def set_force_passwd_change(self, username):
|
||||
return self.set_user_option(username, KEY_FORCE_PASSWD_CHANGE,
|
||||
VAL_FORCE_PASSWD_CHANGE)
|
||||
|
||||
def unset_force_passwd_change(self, username):
|
||||
return self.unset_user_option(username, KEY_FORCE_PASSWD_CHANGE)
|
||||
|
||||
class UserOptions(models.Model):
|
||||
email = LowerCaseCharField(max_length=255, db_index=True)
|
||||
option_key = models.CharField(max_length=50)
|
||||
|
@ -117,7 +117,8 @@ MIDDLEWARE_CLASSES = (
|
||||
'seahub.auth.middleware.AuthenticationMiddleware',
|
||||
'seahub.base.middleware.BaseMiddleware',
|
||||
'seahub.base.middleware.InfobarMiddleware',
|
||||
'seahub.password_session.middleware.CheckPasswordHash'
|
||||
'seahub.password_session.middleware.CheckPasswordHash',
|
||||
'seahub.base.middleware.ForcePasswdChangeMiddleware',
|
||||
)
|
||||
|
||||
SITE_ROOT_URLCONF = 'seahub.urls'
|
||||
|
@ -7,6 +7,10 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block main_panel %}
|
||||
{% if force_passwd_change %}
|
||||
<p>{% trans "Please update your password before continue." %} </p>
|
||||
{% endif %}
|
||||
|
||||
<div class="new-narrow-panel">
|
||||
<h2 class="hd">{% trans "Password Modification" %}</h2>
|
||||
<form action="" method="post" class="con">{% csrf_token %}
|
||||
|
@ -104,7 +104,7 @@ class Fixtures(Exam):
|
||||
|
||||
class BaseTestCase(TestCase, Fixtures):
|
||||
def login_as(self, user):
|
||||
self.client.post(
|
||||
return self.client.post(
|
||||
reverse('auth_login'), {'login': user.username,
|
||||
'password': 'secret'}
|
||||
'password': self.user_password}
|
||||
)
|
||||
|
@ -1,5 +1,7 @@
|
||||
"""Copied from latest django/utils/http.py::is_safe_url
|
||||
"""
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import unicodedata
|
||||
import urlparse
|
||||
import json
|
||||
|
@ -46,6 +46,7 @@ from seahub.views.ajax import (get_related_users_by_org_repo,
|
||||
get_related_users_by_repo)
|
||||
from seahub.views import get_system_default_repo_id, gen_path_link
|
||||
from seahub.forms import SetUserQuotaForm, AddUserForm, BatchAddUserForm
|
||||
from seahub.options.models import UserOptions
|
||||
from seahub.profile.models import Profile, DetailedProfile
|
||||
from seahub.signals import repo_deleted
|
||||
from seahub.share.models import FileShare, UploadLinkShare
|
||||
@ -1236,7 +1237,9 @@ def user_reset(request, email):
|
||||
new_password = INIT_PASSWD
|
||||
user.set_password(new_password)
|
||||
user.save()
|
||||
|
||||
clear_token(user.username)
|
||||
UserOptions.objects.set_force_passwd_change(user.username)
|
||||
|
||||
if IS_EMAIL_CONFIGURED:
|
||||
if SEND_EMAIL_ON_RESETTING_USER_PASSWD:
|
||||
@ -1309,6 +1312,7 @@ def user_add(request):
|
||||
|
||||
if user:
|
||||
User.objects.update_role(email, role)
|
||||
UserOptions.objects.set_force_passwd_change(email)
|
||||
|
||||
if request.user.org:
|
||||
org_id = request.user.org.org_id
|
||||
|
25
tests/seahub/auth/test_login.py
Normal file
25
tests/seahub/auth/test_login.py
Normal file
@ -0,0 +1,25 @@
|
||||
from django.conf import settings
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
from seahub.options.models import UserOptions
|
||||
from seahub.test_utils import BaseTestCase
|
||||
|
||||
|
||||
class LoginTest(BaseTestCase):
|
||||
def test_can_login(self):
|
||||
resp = self.login_as(self.user)
|
||||
|
||||
self.assertEqual(302, resp.status_code)
|
||||
self.assertRedirects(resp, settings.LOGIN_REDIRECT_URL)
|
||||
|
||||
def test_force_passwd_change_when_login(self):
|
||||
UserOptions.objects.set_force_passwd_change(self.user.username)
|
||||
|
||||
resp = self.login_as(self.user)
|
||||
|
||||
self.assertEqual(302, resp.status_code)
|
||||
self.assertRedirects(resp, '/accounts/password/change/')
|
||||
|
||||
resp = self.client.get(reverse('auth_password_change'))
|
||||
self.assertEqual(200, resp.status_code)
|
||||
self.assertEqual(resp.context['force_passwd_change'], True)
|
26
tests/seahub/auth/test_password_change.py
Normal file
26
tests/seahub/auth/test_password_change.py
Normal file
@ -0,0 +1,26 @@
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
from seahub.test_utils import BaseTestCase
|
||||
|
||||
|
||||
class PasswordChangeTest(BaseTestCase):
|
||||
def test_can_render(self):
|
||||
self.login_as(self.user)
|
||||
|
||||
resp = self.client.get(reverse('auth_password_change'))
|
||||
|
||||
self.assertEqual(200, resp.status_code)
|
||||
self.assertContains(resp, 'Password Modification')
|
||||
|
||||
def test_can_change(self):
|
||||
self.login_as(self.user)
|
||||
|
||||
resp = self.client.post(
|
||||
reverse('auth_password_change'), {
|
||||
'old_password': self.user_password,
|
||||
'new_password1': '123',
|
||||
'new_password2': '123',
|
||||
}
|
||||
)
|
||||
self.assertEqual(302, resp.status_code)
|
||||
self.assertRedirects(resp, reverse('auth_password_change_done'))
|
@ -6,9 +6,11 @@ from django.http.cookie import parse_cookie
|
||||
from tests.common.utils import randstring
|
||||
|
||||
from seahub.base.accounts import User
|
||||
from seahub.utils.ms_excel import write_xls as real_write_xls
|
||||
from seahub.test_utils import BaseTestCase
|
||||
from seahub.options.models import (UserOptions, KEY_FORCE_PASSWD_CHANGE,
|
||||
VAL_FORCE_PASSWD_CHANGE)
|
||||
from seahub.share.models import FileShare
|
||||
from seahub.test_utils import BaseTestCase
|
||||
from seahub.utils.ms_excel import write_xls as real_write_xls
|
||||
|
||||
from seaserv import ccnet_threaded_rpc, seafile_api
|
||||
|
||||
@ -50,6 +52,9 @@ class UserResetTest(BaseTestCase):
|
||||
self.login_as(self.admin)
|
||||
|
||||
def test_can_reset(self):
|
||||
assert len(UserOptions.objects.filter(
|
||||
email=self.user.username, option_key=KEY_FORCE_PASSWD_CHANGE)) == 0
|
||||
|
||||
old_passwd = self.user.enc_password
|
||||
resp = self.client.post(
|
||||
reverse('user_reset', args=[self.user.email])
|
||||
@ -58,7 +63,9 @@ class UserResetTest(BaseTestCase):
|
||||
|
||||
u = User.objects.get(email=self.user.username)
|
||||
assert u.enc_password != old_passwd
|
||||
|
||||
assert UserOptions.objects.get(
|
||||
email=self.user.username,
|
||||
option_key=KEY_FORCE_PASSWD_CHANGE).option_val == VAL_FORCE_PASSWD_CHANGE
|
||||
|
||||
class BatchUserMakeAdminTest(BaseTestCase):
|
||||
def setUp(self):
|
||||
@ -98,6 +105,29 @@ class BatchUserMakeAdminTest(BaseTestCase):
|
||||
# assert u.enc_password == old_passwd
|
||||
|
||||
|
||||
class UserAddTest(BaseTestCase):
|
||||
def setUp(self):
|
||||
self.new_user = 'new_user@test.com'
|
||||
self.login_as(self.admin)
|
||||
self.remove_user(self.new_user)
|
||||
|
||||
def test_can_add(self):
|
||||
assert len(UserOptions.objects.filter(
|
||||
email=self.new_user, option_key=KEY_FORCE_PASSWD_CHANGE)) == 0
|
||||
|
||||
resp = self.client.post(
|
||||
reverse('user_add',), {
|
||||
'email': self.new_user,
|
||||
'password1': '123',
|
||||
'password2': '123',
|
||||
}, HTTP_X_REQUESTED_WITH='XMLHttpRequest'
|
||||
)
|
||||
|
||||
self.assertEqual(200, resp.status_code)
|
||||
assert UserOptions.objects.get(
|
||||
email=self.new_user,
|
||||
option_key=KEY_FORCE_PASSWD_CHANGE).option_val == VAL_FORCE_PASSWD_CHANGE
|
||||
|
||||
class UserRemoveTest(BaseTestCase):
|
||||
def setUp(self):
|
||||
self.login_as(self.admin)
|
||||
|
Loading…
Reference in New Issue
Block a user