mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-17 05:41:25 +02:00
Merge pull request #1154 from modoboa/feature/use_internal_password_validation
Replaced django-passwords by django's builtins.
This commit is contained in:
@@ -10,7 +10,7 @@ from django.core.urlresolvers import reverse
|
||||
from django.http import QueryDict
|
||||
from django.utils.translation import ugettext as _, ugettext_lazy
|
||||
|
||||
from passwords.fields import PasswordField
|
||||
from django.contrib.auth import password_validation
|
||||
|
||||
from modoboa.core import signals as core_signals
|
||||
from modoboa.core.models import User
|
||||
@@ -45,11 +45,11 @@ class AccountFormGeneral(forms.ModelForm):
|
||||
choices=[("", ugettext_lazy("Choose"))],
|
||||
help_text=ugettext_lazy("What level of permission this user will have")
|
||||
)
|
||||
password1 = PasswordField(
|
||||
password1 = forms.CharField(
|
||||
label=ugettext_lazy("Password"), widget=forms.widgets.PasswordInput
|
||||
)
|
||||
|
||||
password2 = PasswordField(
|
||||
password2 = forms.CharField(
|
||||
label=ugettext_lazy("Confirmation"),
|
||||
widget=forms.widgets.PasswordInput,
|
||||
help_text=ugettext_lazy(
|
||||
@@ -157,6 +157,8 @@ class AccountFormGeneral(forms.ModelForm):
|
||||
if password1 != password2:
|
||||
raise forms.ValidationError(
|
||||
_("The two password fields didn't match."))
|
||||
if password2 != "":
|
||||
password_validation.validate_password(password2, self.instance)
|
||||
return password2
|
||||
|
||||
def clean(self):
|
||||
@@ -181,9 +183,8 @@ class AccountFormGeneral(forms.ModelForm):
|
||||
raise lib_exceptions.PermDeniedException(
|
||||
_("You can't disable your own account"))
|
||||
if commit:
|
||||
if "password1" in self.cleaned_data \
|
||||
and self.cleaned_data["password1"] != "":
|
||||
account.set_password(self.cleaned_data["password1"])
|
||||
if self.cleaned_data.get("password2", "") != "":
|
||||
account.set_password(self.cleaned_data["password2"])
|
||||
account.save()
|
||||
account.role = self.cleaned_data["role"]
|
||||
return account
|
||||
|
||||
@@ -7,8 +7,9 @@ from django.shortcuts import get_object_or_404
|
||||
from django.utils.translation import ugettext as _, ugettext_lazy
|
||||
from django.utils.encoding import force_text
|
||||
|
||||
from django.contrib.auth import password_validation
|
||||
|
||||
from rest_framework import serializers
|
||||
from passwords import validators
|
||||
|
||||
from modoboa.admin import models as admin_models
|
||||
from modoboa.core import constants as core_constants
|
||||
@@ -159,8 +160,7 @@ class AccountPasswordSerializer(serializers.ModelSerializer):
|
||||
def validate_new_password(self, value):
|
||||
"""Check new password."""
|
||||
try:
|
||||
validators.validate_length(value)
|
||||
validators.complexity(value)
|
||||
password_validation.validate_password(value, self.instance)
|
||||
except ValidationError as exc:
|
||||
raise serializers.ValidationError(exc.messages[0])
|
||||
return value
|
||||
@@ -198,8 +198,7 @@ class WritableAccountSerializer(AccountSerializer):
|
||||
def validate_password(self, value):
|
||||
"""Check password constraints."""
|
||||
try:
|
||||
validators.validate_length(value)
|
||||
validators.complexity(value)
|
||||
password_validation.validate_password(value, self.instance)
|
||||
except ValidationError as exc:
|
||||
raise serializers.ValidationError(exc.messages[0])
|
||||
return value
|
||||
|
||||
@@ -6,7 +6,7 @@ from django import forms
|
||||
from django.conf import settings
|
||||
from django.utils.translation import ugettext as _, ugettext_lazy
|
||||
|
||||
from passwords import validators
|
||||
from django.contrib.auth import password_validation
|
||||
|
||||
from modoboa.lib import fields as lib_fields
|
||||
from modoboa.lib.cryptutils import random_key
|
||||
@@ -83,8 +83,7 @@ class GeneralParametersForm(param_forms.AdminParametersForm):
|
||||
label=ugettext_lazy("Default password"),
|
||||
initial="password",
|
||||
help_text=ugettext_lazy(
|
||||
"Default password for automatically created accounts."),
|
||||
validators=[validators.validate_length, validators.complexity]
|
||||
"Default password for automatically created accounts.")
|
||||
)
|
||||
|
||||
# LDAP specific settings
|
||||
@@ -351,6 +350,12 @@ class GeneralParametersForm(param_forms.AdminParametersForm):
|
||||
raise forms.ValidationError(_("Invalid rounds number"))
|
||||
return value
|
||||
|
||||
def clean_default_password(self):
|
||||
"""Check password complexity."""
|
||||
value = self.cleaned_data["default_password"]
|
||||
password_validation.validate_password(value)
|
||||
return value
|
||||
|
||||
def clean(self):
|
||||
"""Custom validation method
|
||||
|
||||
|
||||
@@ -178,15 +178,31 @@ REST_FRAMEWORK = {
|
||||
|
||||
MODOBOA_API_URL = 'https://api.modoboa.org/1/'
|
||||
|
||||
# django-passwords
|
||||
# Password validation rules
|
||||
|
||||
PASSWORD_MIN_LENGTH = 8
|
||||
|
||||
PASSWORD_COMPLEXITY = {
|
||||
"UPPER": 1,
|
||||
"LOWER": 1,
|
||||
"DIGITS": 1
|
||||
}
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'modoboa.core.password_validation.ComplexityValidator',
|
||||
'OPTIONS': {
|
||||
'upper': 1,
|
||||
'lower': 1,
|
||||
'digits': 1,
|
||||
'specials': 0
|
||||
}
|
||||
},
|
||||
]
|
||||
|
||||
# CKeditor
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ from __future__ import unicode_literals
|
||||
from django import forms
|
||||
from django.utils.translation import ugettext as _, ugettext_lazy
|
||||
|
||||
from passwords.fields import PasswordField
|
||||
from django.contrib.auth import password_validation
|
||||
|
||||
from modoboa.core.models import User
|
||||
from modoboa.parameters import tools as param_tools
|
||||
@@ -37,11 +37,11 @@ class ProfileForm(forms.ModelForm):
|
||||
label=ugettext_lazy("Old password"), required=False,
|
||||
widget=forms.PasswordInput(attrs={"class": "form-control"})
|
||||
)
|
||||
newpassword = PasswordField(
|
||||
newpassword = forms.CharField(
|
||||
label=ugettext_lazy("New password"), required=False,
|
||||
widget=forms.PasswordInput(attrs={"class": "form-control"})
|
||||
)
|
||||
confirmation = PasswordField(
|
||||
confirmation = forms.CharField(
|
||||
label=ugettext_lazy("Confirmation"), required=False,
|
||||
widget=forms.PasswordInput(attrs={"class": "form-control"})
|
||||
)
|
||||
@@ -78,7 +78,8 @@ class ProfileForm(forms.ModelForm):
|
||||
confirmation = self.cleaned_data["confirmation"]
|
||||
if newpassword != confirmation:
|
||||
raise forms.ValidationError(_("Passwords mismatch"))
|
||||
return self.cleaned_data["confirmation"]
|
||||
password_validation.validate_password(confirmation, self.instance)
|
||||
return confirmation
|
||||
|
||||
def save(self, commit=True):
|
||||
user = super(ProfileForm, self).save(commit=False)
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
"""Custom password validators."""
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.utils.translation import ugettext as _, ungettext
|
||||
|
||||
|
||||
class ComplexityValidator(object):
|
||||
"""Check password contains at least a few things."""
|
||||
|
||||
def __init__(self, upper=1, lower=1, digits=1, specials=1):
|
||||
self.upper = upper
|
||||
self.lower = lower
|
||||
self.digits = digits
|
||||
self.specials = specials
|
||||
|
||||
def validate(self, password, user=None):
|
||||
special_characters = "~!@#$%^&*()_+{}\":;,'[]"
|
||||
condition = (
|
||||
self.digits > 0 and
|
||||
sum([1 for char in password if char.isdigit()]) < self.digits)
|
||||
if condition:
|
||||
raise ValidationError(
|
||||
ungettext(
|
||||
"Password must contain at least {} digit.",
|
||||
"Password must contain at least {} digits.",
|
||||
self.digits
|
||||
).format(self.digits))
|
||||
condition = (
|
||||
self.lower > 0 and
|
||||
sum([1 for char in password if char.islower()]) < self.lower)
|
||||
if condition:
|
||||
raise ValidationError(
|
||||
ungettext(
|
||||
"Password must contain at least {} lowercase letter.",
|
||||
"Password must contain at least {} lowercase letters.",
|
||||
self.lower
|
||||
)
|
||||
.format(self.lower))
|
||||
condition = (
|
||||
self.upper > 0 and
|
||||
sum([1 for char in password if char.isupper()]) < self.upper)
|
||||
if condition:
|
||||
raise ValidationError(
|
||||
ungettext(
|
||||
"Password must contain at least {} uppercase letter.",
|
||||
"Password must contain at least {} uppercase letters.",
|
||||
self.upper
|
||||
)
|
||||
.format(self.upper))
|
||||
condition = (
|
||||
self.specials > 0 and
|
||||
sum([1 for char in password if char in special_characters]) <
|
||||
self.specials)
|
||||
if condition:
|
||||
raise ValidationError(
|
||||
ungettext(
|
||||
"Password must contain at least {} special character.",
|
||||
"Password must contain at least {} special characters.",
|
||||
self.specials
|
||||
)
|
||||
.format(self.specials))
|
||||
|
||||
def get_help_text(self):
|
||||
return _(
|
||||
"Your password must contain a combination of different "
|
||||
"character types.")
|
||||
@@ -1,6 +1,5 @@
|
||||
django>=1.10,<=1.10.99
|
||||
django-ckeditor==5.2.1
|
||||
django-passwords==0.3.12
|
||||
django-reversion==1.10.2
|
||||
django-subcommand2==0.1.1
|
||||
django-versionfield2>=0.5.0
|
||||
|
||||
@@ -87,6 +87,31 @@ AUTHENTICATION_BACKENDS = (
|
||||
'django.contrib.auth.backends.ModelBackend',
|
||||
)
|
||||
|
||||
# Password validation rules
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'modoboa.core.password_validation.ComplexityValidator',
|
||||
'OPTIONS': {
|
||||
'upper': 1,
|
||||
'lower': 1,
|
||||
'digits': 1,
|
||||
'specials': 0
|
||||
}
|
||||
},
|
||||
]
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
|
||||
Reference in New Issue
Block a user