Skip to content

Commit ca6c12e

Browse files
authored
Merge pull request #25 from NethServer/LDAP
Add LDAP authentication
2 parents 689ab89 + c92ae1e commit ca6c12e

File tree

14 files changed

+334
-56
lines changed

14 files changed

+334
-56
lines changed

build-images.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ buildah add "${container}" ui/dist /ui
5353
buildah config --entrypoint=/ \
5454
--label="org.nethserver.tcp-ports-demand=1" \
5555
--label="org.nethserver.rootfull=0" \
56-
--label="org.nethserver.authorizations=traefik@any:routeadm" \
56+
--label="org.nethserver.authorizations=traefik@any:routeadm cluster:accountconsumer" \
5757
--label="org.nethserver.images=docker.io/bitnami/dokuwiki:20240206-debian-12" \
5858
"${container}"
5959
# Commit everything

imageroot/actions/configure-module/20configure

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,13 @@ username = data.get("username","admin")
4040
password = data.get("password","admin")
4141
email = data.get("email", "admin@example.org")
4242
full_name = data.get("user_full_name","Administrator")
43+
ldap_domain = data.get("ldap_domain", "")
44+
# bind user to the domain
45+
if ldap_domain:
46+
agent.bind_user_domains([ldap_domain])
47+
else:
48+
agent.bind_user_domains([])
49+
4350

4451
# Talk with agent using file descriptor.
4552
# Setup configuration from user input.
@@ -53,6 +60,9 @@ agent.set_env("DOKUWIKI_FULL_NAME", full_name)
5360
agent.set_env("PHP_ENABLE_OPCACHE", "1")
5461
agent.set_env("PHP_MEMORY_LIMIT", "512M")
5562

63+
# Setup LDAP domain
64+
agent.set_env("LDAP_DOMAIN", ldap_domain)
65+
5666
# Make sure everything is saved inside the environment file
5767
# just before starting systemd unit
5868
agent.dump_env()

imageroot/actions/configure-module/validate-input.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
"email",
2424
"host",
2525
"http2https",
26-
"lets_encrypt"
26+
"lets_encrypt",
27+
"ldap_domain"
2728
],
2829
"properties": {
2930
"wiki_name": {
@@ -61,6 +62,10 @@
6162
"type": "boolean",
6263
"title": "HTTP to HTTPS redirection",
6364
"description": "Redirect all the HTTP requests to HTTPS"
65+
},
66+
"ldap_domain": {
67+
"type": "string",
68+
"description": "LDAP domain name"
6469
}
6570
}
6671
}

imageroot/actions/get-configuration/20read

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import os
2828
import sys
2929
import json
3030
import agent
31+
from agent.ldapproxy import Ldapproxy
3132

3233
# Prepare return variable
3334
config = {}
@@ -43,6 +44,17 @@ config["user_full_name"] = rdb.hget(env, "DOKUWIKI_FULL_NAME");
4344
config["host"] = rdb.hget(env, "TRAEFIK_HOST");
4445
config["http2https"] = rdb.hget(env, "TRAEFIK_HTTP2HTTPS") == "True";
4546
config["lets_encrypt"] = rdb.hget(env, "TRAEFIK_LETS_ENCRYPT") == "True";
47+
# retrieve LDAP domains list
48+
lp = Ldapproxy()
49+
domains = []
50+
for key in lp.get_domains_list():
51+
domains.append({
52+
"name": key,
53+
"label": key,
54+
"value": key,
55+
})
4656

57+
config['ldap_domain_list'] = domains
58+
config['ldap_domain'] = os.environ.get("LDAP_DOMAIN",'')
4759
# Dump the configuratio to stdou
4860
json.dump(config, fp=sys.stdout)

imageroot/actions/get-configuration/validate-output.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
"email",
2424
"host",
2525
"http2https",
26-
"lets_encrypt"
26+
"lets_encrypt",
27+
"ldap_domain"
2728
],
2829
"properties": {
2930
"wiki_name": {
@@ -59,6 +60,10 @@
5960
"type": "boolean",
6061
"title": "HTTP to HTTPS redirection",
6162
"description": "Redirect all the HTTP requests to HTTPS"
63+
},
64+
"ldap_domain": {
65+
"type": "string",
66+
"description": "The LDAP domain name"
6267
}
6368
}
6469
}

imageroot/bin/discover-ldap

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#!/usr/bin/env python3
2+
3+
#
4+
# Copyright (C) 2024 Nethesis S.r.l.
5+
# SPDX-License-Identifier: GPL-3.0-or-later
6+
#
7+
8+
#
9+
# Find settings for LDAP service
10+
#
11+
12+
import os
13+
import agent
14+
from agent.ldapproxy import Ldapproxy
15+
16+
udomname = os.environ.get('LDAP_DOMAIN','')
17+
18+
try:
19+
odom = Ldapproxy().get_domain(udomname)
20+
'host' in odom # Throw exception if odom is None
21+
except:
22+
# During restore the domain could be unavailable. Use a fallback
23+
# configuration, pointing to nowhere, just to set the variables.
24+
# Once the domain becomes available, the event will fix them.
25+
odom = {
26+
'host': '127.0.0.1',
27+
'port': 20000,
28+
'schema': 'rfc2307',
29+
'location': 'internal',
30+
'base_dn': 'dc=dokuwiki,dc=invalid',
31+
'bind_dn': 'cn=example,dc=dokuwiki,dc=invalid',
32+
'bind_password': 'invalid',
33+
}
34+
35+
tmpfile = "discover.env." + str(os.getpid())
36+
37+
with open(tmpfile, "w") as denv:
38+
print('LDAP_PORT=' + str(odom['port']), file=denv)
39+
print('LDAP_USER=' + odom['bind_dn'], file=denv)
40+
print('LDAP_HOST=' + odom['host'], file=denv)
41+
print('LDAP_PASS=' + odom['bind_password'], file=denv)
42+
print('LDAP_SCHEMA=' + odom['schema'], file=denv)
43+
print('LDAP_BASE=' + odom['base_dn'], file=denv)
44+
45+
os.replace(tmpfile, "discovery_ldap.env")

imageroot/bin/wait-after-boot

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#!/bin/bash
2+
3+
#
4+
# Copyright (C) 2024 Nethesis S.r.l.
5+
# SPDX-License-Identifier: GPL-3.0-or-later
6+
#
7+
8+
# specific to dokuwiki, it creates its own configuration file after a long time boot
9+
10+
count=0
11+
while [[ $count -lt 60 ]]; do
12+
if podman exec -ti dokuwiki ls /bitnami/dokuwiki/conf/local.php.dist >/dev/null 2>&1; then
13+
echo "First Configuration done. We push custom configuration files."
14+
exit 0
15+
fi
16+
((count++))
17+
echo "Waiting for dokuwiki container to be ready..."
18+
sleep 1
19+
done
20+
21+
echo "Dokuwiki container is not ready after 60s. Exiting..."
22+
exit 1

imageroot/bin/write-ldap-conf

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#!/bin/bash
2+
3+
#
4+
# Copyright (C) 2024 Nethesis S.r.l.
5+
# SPDX-License-Identifier: GPL-3.0-or-later
6+
#
7+
8+
# Retrieving environment variables
9+
LDAP_DOMAIN=${LDAP_DOMAIN}
10+
LDAP_PORT=${LDAP_PORT}
11+
LDAP_USER=${LDAP_USER}
12+
LDAP_HOST=${LDAP_HOST}
13+
LDAP_PASS=${LDAP_PASS}
14+
LDAP_SCHEMA=${LDAP_SCHEMA}
15+
LDAP_BASE=${LDAP_BASE}
16+
17+
mkdir -vp dokuwiki-config
18+
cat <<EOF > dokuwiki-config/local.protected.php
19+
<?php
20+
/**
21+
* this is file is generated by the dokuwki container automatically
22+
* do not edit it manually
23+
*/
24+
EOF
25+
# Check the value of $LDAP_DOMAIN
26+
if [[ "$LDAP_DOMAIN" == "" ]]; then
27+
cat <<EOF >> dokuwiki-config/local.protected.php
28+
\$conf['authtype'] = 'authplain';
29+
EOF
30+
31+
elif [[ "$LDAP_DOMAIN" != "" ]]; then
32+
if [[ "$LDAP_SCHEMA" == "rfc2307" ]]; then
33+
cat <<EOF >> dokuwiki-config/local.protected.php
34+
\$conf['authtype'] = 'authldap';
35+
\$conf['plugin'][\$conf['authtype']]['server'] = "ldap://accountprovider:${LDAP_PORT}";
36+
\$conf['plugin'][\$conf['authtype']]['version'] = '3';
37+
\$conf['plugin'][\$conf['authtype']]['usertree'] = "ou=People,${LDAP_BASE}";
38+
\$conf['plugin'][\$conf['authtype']]['grouptree'] = "ou=Groups,${LDAP_BASE}";
39+
\$conf['plugin'][\$conf['authtype']]['userfilter'] = '(|(uid=%{user})(mail=%{user}))';
40+
\$conf['plugin']['authldap']['groupfilter'] = '(memberUid=%{uid})';
41+
\$conf['plugin'][\$conf['authtype']]['groupkey'] = 'cn';
42+
\$conf['plugin']['authldap']['binddn'] = "${LDAP_USER}";
43+
\$conf['plugin']['authldap']['bindpw'] = "${LDAP_PASS}";
44+
\$conf['plugin']['authldap']['starttls'] = 0;
45+
\$conf['plugin']['authldap']['modPass'] = 0;
46+
EOF
47+
elif [[ "$LDAP_SCHEMA" == "ad" ]]; then
48+
cat <<EOF >> dokuwiki-config/local.protected.php
49+
\$conf['authtype'] = 'authad';
50+
\$conf['plugin']['authad']['account_suffix'] = '@${LDAP_DOMAIN}';
51+
\$conf['plugin']['authad']['base_dn'] = '${LDAP_BASE}';
52+
\$conf['plugin']['authad']['domain_controllers'] = 'ldap://accountprovider:${LDAP_PORT}'; //multiple can be given
53+
\$conf['plugin']['authad']['use_tls'] = 0;
54+
EOF
55+
56+
fi
57+
fi
58+
cat <<EOF >> dokuwiki-config/local.protected.php
59+
\$conf['useacl'] = 1;
60+
\$conf['superuser'] = 'admin,admin@${LDAP_DOMAIN},administrator,administrator@${LDAP_DOMAIN}';
61+
EOF
62+
63+
echo "Configuration written to dokuwiki-config/local.protected.php"
64+
65+
cat <<EOF > dokuwiki-config/plugins.local.php
66+
<?php
67+
/*
68+
* Local plugin enable/disable settings
69+
*
70+
* Auto-generated by install s
71+
*/
72+
73+
\$plugins['authad'] = 1;
74+
\$plugins['authldap'] = 1;
75+
\$plugins['authmysql'] = 0;
76+
\$plugins['authpgsql'] = 0;
77+
EOF
78+
echo "Configuration written to dokuwiki-config/plugins.local.php"
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#!/usr/bin/env python3
2+
3+
#
4+
# Copyright (C) 2024 Nethesis S.r.l.
5+
# SPDX-License-Identifier: GPL-3.0-or-later
6+
#
7+
8+
import json
9+
import sys
10+
import agent
11+
import os
12+
13+
event = json.load(sys.stdin)
14+
15+
if event.get('domain') != os.getenv('LDAP_DOMAIN'):
16+
exit(0)
17+
18+
if 'node' in event and str(event['node']) != os.getenv('NODE_ID'):
19+
exit(0) # ignore event if the source is not in our node
20+
21+
agent.run_helper('systemctl', '--user', '-T', 'try-restart', 'dokuwiki.service').check_returncode()

imageroot/systemd/user/dokuwiki.service

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,27 @@ Environment=PODMAN_SYSTEMD_UNIT=%n
1111
# - DOKUWIKI_IMAGE: the podman/docker image to rung
1212
# - TCP_PORT, TCP_PORTS: the random ports assigned by system
1313
EnvironmentFile=%S/state/environment
14+
EnvironmentFile=-%S/state/discovery_ldap.env
1415
WorkingDirectory=%S/state
1516
Restart=always
17+
ExecStartPre=/usr/local/bin/runagent discover-ldap
18+
ExecStartPre=/usr/local/bin/runagent write-ldap-conf
1619
ExecStartPre=/bin/rm -f %t/dokuwiki.pid %t/dokuwiki.ctr-id
1720
# Podman should bind only to 127.0.0.1:TCP_PORT
1821
# Data are persistend inside dokuwiki-data volume
19-
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}
22+
ExecStart=/usr/bin/podman run --conmon-pidfile %t/dokuwiki.pid \
23+
--cidfile %t/dokuwiki.ctr-id \
24+
--cgroups=no-conmon \
25+
--replace --name dokuwiki -d \
26+
--env-file=%S/state/environment \
27+
--publish 127.0.0.1:${TCP_PORT}:8080 \
28+
--volume dokuwiki-data:/bitnami/dokuwiki:z \
29+
--network=slirp4netns:allow_host_loopback=true \
30+
--add-host=accountprovider:10.0.2.2 \
31+
${DOKUWIKI_IMAGE}
32+
ExecStartPost=/usr/local/bin/runagent wait-after-boot
33+
ExecStartPost=podman cp ./dokuwiki-config/local.protected.php dokuwiki:/bitnami/dokuwiki/conf/local.protected.php
34+
ExecStartPost=podman cp ./dokuwiki-config/plugins.local.php dokuwiki:/bitnami/dokuwiki/conf/plugins.local.php
2035
ExecStop=/usr/bin/podman stop --ignore --cidfile %t/dokuwiki.ctr-id -t 10
2136
ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/dokuwiki.ctr-id
2237
PIDFile=%t/dokuwiki.pid

0 commit comments

Comments
 (0)