🔒️(passwords) add validators for production
This enabled various password validators to enforce password complexity.
This commit is contained in:
@@ -10,6 +10,7 @@ and this project adheres to
|
|||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
- 🔒️(passwords) add validators for production #850
|
||||||
- ✨(domains) allow to re-run check on domain if status is failed
|
- ✨(domains) allow to re-run check on domain if status is failed
|
||||||
- ✨(organization) add `is_active` field
|
- ✨(organization) add `is_active` field
|
||||||
- ✨(domains) notify support when domain status changes #668
|
- ✨(domains) notify support when domain status changes #668
|
||||||
|
|||||||
50
src/backend/core/tests/test_password_validators.py
Normal file
50
src/backend/core/tests/test_password_validators.py
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
"""Test the production settings for password validation is correct."""
|
||||||
|
|
||||||
|
from django.contrib.auth.password_validation import (
|
||||||
|
get_default_password_validators,
|
||||||
|
validate_password,
|
||||||
|
)
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from core.factories import UserFactory
|
||||||
|
|
||||||
|
from people.settings import Production
|
||||||
|
|
||||||
|
pytestmark = pytest.mark.django_db
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name="use_production_password_validators")
|
||||||
|
def use_production_password_validators_fixture(settings):
|
||||||
|
"""Set the production password validators."""
|
||||||
|
settings.AUTH_PASSWORD_VALIDATORS = Production.AUTH_PASSWORD_VALIDATORS
|
||||||
|
|
||||||
|
get_default_password_validators.cache_clear()
|
||||||
|
assert len(get_default_password_validators()) == 5
|
||||||
|
|
||||||
|
yield
|
||||||
|
|
||||||
|
get_default_password_validators.cache_clear()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"password, error",
|
||||||
|
[
|
||||||
|
("password", "This password is too common."),
|
||||||
|
("password123", "This password is too common."),
|
||||||
|
("123", "This password is too common."),
|
||||||
|
("coucou", "This password is too common."),
|
||||||
|
("john doe 123", "The password is too similar to the name"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_validate_password_validator(
|
||||||
|
use_production_password_validators, # pylint: disable=unused-argument
|
||||||
|
password,
|
||||||
|
error,
|
||||||
|
):
|
||||||
|
"""Test the Mailbox password validation."""
|
||||||
|
user = UserFactory(name="John Doe")
|
||||||
|
|
||||||
|
with pytest.raises(Exception) as excinfo:
|
||||||
|
validate_password(password, user)
|
||||||
|
assert error in str(excinfo.value)
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
"""Test the production settings for password validation is correct."""
|
||||||
|
|
||||||
|
from django.contrib.auth.password_validation import (
|
||||||
|
get_default_password_validators,
|
||||||
|
validate_password,
|
||||||
|
)
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from mailbox_manager.factories import MailboxFactory
|
||||||
|
from people.settings import Production
|
||||||
|
|
||||||
|
pytestmark = pytest.mark.django_db
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name="use_production_password_validators")
|
||||||
|
def use_production_password_validators_fixture(settings):
|
||||||
|
"""Set the production password validators."""
|
||||||
|
settings.AUTH_PASSWORD_VALIDATORS = Production.AUTH_PASSWORD_VALIDATORS
|
||||||
|
|
||||||
|
get_default_password_validators.cache_clear()
|
||||||
|
assert len(get_default_password_validators()) == 5
|
||||||
|
|
||||||
|
yield
|
||||||
|
|
||||||
|
get_default_password_validators.cache_clear()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"password, error",
|
||||||
|
[
|
||||||
|
("password", "This password is too common."),
|
||||||
|
("password123", "This password is too common."),
|
||||||
|
("123", "This password is too common."),
|
||||||
|
("coucou", "This password is too common."),
|
||||||
|
("john doe 123", "The password is too similar to the"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_validate_password_validator(
|
||||||
|
use_production_password_validators, # pylint: disable=unused-argument
|
||||||
|
password,
|
||||||
|
error,
|
||||||
|
):
|
||||||
|
"""Test the Mailbox password validation."""
|
||||||
|
mailbox_1 = MailboxFactory(
|
||||||
|
first_name="John",
|
||||||
|
last_name="Doe",
|
||||||
|
)
|
||||||
|
mailbox_2 = MailboxFactory(
|
||||||
|
local_part="john.doe",
|
||||||
|
)
|
||||||
|
|
||||||
|
with pytest.raises(Exception) as excinfo:
|
||||||
|
validate_password(password, mailbox_1)
|
||||||
|
assert error in str(excinfo.value)
|
||||||
|
|
||||||
|
with pytest.raises(Exception) as excinfo:
|
||||||
|
validate_password(password, mailbox_2)
|
||||||
|
assert error in str(excinfo.value)
|
||||||
@@ -231,6 +231,7 @@ class Base(Configuration):
|
|||||||
"mailbox_oauth2",
|
"mailbox_oauth2",
|
||||||
*INSTALLED_PLUGINS,
|
*INSTALLED_PLUGINS,
|
||||||
# Third party apps
|
# Third party apps
|
||||||
|
"django_zxcvbn_password_validator",
|
||||||
"drf_spectacular",
|
"drf_spectacular",
|
||||||
"drf_spectacular_sidecar", # required for Django collectstatic discovery
|
"drf_spectacular_sidecar", # required for Django collectstatic discovery
|
||||||
"corsheaders",
|
"corsheaders",
|
||||||
@@ -915,6 +916,47 @@ class Production(Base):
|
|||||||
CSRF_COOKIE_SECURE = True
|
CSRF_COOKIE_SECURE = True
|
||||||
SESSION_COOKIE_SECURE = True
|
SESSION_COOKIE_SECURE = True
|
||||||
|
|
||||||
|
# Password management
|
||||||
|
|
||||||
|
# - Password strength for ZxcvbnPasswordValidator
|
||||||
|
# 0 too guessable: risky password. (guesses < 10^3)
|
||||||
|
# 1 very guessable: protection from throttled online attacks. (guesses < 10^6)
|
||||||
|
# 2 somewhat guessable: protection from unthrottled online attacks. (guesses < 10^8)
|
||||||
|
# 3 safely unguessable: moderate protection from offline slow-hash scenario. (guesses < 10^10)
|
||||||
|
# 4 very unguessable: strong protection from offline slow-hash scenario. (guesses >= 10^10)
|
||||||
|
PASSWORD_MINIMAL_STRENGTH = values.IntegerValue(
|
||||||
|
default=3,
|
||||||
|
environ_name="PASSWORD_MINIMAL_STRENGTH",
|
||||||
|
environ_prefix=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
AUTH_PASSWORD_VALIDATORS = [
|
||||||
|
{
|
||||||
|
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
|
||||||
|
"OPTIONS": {
|
||||||
|
"user_attributes": (
|
||||||
|
"email", # for core.User
|
||||||
|
"name", # for core.User
|
||||||
|
"first_name", # for mailbox_manager.Mailbox
|
||||||
|
"last_name", # for mailbox_manager.Mailbox
|
||||||
|
"local_part", # for mailbox_manager.Mailbox
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"NAME": "django_zxcvbn_password_validator.ZxcvbnPasswordValidator",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
# For static files in production, we want to use a backend that includes a hash in
|
# For static files in production, we want to use a backend that includes a hash in
|
||||||
# the filename, that is calculated from the file content, so that browsers always
|
# the filename, that is calculated from the file content, so that browsers always
|
||||||
# get the updated version of each file.
|
# get the updated version of each file.
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ dependencies = [
|
|||||||
"django-storages==1.14.5",
|
"django-storages==1.14.5",
|
||||||
"django-timezone-field>=5.1",
|
"django-timezone-field>=5.1",
|
||||||
"django-treebeard==4.7.1",
|
"django-treebeard==4.7.1",
|
||||||
|
"django-zxcvbn-password-validator==1.4.5",
|
||||||
"django==5.1.7",
|
"django==5.1.7",
|
||||||
"djangorestframework==3.15.2",
|
"djangorestframework==3.15.2",
|
||||||
"dockerflow==2024.4.2",
|
"dockerflow==2024.4.2",
|
||||||
|
|||||||
Reference in New Issue
Block a user