
Both of them use the same client ID and client secret, but Roundcube depends on mailserver generally, so mailserver is the one to share OAuth client id and secret.
152 lines
4.8 KiB
Nix
152 lines
4.8 KiB
Nix
{ config, lib, pkgs, ... }@nixos-args:
|
|
let
|
|
inherit (import ./common.nix nixos-args)
|
|
appendSetting
|
|
auth-passthru
|
|
cfg
|
|
domain
|
|
group
|
|
is-auth-enabled
|
|
;
|
|
|
|
runtime-directory = group;
|
|
|
|
ldapConfFile = "/run/${runtime-directory}/dovecot-ldap.conf.ext";
|
|
mkLdapSearchScope = scope: (
|
|
if scope == "sub" then "subtree"
|
|
else if scope == "one" then "onelevel"
|
|
else scope
|
|
);
|
|
dovecot-ldap-config = pkgs.writeTextFile {
|
|
name = "dovecot-ldap.conf.ext.template";
|
|
text = ''
|
|
ldap_version = 3
|
|
uris = ${lib.concatStringsSep " " config.mailserver.ldap.uris}
|
|
${lib.optionalString config.mailserver.ldap.startTls ''
|
|
tls = yes
|
|
''}
|
|
tls_require_cert = hard
|
|
tls_ca_cert_file = ${config.mailserver.ldap.tlsCAFile}
|
|
dn = ${config.mailserver.ldap.bind.dn}
|
|
sasl_bind = no
|
|
auth_bind = no
|
|
base = ${config.mailserver.ldap.searchBase}
|
|
scope = ${mkLdapSearchScope config.mailserver.ldap.searchScope}
|
|
${lib.optionalString (config.mailserver.ldap.dovecot.userAttrs != null) ''
|
|
user_attrs = ${config.mailserver.ldap.dovecot.userAttrs}
|
|
''}
|
|
user_filter = ${config.mailserver.ldap.dovecot.userFilter}
|
|
'';
|
|
};
|
|
setPwdInLdapConfFile = appendSetting {
|
|
name = "ldap-conf-file";
|
|
file = dovecot-ldap-config;
|
|
prefix = ''dnpass = "'';
|
|
suffix = ''"'';
|
|
passwordFile = config.mailserver.ldap.bind.passwordFile;
|
|
destination = ldapConfFile;
|
|
};
|
|
oauth-client-id = "mailserver";
|
|
oauth-client-secret-fp =
|
|
"/run/keys/${group}/kanidm-oauth-client-secret";
|
|
oauth-secret-ExecStartPreScript = pkgs.writeShellScript
|
|
"${oauth-client-id}-kanidm-ExecStartPre-script.sh" ''
|
|
set -o xtrace
|
|
[ -f "${oauth-client-secret-fp}" ] || \
|
|
"${lib.getExe pkgs.openssl}" rand -base64 32 | tr -d "\n" > "${oauth-client-secret-fp}"
|
|
'';
|
|
dovecot-oauth2-conf-fp = "/run/${runtime-directory}/dovecot-oauth2.conf.ext";
|
|
write-dovecot-oauth2-conf = appendSetting {
|
|
name = "oauth2-conf-file";
|
|
file = builtins.toFile "dovecot-oauth2.conf.ext.template" ''
|
|
introspection_mode = post
|
|
username_attribute = username
|
|
scope = email profile openid
|
|
tls_ca_cert_file = /etc/ssl/certs/ca-certificates.crt
|
|
active_attribute = active
|
|
active_value = true
|
|
openid_configuration_url = ${auth-passthru.oauth2-discovery-url oauth-client-id}
|
|
debug = "no"
|
|
'';
|
|
prefix = ''introspection_url = "'' +
|
|
(auth-passthru.oauth2-introspection-url-prefix oauth-client-id);
|
|
suffix = auth-passthru.oauth2-introspection-url-postfix + ''"'';
|
|
passwordFile = oauth-client-secret-fp;
|
|
destination = dovecot-oauth2-conf-fp;
|
|
};
|
|
in
|
|
{
|
|
# for dovecot2 to have access to get through /run/keys directory
|
|
users.groups.keys.members = [ group ];
|
|
|
|
mailserver.ldap = {
|
|
# note: in `ldapsearch` first comes filter, then attributes
|
|
dovecot.userAttrs = "+"; # all operational attributes
|
|
# TODO: investigate whether "mail=%u" is better than:
|
|
# dovecot.userFilter = "(&(class=person)(uid=%n))";
|
|
};
|
|
|
|
services.dovecot2.extraConfig = ''
|
|
auth_mechanisms = xoauth2 oauthbearer
|
|
|
|
passdb {
|
|
driver = oauth2
|
|
mechanisms = xoauth2 oauthbearer
|
|
args = ${dovecot-oauth2-conf-fp}
|
|
}
|
|
|
|
userdb {
|
|
driver = static
|
|
args = uid=virtualMail gid=virtualMail home=/var/vmail/${domain}/%u
|
|
}
|
|
|
|
# provide SASL via unix socket to postfix
|
|
service auth {
|
|
unix_listener /var/lib/postfix/private-auth {
|
|
mode = 0660
|
|
user = postfix
|
|
group = postfix
|
|
}
|
|
}
|
|
service auth {
|
|
unix_listener auth-userdb {
|
|
mode = 0660
|
|
user = ${config.services.dovecot2.user}
|
|
}
|
|
unix_listener dovecot-auth {
|
|
mode = 0660
|
|
# Assuming the default Postfix user and group
|
|
user = postfix
|
|
group = postfix
|
|
}
|
|
}
|
|
|
|
userdb {
|
|
driver = ldap
|
|
args = ${ldapConfFile}
|
|
default_fields = home=/var/vmail/${domain}/%u uid=${toString config.mailserver.vmailUID} gid=${toString config.mailserver.vmailUID}
|
|
}
|
|
'';
|
|
services.dovecot2.enablePAM = false;
|
|
systemd.services.dovecot2 = {
|
|
# TODO does it merge with existing preStart?
|
|
preStart = setPwdInLdapConfFile + "\n" + write-dovecot-oauth2-conf + "\n";
|
|
# FIXME pass dependant services to auth module option instead?
|
|
wants = [ auth-passthru.oauth2-systemd-service ];
|
|
after = [ auth-passthru.oauth2-systemd-service ];
|
|
serviceConfig.RuntimeDirectory = lib.mkForce [ runtime-directory ];
|
|
};
|
|
|
|
systemd.services.kanidm.serviceConfig.ExecStartPre = lib.mkAfter [
|
|
("-" + oauth-secret-ExecStartPreScript)
|
|
];
|
|
# does it merge with existing restartTriggers?
|
|
systemd.services.postfix.restartTriggers = [
|
|
setPwdInLdapConfFile
|
|
write-dovecot-oauth2-conf
|
|
];
|
|
selfprivacy.passthru.mailserver = {
|
|
inherit oauth-client-id oauth-client-secret-fp;
|
|
};
|
|
}
|