Merge branch 'master' into patch-1

This commit is contained in:
Akshat Soni
2021-02-10 09:48:04 +05:30
committed by GitHub
7 changed files with 82 additions and 26 deletions
+13 -2
View File
@@ -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'),
),
]
+1 -1
View File
@@ -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/'
+17 -12
View File
@@ -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()]
+18 -4
View File
@@ -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."""
+2
View File
@@ -21,3 +21,5 @@ max-line-length = 80
[flake8]
exclude = migrations
max-line-length = 80
per-file-ignores =
modoboa/core/commands/templates/settings.py.tpl: E265