mirror of
https://git.selfprivacy.org/SelfPrivacy/selfprivacy-nixos-config.git
synced 2025-03-12 17:03:49 +00:00
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:
parent
89e7145a01
commit
4c6228d694
7 changed files with 86 additions and 52 deletions
sp-modules
roundcube
simple-nixos-mailserver
|
@ -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,24 +5,21 @@ 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
|
||||
{
|
||||
options.selfprivacy.modules.roundcube = {
|
||||
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue