From dd585a7a6942810666dc7356105728551d2c0df2 Mon Sep 17 00:00:00 2001 From: Michael Lux Date: Wed, 20 Dec 2017 14:27:01 +0100 Subject: [PATCH] adaptations for official ChurchTools interface --- CHANGELOG.md | 3 +++ README.md | 28 ++++++++++++---------- ctldap.example.config | 13 +++++----- ctldap.js | 55 +++++++++++++++++++++++++++++++++++++------ ctldap_raw.sh | 4 ++-- install.sh | 30 +++++++++++++++-------- 6 files changed, 95 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 943f1b0..257155d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,7 @@ # Changelog +### 2.0 +- adapted to built-in ChurchTools ctldap API + ### 1.0.1 - re-added missing autoload code to PHP API \ No newline at end of file diff --git a/README.md b/README.md index eb4ee62..2224a89 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# LDAP Wrapper for ChurchTools v1.0.1 +# LDAP Wrapper for ChurchTools v2.0 -This software acts as an LDAP server for ChurchTools version 3.x +This software acts as an LDAP server for ChurchTools >= 3.25.0 **This software was tested in a common environment, yet no warranties of any kind!** @@ -13,14 +13,20 @@ http://nodejs.org/ ### Run the install.sh script as root user. It will - run "npm install" to install required Node.js dependencies for the server - create a new user "ctldap" to run the server with limited privileges -- create log/error log files for stdout/stderr output and set the required ownership attributes -- create the configuration file with secure random keys and offer to adapt it, asking for reset if it already exists -- (optionally) adapt and create the ctldap.sh file in /etc/init.d and call "update-rc.d ctldap.sh defaults" +- create the configuration file, asking for a reset if it already exists +- *[new config or reset]* ask for the ChurchTools domain (and directory) +- *[new config or reset]* ask for the ChurchTools API user credentials and insert them into the config file +- *[new config or reset]* insert a secure random LDAP root user password into the config file +- *[new config or reset]* offer to customize the config file +- *optionally adapt and create the ctldap.sh file in /etc/init.d and call "update-rc.d ctldap.sh defaults"* #### ctldap.sh remarks: -The file "ctldap.sh" contains a shell script for (re)starting ctldap.sh with Node.js as a background service. -It will attempt to create/remove an iptables NAT rule on start/stop in order to redirect traffic from a standard LDAP port (< 1024) to ldap_port without root. -The script can be used to start/stop the service manually, but will not work correctly without root privileges. +The file "ctldap.sh" contains a shell script for (re)starting ctldap.sh with Node.js as a background service, redirecting all output to the system log with systemd-cat. The logs can be reviewed with the shell command `journalctl -t ctldap`. See https://wiki.ubuntuusers.de/systemd/journalctl/ for further options. + +The script will attempt to create/remove an iptables NAT rule on start/stop in order to redirect traffic from a standard LDAP port (< 1024) to ldap_port without root. + +It can be used to start/stop the service manually, but will not work correctly without root privileges! + Usage: ctldap.sh {start|stop|status|restart} ### If you don't have root privileges: @@ -28,12 +34,8 @@ Usage: ctldap.sh {start|stop|status|restart} - copy "ctldap.example.config" to "ctldap.config" and adjust the required settings accordingly - register "ctldap.js" to be run by Node.js, or start the server directly by executing `node ctldap.js` -## PHP API install -- copy the contents of "php_api" to the root folder of your ChurchTools installation (the composer.* files can be safely ignored) -- copy the line "api_key=" from your "ctldap.config" to your ChuchTools configuration at /sites/[default|subdomain]/churchtools.config - # Usage -The LDAP DNs depend on your configuration. We assume the following configuration: +The LDAP DNs depend on your configuration. Let's assume the following configuration: ``` ldap_user=root ldap_password=0a1b2c3d4e5f6g7h8i9j diff --git a/ctldap.example.config b/ctldap.example.config index 02a20e1..7abc284 100644 --- a/ctldap.example.config +++ b/ctldap.example.config @@ -16,11 +16,12 @@ iptables_port=389 ldap_base_dn=churchtools ; The URI pointing to the root of your ChurchTools installation -ct_uri=https://mghh.churchtools.de/ -; This API key is used to authenticate against the PHP API -; IMPORTANT: AFTER using install.sh or choosing a LONG SECURE RANDOM API key from a password generator like KeePass, -; copy this line into your CT configuration at /sites/[default|subdomain]/churchtools.config -api_key=XXXXXXXXXXXXXXXXXXXX +ct_uri=https://mysite.church.tools/ +; This user credentials are used to authenticate against ChurchTools for API access +; The user must be granted "churchcore:administer persons" and "churchdb:view" rights for the wrapper to work properly! +; IMPORTANT: It is strongly recommended to use a LONG SECURE RANDOM password from a generator like KeePass for this user! +api_user=XXXXXXXXXXXXXXXXXXXX +api_password=XXXXXXXXXXXXXXXXXXXX ; This controls (in milliseconds) how old the user/group data can be until it is fetched from ChurchTools again cache_lifetime=10000 @@ -30,4 +31,4 @@ cache_lifetime=10000 ; Use this command to remove the encryption password: ; openssl rsa -in key.pem -out newkey.pem && mv newkey.pem key.pem ; ldap_cert_filename=cert.pem -; ldap_key_filename=key.pem +; ldap_key_filename=key.pem \ No newline at end of file diff --git a/ctldap.js b/ctldap.js index c6da6b2..6c53956 100644 --- a/ctldap.js +++ b/ctldap.js @@ -1,5 +1,5 @@ -// ChurchTools 3.2 LDAP-Wrapper -// This tool requires a node.js-Server +// ChurchTools LDAP-Wrapper 2.0 +// This tool requires a node.js-Server and ChurchTools >= 3.25.0 // (c) 2017 Michael Lux // License: GNU/GPL v3.0 @@ -20,6 +20,8 @@ if (config.debug) { var fnUserDn = ldapEsc.dn("cn=${cn},ou=users,o=" + config.ldap_base_dn); var fnGroupDn = ldapEsc.dn("cn=${cn},ou=groups,o=" + config.ldap_base_dn); var adminDn = fnUserDn({ cn: config.ldap_user }); +var cookieJar = rp.jar(); +var loginPromise = null; if (config.dn_lower_case) { var compatTransform = function (s) { @@ -40,26 +42,65 @@ if (config.ldap_cert_filename && config.ldap_key_filename) { } if (typeof config.cache_lifetime !== 'number') { - config.cache_lifetime = 10000; + config.cache_lifetime = 10000; // 10 seconds } if (config.ct_uri.slice(-1) !== "/") { config.ct_uri += "/"; } +/** + * Returns a promise for the login on the ChurchTools API. + * If a pending login promise already exists, it is returned right away. + */ +function apiLogin() { + if (loginPromise === null) { + loginPromise = rp({ + "method": "POST", + "jar": cookieJar, + "uri": config.ct_uri + "?q=login/ajax", + "form": { + "func": "login", + "email": config.api_user, + "password": config.api_password + }, + "json": true + }).then(function (result) { + if (result.status !== "success") { + throw result.message; + } + // clear login promise + loginPromise = null; + // end gracefully + return null; + }); + } + return loginPromise; +} + /** * Retrieves data from the PHP API via a POST call. * @param {function} func - The function to call in the API class * @param {object} [data] - The optional form data to pass along with the POST request + * @param {boolean} [triedLogin] - Is true if this is the second attempt after API login */ -function apiPost(func, data) { +function apiPost(func, data, triedLogin) { return rp({ "method": "POST", - "uri": config.ct_uri + "api.php/API/" + func, - "form": extend({ api_key: config.api_key }, data || {}), + "jar": cookieJar, + "uri": config.ct_uri + "?q=churchdb/ajax", + "form": extend({ "func": func }, data || {}), "json": true }).then(function (result) { if (result.status !== "success") { - throw result.status; + // If session has expired, get a login Promise and await login + if (result.message === "Session expired!" && !triedLogin) { + // Remember that we tried to login to prevent looping + return apiLogin().then(function () { + // Retry operation after login + return apiPost(func, data, true); + }); + } + throw result.message; } return result.data; }); diff --git a/ctldap_raw.sh b/ctldap_raw.sh index 03f62b7..fbefa49 100644 --- a/ctldap_raw.sh +++ b/ctldap_raw.sh @@ -6,7 +6,7 @@ # Required-Stop: $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 -# Short-Description: ChurchTools 3.2 LDAP-Wrapper +# Short-Description: ChurchTools LDAP-Wrapper v2.0 # Description: Init script for the ChurchTools LDAP Wrapper. ### END INIT INFO @@ -32,7 +32,7 @@ start) sh $DIR/$0 stop fi fi - su -c "nohup node $CTLDAP/ctldap.js 2>>$CTLDAP/error.log >>$CTLDAP/output.log &" - ctldap + su -c "systemd-cat -t ctldap node $CTLDAP/ctldap.js &" - ctldap PID=$( ps axf | grep "node $CTLDAP/ctldap.js" | grep -v grep | awk '{print $1}' ) if [ -z "$PID" ]; then echo "Fail" diff --git a/install.sh b/install.sh index d4eebe0..c87653d 100644 --- a/install.sh +++ b/install.sh @@ -1,6 +1,6 @@ #!/bin/bash -# ChurchTools 3.2 LDAP-Wrapper +# ChurchTools LDAP-Wrapper 2.0 # (c) 2017 Michael Lux # License: GNU/GPL v3.0 @@ -24,22 +24,32 @@ echo "Now creating the \"ctldap\" user..." useradd ctldap echo "" -echo "Init logging files..." -touch output.log -touch error.log -chown ctldap:ctldap *.log -echo "" - ANSWER="y" if [ -f "ctldap.config" ]; then read -n1 -p "Reset configuration file? [y/n]" ANSWER echo "" fi if [ $ANSWER = "y" ]; then - PRNG_CMD="tr -cd '[:alnum:]' < /dev/urandom | fold -w20 | head -n1" + PRNG_PASSWORD=$(tr -cd '[:alnum:]' < /dev/urandom | fold -w20 | head -n1) + echo "" + echo "The new password for the LDAP root user is: $PRNG_PASSWORD" + echo "" + read -r -p "Please enter the domain (and directory) of your ChurchTools installation (example: mychurch.church.tools): " CTLOC + echo "Assumed (HTTPS) ChurchTools URL: https://$CTLOC/" + echo "If this is wrong, please fix it manually when the configuration file is opened for customization." + echo "" + read -r -p "Please enter ChurchTools username for authentication: " USERNAME + read -r -p "Please enter ChurchTools user password for authentication: " PASSWORD cat ctldap.example.config | \ - sed "s/ldap_password=XXXXXXXXXXXXXXXXXXXX/ldap_password=$(eval ${PRNG_CMD})/" | \ - sed "s/api_key=XXXXXXXXXXXXXXXXXXXX/api_key=$(eval ${PRNG_CMD})/" > ctldap.config + sed "s?mysite.church.tools?$CTLOC?" | \ + sed "s/ldap_password=XXXXXXXXXXXXXXXXXXXX/ldap_password=$PRNG_PASSWORD/" | \ + sed "s/api_user=XXXXXXXXXXXXXXXXXXXX/api_user=$USERNAME/" | \ + sed "s/api_password=XXXXXXXXXXXXXXXXXXXX/api_password=$PASSWORD/" > ctldap.config + echo "" + echo "Don't forget to grant your ChurchTools API user this privileges:" + echo "- churchcore:administer persons (Required to access the user data)" + echo "- churchdb:view (Required for ChurchDB API access)" + echo "" fi echo "Trying to open ctldap.config now, modify it according to your needs!"