mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-16 20:22:53 -06:00
* Closes #16964: Validate password when creating a new user or updating password for an existing user * Add serializer validation & tests --------- Co-authored-by: Nishant Gaglani <nishantgaglani@gmail.com>
This commit is contained in:
parent
93cebae55c
commit
cb59f6e6f7
@ -1,4 +1,4 @@
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth import get_user_model, password_validation
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import extend_schema_field
|
||||
from rest_framework import serializers
|
||||
@ -61,6 +61,14 @@ class UserSerializer(ValidatedModelSerializer):
|
||||
'password': {'write_only': True}
|
||||
}
|
||||
|
||||
def validate(self, data):
|
||||
|
||||
# Enforce password validation rules (if configured)
|
||||
if not self.nested and data.get('password'):
|
||||
password_validation.validate_password(data['password'], self.instance)
|
||||
|
||||
return super().validate(data)
|
||||
|
||||
def create(self, validated_data):
|
||||
"""
|
||||
Extract the password from validated data and set it separately to ensure proper hash generation.
|
||||
|
@ -1,6 +1,6 @@
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth import get_user_model, password_validation
|
||||
from django.contrib.postgres.forms import SimpleArrayField
|
||||
from django.core.exceptions import FieldError
|
||||
from django.utils.safestring import mark_safe
|
||||
@ -227,6 +227,10 @@ class UserForm(forms.ModelForm):
|
||||
if self.cleaned_data['password'] and self.cleaned_data['password'] != self.cleaned_data['confirm_password']:
|
||||
raise forms.ValidationError(_("Passwords do not match! Please check your input and try again."))
|
||||
|
||||
# Enforce password validation rules (if configured)
|
||||
if self.cleaned_data['password']:
|
||||
password_validation.validate_password(self.cleaned_data['password'], self.instance)
|
||||
|
||||
|
||||
class GroupForm(forms.ModelForm):
|
||||
users = DynamicModelMultipleChoiceField(
|
||||
|
@ -1,4 +1,5 @@
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.test import override_settings
|
||||
from django.urls import reverse
|
||||
|
||||
from core.models import ObjectType
|
||||
@ -93,6 +94,31 @@ class UserTest(APIViewTestCases.APIViewTestCase):
|
||||
user.refresh_from_db()
|
||||
self.assertTrue(user.check_password(data['password']))
|
||||
|
||||
@override_settings(AUTH_PASSWORD_VALIDATORS=[{
|
||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||
'OPTIONS': {'min_length': 8}
|
||||
}])
|
||||
def test_password_validation_enforced(self):
|
||||
"""
|
||||
Test that any configured password validation rules (AUTH_PASSWORD_VALIDATORS) are enforced.
|
||||
"""
|
||||
self.add_permissions('users.add_user')
|
||||
|
||||
data = {
|
||||
'username': 'new_user',
|
||||
'password': 'foo',
|
||||
}
|
||||
url = reverse('users-api:user-list')
|
||||
|
||||
# Password too short
|
||||
response = self.client.post(url, data, format='json', **self.header)
|
||||
self.assertEqual(response.status_code, 400)
|
||||
|
||||
# Password long enough
|
||||
data['password'] = 'foobar123'
|
||||
response = self.client.post(url, data, format='json', **self.header)
|
||||
self.assertEqual(response.status_code, 201)
|
||||
|
||||
|
||||
class GroupTest(APIViewTestCases.APIViewTestCase):
|
||||
model = Group
|
||||
|
@ -1,6 +1,8 @@
|
||||
from django.test import override_settings
|
||||
|
||||
from core.models import ObjectType
|
||||
from users.models import *
|
||||
from utilities.testing import ViewTestCases, create_test_user
|
||||
from utilities.testing import ViewTestCases, create_test_user, extract_form_failures
|
||||
|
||||
|
||||
class UserTestCase(
|
||||
@ -58,6 +60,34 @@ class UserTestCase(
|
||||
'last_name': 'newlastname',
|
||||
}
|
||||
|
||||
@override_settings(AUTH_PASSWORD_VALIDATORS=[{
|
||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||
'OPTIONS': {'min_length': 8}
|
||||
}])
|
||||
def test_password_validation_enforced(self):
|
||||
"""
|
||||
Test that any configured password validation rules (AUTH_PASSWORD_VALIDATORS) are enforced.
|
||||
"""
|
||||
self.add_permissions('users.add_user')
|
||||
data = {
|
||||
'username': 'new_user',
|
||||
'password': 'foo',
|
||||
'confirm_password': 'foo',
|
||||
}
|
||||
|
||||
# Password too short
|
||||
request = {
|
||||
'path': self._get_url('add'),
|
||||
'data': data,
|
||||
}
|
||||
response = self.client.post(**request)
|
||||
self.assertHttpStatus(response, 200)
|
||||
|
||||
# Password long enough
|
||||
data['password'] = 'foobar123'
|
||||
data['confirm_password'] = 'foobar123'
|
||||
self.assertHttpStatus(self.client.post(**request), 302)
|
||||
|
||||
|
||||
class GroupTestCase(
|
||||
ViewTestCases.GetObjectViewTestCase,
|
||||
|
Loading…
Reference in New Issue
Block a user