Skip to content

Commit 7463fca

Browse files
authored
Merge pull request #1220 from userlocalhost/feature/user/prohibit_to_change_password
Added safety processing to prevent changing user password when PASSWORD_RESET_DISABLED is set
2 parents 362db96 + 5470008 commit 7463fca

File tree

3 files changed

+64
-2
lines changed

3 files changed

+64
-2
lines changed

airone/lib/test.py

+29
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import functools
12
import inspect
23
import os
34
import sys
@@ -188,3 +189,31 @@ def __enter__(self):
188189
def __exit__(self, *arg, **kwargs):
189190
sys.stderr = self.tmp_stderr
190191
self.f.close()
192+
193+
194+
def with_airone_settings(info={}):
195+
"""
196+
This update AIRONE.settings parameter duing running test and retrieve it
197+
after running test.
198+
"""
199+
200+
def _with_settings(method):
201+
@functools.wraps(method)
202+
def wrapper(*args, **kwargs):
203+
# This evacuates original values in settings.AIRONE and set specified one
204+
evacuation_place = {}
205+
for k, v in info.items():
206+
evacuation_place[k] = settings.AIRONE.get(k)
207+
settings.AIRONE[k] = v
208+
209+
# Run test case
210+
method(*args, **kwargs)
211+
212+
# Revert original configuration that were set in the settings.AIRONE
213+
for k, v in evacuation_place.items():
214+
if v:
215+
settings.AIRONE[k] = v
216+
217+
return wrapper
218+
219+
return _with_settings

user/api_v2/serializers.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
from datetime import timedelta
22
from typing import Dict, TypedDict
33

4+
from django.conf import settings
45
from django.contrib.auth import password_validation
56
from django.contrib.auth.tokens import default_token_generator
67
from django.core.exceptions import ValidationError as DjangoCoreValidationError
78
from django.utils.http import urlsafe_base64_decode
89
from drf_spectacular.utils import extend_schema_field
910
from rest_framework import serializers
1011
from rest_framework.authtoken.models import Token
11-
from rest_framework.exceptions import ValidationError
12+
from rest_framework.exceptions import PermissionDenied, ValidationError
1213

1314
from airone.auth.ldap import LDAPBackend
1415
from user.models import User
@@ -163,6 +164,11 @@ def validate(self, attrs: Dict):
163164
request = self.context["request"]
164165
user = self.context["user"]
165166

167+
# When PASSWORD_RESET_DISABLED is set in the settings.AIRONE
168+
# request shouldn't be accepted.
169+
if settings.AIRONE.get("PASSWORD_RESET_DISABLED"):
170+
raise PermissionDenied("It is not allowed to change password")
171+
166172
# Identification
167173
if int(request.user.id) != int(user.id):
168174
raise ValidationError("You don't have permission to access this object")

user/tests/test_api_v2.py

+28-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from django.utils.http import urlsafe_base64_encode
99
from rest_framework.authtoken.models import Token
1010

11-
from airone.lib.test import AironeViewTest
11+
from airone.lib.test import AironeViewTest, with_airone_settings
1212
from group.models import Group
1313
from user.models import User
1414

@@ -313,6 +313,33 @@ def test_patch_user_password(self):
313313
self.assertIsNotNone(updated_user)
314314
self.assertTrue(updated_user.check_password(new_passwd))
315315

316+
@with_airone_settings(
317+
{
318+
"PASSWORD_RESET_DISABLED": True,
319+
}
320+
)
321+
def test_patch_user_password_when_PASSWORD_RESET_DISABLED_is_set(self):
322+
user = self.guest_login()
323+
old_passwd = user.username
324+
new_passwd = "new-passwd"
325+
326+
params = {
327+
"old_passwd": old_passwd,
328+
"new_passwd": new_passwd,
329+
"chk_passwd": new_passwd,
330+
}
331+
resp = self.client.patch(
332+
"/user/api/v2/%d/edit_passwd" % user.id, json.dumps(params), "application/json"
333+
)
334+
self.assertEqual(resp.status_code, 403)
335+
336+
# check password wasn't changed
337+
self.assertEqual(
338+
resp.json(), {"message": "It is not allowed to change password", "code": "AE-210000"}
339+
)
340+
self.assertFalse(user.check_password(new_passwd))
341+
self.assertTrue(user.check_password(old_passwd))
342+
316343
def test_patch_user_password_with_invalid_params(self):
317344
user = self.guest_login()
318345
old_passwd = user.username

0 commit comments

Comments
 (0)