From b015d1789eb29782581c5ca0c0926c92b509a1f1 Mon Sep 17 00:00:00 2001 From: Stephane de Labrusse Date: Fri, 15 Mar 2024 14:48:10 +0100 Subject: [PATCH 01/22] Update org.nethserver.authorizations label in build-images.sh --- build-images.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-images.sh b/build-images.sh index 595f605..cea0f24 100644 --- a/build-images.sh +++ b/build-images.sh @@ -53,7 +53,7 @@ buildah add "${container}" ui/dist /ui buildah config --entrypoint=/ \ --label="org.nethserver.tcp-ports-demand=1" \ --label="org.nethserver.rootfull=0" \ - --label="org.nethserver.authorizations=traefik@any:routeadm" \ + --label="org.nethserver.authorizations=traefik@any:routeadm cluster:accountconsumer" \ --label="org.nethserver.images=docker.io/bitnami/dokuwiki:20230404.1.0-debian-11-r77" \ "${container}" # Commit everything From 8fd4e1d9c643ee8d0b448416c185e9b0e27d01b3 Mon Sep 17 00:00:00 2001 From: Stephane de Labrusse Date: Fri, 15 Mar 2024 14:48:17 +0100 Subject: [PATCH 02/22] Add discover-ldap script for LDAP service configuration --- imageroot/bin/discover-ldap | 50 +++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100755 imageroot/bin/discover-ldap diff --git a/imageroot/bin/discover-ldap b/imageroot/bin/discover-ldap new file mode 100755 index 0000000..47d9683 --- /dev/null +++ b/imageroot/bin/discover-ldap @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 + +# +# Copyright (C) 2024 Nethesis S.r.l. +# SPDX-License-Identifier: GPL-3.0-or-later +# + +# +# Find settings for LDAP service +# + +import os +import sys +import json +import agent +from agent.ldapproxy import Ldapproxy + +udomname = os.environ.get('LDAP_DOMAIN','') + +if udomname: + agent.bind_user_domains([udomname]) + +try: + odom = Ldapproxy().get_domain(udomname) + 'host' in odom # Throw exception if odom is None +except: + # During restore the domain could be unavailable. Use a fallback + # configuration, pointing to nowhere, just to set the variables. + # Once the domain becomes available, the event will fix them. + odom = { + 'host': '127.0.0.1', + 'port': 20000, + 'schema': 'rfc2307', + 'location': 'internal', + 'base_dn': 'dc=dokuwiki,dc=invalid', + 'bind_dn': 'cn=example,dc=dokuwiki,dc=invalid', + 'bind_password': 'invalid', + } + +tmpfile = "discover.env." + str(os.getpid()) + +with open(tmpfile, "w") as denv: + print('LDAP_PORT=' + str(odom['port']), file=denv) + print('LDAP_USER=' + odom['bind_dn'], file=denv) + print('LDAP_HOST=' + odom['host'], file=denv) + print('LDAP_PASS=' + odom['bind_password'], file=denv) + print('LDAP_SCHEMA=' + odom['schema'], file=denv) + print('LDAP_BASE=' + odom['base_dn'], file=denv) + +os.replace(tmpfile, "discovery_ldap.env") From 616e76d08dc9a92eebb1ad30374c95ce219daa53 Mon Sep 17 00:00:00 2001 From: Stephane de Labrusse Date: Fri, 15 Mar 2024 14:48:23 +0100 Subject: [PATCH 03/22] Add wait-after-boot script for Dokuwiki container initialization --- imageroot/bin/wait-after-boot | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100755 imageroot/bin/wait-after-boot diff --git a/imageroot/bin/wait-after-boot b/imageroot/bin/wait-after-boot new file mode 100755 index 0000000..172e763 --- /dev/null +++ b/imageroot/bin/wait-after-boot @@ -0,0 +1,22 @@ +#!/bin/bash + +# +# Copyright (C) 2024 Nethesis S.r.l. +# SPDX-License-Identifier: GPL-3.0-or-later +# + +# specific to dokuwiki, it creates its own configuration file after a long time boot + +count=0 +while [[ $count -lt 60 ]]; do + if podman exec -ti dokuwiki ls /bitnami/dokuwiki/conf/local.php.dist >/dev/null 2>&1; then + echo "First Configuration done. We push custom configuration files." + exit 0 + fi + ((count++)) + echo "Waiting for dokuwiki container to be ready..." + sleep 1 +done + +echo "Dokuwiki container is not ready after 60s. Exiting..." +exit 1 From e5a93e79b0213ae87adbd5602b93f13b3f373318 Mon Sep 17 00:00:00 2001 From: Stephane de Labrusse Date: Fri, 15 Mar 2024 14:48:29 +0100 Subject: [PATCH 04/22] Add script to write LDAP configuration file --- imageroot/bin/write-ldap-conf | 79 +++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100755 imageroot/bin/write-ldap-conf diff --git a/imageroot/bin/write-ldap-conf b/imageroot/bin/write-ldap-conf new file mode 100755 index 0000000..81160f4 --- /dev/null +++ b/imageroot/bin/write-ldap-conf @@ -0,0 +1,79 @@ +#!/bin/bash + +# +# Copyright (C) 2024 Nethesis S.r.l. +# SPDX-License-Identifier: GPL-3.0-or-later +# + +# Retrieving environment variables +LDAP_DOMAIN=${LDAP_DOMAIN} +LDAP_PORT=${LDAP_PORT} +LDAP_USER=${LDAP_USER} +LDAP_HOST=${LDAP_HOST} +LDAP_PASS=${LDAP_PASS} +LDAP_SCHEMA=${LDAP_SCHEMA} +LDAP_BASE=${LDAP_BASE} + +mkdir -vp dokuwiki-config +cat < dokuwiki-config/local.protected.php +> dokuwiki-config/local.protected.php +\$conf['authtype'] = 'authplain'; +EOF + +elif [[ "$LDAP_DOMAIN" != "" ]]; then + if [[ "$LDAP_SCHEMA" == "rfc2307" ]]; then + cat <> dokuwiki-config/local.protected.php +\$conf['authtype'] = 'authldap'; +\$conf['plugin'][\$conf['authtype']]['server'] = "ldap://accountprovider:${LDAP_PORT}"; +\$conf['plugin'][\$conf['authtype']]['version'] = '3'; +\$conf['plugin'][\$conf['authtype']]['usertree'] = "ou=People,${LDAP_BASE}"; +\$conf['plugin'][\$conf['authtype']]['grouptree'] = "ou=Groups,${LDAP_BASE}"; +\$conf['plugin'][\$conf['authtype']]['userfilter'] = '(|(uid=%{user})(mail=%{user}))'; +\$conf['plugin']['authldap']['groupfilter'] = '(memberUid=%{uid})'; +\$conf['plugin'][\$conf['authtype']]['groupkey'] = 'cn'; +\$conf['plugin']['authldap']['binddn'] = "${LDAP_USER}"; +\$conf['plugin']['authldap']['bindpw'] = "${LDAP_PASS}"; +\$conf['plugin']['authldap']['starttls'] = 0; +\$conf['plugin']['authldap']['modPass'] = 0; +EOF + elif [[ "$LDAP_SCHEMA" == "ad" ]]; then + cat <> dokuwiki-config/local.protected.php +\$conf['authtype'] = 'authad'; +\$conf['plugin']['authad']['account_suffix'] = '@${LDAP_DOMAIN}'; +\$conf['plugin']['authad']['base_dn'] = '${LDAP_BASE}'; +\$conf['plugin']['authad']['domain_controllers'] = 'ldap://accountprovider:${LDAP_PORT}'; //multiple can be given +\$conf['plugin']['authad']['use_tls'] = 0; +EOF + + fi +fi +cat <> dokuwiki-config/local.protected.php +\$conf['useacl'] = 1; +\$conf['superuser'] = 'admin,admin@${LDAP_DOMAIN},administrator,administrator@${LDAP_DOMAIN}'; +EOF + +echo "Configuration written to dokuwiki-config/local.protected.php" + +cat < dokuwiki-config/plugins.local.php + Date: Fri, 15 Mar 2024 14:48:35 +0100 Subject: [PATCH 05/22] Update dokuwiki.service with additional environment files and commands --- imageroot/systemd/user/dokuwiki.service | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/imageroot/systemd/user/dokuwiki.service b/imageroot/systemd/user/dokuwiki.service index dfb13a4..3ab0228 100644 --- a/imageroot/systemd/user/dokuwiki.service +++ b/imageroot/systemd/user/dokuwiki.service @@ -11,12 +11,27 @@ Environment=PODMAN_SYSTEMD_UNIT=%n # - DOKUWIKI_IMAGE: the podman/docker image to rung # - TCP_PORT, TCP_PORTS: the random ports assigned by system EnvironmentFile=%S/state/environment +EnvironmentFile=-%S/state/discovery_ldap.env WorkingDirectory=%S/state Restart=always +ExecStartPre=/usr/local/bin/runagent discover-ldap +ExecStartPre=/usr/local/bin/runagent write-ldap-conf ExecStartPre=/bin/rm -f %t/dokuwiki.pid %t/dokuwiki.ctr-id # Podman should bind only to 127.0.0.1:TCP_PORT # Data are persistend inside dokuwiki-data volume -ExecStart=/usr/bin/podman run --conmon-pidfile %t/dokuwiki.pid --cidfile %t/dokuwiki.ctr-id --cgroups=no-conmon --replace --name dokuwiki -d --env-file=%S/state/environment -p 127.0.0.1:${TCP_PORT}:8080 -v dokuwiki-data:/bitnami/dokuwiki:z ${DOKUWIKI_IMAGE} +ExecStart=/usr/bin/podman run --conmon-pidfile %t/dokuwiki.pid \ + --cidfile %t/dokuwiki.ctr-id \ + --cgroups=no-conmon \ + --replace --name dokuwiki -d \ + --env-file=%S/state/environment \ + --publish 127.0.0.1:${TCP_PORT}:8080 \ + --volume dokuwiki-data:/bitnami/dokuwiki:z \ + --network=slirp4netns:allow_host_loopback=true \ + --add-host=accountprovider:10.0.2.2 \ + ${DOKUWIKI_IMAGE} +ExecStartPost=/usr/local/bin/runagent wait-after-boot +ExecStartPost=podman cp ./dokuwiki-config/local.protected.php dokuwiki:/bitnami/dokuwiki/conf/local.protected.php +ExecStartPost=podman cp ./dokuwiki-config/plugins.local.php dokuwiki:/bitnami/dokuwiki/conf/plugins.local.php ExecStop=/usr/bin/podman stop --ignore --cidfile %t/dokuwiki.ctr-id -t 10 ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/dokuwiki.ctr-id PIDFile=%t/dokuwiki.pid From 2956b718ac12996a2629b3cbf176c689e0e3b21c Mon Sep 17 00:00:00 2001 From: Stephane de Labrusse Date: Fri, 15 Mar 2024 16:18:54 +0100 Subject: [PATCH 06/22] Add LDAP domain configuration --- imageroot/actions/configure-module/20configure | 4 ++++ imageroot/actions/configure-module/validate-input.json | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/imageroot/actions/configure-module/20configure b/imageroot/actions/configure-module/20configure index b0ea21f..8e08d2d 100755 --- a/imageroot/actions/configure-module/20configure +++ b/imageroot/actions/configure-module/20configure @@ -40,6 +40,7 @@ username = data.get("username","admin") password = data.get("password","admin") email = data.get("email", "admin@example.org") full_name = data.get("user_full_name","Administrator") +ldap_domain = data.get("ldap_domain", "") # Talk with agent using file descriptor. # Setup configuration from user input. @@ -53,6 +54,9 @@ agent.set_env("DOKUWIKI_FULL_NAME", full_name) agent.set_env("PHP_ENABLE_OPCACHE", "1") agent.set_env("PHP_MEMORY_LIMIT", "512M") +# Setup LDAP domain +agent.set_env("LDAP_DOMAIN", ldap_domain) + # Make sure everything is saved inside the environment file # just before starting systemd unit agent.dump_env() diff --git a/imageroot/actions/configure-module/validate-input.json b/imageroot/actions/configure-module/validate-input.json index 28ec857..fd3db3e 100644 --- a/imageroot/actions/configure-module/validate-input.json +++ b/imageroot/actions/configure-module/validate-input.json @@ -23,7 +23,8 @@ "email", "host", "http2https", - "lets_encrypt" + "lets_encrypt", + "ldap_domain" ], "properties": { "wiki_name": { @@ -61,6 +62,10 @@ "type": "boolean", "title": "HTTP to HTTPS redirection", "description": "Redirect all the HTTP requests to HTTPS" + }, + "ldap_domain": { + "type": "string", + "description": "LDAP domain name" } } } From a6df6f819bf8afdc34670996753e595090a01cc9 Mon Sep 17 00:00:00 2001 From: Stephane de Labrusse Date: Fri, 15 Mar 2024 16:19:03 +0100 Subject: [PATCH 07/22] Add LDAP domain list to configuration --- imageroot/actions/get-configuration/20read | 12 ++++++++++++ .../actions/get-configuration/validate-output.json | 7 ++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/imageroot/actions/get-configuration/20read b/imageroot/actions/get-configuration/20read index 12d017b..390cb00 100755 --- a/imageroot/actions/get-configuration/20read +++ b/imageroot/actions/get-configuration/20read @@ -28,6 +28,7 @@ import os import sys import json import agent +from agent.ldapproxy import Ldapproxy # Prepare return variable config = {} @@ -43,6 +44,17 @@ config["user_full_name"] = rdb.hget(env, "DOKUWIKI_FULL_NAME"); config["host"] = rdb.hget(env, "TRAEFIK_HOST"); config["http2https"] = rdb.hget(env, "TRAEFIK_HTTP2HTTPS") == "True"; config["lets_encrypt"] = rdb.hget(env, "TRAEFIK_LETS_ENCRYPT") == "True"; +# retrieve LDAP domains list +lp = Ldapproxy() +domains = [] +for key in lp.get_domains_list(): + domains.append({ + "name": key, + "label": key, + "value": key, + }) +config['ldap_domain_list'] = domains +config['ldap_domain'] = os.environ.get("LDAP_DOMAIN",'') # Dump the configuratio to stdou json.dump(config, fp=sys.stdout) diff --git a/imageroot/actions/get-configuration/validate-output.json b/imageroot/actions/get-configuration/validate-output.json index 6c5dfab..c398f99 100644 --- a/imageroot/actions/get-configuration/validate-output.json +++ b/imageroot/actions/get-configuration/validate-output.json @@ -23,7 +23,8 @@ "email", "host", "http2https", - "lets_encrypt" + "lets_encrypt", + "ldap_domain" ], "properties": { "wiki_name": { @@ -59,6 +60,10 @@ "type": "boolean", "title": "HTTP to HTTPS redirection", "description": "Redirect all the HTTP requests to HTTPS" + }, + "ldap_domain": { + "type": "string", + "description": "The LDAP domain name" } } } From 0a4de4725b7168ae7e865d7c1a561ae687f6881d Mon Sep 17 00:00:00 2001 From: Stephane de Labrusse Date: Fri, 15 Mar 2024 16:19:22 +0100 Subject: [PATCH 08/22] Add LDAP domain selection for user authentication --- ui/public/i18n/en/translation.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ui/public/i18n/en/translation.json b/ui/public/i18n/en/translation.json index 5cfafa9..3b61263 100644 --- a/ui/public/i18n/en/translation.json +++ b/ui/public/i18n/en/translation.json @@ -41,7 +41,10 @@ "configuring": "Configuring...", "email_format": "Invalid email address", "host_pattern": "Must be a valid fully qualified domain name", - "host_format": "Must be a valid fully qualified domain name" + "host_format": "Must be a valid fully qualified domain name", + "choose_the_ldap_domain_to_authenticate_users": "Choose the LDAP domain to authenticate users (empty to disable)", + "choose_ldap_domain": "Choose LDAP domain", + "internal_authentication": "Internal authentication" }, "about": { "title": "About" From e73b3883fc5cfd3a73c4fb7171b81105b6420068 Mon Sep 17 00:00:00 2001 From: Stephane de Labrusse Date: Fri, 15 Mar 2024 16:46:52 +0100 Subject: [PATCH 09/22] Update @nethserver/ns8-ui-lib version to 0.1.32 --- ui/package.json | 2 +- ui/yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ui/package.json b/ui/package.json index 2fffd13..fdab8e2 100644 --- a/ui/package.json +++ b/ui/package.json @@ -11,7 +11,7 @@ "dependencies": { "@carbon/icons-vue": "^10.37.0", "@carbon/vue": "^2.40.0", - "@nethserver/ns8-ui-lib": "^0.0.91", + "@nethserver/ns8-ui-lib": "^0.1.32", "await-to-js": "^3.0.0", "axios": "^0.21.2", "carbon-components": "^10.41.0", diff --git a/ui/yarn.lock b/ui/yarn.lock index 0561939..315d93b 100644 --- a/ui/yarn.lock +++ b/ui/yarn.lock @@ -1012,10 +1012,10 @@ call-me-maybe "^1.0.1" glob-to-regexp "^0.3.0" -"@nethserver/ns8-ui-lib@^0.0.91": - version "0.0.91" - resolved "https://registry.yarnpkg.com/@nethserver/ns8-ui-lib/-/ns8-ui-lib-0.0.91.tgz#9685e12233958007f2d10b48236f42bfd59d7c46" - integrity sha512-nfc31uumTaHfujuksPkiKgNKdG81ccpj80jD1/tcQcwvW9rLsIlJaT3XGwTeNPJ9d04WQ5SAIsCcn0gdQ0yPMw== +"@nethserver/ns8-ui-lib@^0.1.32": + version "0.1.32" + resolved "https://registry.npmmirror.com/@nethserver/ns8-ui-lib/-/ns8-ui-lib-0.1.32.tgz#7556dd5c7f96ff166597552c9b20e02599d86ba6" + integrity sha512-CqW+Qr65uFiKYe/cG0qahRD+3ojXhDxMJ8Mf8M9CXDHY0WSWygyGYAftLxF8rtQkOdGHlaYv7cSK7TctHggHGA== dependencies: "@rollup/plugin-json" "^4.1.0" core-js "^3.15.2" From c764b477c388aceaa7661188e15cd45be07cd157 Mon Sep 17 00:00:00 2001 From: Stephane de Labrusse Date: Fri, 15 Mar 2024 16:47:07 +0100 Subject: [PATCH 10/22] Refactor Settings.vue to conditionally render LDAP domain input --- ui/src/views/Settings.vue | 118 +++++++++++++++++++++++++------------- 1 file changed, 78 insertions(+), 40 deletions(-) diff --git a/ui/src/views/Settings.vue b/ui/src/views/Settings.vue index 14d6652..6cf4256 100644 --- a/ui/src/views/Settings.vue +++ b/ui/src/views/Settings.vue @@ -28,46 +28,48 @@ ref="wikiName" > - - - - - - - - + + + + { + this.ldap_domain = config.ldap_domain; + }); + this.ldap_domain_list = config.ldap_domain_list; + this.ldap_domain_list.unshift({ + name: "no_user_domain", + label: this.$t("settings.internal_authentication"), + value: "", + }); this.loading.getConfiguration = false; this.focusElement("wikiName"); }, @@ -377,6 +414,7 @@ export default { host: this.host, lets_encrypt: this.isLetsEncryptEnabled, http2https: this.isHttpToHttpsEnabled, + ldap_domain: this.ldap_domain, }, extra: { title: this.$t("settings.instance_configuration", { From 92615faaefa3013b2f17cf426abc192966c3cd11 Mon Sep 17 00:00:00 2001 From: Stephane de Labrusse Date: Fri, 15 Mar 2024 17:36:50 +0100 Subject: [PATCH 11/22] Update Dokuwiki configuration options in translation.json --- ui/public/i18n/en/translation.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/public/i18n/en/translation.json b/ui/public/i18n/en/translation.json index c00efe2..a4d9250 100644 --- a/ui/public/i18n/en/translation.json +++ b/ui/public/i18n/en/translation.json @@ -45,10 +45,10 @@ "instance_configuration": "Configure {instance}", "configuring": "Configuring...", "dokuwiki_note": "Note", - "must_be_configured_inside_dokuwiki": "You can configure only Dokuwiki FQDN in this page. To configure other setting go to Dokuwiki webapp", + "must_be_configured_inside_dokuwiki": "You can configure only Dokuwiki FQDN and authentication in this page. To configure other setting go to Dokuwiki webapp", "go_to_dokuwiki": "Go to Dokuwiki", "email_format": "Invalid email address", - "host_pattern": "Must be a valid fully qualified domain name", + "ldap_domain": "LDAP domain", "host_format": "Must be a valid fully qualified domain name", "choose_the_ldap_domain_to_authenticate_users": "Choose the LDAP domain to authenticate users (empty to disable)", "choose_ldap_domain": "Choose LDAP domain", From 14a0abacd63dd64a480d35011032467a0f5d0026 Mon Sep 17 00:00:00 2001 From: Stephane de Labrusse Date: Fri, 15 Mar 2024 17:37:24 +0100 Subject: [PATCH 12/22] Refactor Settings.vue component to disable input fields based on loading and already_set conditions --- ui/src/views/Settings.vue | 46 +++++++++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/ui/src/views/Settings.vue b/ui/src/views/Settings.vue index 208cbe9..b24928c 100644 --- a/ui/src/views/Settings.vue +++ b/ui/src/views/Settings.vue @@ -36,17 +36,25 @@ v-model.trim="wikiName" class="mg-bottom" :invalid-message="$t(error.wiki_name)" - :disabled="loading.getConfiguration || loading.configureModule || already_set" + :disabled=" + loading.getConfiguration || + loading.configureModule || + already_set + " ref="wikiName" > -