style: format tree
This commit is contained in:
@@ -1,4 +1,9 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (import ./common.nix config)
|
||||
admin-pass-filepath
|
||||
@@ -27,391 +32,417 @@ let
|
||||
usersGroup = "sp.${oauthClientID}.users";
|
||||
wildcardGroup = "sp.${oauthClientID}.*";
|
||||
|
||||
serviceAccountTokenFP =
|
||||
auth-passthru.mkServiceAccountTokenFP linuxUserOfService;
|
||||
oauthClientSecretFP =
|
||||
auth-passthru.mkOAuth2ClientSecretFP linuxUserOfService;
|
||||
serviceAccountTokenFP = auth-passthru.mkServiceAccountTokenFP linuxUserOfService;
|
||||
oauthClientSecretFP = auth-passthru.mkOAuth2ClientSecretFP linuxUserOfService;
|
||||
|
||||
updater-page-substitute =
|
||||
pkgs.runCommandNoCC "nextcloud-updater-page-substitute" { } ''
|
||||
install -m644 ${./updater.html} -DT $out/index.html
|
||||
'';
|
||||
updater-page-substitute = pkgs.runCommandNoCC "nextcloud-updater-page-substitute" { } ''
|
||||
install -m644 ${./updater.html} -DT $out/index.html
|
||||
'';
|
||||
in
|
||||
{
|
||||
options.selfprivacy.modules.nextcloud = with lib; {
|
||||
enable = (lib.mkOption {
|
||||
default = false;
|
||||
type = lib.types.bool;
|
||||
description = "Enable Nextcloud";
|
||||
}) // {
|
||||
meta = {
|
||||
type = "enable";
|
||||
enable =
|
||||
(lib.mkOption {
|
||||
default = false;
|
||||
type = lib.types.bool;
|
||||
description = "Enable Nextcloud";
|
||||
})
|
||||
// {
|
||||
meta = {
|
||||
type = "enable";
|
||||
};
|
||||
};
|
||||
};
|
||||
location = (lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "Nextcloud location";
|
||||
}) // {
|
||||
meta = {
|
||||
type = "location";
|
||||
location =
|
||||
(lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "Nextcloud location";
|
||||
})
|
||||
// {
|
||||
meta = {
|
||||
type = "location";
|
||||
};
|
||||
};
|
||||
};
|
||||
subdomain = (lib.mkOption {
|
||||
default = "cloud";
|
||||
type = lib.types.strMatching "[A-Za-z0-9][A-Za-z0-9\-]{0,61}[A-Za-z0-9]";
|
||||
description = "Subdomain";
|
||||
}) // {
|
||||
meta = {
|
||||
widget = "subdomain";
|
||||
type = "string";
|
||||
regex = "[A-Za-z0-9][A-Za-z0-9\-]{0,61}[A-Za-z0-9]";
|
||||
weight = 0;
|
||||
subdomain =
|
||||
(lib.mkOption {
|
||||
default = "cloud";
|
||||
type = lib.types.strMatching "[A-Za-z0-9][A-Za-z0-9\-]{0,61}[A-Za-z0-9]";
|
||||
description = "Subdomain";
|
||||
})
|
||||
// {
|
||||
meta = {
|
||||
widget = "subdomain";
|
||||
type = "string";
|
||||
regex = "[A-Za-z0-9][A-Za-z0-9\-]{0,61}[A-Za-z0-9]";
|
||||
weight = 0;
|
||||
};
|
||||
};
|
||||
};
|
||||
enableImagemagick = (lib.mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Enable ImageMagick";
|
||||
}) // {
|
||||
meta = {
|
||||
type = "bool";
|
||||
weight = 1;
|
||||
enableImagemagick =
|
||||
(lib.mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Enable ImageMagick";
|
||||
})
|
||||
// {
|
||||
meta = {
|
||||
type = "bool";
|
||||
weight = 1;
|
||||
};
|
||||
};
|
||||
};
|
||||
enableSso = (lib.mkOption {
|
||||
default = false;
|
||||
type = lib.types.bool;
|
||||
description = "Enable Single Sign-On";
|
||||
}) // {
|
||||
meta = {
|
||||
type = "bool";
|
||||
weight = 2;
|
||||
enableSso =
|
||||
(lib.mkOption {
|
||||
default = false;
|
||||
type = lib.types.bool;
|
||||
description = "Enable Single Sign-On";
|
||||
})
|
||||
// {
|
||||
meta = {
|
||||
type = "bool";
|
||||
weight = 2;
|
||||
};
|
||||
};
|
||||
};
|
||||
enableSambaFeatures = (lib.mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Enable support for Samba/CIFS features";
|
||||
}) // {
|
||||
meta = {
|
||||
type = "bool";
|
||||
weight = 3;
|
||||
enableSambaFeatures =
|
||||
(lib.mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Enable support for Samba/CIFS features";
|
||||
})
|
||||
// {
|
||||
meta = {
|
||||
type = "bool";
|
||||
weight = 3;
|
||||
};
|
||||
};
|
||||
};
|
||||
debug = (lib.mkOption {
|
||||
default = false;
|
||||
type = lib.types.bool;
|
||||
description = "Enable debug logging";
|
||||
}) // {
|
||||
meta = {
|
||||
type = "bool";
|
||||
weight = 4;
|
||||
debug =
|
||||
(lib.mkOption {
|
||||
default = false;
|
||||
type = lib.types.bool;
|
||||
description = "Enable debug logging";
|
||||
})
|
||||
// {
|
||||
meta = {
|
||||
type = "bool";
|
||||
weight = 4;
|
||||
};
|
||||
};
|
||||
};
|
||||
disableMaintenanceModeAtStart = (lib.mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Disable maintenance mode at Nextcloud service startup";
|
||||
}) // {
|
||||
meta = {
|
||||
type = "bool";
|
||||
weight = 5;
|
||||
disableMaintenanceModeAtStart =
|
||||
(lib.mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Disable maintenance mode at Nextcloud service startup";
|
||||
})
|
||||
// {
|
||||
meta = {
|
||||
type = "bool";
|
||||
weight = 5;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# config = lib.mkIf sp.modules.nextcloud.enable
|
||||
config = lib.mkIf sp.modules.nextcloud.enable (lib.mkMerge [
|
||||
{
|
||||
assertions = [
|
||||
{
|
||||
assertion = cfg.enableSso -> sp.sso.enable;
|
||||
message =
|
||||
"SSO cannot be enabled for Nextcloud when SSO is disabled globally.";
|
||||
}
|
||||
];
|
||||
fileSystems = lib.mkIf sp.useBinds {
|
||||
"/var/lib/nextcloud" = {
|
||||
device = "/volumes/${cfg.location}/nextcloud";
|
||||
options = [
|
||||
"bind"
|
||||
"x-systemd.required-by=nextcloud-setup.service"
|
||||
"x-systemd.required-by=nextcloud-secrets.service"
|
||||
"x-systemd.before=nextcloud-setup.service"
|
||||
"x-systemd.before=nextcloud-secrets.service"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
# for ExecStartPost script to have access to /run/keys/*
|
||||
users.groups.keys.members =
|
||||
lib.mkIf is-auth-enabled [ linuxUserOfService ];
|
||||
|
||||
# not needed, due to turnOffCertCheck=1 in used_ldap
|
||||
# users.groups.${config.security.acme.certs.${domain}.group}.members =
|
||||
# [ config.services.phpfpm.pools.nextcloud.user ];
|
||||
|
||||
systemd = {
|
||||
services = {
|
||||
phpfpm-nextcloud.serviceConfig.Slice = lib.mkForce "nextcloud.slice";
|
||||
nextcloud-setup = {
|
||||
serviceConfig.Slice = "nextcloud.slice";
|
||||
serviceConfig.Group = config.services.phpfpm.pools.nextcloud.group;
|
||||
config = lib.mkIf sp.modules.nextcloud.enable (
|
||||
lib.mkMerge [
|
||||
{
|
||||
assertions = [
|
||||
{
|
||||
assertion = cfg.enableSso -> sp.sso.enable;
|
||||
message = "SSO cannot be enabled for Nextcloud when SSO is disabled globally.";
|
||||
}
|
||||
];
|
||||
fileSystems = lib.mkIf sp.useBinds {
|
||||
"/var/lib/nextcloud" = {
|
||||
device = "/volumes/${cfg.location}/nextcloud";
|
||||
options = [
|
||||
"bind"
|
||||
"x-systemd.required-by=nextcloud-setup.service"
|
||||
"x-systemd.required-by=nextcloud-secrets.service"
|
||||
"x-systemd.before=nextcloud-setup.service"
|
||||
"x-systemd.before=nextcloud-secrets.service"
|
||||
];
|
||||
};
|
||||
nextcloud-cron.serviceConfig.Slice = "nextcloud.slice";
|
||||
nextcloud-update-db.serviceConfig.Slice = "nextcloud.slice";
|
||||
nextcloud-update-plugins.serviceConfig.Slice = "nextcloud.slice";
|
||||
nextcloud-secrets = {
|
||||
before = [ "nextcloud-setup.service" ];
|
||||
requiredBy = [ "nextcloud-setup.service" ];
|
||||
serviceConfig.Type = "oneshot";
|
||||
path = with pkgs; [ coreutils jq ];
|
||||
script = ''
|
||||
databasePassword=$(jq -re '.modules.nextcloud.databasePassword' ${secrets-filepath})
|
||||
adminPassword=$(jq -re '.modules.nextcloud.adminPassword' ${secrets-filepath})
|
||||
};
|
||||
|
||||
install -C -m 0440 -o nextcloud -g nextcloud -DT \
|
||||
<(printf "%s\n" "$databasePassword") \
|
||||
${db-pass-filepath}
|
||||
# for ExecStartPost script to have access to /run/keys/*
|
||||
users.groups.keys.members = lib.mkIf is-auth-enabled [ linuxUserOfService ];
|
||||
|
||||
install -C -m 0440 -o nextcloud -g nextcloud -DT \
|
||||
<(printf "%s\n" "$adminPassword") \
|
||||
${admin-pass-filepath}
|
||||
# not needed, due to turnOffCertCheck=1 in used_ldap
|
||||
# users.groups.${config.security.acme.certs.${domain}.group}.members =
|
||||
# [ config.services.phpfpm.pools.nextcloud.user ];
|
||||
|
||||
systemd = {
|
||||
services = {
|
||||
phpfpm-nextcloud.serviceConfig.Slice = lib.mkForce "nextcloud.slice";
|
||||
nextcloud-setup = {
|
||||
serviceConfig.Slice = "nextcloud.slice";
|
||||
serviceConfig.Group = config.services.phpfpm.pools.nextcloud.group;
|
||||
};
|
||||
nextcloud-cron.serviceConfig.Slice = "nextcloud.slice";
|
||||
nextcloud-update-db.serviceConfig.Slice = "nextcloud.slice";
|
||||
nextcloud-update-plugins.serviceConfig.Slice = "nextcloud.slice";
|
||||
nextcloud-secrets = {
|
||||
before = [ "nextcloud-setup.service" ];
|
||||
requiredBy = [ "nextcloud-setup.service" ];
|
||||
serviceConfig.Type = "oneshot";
|
||||
path = with pkgs; [
|
||||
coreutils
|
||||
jq
|
||||
];
|
||||
script = ''
|
||||
databasePassword=$(jq -re '.modules.nextcloud.databasePassword' ${secrets-filepath})
|
||||
adminPassword=$(jq -re '.modules.nextcloud.adminPassword' ${secrets-filepath})
|
||||
|
||||
install -C -m 0440 -o nextcloud -g nextcloud -DT \
|
||||
<(printf "%s\n" "$databasePassword") \
|
||||
${db-pass-filepath}
|
||||
|
||||
install -C -m 0440 -o nextcloud -g nextcloud -DT \
|
||||
<(printf "%s\n" "$adminPassword") \
|
||||
${admin-pass-filepath}
|
||||
'';
|
||||
};
|
||||
};
|
||||
slices.nextcloud = {
|
||||
description = "Nextcloud service slice";
|
||||
};
|
||||
};
|
||||
services.nextcloud = {
|
||||
enable = true;
|
||||
package = pkgs.nextcloud30;
|
||||
inherit hostName;
|
||||
|
||||
# Use HTTPS for links
|
||||
https = true;
|
||||
|
||||
# auto-update Nextcloud Apps
|
||||
autoUpdateApps.enable = true;
|
||||
# set what time makes sense for you
|
||||
autoUpdateApps.startAt = "05:00:00";
|
||||
|
||||
phpOptions.display_errors = "Off";
|
||||
phpOptions."opcache.interned_strings_buffer" = "32";
|
||||
|
||||
configureRedis = true;
|
||||
|
||||
settings =
|
||||
{
|
||||
# further forces Nextcloud to use HTTPS
|
||||
overwriteprotocol = "https";
|
||||
}
|
||||
// lib.attrsets.optionalAttrs is-auth-enabled {
|
||||
loglevel = 0;
|
||||
# log_type = "file";
|
||||
social_login_auto_redirect = false;
|
||||
|
||||
allow_local_remote_servers = true;
|
||||
allow_user_to_change_display_name = false;
|
||||
lost_password_link = "disabled";
|
||||
allow_multiple_user_backends = false;
|
||||
|
||||
updatechecker = false; # nixpkgs handles updates for us, update via web ui will fail on nixos.
|
||||
|
||||
user_oidc = {
|
||||
single_logout = true;
|
||||
use_pkce = true;
|
||||
auto_provision = true;
|
||||
soft_auto_provision = true;
|
||||
disable_account_creation = false;
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
dbtype = "sqlite";
|
||||
dbuser = "nextcloud";
|
||||
dbname = "nextcloud";
|
||||
dbpassFile = db-pass-filepath;
|
||||
# TODO review whether admin user is needed at all - admin group works
|
||||
adminpassFile = admin-pass-filepath;
|
||||
adminuser = "admin";
|
||||
};
|
||||
};
|
||||
services.nginx.virtualHosts.${hostName} = {
|
||||
useACMEHost = sp.domain;
|
||||
forceSSL = true;
|
||||
#locations."/".extraConfig = lib.mkIf is-auth-enabled ''
|
||||
# # FIXME does not work
|
||||
# rewrite ^/login$ /apps/user_oidc/login/1 last;
|
||||
#'';
|
||||
# show an error instead of a blank page on Nextcloud PHP/FastCGI error
|
||||
locations."~ \\.php(?:$|/)".extraConfig = ''
|
||||
error_page 500 502 503 504 ${pkgs.nginx}/html/50x.html;
|
||||
'';
|
||||
locations."^~ /updater/" = {
|
||||
alias = updater-page-substitute + "/";
|
||||
extraConfig = ''
|
||||
error_page 410 /index.html;
|
||||
# otherwise, nginx returns 405 for POST requests to static content
|
||||
error_page 405 =200 $uri;
|
||||
'';
|
||||
};
|
||||
};
|
||||
slices.nextcloud = {
|
||||
description = "Nextcloud service slice";
|
||||
}
|
||||
# enables samba features when requested
|
||||
(lib.mkIf cfg.enableSambaFeatures {
|
||||
# only apply cifs-utils package to this module
|
||||
services.phpfpm.pools.nextcloud.phpEnv.PATH =
|
||||
lib.mkForce "${pkgs.samba}/bin:${pkgs.cifs-utils}/bin:/run/wrappers/bin:/nix/var/nix/profiles/default/bin:/run/current-system/sw/bin:/usr/bin:/bin";
|
||||
systemd.services.nextcloud-cron.path = [
|
||||
pkgs.samba
|
||||
pkgs.cifs-utils
|
||||
];
|
||||
})
|
||||
# the following part is active only when "auth" module is enabled
|
||||
(lib.mkIf is-auth-enabled {
|
||||
systemd.services.nextcloud-setup = {
|
||||
serviceConfig = {
|
||||
Restart = "on-failure";
|
||||
RestartSec = "60";
|
||||
};
|
||||
path = [ pkgs.jq ];
|
||||
script = lib.mkMerge [
|
||||
(lib.strings.optionalString cfg.disableMaintenanceModeAtStart (
|
||||
lib.mkBefore "${occ} maintenance:mode --no-interaction --off"
|
||||
))
|
||||
''
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
${lib.strings.optionalString cfg.debug "set -o xtrace"}
|
||||
|
||||
${occ} app:disable logreader
|
||||
|
||||
${occ} app:install user_ldap || :
|
||||
${occ} app:enable user_ldap
|
||||
|
||||
# The following code tries to match an existing config or creates a new one.
|
||||
# The criteria for matching is the ldapHost value.
|
||||
|
||||
# remove broken link after previous nextcloud (un)installation
|
||||
[[ ! -f "${override-config-fp}" && -L "${override-config-fp}" ]] && \
|
||||
rm -v "${override-config-fp}"
|
||||
|
||||
ALL_CONFIG="$(${occ} ldap:show-config --output=json)"
|
||||
|
||||
MATCHING_CONFIG_IDs="$(jq '[to_entries[] | select(.value.ldapHost=="${ldap_scheme_and_host}") | .key]' <<<"$ALL_CONFIG")"
|
||||
if [[ $(jq 'length' <<<"$MATCHING_CONFIG_IDs") > 0 ]]; then
|
||||
CONFIG_ID="$(jq --raw-output '.[0]' <<<"$MATCHING_CONFIG_IDs")"
|
||||
else
|
||||
CONFIG_ID="$(${occ} ldap:create-empty-config --only-print-prefix)"
|
||||
fi
|
||||
|
||||
echo "Using configId $CONFIG_ID"
|
||||
|
||||
# The following CLI commands follow
|
||||
# https://github.com/lldap/lldap/blob/main/example_configs/nextcloud.md#nextcloud-config--the-cli-way
|
||||
|
||||
# StartTLS is not supported in Kanidm due to security risks, whereas
|
||||
# user_ldap doesn't support SASL. Importing certificate doesn't
|
||||
# help:
|
||||
# ${occ} security:certificates:import "${config.security.acme.certs.${domain}.directory}/cert.pem"
|
||||
${occ} ldap:set-config "$CONFIG_ID" 'turnOffCertCheck' '1'
|
||||
|
||||
${occ} ldap:set-config "$CONFIG_ID" 'ldapHost' '${ldap_scheme_and_host}'
|
||||
${occ} ldap:set-config "$CONFIG_ID" 'ldapPort' '${toString auth-passthru.ldap-port}'
|
||||
${occ} ldap:set-config "$CONFIG_ID" 'ldapAgentName' 'dn=token'
|
||||
${occ} ldap:set-config "$CONFIG_ID" 'ldapAgentPassword' "$(<${serviceAccountTokenFP})"
|
||||
${occ} ldap:set-config "$CONFIG_ID" 'ldapBase' '${auth-passthru.ldap-base-dn}'
|
||||
${occ} ldap:set-config "$CONFIG_ID" 'ldapBaseGroups' '${auth-passthru.ldap-base-dn}'
|
||||
${occ} ldap:set-config "$CONFIG_ID" 'ldapBaseUsers' '${auth-passthru.ldap-base-dn}'
|
||||
${occ} ldap:set-config "$CONFIG_ID" 'ldapEmailAttribute' 'mail'
|
||||
${occ} ldap:set-config "$CONFIG_ID" 'ldapGroupFilter' \
|
||||
'(&(class=group)(${wildcardGroup})'
|
||||
${occ} ldap:set-config "$CONFIG_ID" 'ldapGroupFilterGroups' \
|
||||
'(&(class=group)(${wildcardGroup}))'
|
||||
# ${occ} ldap:set-config "$CONFIG_ID" 'ldapGroupFilterObjectclass' \
|
||||
# 'groupOfUniqueNames'
|
||||
# ${occ} ldap:set-config "$CONFIG_ID" 'ldapGroupMemberAssocAttr' \
|
||||
# 'uniqueMember'
|
||||
${occ} ldap:set-config "$CONFIG_ID" 'ldapLoginFilter' \
|
||||
'(&(class=person)(memberof=${usersGroup})(uid=%uid))'
|
||||
${occ} ldap:set-config "$CONFIG_ID" 'ldapLoginFilterAttributes' \
|
||||
'uid'
|
||||
${occ} ldap:set-config "$CONFIG_ID" 'ldapUserDisplayName' \
|
||||
'displayname'
|
||||
${occ} ldap:set-config "$CONFIG_ID" 'ldapUserFilter' \
|
||||
'(&(class=person)(memberof=${usersGroup})(name=%s))'
|
||||
${occ} ldap:set-config "$CONFIG_ID" 'ldapUserFilterMode' \
|
||||
'1'
|
||||
${occ} ldap:set-config "$CONFIG_ID" 'ldapUserFilterObjectclass' \
|
||||
'person'
|
||||
|
||||
${occ} ldap:test-config -- "$CONFIG_ID"
|
||||
|
||||
# delete all configs except "$CONFIG_ID"
|
||||
for configid in $(jq --raw-output "keys[] | select(. != \"$CONFIG_ID\")" <<<"$ALL_CONFIG"); do
|
||||
echo "Deactivating $configid"
|
||||
${occ} ldap:set-config "$configid" 'ldapConfigurationActive' '0'
|
||||
echo "Deactivated $configid"
|
||||
echo "Deleting $configid"
|
||||
${occ} ldap:delete-config "$configid"
|
||||
echo "Deleted $configid"
|
||||
done
|
||||
|
||||
${occ} ldap:set-config "$CONFIG_ID" 'ldapConfigurationActive' '1'
|
||||
|
||||
############################################################################
|
||||
# OIDC app
|
||||
############################################################################
|
||||
${occ} app:install user_oidc || :
|
||||
${occ} app:enable user_oidc
|
||||
|
||||
${occ} user_oidc:provider ${auth-passthru.oauth2-provider-name} \
|
||||
--clientid="${oauthClientID}" \
|
||||
--clientsecret="$(<${oauthClientSecretFP})" \
|
||||
--discoveryuri="${auth-passthru.oauth2-discovery-url "nextcloud"}" \
|
||||
--unique-uid=0 \
|
||||
--scope="email openid profile" \
|
||||
--mapping-uid=preferred_username \
|
||||
--no-interaction \
|
||||
--mapping-groups=groups \
|
||||
--group-provisioning=1 \
|
||||
-vvv
|
||||
|
||||
''
|
||||
(lib.optionalString deleteNextcloudAdmin ''
|
||||
if [[ ! -f /var/lib/nextcloud/.admin-user-deleted ]]; then
|
||||
${occ} user:delete admin
|
||||
touch /var/lib/nextcloud/.admin-user-deleted
|
||||
fi
|
||||
'')
|
||||
];
|
||||
};
|
||||
};
|
||||
services.nextcloud = {
|
||||
enable = true;
|
||||
package = pkgs.nextcloud30;
|
||||
inherit hostName;
|
||||
|
||||
# Use HTTPS for links
|
||||
https = true;
|
||||
|
||||
# auto-update Nextcloud Apps
|
||||
autoUpdateApps.enable = true;
|
||||
# set what time makes sense for you
|
||||
autoUpdateApps.startAt = "05:00:00";
|
||||
|
||||
phpOptions.display_errors = "Off";
|
||||
phpOptions."opcache.interned_strings_buffer" = "32";
|
||||
|
||||
configureRedis = true;
|
||||
|
||||
settings = {
|
||||
# further forces Nextcloud to use HTTPS
|
||||
overwriteprotocol = "https";
|
||||
} // lib.attrsets.optionalAttrs is-auth-enabled {
|
||||
loglevel = 0;
|
||||
# log_type = "file";
|
||||
social_login_auto_redirect = false;
|
||||
|
||||
allow_local_remote_servers = true;
|
||||
allow_user_to_change_display_name = false;
|
||||
lost_password_link = "disabled";
|
||||
allow_multiple_user_backends = false;
|
||||
|
||||
updatechecker = false; # nixpkgs handles updates for us, update via web ui will fail on nixos.
|
||||
|
||||
user_oidc = {
|
||||
single_logout = true;
|
||||
use_pkce = true;
|
||||
auto_provision = true;
|
||||
soft_auto_provision = true;
|
||||
disable_account_creation = false;
|
||||
selfprivacy.auth.clients."${oauthClientID}" = {
|
||||
inherit adminsGroup usersGroup;
|
||||
imageFile = ./icon.svg;
|
||||
displayName = "Nextcloud";
|
||||
subdomain = cfg.subdomain;
|
||||
isTokenNeeded = true;
|
||||
originUrl = "https://${cfg.subdomain}.${domain}/apps/user_oidc/code";
|
||||
originLanding = "https://${cfg.subdomain}.${domain}/apps/user_oidc/login/1";
|
||||
useShortPreferredUsername = true;
|
||||
clientSystemdUnits = [
|
||||
"nextcloud-setup.service"
|
||||
"phpfpm-nextcloud.service"
|
||||
];
|
||||
enablePkce = true;
|
||||
linuxUserOfClient = linuxUserOfService;
|
||||
linuxGroupOfClient = linuxGroupOfService;
|
||||
scopeMaps.${usersGroup} = [
|
||||
"email"
|
||||
"openid"
|
||||
"profile"
|
||||
];
|
||||
claimMaps.groups = {
|
||||
joinType = "array";
|
||||
valuesByGroup.${adminsGroup} = [ "admin" ];
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
dbtype = "sqlite";
|
||||
dbuser = "nextcloud";
|
||||
dbname = "nextcloud";
|
||||
dbpassFile = db-pass-filepath;
|
||||
# TODO review whether admin user is needed at all - admin group works
|
||||
adminpassFile = admin-pass-filepath;
|
||||
adminuser = "admin";
|
||||
};
|
||||
};
|
||||
services.nginx.virtualHosts.${hostName} = {
|
||||
useACMEHost = sp.domain;
|
||||
forceSSL = true;
|
||||
#locations."/".extraConfig = lib.mkIf is-auth-enabled ''
|
||||
# # FIXME does not work
|
||||
# rewrite ^/login$ /apps/user_oidc/login/1 last;
|
||||
#'';
|
||||
# show an error instead of a blank page on Nextcloud PHP/FastCGI error
|
||||
locations."~ \\.php(?:$|/)".extraConfig = ''
|
||||
error_page 500 502 503 504 ${pkgs.nginx}/html/50x.html;
|
||||
'';
|
||||
locations."^~ /updater/" = {
|
||||
alias = updater-page-substitute + "/";
|
||||
extraConfig = ''
|
||||
error_page 410 /index.html;
|
||||
# otherwise, nginx returns 405 for POST requests to static content
|
||||
error_page 405 =200 $uri;
|
||||
})
|
||||
(lib.mkIf (!is-auth-enabled) {
|
||||
systemd.services.nextcloud-setup = {
|
||||
script = ''
|
||||
${occ} app:disable logreader
|
||||
${occ} app:disable user_oidc
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
# enables samba features when requested
|
||||
(lib.mkIf cfg.enableSambaFeatures {
|
||||
# only apply cifs-utils package to this module
|
||||
services.phpfpm.pools.nextcloud.phpEnv.PATH =
|
||||
lib.mkForce "${pkgs.samba}/bin:${pkgs.cifs-utils}/bin:/run/wrappers/bin:/nix/var/nix/profiles/default/bin:/run/current-system/sw/bin:/usr/bin:/bin";
|
||||
systemd.services.nextcloud-cron.path = [ pkgs.samba pkgs.cifs-utils ];
|
||||
})
|
||||
# the following part is active only when "auth" module is enabled
|
||||
(lib.mkIf is-auth-enabled {
|
||||
systemd.services.nextcloud-setup = {
|
||||
serviceConfig = {
|
||||
Restart = "on-failure";
|
||||
RestartSec = "60";
|
||||
};
|
||||
path = [ pkgs.jq ];
|
||||
script = lib.mkMerge [
|
||||
(lib.strings.optionalString cfg.disableMaintenanceModeAtStart (
|
||||
lib.mkBefore "${occ} maintenance:mode --no-interaction --off"
|
||||
))
|
||||
''
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
${lib.strings.optionalString cfg.debug "set -o xtrace"}
|
||||
|
||||
${occ} app:disable logreader
|
||||
|
||||
${occ} app:install user_ldap || :
|
||||
${occ} app:enable user_ldap
|
||||
|
||||
# The following code tries to match an existing config or creates a new one.
|
||||
# The criteria for matching is the ldapHost value.
|
||||
|
||||
# remove broken link after previous nextcloud (un)installation
|
||||
[[ ! -f "${override-config-fp}" && -L "${override-config-fp}" ]] && \
|
||||
rm -v "${override-config-fp}"
|
||||
|
||||
ALL_CONFIG="$(${occ} ldap:show-config --output=json)"
|
||||
|
||||
MATCHING_CONFIG_IDs="$(jq '[to_entries[] | select(.value.ldapHost=="${ldap_scheme_and_host}") | .key]' <<<"$ALL_CONFIG")"
|
||||
if [[ $(jq 'length' <<<"$MATCHING_CONFIG_IDs") > 0 ]]; then
|
||||
CONFIG_ID="$(jq --raw-output '.[0]' <<<"$MATCHING_CONFIG_IDs")"
|
||||
else
|
||||
CONFIG_ID="$(${occ} ldap:create-empty-config --only-print-prefix)"
|
||||
fi
|
||||
|
||||
echo "Using configId $CONFIG_ID"
|
||||
|
||||
# The following CLI commands follow
|
||||
# https://github.com/lldap/lldap/blob/main/example_configs/nextcloud.md#nextcloud-config--the-cli-way
|
||||
|
||||
# StartTLS is not supported in Kanidm due to security risks, whereas
|
||||
# user_ldap doesn't support SASL. Importing certificate doesn't
|
||||
# help:
|
||||
# ${occ} security:certificates:import "${config.security.acme.certs.${domain}.directory}/cert.pem"
|
||||
${occ} ldap:set-config "$CONFIG_ID" 'turnOffCertCheck' '1'
|
||||
|
||||
${occ} ldap:set-config "$CONFIG_ID" 'ldapHost' '${ldap_scheme_and_host}'
|
||||
${occ} ldap:set-config "$CONFIG_ID" 'ldapPort' '${toString auth-passthru.ldap-port}'
|
||||
${occ} ldap:set-config "$CONFIG_ID" 'ldapAgentName' 'dn=token'
|
||||
${occ} ldap:set-config "$CONFIG_ID" 'ldapAgentPassword' "$(<${serviceAccountTokenFP})"
|
||||
${occ} ldap:set-config "$CONFIG_ID" 'ldapBase' '${auth-passthru.ldap-base-dn}'
|
||||
${occ} ldap:set-config "$CONFIG_ID" 'ldapBaseGroups' '${auth-passthru.ldap-base-dn}'
|
||||
${occ} ldap:set-config "$CONFIG_ID" 'ldapBaseUsers' '${auth-passthru.ldap-base-dn}'
|
||||
${occ} ldap:set-config "$CONFIG_ID" 'ldapEmailAttribute' 'mail'
|
||||
${occ} ldap:set-config "$CONFIG_ID" 'ldapGroupFilter' \
|
||||
'(&(class=group)(${wildcardGroup})'
|
||||
${occ} ldap:set-config "$CONFIG_ID" 'ldapGroupFilterGroups' \
|
||||
'(&(class=group)(${wildcardGroup}))'
|
||||
# ${occ} ldap:set-config "$CONFIG_ID" 'ldapGroupFilterObjectclass' \
|
||||
# 'groupOfUniqueNames'
|
||||
# ${occ} ldap:set-config "$CONFIG_ID" 'ldapGroupMemberAssocAttr' \
|
||||
# 'uniqueMember'
|
||||
${occ} ldap:set-config "$CONFIG_ID" 'ldapLoginFilter' \
|
||||
'(&(class=person)(memberof=${usersGroup})(uid=%uid))'
|
||||
${occ} ldap:set-config "$CONFIG_ID" 'ldapLoginFilterAttributes' \
|
||||
'uid'
|
||||
${occ} ldap:set-config "$CONFIG_ID" 'ldapUserDisplayName' \
|
||||
'displayname'
|
||||
${occ} ldap:set-config "$CONFIG_ID" 'ldapUserFilter' \
|
||||
'(&(class=person)(memberof=${usersGroup})(name=%s))'
|
||||
${occ} ldap:set-config "$CONFIG_ID" 'ldapUserFilterMode' \
|
||||
'1'
|
||||
${occ} ldap:set-config "$CONFIG_ID" 'ldapUserFilterObjectclass' \
|
||||
'person'
|
||||
|
||||
${occ} ldap:test-config -- "$CONFIG_ID"
|
||||
|
||||
# delete all configs except "$CONFIG_ID"
|
||||
for configid in $(jq --raw-output "keys[] | select(. != \"$CONFIG_ID\")" <<<"$ALL_CONFIG"); do
|
||||
echo "Deactivating $configid"
|
||||
${occ} ldap:set-config "$configid" 'ldapConfigurationActive' '0'
|
||||
echo "Deactivated $configid"
|
||||
echo "Deleting $configid"
|
||||
${occ} ldap:delete-config "$configid"
|
||||
echo "Deleted $configid"
|
||||
done
|
||||
|
||||
${occ} ldap:set-config "$CONFIG_ID" 'ldapConfigurationActive' '1'
|
||||
|
||||
############################################################################
|
||||
# OIDC app
|
||||
############################################################################
|
||||
${occ} app:install user_oidc || :
|
||||
${occ} app:enable user_oidc
|
||||
|
||||
${occ} user_oidc:provider ${auth-passthru.oauth2-provider-name} \
|
||||
--clientid="${oauthClientID}" \
|
||||
--clientsecret="$(<${oauthClientSecretFP})" \
|
||||
--discoveryuri="${auth-passthru.oauth2-discovery-url "nextcloud"}" \
|
||||
--unique-uid=0 \
|
||||
--scope="email openid profile" \
|
||||
--mapping-uid=preferred_username \
|
||||
--no-interaction \
|
||||
--mapping-groups=groups \
|
||||
--group-provisioning=1 \
|
||||
-vvv
|
||||
|
||||
''
|
||||
(lib.optionalString deleteNextcloudAdmin ''
|
||||
if [[ ! -f /var/lib/nextcloud/.admin-user-deleted ]]; then
|
||||
${occ} user:delete admin
|
||||
touch /var/lib/nextcloud/.admin-user-deleted
|
||||
fi
|
||||
'')
|
||||
];
|
||||
};
|
||||
selfprivacy.auth.clients."${oauthClientID}" = {
|
||||
inherit adminsGroup usersGroup;
|
||||
imageFile = ./icon.svg;
|
||||
displayName = "Nextcloud";
|
||||
subdomain = cfg.subdomain;
|
||||
isTokenNeeded = true;
|
||||
originUrl = "https://${cfg.subdomain}.${domain}/apps/user_oidc/code";
|
||||
originLanding =
|
||||
"https://${cfg.subdomain}.${domain}/apps/user_oidc/login/1";
|
||||
useShortPreferredUsername = true;
|
||||
clientSystemdUnits =
|
||||
[ "nextcloud-setup.service" "phpfpm-nextcloud.service" ];
|
||||
enablePkce = true;
|
||||
linuxUserOfClient = linuxUserOfService;
|
||||
linuxGroupOfClient = linuxGroupOfService;
|
||||
scopeMaps.${usersGroup} = [ "email" "openid" "profile" ];
|
||||
claimMaps.groups = {
|
||||
joinType = "array";
|
||||
valuesByGroup.${adminsGroup} = [ "admin" ];
|
||||
};
|
||||
};
|
||||
})
|
||||
(lib.mkIf (! is-auth-enabled) {
|
||||
systemd.services.nextcloud-setup = {
|
||||
script = ''
|
||||
${occ} app:disable logreader
|
||||
${occ} app:disable user_oidc
|
||||
'';
|
||||
};
|
||||
})
|
||||
]);
|
||||
})
|
||||
]
|
||||
);
|
||||
}
|
||||
|
Reference in New Issue
Block a user