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