roundcube & mailserver: fix oauth: mailserver is an OAuth secret donor
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.
This commit is contained in:
@@ -7,5 +7,7 @@
|
||||
[ "passthru", "selfprivacy", "auth", "oauth2-systemd-service" ],
|
||||
[ "selfprivacy", "domain" ],
|
||||
[ "selfprivacy", "modules", "auth" ],
|
||||
[ "selfprivacy", "modules", "roundcube" ]
|
||||
[ "selfprivacy", "modules", "roundcube" ],
|
||||
[ "selfprivacy", "passthru", "mailserver", "oauth-client-id" ],
|
||||
[ "selfprivacy", "passthru", "mailserver", "oauth-client-secret-fp" ]
|
||||
]
|
||||
|
@@ -5,23 +5,20 @@ let
|
||||
is-auth-enabled = config.selfprivacy.modules.auth.enable or false;
|
||||
auth-passthru = config.passthru.selfprivacy.auth;
|
||||
auth-fqdn = auth-passthru.auth-fqdn;
|
||||
oauth-client-id = "roundcube";
|
||||
roundcube-user = "roundcube";
|
||||
roundcube-group = "roundcube";
|
||||
kanidmExecStartPreScriptRoot = pkgs.writeShellScript
|
||||
"${oauth-client-id}-kanidm-ExecStartPre-root-script.sh"
|
||||
''
|
||||
# set-group-ID bit allows for kanidm user to create files,
|
||||
mkdir -p -v --mode=u+rwx,g+rs,g-w,o-rwx /run/keys/${oauth-client-id}
|
||||
chown kanidm:${roundcube-group} /run/keys/${oauth-client-id}
|
||||
'';
|
||||
sp-module-name = "roundcube";
|
||||
user = "roundcube";
|
||||
group = "roundcube";
|
||||
oauth-donor = config.selfprivacy.passthru.mailserver;
|
||||
kanidm-oauth-client-secret-fp =
|
||||
"/run/keys/${oauth-client-id}/kanidm-oauth-client-secret";
|
||||
kanidmExecStartPreScript = pkgs.writeShellScript
|
||||
"${oauth-client-id}-kanidm-ExecStartPre-script.sh" ''
|
||||
set -o xtrace
|
||||
[ -f "${kanidm-oauth-client-secret-fp}" ] || \
|
||||
"${lib.getExe pkgs.openssl}" rand -base64 -out "${kanidm-oauth-client-secret-fp}" 32
|
||||
"/run/keys/${group}/kanidm-oauth-client-secret";
|
||||
kanidmExecStartPreScriptRoot = pkgs.writeShellScript
|
||||
"${sp-module-name}-kanidm-ExecStartPre-root-script.sh"
|
||||
''
|
||||
# set-group-ID bit allows for kanidm user to create files inheriting group
|
||||
mkdir -p -v --mode=u+rwx,g+rs,g-w,o-rwx /run/keys/${group}
|
||||
chown kanidm:${group} /run/keys/${group}
|
||||
|
||||
install -v -m640 -o kanidm -g ${group} ${oauth-donor.oauth-client-secret-fp} ${kanidm-oauth-client-secret-fp}
|
||||
'';
|
||||
in
|
||||
{
|
||||
@@ -72,21 +69,23 @@ in
|
||||
};
|
||||
|
||||
systemd.slices.roundcube.description = "Roundcube service slice";
|
||||
# Roundcube depends on Dovecot and its OAuth2 client secret.
|
||||
systemd.services.roundcube.after = [ "dovecot2.service" ];
|
||||
}
|
||||
# the following part is active only when "auth" module is enabled
|
||||
(lib.attrsets.optionalAttrs
|
||||
(options.selfprivacy.modules ? "auth")
|
||||
(lib.mkIf is-auth-enabled {
|
||||
# for phpfpm-roundcube to have access to get through /run/keys directory
|
||||
users.groups.keys.members = [ roundcube-user ];
|
||||
users.groups.keys.members = [ user ];
|
||||
services.roundcube.extraConfig = lib.mkAfter ''
|
||||
$config['oauth_provider'] = 'generic';
|
||||
$config['oauth_provider_name'] = '${auth-passthru.oauth2-provider-name}';
|
||||
$config['oauth_client_id'] = '${oauth-client-id}';
|
||||
$config['oauth_client_id'] = '${oauth-donor.oauth-client-id}';
|
||||
$config['oauth_client_secret'] = file_get_contents('${kanidm-oauth-client-secret-fp}');
|
||||
$config['oauth_auth_uri'] = 'https://${auth-fqdn}/ui/oauth2';
|
||||
$config['oauth_token_uri'] = 'https://${auth-fqdn}/oauth2/token';
|
||||
$config['oauth_identity_uri'] = 'https://${auth-fqdn}/oauth2/openid/${oauth-client-id}/userinfo';
|
||||
$config['oauth_identity_uri'] = 'https://${auth-fqdn}/oauth2/openid/${oauth-donor.oauth-client-id}/userinfo';
|
||||
$config['oauth_scope'] = 'email profile openid'; # FIXME
|
||||
$config['oauth_auth_parameters'] = [];
|
||||
$config['oauth_identity_fields'] = ['email'];
|
||||
@@ -96,11 +95,9 @@ in
|
||||
# $config['oauth_pkce'] = 'S256'; # FIXME
|
||||
'';
|
||||
systemd.services.kanidm = {
|
||||
serviceConfig.ExecStartPre = lib.mkAfter [
|
||||
serviceConfig.ExecStartPre = lib.mkBefore [
|
||||
("-+" + kanidmExecStartPreScriptRoot)
|
||||
("-" + kanidmExecStartPreScript)
|
||||
];
|
||||
requires = [ auth-passthru.oauth2-systemd-service ];
|
||||
};
|
||||
services.kanidm.provision = {
|
||||
groups = {
|
||||
@@ -108,7 +105,7 @@ in
|
||||
"sp.roundcube.users".members =
|
||||
[ "sp.roundcube.admins" auth-passthru.full-users-group ];
|
||||
};
|
||||
systems.oauth2.roundcube = {
|
||||
systems.oauth2.${oauth-donor.oauth-client-id} = {
|
||||
displayName = "Roundcube";
|
||||
originUrl = "https://${cfg.subdomain}.${domain}/index.php/login/oauth";
|
||||
originLanding = "https://${cfg.subdomain}.${domain}/";
|
||||
|
@@ -1,14 +1,15 @@
|
||||
{ config, lib, pkgs, ... }@nixos-args:
|
||||
let
|
||||
inherit (import ./common.nix nixos-args)
|
||||
appendLdapBindPwd
|
||||
appendSetting
|
||||
auth-passthru
|
||||
cfg
|
||||
domain
|
||||
group
|
||||
is-auth-enabled
|
||||
;
|
||||
|
||||
runtime-directory = "dovecot2";
|
||||
runtime-directory = group;
|
||||
|
||||
ldapConfFile = "/run/${runtime-directory}/dovecot-ldap.conf.ext";
|
||||
mkLdapSearchScope = scope: (
|
||||
@@ -37,7 +38,7 @@ let
|
||||
user_filter = ${config.mailserver.ldap.dovecot.userFilter}
|
||||
'';
|
||||
};
|
||||
setPwdInLdapConfFile = appendLdapBindPwd {
|
||||
setPwdInLdapConfFile = appendSetting {
|
||||
name = "ldap-conf-file";
|
||||
file = dovecot-ldap-config;
|
||||
prefix = ''dnpass = "'';
|
||||
@@ -45,24 +46,39 @@ let
|
||||
passwordFile = config.mailserver.ldap.bind.passwordFile;
|
||||
destination = ldapConfFile;
|
||||
};
|
||||
dovecot-oauth2-conf-file = pkgs.writeTextFile {
|
||||
name = "dovecot-oauth2.conf.ext";
|
||||
text = ''
|
||||
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
|
||||
introspection_url = ${auth-passthru.oauth2-introspection-url "roundcube" "VERYSTRONGSECRETFORROUNDCUBE"}
|
||||
client_id = roundcube
|
||||
client_secret = VERYSTRONGSECRETFORROUNDCUBE # FIXME
|
||||
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 "roundcube"}
|
||||
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
|
||||
@@ -76,7 +92,7 @@ in
|
||||
passdb {
|
||||
driver = oauth2
|
||||
mechanisms = xoauth2 oauthbearer
|
||||
args = ${dovecot-oauth2-conf-file}
|
||||
args = ${dovecot-oauth2-conf-fp}
|
||||
}
|
||||
|
||||
userdb {
|
||||
@@ -114,13 +130,22 @@ in
|
||||
services.dovecot2.enablePAM = false;
|
||||
systemd.services.dovecot2 = {
|
||||
# TODO does it merge with existing preStart?
|
||||
preStart = setPwdInLdapConfFile + "\n";
|
||||
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 ];
|
||||
systemd.services.postfix.restartTriggers = [
|
||||
setPwdInLdapConfFile
|
||||
write-dovecot-oauth2-conf
|
||||
];
|
||||
selfprivacy.passthru.mailserver = {
|
||||
inherit oauth-client-id oauth-client-secret-fp;
|
||||
};
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
{ config, lib, pkgs, ... }@nixos-args:
|
||||
let
|
||||
inherit (import ./common.nix nixos-args)
|
||||
appendLdapBindPwd
|
||||
appendSetting
|
||||
auth-passthru
|
||||
is-auth-enabled
|
||||
;
|
||||
@@ -29,7 +29,7 @@ let
|
||||
query_filter = ${cfg.ldap.postfix.filter}
|
||||
result_attribute = ${cfg.ldap.postfix.mailAttribute}
|
||||
'';
|
||||
appendPwdInSenderLoginMap = appendLdapBindPwd {
|
||||
appendPwdInSenderLoginMap = appendSetting {
|
||||
name = "ldap-sender-login-map";
|
||||
file = ldapSenderLoginMap;
|
||||
prefix = "bind_pw = ";
|
||||
@@ -43,7 +43,7 @@ let
|
||||
result_attribute = ${cfg.ldap.postfix.uidAttribute}
|
||||
'';
|
||||
ldapVirtualMailboxMapFile = "/run/postfix/ldap-virtual-mailbox-map.cf";
|
||||
appendPwdInVirtualMailboxMap = appendLdapBindPwd {
|
||||
appendPwdInVirtualMailboxMap = appendSetting {
|
||||
name = "ldap-virtual-mailbox-map";
|
||||
file = ldapVirtualMailboxMap;
|
||||
prefix = "bind_pw = ";
|
||||
|
@@ -3,8 +3,9 @@ rec {
|
||||
auth-passthru = config.passthru.selfprivacy.auth;
|
||||
domain = config.selfprivacy.domain;
|
||||
is-auth-enabled = config.selfprivacy.modules.auth.enable or false;
|
||||
group = "dovecot2";
|
||||
|
||||
appendLdapBindPwd =
|
||||
appendSetting =
|
||||
{ name, file, prefix, suffix ? "", passwordFile, destination }:
|
||||
pkgs.writeScript "append-ldap-bind-pwd-in-${name}" ''
|
||||
#!${pkgs.stdenv.shell}
|
||||
|
@@ -1,10 +1,15 @@
|
||||
[
|
||||
[ "mailserver" ],
|
||||
[ "passthru", "selfprivacy", "auth", "admins-group" ],
|
||||
[ "passthru", "selfprivacy", "auth", "full-users-group" ],
|
||||
[ "passthru", "selfprivacy", "auth", "ldap-base-dn" ],
|
||||
[ "passthru", "selfprivacy", "auth", "ldap-port" ],
|
||||
[ "passthru", "selfprivacy", "auth", "oauth2-discovery-url" ],
|
||||
[ "passthru", "selfprivacy", "auth", "oauth2-introspection-url" ],
|
||||
[ "passthru", "selfprivacy", "auth", "oauth2-introspection-url-postfix" ],
|
||||
[ "passthru", "selfprivacy", "auth", "oauth2-introspection-url-prefix" ],
|
||||
[ "passthru", "selfprivacy", "auth", "oauth2-systemd-service" ],
|
||||
[ "passthru", "selfprivacy", "roundcube", "oauth-client-id" ],
|
||||
[ "passthru", "selfprivacy", "roundcube", "oauth-client-secret-fp" ],
|
||||
[ "security", "acme", "certs" ],
|
||||
[ "selfprivacy", "domain" ],
|
||||
[ "selfprivacy", "hashedMasterPassword" ],
|
||||
|
@@ -5,20 +5,22 @@ let
|
||||
inherit (import ./common.nix { inherit config pkgs; })
|
||||
auth-passthru
|
||||
domain
|
||||
group
|
||||
is-auth-enabled
|
||||
;
|
||||
|
||||
mailserver-service-account-name = "sp.mailserver.service-account";
|
||||
mailserver-service-account-token-name = "mailserver-service-account-token";
|
||||
mailserver-service-account-token-fp =
|
||||
"/run/keys/mailserver/kanidm-service-account-token"; # FIXME sync with auth module
|
||||
kanidmExecStartPostScriptRoot = pkgs.writeShellScript
|
||||
"mailserver-kanidm-ExecStartPost-root-script.sh"
|
||||
"/run/keys/${group}/kanidm-service-account-token"; # FIXME sync with auth module
|
||||
kanidmExecStartPreScriptRoot = pkgs.writeShellScript
|
||||
"mailserver-kanidm-ExecStartPre-root-script.sh"
|
||||
''
|
||||
# set-group-ID bit allows for kanidm user to create files,
|
||||
mkdir -p -v --mode=u+rwx,g+rs,g-w,o-rwx /run/keys/mailserver
|
||||
chown kanidm:kanidm /run/keys/mailserver
|
||||
# set-group-ID bit allows for kanidm user to create files inheriting group
|
||||
mkdir -p -v --mode=u+rwx,g+rs,g-w,o-rwx /run/keys/${group}
|
||||
chown kanidm:${group} /run/keys/${group}
|
||||
'';
|
||||
# create service account token, needed for LDAP
|
||||
kanidmExecStartPostScript = pkgs.writeShellScript
|
||||
"mailserver-kanidm-ExecStartPost-script.sh"
|
||||
''
|
||||
@@ -173,7 +175,7 @@ lib.mkIf sp.modules.simple-nixos-mailserver.enable (lib.mkMerge [
|
||||
};
|
||||
};
|
||||
}
|
||||
# the following part is active only when "auth" module is enabled
|
||||
# the following parts are active only when "auth" module is enabled
|
||||
(lib.attrsets.optionalAttrs
|
||||
(options.selfprivacy.modules ? "auth")
|
||||
(lib.mkIf is-auth-enabled {
|
||||
@@ -199,9 +201,11 @@ lib.mkIf sp.modules.simple-nixos-mailserver.enable (lib.mkMerge [
|
||||
};
|
||||
};
|
||||
# FIXME set auth module option instead
|
||||
systemd.services.kanidm.serviceConfig.ExecStartPre = lib.mkBefore [
|
||||
("-+" + kanidmExecStartPreScriptRoot)
|
||||
];
|
||||
systemd.services.kanidm.serviceConfig.ExecStartPost = lib.mkAfter [
|
||||
("+" + kanidmExecStartPostScriptRoot)
|
||||
kanidmExecStartPostScript
|
||||
("-" + kanidmExecStartPostScript)
|
||||
];
|
||||
}))
|
||||
(lib.attrsets.optionalAttrs
|
||||
|
Reference in New Issue
Block a user