Added setup instructions for Dovecot oauth2 support

This commit is contained in:
Antoine Nguyen
2024-07-07 10:48:05 +02:00
parent d05618e53d
commit 2572dd64d1
5 changed files with 47 additions and 7 deletions

View File

@@ -4,6 +4,7 @@ import glob
import os import os
import pwd import pwd
import shutil import shutil
import uuid
from .. import database from .. import database
from .. import package from .. import package
@@ -14,7 +15,6 @@ from . import base
class Dovecot(base.Installer): class Dovecot(base.Installer):
"""Dovecot installer.""" """Dovecot installer."""
appname = "dovecot" appname = "dovecot"
@@ -27,7 +27,9 @@ class Dovecot(base.Installer):
} }
config_files = [ config_files = [
"dovecot.conf", "dovecot-dict-sql.conf.ext", "conf.d/10-ssl.conf", "dovecot.conf", "dovecot-dict-sql.conf.ext", "conf.d/10-ssl.conf",
"conf.d/10-master.conf", "conf.d/20-lmtp.conf", "conf.d/10-ssl-keys.try"] "conf.d/10-master.conf", "conf.d/20-lmtp.conf", "conf.d/10-ssl-keys.try",
"conf.d/dovecot-oauth2.conf.ext"
]
with_user = True with_user = True
def setup_user(self): def setup_user(self):
@@ -53,17 +55,35 @@ class Dovecot(base.Installer):
if package.backend.FORMAT == "deb": if package.backend.FORMAT == "deb":
if "pop3" in self.config.get("dovecot", "extra_protocols"): if "pop3" in self.config.get("dovecot", "extra_protocols"):
packages += ["dovecot-pop3d"] packages += ["dovecot-pop3d"]
return super(Dovecot, self).get_packages() + packages return super().get_packages() + packages
def install_packages(self): def install_packages(self):
"""Preconfigure Dovecot if needed.""" """Preconfigure Dovecot if needed."""
package.backend.preconfigure( package.backend.preconfigure(
"dovecot-core", "create-ssl-cert", "boolean", "false") "dovecot-core", "create-ssl-cert", "boolean", "false")
super(Dovecot, self).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 = str(uuid.uuid4())
client_secret = str(uuid.uuid4())
cmd = (
f"{python_path} {script_path} createapplication "
f"--name=Dovecot --algorithm=RS256 --skip-authorization "
f"--client-id={client_id} --client-secret={client_secret} "
f"public authorization-code"
)
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(Dovecot, self).get_template_context() context = super().get_template_context()
pw_mailbox = pwd.getpwnam(self.mailboxes_owner) pw_mailbox = pwd.getpwnam(self.mailboxes_owner)
dovecot_package = {"deb": "dovecot-core", "rpm": "dovecot"} dovecot_package = {"deb": "dovecot-core", "rpm": "dovecot"}
ssl_protocol_parameter = "ssl_protocols" ssl_protocol_parameter = "ssl_protocols"
@@ -84,6 +104,13 @@ 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()
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({
"db_driver": self.db_driver, "db_driver": self.db_driver,
"mailboxes_owner_uid": pw_mailbox[2], "mailboxes_owner_uid": pw_mailbox[2],
@@ -100,7 +127,8 @@ class Dovecot(base.Installer):
"radicale_auth_socket_path": os.path.basename( "radicale_auth_socket_path": os.path.basename(
self.config.get("dovecot", "radicale_auth_socket_path")), 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
}) })
return context return context

View File

@@ -96,7 +96,7 @@ auth_master_user_separator = *
# plain login digest-md5 cram-md5 ntlm rpa apop anonymous gssapi otp skey # plain login digest-md5 cram-md5 ntlm rpa apop anonymous gssapi otp skey
# gss-spnego # gss-spnego
# NOTE: See also disable_plaintext_auth setting. # NOTE: See also disable_plaintext_auth setting.
auth_mechanisms = plain login auth_mechanisms = plain login oauthbearer xoauth2
## ##
## Password and user databases ## Password and user databases
@@ -120,6 +120,7 @@ auth_mechanisms = plain login
#!include auth-system.conf.ext #!include auth-system.conf.ext
!include auth-sql.conf.ext !include auth-sql.conf.ext
!include auth-oauth2.conf.ext
#!include auth-ldap.conf.ext #!include auth-ldap.conf.ext
#!include auth-passwdfile.conf.ext #!include auth-passwdfile.conf.ext
#!include auth-checkpassword.conf.ext #!include auth-checkpassword.conf.ext

View File

@@ -0,0 +1,5 @@
passdb {
driver = oauth2
mechanisms = xoauth2 oauthbearer
args = /etc/dovecot/conf.d/dovecot-oauth2.conf.ext
}

View File

@@ -0,0 +1,6 @@
introspection_mode = post
introspection_url = %{oauth2_introspection_url}
username_attribute = username
tls_ca_cert_file = /etc/ssl/certs/ca-certificates.crt
active_attribute = active
active_value = true