mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-17 05:41:25 +02:00
Merge branch 'master' into patch-1
This commit is contained in:
+13
-2
@@ -31,7 +31,7 @@ The *admin* application exposes several parameters, they are presented below:
|
||||
|Authentication type |General |The backend used for |Local |
|
||||
| | |authentication | |
|
||||
+--------------------+---------------------+-------------------------------+--------------------+
|
||||
|Default password |General |Scheme used to crypt |crypt |
|
||||
|Default password |General |Scheme used to crypt |sha512crypt |
|
||||
|scheme | |mailbox passwords | |
|
||||
+--------------------+---------------------+-------------------------------+--------------------+
|
||||
|Rounds |General |Number of rounds (only used by |70000 |
|
||||
@@ -144,6 +144,13 @@ The *admin* application exposes several parameters, they are presented below:
|
||||
| | | | |
|
||||
+--------------------+---------------------+-------------------------------+--------------------+
|
||||
|
||||
.. warning::
|
||||
|
||||
If Dovecot is not running on the same host than Modoboa, you will have
|
||||
to define which password schemes are supported. To do so, open the
|
||||
:file:`settings.py` file and add a ``DOVECOT_SUPPORTED_SCHEMES``
|
||||
variable with the output of the command: ``doveadm pw -l``.
|
||||
|
||||
.. note::
|
||||
|
||||
If you are not familiar with virtual domain hosting, you should
|
||||
@@ -202,7 +209,11 @@ Host configuration
|
||||
.. note::
|
||||
|
||||
This section is only relevant when Modoboa handles mailboxes
|
||||
renaming and removal from the filesystem.
|
||||
renaming and removal from the filesystem, which requires that
|
||||
Dovecot is installed and running on this host. If it is installed
|
||||
at a non-standard directory, paths to its binaries can be set in the
|
||||
:file:`settings.py` file with the ``DOVECOT_LOOKUP_PATH`` and
|
||||
``DOVEADM_LOOKUP_PATH`` variables.
|
||||
|
||||
To manipulate mailboxes on the filesystem, you must allow the user who
|
||||
runs Modoboa to execute commands as the user who owns mailboxes.
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 2.2.17 on 2021-01-30 22:26
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('admin', '0018_update_disabled_accounts_aliases'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='domain',
|
||||
name='name',
|
||||
field=models.CharField(help_text='The domain name', max_length=253, unique=True, verbose_name='name'),
|
||||
),
|
||||
]
|
||||
@@ -23,7 +23,7 @@ from . import mixins
|
||||
class Domain(mixins.MessageLimitMixin, AdminObject):
|
||||
"""Mail domain."""
|
||||
|
||||
name = models.CharField(ugettext_lazy("name"), max_length=100, unique=True,
|
||||
name = models.CharField(ugettext_lazy("name"), max_length=253, unique=True,
|
||||
help_text=ugettext_lazy("The domain name"))
|
||||
quota = models.PositiveIntegerField(
|
||||
default=0,
|
||||
|
||||
@@ -114,15 +114,15 @@ MIDDLEWARE = (
|
||||
)
|
||||
|
||||
AUTHENTICATION_BACKENDS = (
|
||||
# 'modoboa.lib.authbackends.LDAPBackend',
|
||||
# 'modoboa.lib.authbackends.SMTPBackend',
|
||||
#'modoboa.lib.authbackends.LDAPBackend',
|
||||
#'modoboa.lib.authbackends.SMTPBackend',
|
||||
'django.contrib.auth.backends.ModelBackend',
|
||||
)
|
||||
|
||||
# SMTP authentication
|
||||
# AUTH_SMTP_SERVER_ADDRESS = 'localhost'
|
||||
# AUTH_SMTP_SERVER_PORT = 25
|
||||
# AUTH_SMTP_SECURED_MODE = None # 'ssl' or 'starttls' are accepted
|
||||
#AUTH_SMTP_SERVER_ADDRESS = 'localhost'
|
||||
#AUTH_SMTP_SERVER_PORT = 25
|
||||
#AUTH_SMTP_SECURED_MODE = None # 'ssl' or 'starttls' are accepted
|
||||
|
||||
|
||||
TEMPLATES = [
|
||||
@@ -202,9 +202,15 @@ SPECTACULAR_SETTINGS = {
|
||||
}
|
||||
|
||||
# Modoboa settings
|
||||
# MODOBOA_CUSTOM_LOGO = os.path.join(MEDIA_URL, "custom_logo.png")
|
||||
|
||||
# DOVECOT_LOOKUP_PATH = ('/path/to/dovecot', )
|
||||
#MODOBOA_CUSTOM_LOGO = os.path.join(MEDIA_URL, "custom_logo.png")
|
||||
|
||||
# Path to Dovecot binaries in case of a non-standard installation
|
||||
#DOVECOT_LOOKUP_PATH = ('/path/to/dovecot', )
|
||||
#DOVEADM_LOOKUP_PATH = ('/path/to/doveadm', )
|
||||
|
||||
# List of supported schemes if doveadm is not available, given by: doveadm pw -l
|
||||
#DOVECOT_SUPPORTED_SCHEMES = 'SHA512-CRYPT SHA256-CRYPT'
|
||||
|
||||
MODOBOA_API_URL = 'https://api.modoboa.org/1/'
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
Password hashers for Modoboa.
|
||||
"""
|
||||
|
||||
from django.conf import settings
|
||||
from django.utils.encoding import smart_text
|
||||
|
||||
from modoboa.core.password_hashers.advanced import ( # NOQA:F401
|
||||
@@ -32,17 +33,21 @@ def get_password_hasher(scheme):
|
||||
|
||||
|
||||
def get_dovecot_schemes():
|
||||
"""Return schemes supported by dovecot"""
|
||||
supported_schemes = None
|
||||
try:
|
||||
_, schemes = doveadm_cmd("pw -l")
|
||||
except OSError:
|
||||
pass
|
||||
else:
|
||||
supported_schemes = ["{{{}}}".format(smart_text(scheme))
|
||||
for scheme in schemes.split()]
|
||||
"""Return schemes supported by Dovecot.
|
||||
|
||||
if not supported_schemes:
|
||||
supported_schemes = ['{PLAIN}']
|
||||
It first try to get supported schemes fron the settings, then from the
|
||||
doveadm output, and fallback to {MD5-CRYPT} and {PLAIN} if the command
|
||||
is not found.
|
||||
|
||||
return supported_schemes
|
||||
:return: A list of supported '{SCHEME}'
|
||||
"""
|
||||
schemes = getattr(settings, "DOVECOT_SUPPORTED_SCHEMES", None)
|
||||
|
||||
if not schemes:
|
||||
try:
|
||||
_, schemes = doveadm_cmd("pw -l")
|
||||
except OSError:
|
||||
schemes = "MD5-CRYPT PLAIN"
|
||||
|
||||
return ["{{{}}}".format(smart_text(scheme))
|
||||
for scheme in schemes.split()]
|
||||
|
||||
@@ -19,9 +19,9 @@ from modoboa.core.password_hashers import (
|
||||
from modoboa.lib.tests import NO_SMTP, ModoTestCase
|
||||
from .. import factories, models
|
||||
|
||||
DOVEADM_TEST_PATH = "{}/doveadm".format(os.path.dirname(__file__))
|
||||
|
||||
|
||||
@override_settings(
|
||||
DOVEADM_LOOKUP_PATH=["{}/doveadm".format(os.path.dirname(__file__))])
|
||||
class AuthenticationTestCase(ModoTestCase):
|
||||
"""Validate authentication scenarios."""
|
||||
|
||||
@@ -89,6 +89,7 @@ class AuthenticationTestCase(ModoTestCase):
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertTrue(response.url.endswith(reverse("core:dashboard")))
|
||||
|
||||
@override_settings(DOVEADM_LOOKUP_PATH=[DOVEADM_TEST_PATH])
|
||||
def test_password_schemes(self):
|
||||
"""Validate password scheme changes."""
|
||||
username = "user@test.com"
|
||||
@@ -130,6 +131,7 @@ class AuthenticationTestCase(ModoTestCase):
|
||||
self.assertTrue(user.password.startswith(pw_hash.scheme))
|
||||
|
||||
@skipUnless(argon2, "argon2-cffi not installed")
|
||||
@override_settings(DOVEADM_LOOKUP_PATH=[DOVEADM_TEST_PATH])
|
||||
def test_password_argon2_parameter_change(self):
|
||||
"""Validate hash parameter update on login works with argon2."""
|
||||
username = "user@test.com"
|
||||
@@ -169,8 +171,9 @@ class AuthenticationTestCase(ModoTestCase):
|
||||
self.assertEqual(parameters.memory_cost, 1000)
|
||||
self.assertEqual(parameters.parallelism, 2)
|
||||
|
||||
def test_supported_schemes(self):
|
||||
"""Validate dovecot supported schemes."""
|
||||
@override_settings(DOVEADM_LOOKUP_PATH=[DOVEADM_TEST_PATH])
|
||||
def test_dovecot_supported_schemes(self):
|
||||
"""Validate Dovecot supported schemes with fake command output."""
|
||||
supported_schemes = get_dovecot_schemes()
|
||||
self.assertEqual(supported_schemes,
|
||||
["{MD5}",
|
||||
@@ -204,6 +207,17 @@ class AuthenticationTestCase(ModoTestCase):
|
||||
"{SHA256-CRYPT}",
|
||||
"{SHA512-CRYPT}"])
|
||||
|
||||
@override_settings(DOVECOT_SUPPORTED_SCHEMES="SHA1 SHA512-CRYPT")
|
||||
def test_dovecot_supported_schemes_from_settings(self):
|
||||
"""Validate dovecot supported schemes from the settings."""
|
||||
supported_schemes = get_dovecot_schemes()
|
||||
self.assertEqual(supported_schemes, ["{SHA1}", "{SHA512-CRYPT}"])
|
||||
|
||||
def test_dovecot_default_schemes(self):
|
||||
"""Check default scheme if doveadm is not found."""
|
||||
supported_schemes = get_dovecot_schemes()
|
||||
self.assertEqual(supported_schemes, ["{MD5-CRYPT}", "{PLAIN}"])
|
||||
|
||||
|
||||
class PasswordResetTestCase(ModoTestCase):
|
||||
"""Test password reset service."""
|
||||
|
||||
Reference in New Issue
Block a user