Compat with Modoboa 2.4.0
This commit is contained in:
@@ -32,5 +32,8 @@ REMOVED_EXTENSIONS = {
|
|||||||
"modoboa-dmarc": "2.1.0",
|
"modoboa-dmarc": "2.1.0",
|
||||||
"modoboa-imap-migration": "2.1.0",
|
"modoboa-imap-migration": "2.1.0",
|
||||||
"modoboa-sievefilters": "2.3.0",
|
"modoboa-sievefilters": "2.3.0",
|
||||||
"modoboa-postfix-autoreply": "2.3.0"
|
"modoboa-postfix-autoreply": "2.3.0",
|
||||||
|
"modoboa-contacts": "2.4.0",
|
||||||
|
"modoboa-radicale": "2.4.0",
|
||||||
|
"modoboa-webmail": "2.4.0",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -187,11 +187,7 @@ ConfigDictTemplate = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"option": "extensions",
|
"option": "extensions",
|
||||||
"default": (
|
"default": ""
|
||||||
"modoboa-amavis "
|
|
||||||
"modoboa-webmail modoboa-contacts "
|
|
||||||
"modoboa-radicale"
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"option": "devmode",
|
"option": "devmode",
|
||||||
@@ -303,10 +299,6 @@ ConfigDictTemplate = [
|
|||||||
"option": "postmaster_address",
|
"option": "postmaster_address",
|
||||||
"default": "postmaster@%(domain)s",
|
"default": "postmaster@%(domain)s",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"option": "radicale_auth_socket_path",
|
|
||||||
"default": "/var/run/dovecot/auth-radicale"
|
|
||||||
},
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -409,7 +401,7 @@ ConfigDictTemplate = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"option": "nb_processes",
|
"option": "nb_processes",
|
||||||
"default": "2",
|
"default": "4",
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ class Backup:
|
|||||||
"""
|
"""
|
||||||
Custom config :
|
Custom config :
|
||||||
- DKIM keys: {{keys_storage_dir}}
|
- DKIM keys: {{keys_storage_dir}}
|
||||||
- Radicale collection (calendat, contacts): {{home_dir}}
|
- Radicale collection (calendars, contacts): {{home_dir}}
|
||||||
- Amavis : /etc/amavis/conf.d/99-custom
|
- Amavis : /etc/amavis/conf.d/99-custom
|
||||||
- Postwhite : /etc/postwhite.conf
|
- Postwhite : /etc/postwhite.conf
|
||||||
Feel free to suggest to add others!
|
Feel free to suggest to add others!
|
||||||
|
|||||||
@@ -72,24 +72,6 @@ class Dovecot(base.Installer):
|
|||||||
"dovecot-core", "create-ssl-cert", "boolean", "false")
|
"dovecot-core", "create-ssl-cert", "boolean", "false")
|
||||||
super().install_packages()
|
super().install_packages()
|
||||||
|
|
||||||
def create_oauth2_app(self):
|
|
||||||
"""Create a application for Oauth2 authentication."""
|
|
||||||
# FIXME: how can we check that application already exists ?
|
|
||||||
venv_path = self.config.get("modoboa", "venv_path")
|
|
||||||
python_path = os.path.join(venv_path, "bin", "python")
|
|
||||||
instance_path = self.config.get("modoboa", "instance_path")
|
|
||||||
script_path = os.path.join(instance_path, "manage.py")
|
|
||||||
client_id = "dovecot"
|
|
||||||
client_secret = str(uuid.uuid4())
|
|
||||||
cmd = (
|
|
||||||
f"{python_path} {script_path} createapplication "
|
|
||||||
f"--name=Dovecot --skip-authorization "
|
|
||||||
f"--client-id={client_id} --client-secret={client_secret} "
|
|
||||||
f"confidential client-credentials"
|
|
||||||
)
|
|
||||||
utils.exec_cmd(cmd)
|
|
||||||
return client_id, client_secret
|
|
||||||
|
|
||||||
def get_template_context(self):
|
def get_template_context(self):
|
||||||
"""Additional variables."""
|
"""Additional variables."""
|
||||||
context = super().get_template_context()
|
context = super().get_template_context()
|
||||||
@@ -113,7 +95,8 @@ class Dovecot(base.Installer):
|
|||||||
# Protocols are automatically guessed on debian/ubuntu
|
# Protocols are automatically guessed on debian/ubuntu
|
||||||
protocols = ""
|
protocols = ""
|
||||||
|
|
||||||
oauth2_client_id, oauth2_client_secret = self.create_oauth2_app()
|
oauth2_client_id, oauth2_client_secret = utils.create_oauth2_app(
|
||||||
|
"Dovecot", "dovecot", self.config)
|
||||||
hostname = self.config.get("general", "hostname")
|
hostname = self.config.get("general", "hostname")
|
||||||
oauth2_introspection_url = (
|
oauth2_introspection_url = (
|
||||||
f"https://{oauth2_client_id}:{oauth2_client_secret}"
|
f"https://{oauth2_client_id}:{oauth2_client_secret}"
|
||||||
@@ -132,9 +115,6 @@ class Dovecot(base.Installer):
|
|||||||
"protocols": protocols,
|
"protocols": protocols,
|
||||||
"ssl_protocols": ssl_protocols,
|
"ssl_protocols": ssl_protocols,
|
||||||
"ssl_protocol_parameter": ssl_protocol_parameter,
|
"ssl_protocol_parameter": ssl_protocol_parameter,
|
||||||
"radicale_user": self.config.get("radicale", "user"),
|
|
||||||
"radicale_auth_socket_path": os.path.basename(
|
|
||||||
self.config.get("dovecot", "radicale_auth_socket_path")),
|
|
||||||
"modoboa_2_2_or_greater": "" if self.modoboa_2_2_or_greater else "#",
|
"modoboa_2_2_or_greater": "" if self.modoboa_2_2_or_greater else "#",
|
||||||
"not_modoboa_2_2_or_greater": "" if not self.modoboa_2_2_or_greater else "#",
|
"not_modoboa_2_2_or_greater": "" if not self.modoboa_2_2_or_greater else "#",
|
||||||
"oauth2_introspection_url": oauth2_introspection_url
|
"oauth2_introspection_url": oauth2_introspection_url
|
||||||
|
|||||||
@@ -131,13 +131,6 @@ service auth {
|
|||||||
group = postfix
|
group = postfix
|
||||||
}
|
}
|
||||||
|
|
||||||
# Radicale auth
|
|
||||||
%{radicale_enabled}unix_listener %{radicale_auth_socket_path} {
|
|
||||||
%{radicale_enabled} mode = 0666
|
|
||||||
%{radicale_enabled} user = %{radicale_user}
|
|
||||||
%{radicale_enabled} group = %{radicale_user}
|
|
||||||
%{radicale_enabled}}
|
|
||||||
|
|
||||||
# Auth process is run as this user.
|
# Auth process is run as this user.
|
||||||
#user = $default_internal_user
|
#user = $default_internal_user
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,13 @@ server {
|
|||||||
try_files $uri $uri/ =404;
|
try_files $uri $uri/ =404;
|
||||||
}
|
}
|
||||||
|
|
||||||
location ^~ /new-admin {
|
location ~ ^/(api|accounts) {
|
||||||
|
include uwsgi_params;
|
||||||
|
uwsgi_param UWSGI_SCRIPT instance.wsgi:application;
|
||||||
|
uwsgi_pass modoboa;
|
||||||
|
}
|
||||||
|
|
||||||
|
location / {
|
||||||
alias %{app_instance_path}/frontend/;
|
alias %{app_instance_path}/frontend/;
|
||||||
index index.html;
|
index index.html;
|
||||||
|
|
||||||
@@ -48,10 +54,5 @@ server {
|
|||||||
try_files $uri $uri/ /index.html = 404;
|
try_files $uri $uri/ /index.html = 404;
|
||||||
}
|
}
|
||||||
|
|
||||||
location / {
|
|
||||||
include uwsgi_params;
|
|
||||||
uwsgi_param UWSGI_SCRIPT instance.wsgi:application;
|
|
||||||
uwsgi_pass modoboa;
|
|
||||||
}
|
|
||||||
%{extra_config}
|
%{extra_config}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -124,11 +124,6 @@ mailman unix - n n - - pipe
|
|||||||
flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py
|
flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py
|
||||||
${nexthop} ${user}
|
${nexthop} ${user}
|
||||||
|
|
||||||
# Modoboa autoreply service
|
|
||||||
#
|
|
||||||
autoreply unix - n n - - pipe
|
|
||||||
flags= user=%{dovecot_mailboxes_owner}:%{dovecot_mailboxes_owner} argv=%{modoboa_venv_path}/bin/python %{modoboa_instance_path}/manage.py autoreply $sender $mailbox
|
|
||||||
|
|
||||||
# Amavis return path
|
# Amavis return path
|
||||||
#
|
#
|
||||||
%{amavis_enabled}127.0.0.1:10025 inet n - n - - smtpd
|
%{amavis_enabled}127.0.0.1:10025 inet n - n - - smtpd
|
||||||
|
|||||||
@@ -71,7 +71,7 @@
|
|||||||
|
|
||||||
# Authentication method
|
# Authentication method
|
||||||
# Value: none | htpasswd | remote_user | http_x_remote_user
|
# Value: none | htpasswd | remote_user | http_x_remote_user
|
||||||
type = dovecot
|
type = radicale_modoboa_auth_oauth2
|
||||||
|
|
||||||
# Htpasswd filename
|
# Htpasswd filename
|
||||||
# htpasswd_filename = users
|
# htpasswd_filename = users
|
||||||
@@ -85,7 +85,7 @@ type = dovecot
|
|||||||
# Incorrect authentication delay (seconds)
|
# Incorrect authentication delay (seconds)
|
||||||
#delay = 1
|
#delay = 1
|
||||||
|
|
||||||
dovecot_socket = %{auth_socket_path}
|
oauth2_introspection_endpoint = %{oauth2_introspection_url}
|
||||||
|
|
||||||
|
|
||||||
[rights]
|
[rights]
|
||||||
|
|||||||
@@ -13,4 +13,5 @@ socket = %uwsgi_socket_path
|
|||||||
chmod-socket = 660
|
chmod-socket = 660
|
||||||
vacuum = true
|
vacuum = true
|
||||||
single-interpreter = True
|
single-interpreter = True
|
||||||
|
max-requests = 5000
|
||||||
buffer-size = 8192
|
buffer-size = 8192
|
||||||
|
|||||||
@@ -56,9 +56,6 @@ class Modoboa(base.Installer):
|
|||||||
self.amavis_enabled = True
|
self.amavis_enabled = True
|
||||||
else:
|
else:
|
||||||
self.extensions.remove("modoboa-amavis")
|
self.extensions.remove("modoboa-amavis")
|
||||||
if "modoboa-radicale" in self.extensions:
|
|
||||||
if not self.config.getboolean("radicale", "enabled"):
|
|
||||||
self.extensions.remove("modoboa-radicale")
|
|
||||||
self.dovecot_enabled = self.config.getboolean("dovecot", "enabled")
|
self.dovecot_enabled = self.config.getboolean("dovecot", "enabled")
|
||||||
self.opendkim_enabled = self.config.getboolean("opendkim", "enabled")
|
self.opendkim_enabled = self.config.getboolean("opendkim", "enabled")
|
||||||
self.dkim_cron_enabled = False
|
self.dkim_cron_enabled = False
|
||||||
@@ -243,8 +240,6 @@ class Modoboa(base.Installer):
|
|||||||
),
|
),
|
||||||
"dovecot_mailboxes_owner": (
|
"dovecot_mailboxes_owner": (
|
||||||
self.config.get("dovecot", "mailboxes_owner")),
|
self.config.get("dovecot", "mailboxes_owner")),
|
||||||
"radicale_enabled": (
|
|
||||||
"" if "modoboa-radicale" in extensions else "#"),
|
|
||||||
"opendkim_user": self.config.get("opendkim", "user"),
|
"opendkim_user": self.config.get("opendkim", "user"),
|
||||||
"minutes": random.randint(1, 59),
|
"minutes": random.randint(1, 59),
|
||||||
"hours": f"{random_hour},{random_hour+12}",
|
"hours": f"{random_hour},{random_hour+12}",
|
||||||
@@ -276,7 +271,7 @@ class Modoboa(base.Installer):
|
|||||||
"pdfcredentials": {
|
"pdfcredentials": {
|
||||||
"storage_dir": pdf_storage_dir
|
"storage_dir": pdf_storage_dir
|
||||||
},
|
},
|
||||||
"modoboa_radicale": {
|
"calendars": {
|
||||||
"server_location": "https://{}/radicale/".format(
|
"server_location": "https://{}/radicale/".format(
|
||||||
self.config.get("general", "hostname")),
|
self.config.get("general", "hostname")),
|
||||||
"rights_file_path": "{}/rights".format(
|
"rights_file_path": "{}/rights".format(
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class Radicale(base.Installer):
|
|||||||
"""Prepare a dedicated virtualenv."""
|
"""Prepare a dedicated virtualenv."""
|
||||||
python.setup_virtualenv(self.venv_path, sudo_user=self.user)
|
python.setup_virtualenv(self.venv_path, sudo_user=self.user)
|
||||||
packages = [
|
packages = [
|
||||||
"Radicale", "pytz"
|
"Radicale", "pytz", "radicale-modoboa-auth-oauth2"
|
||||||
]
|
]
|
||||||
python.install_packages(packages, self.venv_path, sudo_user=self.user)
|
python.install_packages(packages, self.venv_path, sudo_user=self.user)
|
||||||
python.install_package_from_repository(
|
python.install_package_from_repository(
|
||||||
@@ -43,17 +43,22 @@ class Radicale(base.Installer):
|
|||||||
|
|
||||||
def get_template_context(self):
|
def get_template_context(self):
|
||||||
"""Additional variables."""
|
"""Additional variables."""
|
||||||
context = super(Radicale, self).get_template_context()
|
context = super().get_template_context()
|
||||||
radicale_auth_socket_path = self.config.get(
|
oauth2_client_id, oauth2_client_secret = utils.create_oauth2_app(
|
||||||
"dovecot", "radicale_auth_socket_path")
|
"Radicale", "radicale", self.config)
|
||||||
|
hostname = self.config.get("general", "hostname")
|
||||||
|
oauth2_introspection_url = (
|
||||||
|
f"https://{oauth2_client_id}:{oauth2_client_secret}"
|
||||||
|
f"@{hostname}/api/o/introspect/"
|
||||||
|
)
|
||||||
context.update({
|
context.update({
|
||||||
"auth_socket_path": radicale_auth_socket_path
|
"oauth2_introspection_url": oauth2_introspection_url,
|
||||||
})
|
})
|
||||||
return context
|
return context
|
||||||
|
|
||||||
def get_config_files(self):
|
def get_config_files(self):
|
||||||
"""Return appropriate path."""
|
"""Return appropriate path."""
|
||||||
config_files = super(Radicale, self).get_config_files()
|
config_files = super().get_config_files()
|
||||||
if package.backend.FORMAT == "deb":
|
if package.backend.FORMAT == "deb":
|
||||||
path = "supervisor=/etc/supervisor/conf.d/radicale.conf"
|
path = "supervisor=/etc/supervisor/conf.d/radicale.conf"
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import stat
|
|||||||
import string
|
import string
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
import uuid
|
||||||
try:
|
try:
|
||||||
import configparser
|
import configparser
|
||||||
except ImportError:
|
except ImportError:
|
||||||
@@ -485,3 +486,21 @@ def validate_backup_path(path: str, silent_mode: bool):
|
|||||||
mkdir_safe(os.path.join(backup_path, dir),
|
mkdir_safe(os.path.join(backup_path, dir),
|
||||||
stat.S_IRWXU | stat.S_IRWXG, pw[2], pw[3])
|
stat.S_IRWXU | stat.S_IRWXG, pw[2], pw[3])
|
||||||
return backup_path
|
return backup_path
|
||||||
|
|
||||||
|
|
||||||
|
def create_oauth2_app(app_name: str, client_id: str, config) -> tuple[str, str]:
|
||||||
|
"""Create a application for Oauth2 authentication."""
|
||||||
|
# FIXME: how can we check that application already exists ?
|
||||||
|
venv_path = config.get("modoboa", "venv_path")
|
||||||
|
python_path = os.path.join(venv_path, "bin", "python")
|
||||||
|
instance_path = config.get("modoboa", "instance_path")
|
||||||
|
script_path = os.path.join(instance_path, "manage.py")
|
||||||
|
client_secret = str(uuid.uuid4())
|
||||||
|
cmd = (
|
||||||
|
f"{python_path} {script_path} createapplication "
|
||||||
|
f"--name={app_name} --skip-authorization "
|
||||||
|
f"--client-id={client_id} --client-secret={client_secret} "
|
||||||
|
f"confidential client-credentials"
|
||||||
|
)
|
||||||
|
exec_cmd(cmd)
|
||||||
|
return client_id, client_secret
|
||||||
|
|||||||
Reference in New Issue
Block a user