From 05a4a5a9d3b31f78ca2c9c15b230c865d9b33066 Mon Sep 17 00:00:00 2001 From: Nils VAN ZUIJLEN Date: Mon, 1 Mar 2021 09:43:17 +0100 Subject: [PATCH] Make installation work - Use vendored source - Update LDAP settings - Update nginx config - Rename _common(s).sh - Use a CSRF aware local_curl - Remove/update old patches Also trim remove, restore, upgrade and backup scripts --- conf/app.src | 6 +- conf/cron | 2 +- conf/ldap.sql | 36 +- conf/nginx.conf | 33 +- scripts/_common.sh | 79 ++++ scripts/_commons.sh | 21 - scripts/backup | 6 - scripts/install | 199 +++------ scripts/remove | 15 +- scripts/restore | 164 ++++++-- scripts/upgrade | 281 ++++++++++--- sources/fix/AuthClientHelpers.php | 261 ------------ sources/fix/ZendLdapClient.php | 380 ------------------ sources/patches/app-00-no-password-ldap.patch | 13 + sources/version | 2 +- 15 files changed, 542 insertions(+), 956 deletions(-) create mode 100644 scripts/_common.sh delete mode 100644 scripts/_commons.sh delete mode 100644 sources/fix/AuthClientHelpers.php delete mode 100644 sources/fix/ZendLdapClient.php create mode 100644 sources/patches/app-00-no-password-ldap.patch diff --git a/conf/app.src b/conf/app.src index 0e8d690..6a1eea7 100644 --- a/conf/app.src +++ b/conf/app.src @@ -1,7 +1,7 @@ -SOURCE_URL=https://github.com/humhub/humhub/archive/v1.7.2.tar.gz -SOURCE_SUM=dd02b47f995bace4e03aff4750772abaab205769c75ef9f22904171b7649c689 +SOURCE_URL=https://www.humhub.com/download/package/humhub-1.7.2.tar.gz +SOURCE_SUM=e20e6f8d321a0d5c8907b00465846a4d57432fe386181ca6c73ad27a9967e83a SOURCE_SUM_PRG=sha256sum SOURCE_FORMAT=tar.gz SOURCE_IN_SUBDIR=true -SOURCE_FILENAME= +SOURCE_FILENAME=humhub-1.7.2.tar.gz SOURCE_EXTRACT=true diff --git a/conf/cron b/conf/cron index ac9af3a..a0bc207 100644 --- a/conf/cron +++ b/conf/cron @@ -1,2 +1,2 @@ * * * * * /usr/bin/php__PHPVERSION__ __FINALPATH__/protected/yii queue/run >/dev/null 2>&1 -* * * * * /usr/bin/php__PHPVERSION__ __FINALPATH__/protected/yii cron/run >/dev/null 2>&1 \ No newline at end of file +* * * * * /usr/bin/php__PHPVERSION__ __FINALPATH__/protected/yii cron/run >/dev/null 2>&1 diff --git a/conf/ldap.sql b/conf/ldap.sql index 58820ec..53ff5e7 100644 --- a/conf/ldap.sql +++ b/conf/ldap.sql @@ -1,18 +1,28 @@ -REPLACE INTO setting (`name`, `value`, `module_id`) VALUES -('auth.ldap.enabled', '1', 'user'), -('auth.ldap.hostname', 'localhost', 'user'), -('auth.ldap.port', '389', 'user'), -('auth.ldap.encryption', '', 'user'), -('auth.ldap.username', '', 'user'), -('auth.ldap.password', '', 'user'), -('auth.ldap.baseDn', 'ou=users,dc=yunohost,dc=org', 'user'), -('auth.ldap.loginFilter', '(uid=%s)', 'user'), -('auth.ldap.userFilter', 'objectClass=mailAccount', 'user'), -('auth.ldap.emailAttribute', 'mail', 'user'), -('auth.ldap.usernameAttribute', 'uid', 'user'), -('auth.ldap.refreshUsers', '1', 'user'), +BEGIN; + +DELETE FROM setting WHERE +(`name` = 'auth.anonymousRegistration') OR +(`name` = 'auth.allowGuestAccess') OR +(`name` = 'auth.internalUsersCanInvite'); + +INSERT INTO setting (`name`, `value`, `module_id`) VALUES +('enabled', '1', 'ldap'), +('hostname', 'localhost', 'ldap'), +('port', '389', 'ldap'), +('encryption', '', 'ldap'), +('username', '', 'ldap'), +('password', '', 'ldap'), +('baseDn', 'ou=users,dc=yunohost,dc=org', 'ldap'), +('loginFilter', '(uid=%s)', 'ldap'), +('userFilter', 'objectClass=mailAccount', 'ldap'), +('emailAttribute', 'mail', 'ldap'), +('usernameAttribute', 'uid', 'ldap'), +('idAttribute', 'uid', 'ldap'), +('refreshUsers', '1', 'ldap'), ('auth.anonymousRegistration', '0', 'user'), ('auth.allowGuestAccess', '0', 'user'), ('auth.internalUsersCanInvite', '0', 'user'); UPDATE `user` SET `auth_mode` = 'ldap' WHERE `user`.`username` = '__ADMIN__'; + +COMMIT; diff --git a/conf/nginx.conf b/conf/nginx.conf index 6333bd4..ebb051e 100644 --- a/conf/nginx.conf +++ b/conf/nginx.conf @@ -2,7 +2,7 @@ location __PATH__/ { # Path to source - alias __FINALPATH__/ ; + alias __FINALPATH__/ ; index index.php; @@ -10,28 +10,29 @@ location __PATH__/ { location ~ [^/]\.php(/|$) { fastcgi_split_path_info ^(.+?\.php)(/.*)$; - fastcgi_pass unix:/var/run/php__PHPVERSION__-fpm-__NAME__.sock; + + set $fsn /index.php; + if (-f $document_root$fastcgi_script_name){ + set $fsn $fastcgi_script_name; + } + + fastcgi_pass unix:/var/run/php/php__PHPVERSION__-fpm-__NAME__.sock; fastcgi_index index.php; include fastcgi_params; fastcgi_param REMOTE_USER $remote_user; fastcgi_param PATH_INFO $fastcgi_path_info; - fastcgi_param SCRIPT_FILENAME $request_filename; + fastcgi_param SCRIPT_FILENAME $document_root$fsn; } - location ~ ^__PATH__/(?:ico|css|js|gif|jpe?g|png|ttf|woff)$ { - access_log off; - expires 30d; - add_header Pragma public; - add_header Cache-Control "public, mustrevalidate, proxy-revalidate"; - } + location ~ ^__PATH__/(assets|static|themes|uploads) { + access_log off; + expires 10d; + add_header Cache-Control "public, no-transform"; + } - location = __PATH__/protected { - deny all; - } - - location = __PATH__/uploads/file { - deny all; - } + location ~ ^__PATH__/(protected|framework|themes/\w+/views|\.|uploads/file) { + deny all; + } # Include SSOWAT user panel. include conf.d/yunohost_panel.conf.inc; diff --git a/scripts/_common.sh b/scripts/_common.sh new file mode 100644 index 0000000..7123bfb --- /dev/null +++ b/scripts/_common.sh @@ -0,0 +1,79 @@ +#!/bin/bash + +#================================================= +# COMMON VARIABLES +#================================================= + +YNH_PHP_VERSION="7.3" + +extra_php_dependencies="php${YNH_PHP_VERSION}-imagick php${YNH_PHP_VERSION}-curl php${YNH_PHP_VERSION}-bz2 php${YNH_PHP_VERSION}-gd php${YNH_PHP_VERSION}-intl php${YNH_PHP_VERSION}-mysql php${YNH_PHP_VERSION}-zip php${YNH_PHP_VERSION}-apcu-bc php${YNH_PHP_VERSION}-apcu php${YNH_PHP_VERSION}-xml php${YNH_PHP_VERSION}-ldap" + +#================================================= +# PERSONAL HELPERS +#================================================= + +local_curl_csrf () { + # Define url of page to curl + local local_page=$(ynh_normalize_url_path $1) + local full_path=$path_url$local_page + + if [ "${path_url}" == "/" ]; then + full_path=$local_page + fi + + local full_page_url=https://localhost$full_path + + # Concatenate all other arguments with '&' to prepare POST data + local POST_data="" + local arg="" + for arg in "${@:2}" + do + POST_data="${POST_data}${arg}&" + done + if [ -n "$POST_data" ] + then + # Add --data arg and remove the last character, which is an unecessary '&' + POST_data="--data ${POST_data::-1}" + fi + + # Wait untils nginx has fully reloaded (avoid curl fail with http2) + sleep 2 + + local cookiefile=/tmp/ynh-$app-cookie.txt + touch $cookiefile + chown root $cookiefile + chmod 700 $cookiefile + + # Curl the URL for the CSRF token + local token_line=`curl --silent --show-error --insecure --location --header "Host: $domain" --resolve $domain:443:127.0.0.1 "$full_page_url" --cookie-jar $cookiefile --cookie $cookiefile | grep 'meta name="csrf-token"'` + + token_line=${token_line##*content=\"} + local csrf=${token_line%%\">*} + POST_data="${POST_data}&_csrf=${csrf}" + + curl --silent --show-error --insecure --location --header "Host: $domain" --resolve $domain:443:127.0.0.1 $POST_data "$full_page_url" --cookie-jar $cookiefile --cookie $cookiefile +} + +#Convert --data to --data-urlencode before ynh_local_curl +myynh_urlencode() { + local data + if [[ $# != 1 ]]; then + echo "Usage: $0 string-to-urlencode" + return 1 + fi + data="$(curl -s -o /dev/null -w %{url_effective} --get --data-urlencode "$1" "")" + if [[ $? != 3 ]]; then + echo "Unexpected error" 1>&2 + return 2 + fi + echo "${data##/?}" + return 0 +} + +#================================================= +# EXPERIMENTAL HELPERS +#================================================= + +#================================================= +# FUTURE OFFICIAL HELPERS +#================================================= diff --git a/scripts/_commons.sh b/scripts/_commons.sh deleted file mode 100644 index e84d91c..0000000 --- a/scripts/_commons.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash - -#================================================= -# COMMON VARIABLES -#================================================= - -YNH_PHP_VERSION="7.3" - -extra_php_dependencies="php${YNH_PHP_VERSION}-imagick php${YNH_PHP_VERSION}-curl php${YNH_PHP_VERSION}-bz2 php${YNH_PHP_VERSION}-gd php${YNH_PHP_VERSION}-intl php${YNH_PHP_VERSION}-mysql php${YNH_PHP_VERSION}-zip php${YNH_PHP_VERSION}-apcu-bc php${YNH_PHP_VERSION}-apcu php${YNH_PHP_VERSION}-xml php${YNH_PHP_VERSION}-ldap" - -#================================================= -# PERSONAL HELPERS -#================================================= - -#================================================= -# EXPERIMENTAL HELPERS -#================================================= - -#================================================= -# FUTURE OFFICIAL HELPERS -#================================================= diff --git a/scripts/backup b/scripts/backup index 5ea23bb..d01a608 100644 --- a/scripts/backup +++ b/scripts/backup @@ -58,12 +58,6 @@ ynh_backup --src_path="/etc/php/$phpversion/fpm/pool.d/$app.conf" #================================================= # SPECIFIC BACKUP -#================================================= -# BACKUP SYSTEMD -#================================================= - -ynh_backup --src_path="/etc/systemd/system/$app.service" - #================================================= # BACKUP VARIOUS FILES #================================================= diff --git a/scripts/install b/scripts/install index 4da467a..eb8abe1 100644 --- a/scripts/install +++ b/scripts/install @@ -53,22 +53,6 @@ ynh_app_setting_set --app=$app --key=admin --value=$admin #================================================= # STANDARD MODIFICATIONS -#================================================= -# FIND AND OPEN A PORT -#================================================= -ynh_script_progression --message="Finding an available port..." --time --weight=1 - -# Find an available port -port=$(ynh_find_port --port=8095) -ynh_app_setting_set --app=$app --key=port --value=$port - -#================================================= -# INSTALL DEPENDENCIES -#================================================= -ynh_script_progression --message="Installing dependencies..." --time --weight=1 - -ynh_install_app_dependencies $pkg_dependencies - #================================================= # CREATE A MYSQL DATABASE #================================================= @@ -116,9 +100,22 @@ phpversion=$(ynh_app_setting_get --app=$app --key=phpversion) #================================================= # SPECIFIC SETUP #================================================= -# ... +# SETUP SQL CREDENTIALS #================================================= +ynh_add_config --template="../conf/common.php" --destination="$final_path/protected/config/common.php" + +#================================================= +# DEACTIVATE DEBUG MODE +#================================================= + +ynh_replace_string --match_string="defined('YII_DEBUG') or define('YII_DEBUG', true);"\ + --replace_string="// defined('YII_DEBUG') or define('YII_DEBUG', true);"\ + --target_file="$final_path/index.php" +ynh_replace_string --match_string="defined('YII_ENV') or define('YII_ENV', 'dev');"\ + --replace_string="// defined('YII_ENV') or define('YII_ENV', 'dev');"\ + --target_file="$final_path/index.php" + #================================================= # SETUP APPLICATION WITH CURL #================================================= @@ -143,7 +140,36 @@ ynh_systemd_action --service_name=nginx --action=reload # Installation with curl ynh_script_progression --message="Finalizing installation..." --time --weight=1 -ynh_local_curl "/INSTALL_PATH" "key1=value1" "key2=value2" "key3=value3" + +admin_temp_pass=$(ynh_string_random 6) +admin_email=$(yunohost user info "$admin" --output-as plain | ynh_get_plain_key mail) +admin_firstname=$(yunohost user info "$admin" --output-as plain | ynh_get_plain_key firstname) +admin_lastname=$(yunohost user info "$admin" --output-as plain | ynh_get_plain_key lastname) + +ynh_local_curl "/index.php?r=installer/index/go" + +local_curl_csrf "/index.php?r=installer/config/basic" \ + "ConfigBasicForm[name]=YunoHost" + +local_curl_csrf "/index.php?r=installer/config/use-case" \ + "UseCaseForm[useCase]=" \ + "UseCaseForm[useCase]=other" + +local_curl_csrf "/index.php?r=installer/config/admin" \ + `myynh_urlencode "User[username]=$admin"` \ + `myynh_urlencode "User[email]=$admin_email"` \ + `myynh_urlencode "Password[newPassword]=$admin_temp_pass"` \ + `myynh_urlencode "Password[newPasswordConfirm]=$admin_temp_pass"` \ + `myynh_urlencode "Profile[firstname]=${admin_firstname}"` \ + `myynh_urlencode "Profile[lastname]=${admin_lastname}"` \ + "save" + +local_curl_csrf "/index.php?r=installer/config/sample-data" \ + "SampleDataForm[sampleData]=0" + +# Populate the LDAP parameters +sed -i "s@__ADMIN__@$admin@g" ../conf/ldap.sql +mysql -u $db_user -p${db_pwd} $db_name < ../conf/ldap.sql # Remove the public access ynh_permission_update --permission="main" --remove="visitors" @@ -152,10 +178,6 @@ ynh_permission_update --permission="main" --remove="visitors" # MODIFY A CONFIG FILE #================================================= -ynh_add_config --template="../conf/common.php" --destination="$final_path/protected/config/common.php" - -ynh_replace_string --match_string="match_string" --replace_string="replace_string" --target_file="$final_path/CONFIG_FILE" - #================================================= # STORE THE CONFIG FILE CHECKSUM #================================================= @@ -165,7 +187,7 @@ ynh_replace_string --match_string="match_string" --replace_string="replace_strin ### you can make a backup of this file before modifying it again if the admin had modified it. # Calculate and store the config file checksum into the app settings -ynh_store_file_checksum --file="$final_path/CONFIG_FILE" +ynh_store_file_checksum --file="$final_path/protected/config/common.php" #================================================= # GENERIC FINALIZATION @@ -174,70 +196,19 @@ ynh_store_file_checksum --file="$final_path/CONFIG_FILE" #================================================= # Set permissions to app files -chown -R www-data: $final_path +chown -R root: $final_path + +chown -R $app $final_path/assets +chown -R $app $final_path/protected/config +chown -R $app $final_path/protected/modules +chown -R $app $final_path/protected/runtime +chown -R $app $final_path/uploads/* #================================================= -# SETUP LOGROTATE +# SETUP CRON CONFIGURATION #================================================= -ynh_script_progression --message="Configuring log rotation..." --time --weight=1 -### `ynh_use_logrotate` is used to configure a logrotate configuration for the logs of this app. -### Use this helper only if there is effectively a log file for this app. -### If you're not using this helper: -### - Remove the section "BACKUP LOGROTATE" in the backup script -### - Remove also the section "REMOVE LOGROTATE CONFIGURATION" in the remove script -### - As well as the section "RESTORE THE LOGROTATE CONFIGURATION" in the restore script -### - And the section "SETUP LOGROTATE" in the upgrade script - -# Use logrotate to manage application logfile(s) -ynh_use_logrotate - -#================================================= -# INTEGRATE SERVICE IN YUNOHOST -#================================================= -ynh_script_progression --message="Integrating service in YunoHost..." --time --weight=1 - -yunohost service add $app --description="A short description of the app" --log="/var/log/$app/$app.log" - -### Additional options starting with 3.8: -### -### --needs_exposed_ports "$port" a list of ports that needs to be publicly exposed -### which will then be checked by YunoHost's diagnosis system -### (N.B. DO NOT USE THIS is the port is only internal!!!) -### -### --test_status "some command" a custom command to check the status of the service -### (only relevant if 'systemctl status' doesn't do a good job) -### -### --test_conf "some command" some command similar to "nginx -t" that validates the conf of the service -### -### Re-calling 'yunohost service add' during the upgrade script is the right way -### to proceed if you later realize that you need to enable some flags that -### weren't enabled on old installs (be careful it'll override the existing -### service though so you should re-provide all relevant flags when doing so) - -#================================================= -# START SYSTEMD SERVICE -#================================================= -ynh_script_progression --message="Starting a systemd service..." --time --weight=1 - -### `ynh_systemd_action` is used to start a systemd service for an app. -### Only needed if you have configure a systemd service -### If you're not using these lines: -### - Remove the section "STOP SYSTEMD SERVICE" and "START SYSTEMD SERVICE" in the backup script -### - As well as the section "START SYSTEMD SERVICE" in the restore script -### - As well as the section"STOP SYSTEMD SERVICE" and "START SYSTEMD SERVICE" in the upgrade script -### - And the section "STOP SYSTEMD SERVICE" and "START SYSTEMD SERVICE" in the change_url script - -# Start a systemd service -ynh_systemd_action --service_name=$app --action="start" --log_path="/var/log/$app/$app.log" - -#================================================= -# SETUP FAIL2BAN -#================================================= -ynh_script_progression --message="Configuring Fail2Ban..." --time --weight=1 - -# Create a dedicated Fail2Ban config -ynh_add_fail2ban_config --logpath="/var/log/nginx/${domain}-error.log" --failregex="Regex to match into the log for a failed login" +ynh_add_config --template="../conf/cron" --destination="/etc/cron.d/${app}" #================================================= # SETUP SSOWAT @@ -262,65 +233,3 @@ ynh_systemd_action --service_name=nginx --action=reload #================================================= ynh_script_progression --message="Installation of $app completed" --last - - - - - -# Hotfixes - # Fix LDAP email. See https://github.com/humhub/humhub/issues/1949 - sudo cp -a ../sources/fix/AuthClientHelpers.php $src_path/protected/humhub/modules/user/authclient/AuthClientHelpers.php - # Fix to allow passwordless LDAP login - sudo cp -a ../sources/fix/ZendLdapClient.php $src_path/protected/humhub/modules/user/authclient/ZendLdapClient.php - sudo sed -i "s@defined('YII_DEBUG') or define('YII_DEBUG', true);@//defined('YII_DEBUG') or define('YII_DEBUG', true);@g" $src_path/index.php - sudo sed -i "s@defined('YII_ENV') or define('YII_ENV', 'dev');@//defined('YII_ENV') or define('YII_ENV', 'dev');@g" $src_path/index.php - - - -# Set permissions to app files - sudo chown -R www-data: $src_path - -# Cron - echo "30 * * * * $src_path/protected/yii cron hourly >/dev/null 2>&1" > cron - echo "00 18 * * * $src_path/protected/yii cron daily >/dev/null 2>&1" > cron - sudo mv cron /etc/cron.d/${app} - sudo chown root /etc/cron.d/${app} - - -# Install - # Disable SSO - ynh_app_setting_set "$app" unprotected_uris "/" - sudo yunohost app ssowatconf - - # Install with CURL - admin_temp_pass=$(ynh_string_random 6) - admin_email=$(sudo yunohost user info "$admin" --output-as plain | ynh_get_plain_key mail) - admin_firstname=$(sudo yunohost user info "$admin" --output-as plain | ynh_get_plain_key firstname) - admin_lastname=$(sudo yunohost user info "$admin" --output-as plain | ynh_get_plain_key lastname) - - ynh_local_curl "/index.php?r=installer/index/go" "go" - - ynh_local_curl "/index.php?r=installer/config/basic" \ - "ConfigBasicForm[name]=YunoHost" - - ynh_local_curl "/index.php?r=installer/config/use-case" \ - "UseCaseForm[useCase]=" \ - "UseCaseForm[useCase]=other" - - ynh_local_curl "/index.php?r=installer/config/admin" \ - "User[username]=$admin" \ - "User[email]=$admin_email" \ - "Password[newPassword]=$admin_temp_pass" \ - "Password[newPasswordConfirm]=$admin_temp_pass" \ - "Profile[firstname]=$admin_firstname" \ - "Profile[lastname]=$admin_lastname" \ - "save" - - ynh_local_curl "/index.php?r=installer/config/sample-data" \ - "SampleDataForm[sampleData]=0" - - # Populate the LDAP parameters - sed -i "s@YNH_ADMIN_USER@$admin@g" ../conf/ldap.sql - mysql -u $db_user -p${db_pwd} $db_name < ../conf/ldap.sql - - diff --git a/scripts/remove b/scripts/remove index 9b4acfd..618b90f 100644 --- a/scripts/remove +++ b/scripts/remove @@ -24,17 +24,6 @@ final_path=$(ynh_app_setting_get --app=$app --key=final_path) #================================================= # STANDARD REMOVE -#================================================= -# REMOVE SERVICE INTEGRATION IN YUNOHOST -#================================================= - -# Remove the service from the list of services known by YunoHost (added from `yunohost service add`) -if ynh_exec_warn_less yunohost service status $app >/dev/null -then - ynh_script_progression --message="Removing $app service integration..." --time --weight=1 - yunohost service remove $app -fi - #================================================= # REMOVE THE MYSQL DATABASE #================================================= @@ -80,13 +69,11 @@ ynh_remove_fpm_config #================================================= # REMOVE VARIOUS FILES #================================================= +ynh_script_progression --message="Removing CRON configuration..." --time --weight=1 # Remove a cron file ynh_secure_remove --file="/etc/cron.d/$app" -# Remove the log files -ynh_secure_remove --file="/var/log/$app/" - #================================================= # GENERIC FINALIZATION #================================================= diff --git a/scripts/restore b/scripts/restore index 9cc7bc9..d12fad9 100644 --- a/scripts/restore +++ b/scripts/restore @@ -1,42 +1,148 @@ #!/bin/bash -# Exit on command errors and treat unset variables as an error -set -eu +#================================================= +# GENERIC START +#================================================= +# IMPORT GENERIC HELPERS +#================================================= + +# Keep this path for calling _common.sh inside the execution's context of backup and restore scripts +source ../settings/scripts/_common.sh +source /usr/share/yunohost/helpers + +#================================================= +# MANAGE SCRIPT FAILURE +#================================================= + +ynh_clean_setup () { + #### Remove this function if there's nothing to clean before calling the remove script. + true +} +# Exit if an error occurs during the execution of the script +ynh_abort_if_errors + +#================================================= +# LOAD SETTINGS +#================================================= +ynh_script_progression --message="Loading installation settings..." --time --weight=1 app=$YNH_APP_INSTANCE_NAME -# Source YunoHost helpers - source /usr/share/yunohost/helpers +domain=$(ynh_app_setting_get --app=$app --key=domain) +path_url=$(ynh_app_setting_get --app=$app --key=path) +final_path=$(ynh_app_setting_get --app=$app --key=final_path) +db_name=$(ynh_app_setting_get --app=$app --key=db_name) +db_user=$db_name +phpversion=$(ynh_app_setting_get --app=$app --key=phpversion) -# Retrieve old app settings - domain=$(ynh_app_setting_get "$app" domain) - path=$(ynh_app_setting_get "$app" path) +#================================================= +# CHECK IF THE APP CAN BE RESTORED +#================================================= +ynh_script_progression --message="Validating restoration parameters..." --time --weight=1 -# Check domain/path availability - sudo yunohost app checkurl "${domain}${path}" -a "$app" \ - || ynh_die "Path not available: ${domain}${path}" +ynh_webpath_available --domain=$domain --path_url=$path_url \ + || ynh_die --message="Path not available: ${domain}${path_url}" +test ! -d $final_path \ + || ynh_die --message="There is already a directory: $final_path " -# Restore sources & data - src_path="/var/www/${app}" - sudo cp -a ./sources "$src_path" - sudo cp -a ./cron "/etc/cron.d/${app}" +#================================================= +# STANDARD RESTORATION STEPS +#================================================= +# RESTORE THE NGINX CONFIGURATION +#================================================= -# Restore permissions to app files - sudo chown -R www-data: $src_path +ynh_restore_file --origin_path="/etc/nginx/conf.d/$domain.d/$app.conf" -# MySQL - dbname=$app - dbuser=$app - dbpass=$(ynh_app_setting_get "$app" mysqlpwd) - ynh_mysql_create_db "$dbname" "$dbuser" "$dbpass" - ynh_mysql_connect_as "$dbuser" "$dbpass" "$dbname" < ./dump.sql +#================================================= +# RESTORE THE APP MAIN DIR +#================================================= +ynh_script_progression --message="Restoring the app main directory..." --time --weight=1 -# Restore NGINX configuration - sudo cp -a ./nginx.conf "/etc/nginx/conf.d/${domain}.d/${app}.conf" +ynh_restore_file --origin_path="$final_path" -# Restore PHP-FPM configuration - sudo cp -a ./php-fpm.conf "/etc/php5/fpm/pool.d/${app}.conf" +#================================================= +# RECREATE THE DEDICATED USER +#================================================= +ynh_script_progression --message="Recreating the dedicated system user..." --time --weight=1 -# Restart services - sudo service php5-fpm reload - sudo service nginx reload +# Create the dedicated user (if not existing) +ynh_system_user_create --username=$app + +#================================================= +# RESTORE USER RIGHTS +#================================================= + +# Restore permissions on app files +chown -R root: $final_path + +chown -R $app $final_path/assets +chown -R $app $final_path/protected/config +chown -R $app $final_path/protected/modules +chown -R $app $final_path/protected/runtime +chown -R $app $final_path/uploads/* + +# This file contains the db password +chmod g-rwx o-rwx $final_path/protected/config/dynamic.php + + +#================================================= +# RESTORE THE PHP-FPM CONFIGURATION +#================================================= + +ynh_restore_file --origin_path="/etc/php/$phpversion/fpm/pool.d/$app.conf" + +#================================================= +# RESTORE FAIL2BAN CONFIGURATION +#================================================= +ynh_script_progression --message="Restoring the Fail2Ban configuration..." --time --weight=1 + +ynh_restore_file "/etc/fail2ban/jail.d/$app.conf" +ynh_restore_file "/etc/fail2ban/filter.d/$app.conf" +ynh_systemd_action --action=restart --service_name=fail2ban + +#================================================= +# SPECIFIC RESTORATION +#================================================= +# REINSTALL DEPENDENCIES +#================================================= +ynh_script_progression --message="Reinstalling dependencies..." --time --weight=1 + +# Define and install dependencies +ynh_install_app_dependencies $pkg_dependencies + +#================================================= +# RESTORE THE MYSQL DATABASE +#================================================= +ynh_script_progression --message="Restoring the MySQL database..." --time --weight=1 + +db_pwd=$(ynh_app_setting_get --app=$app --key=mysqlpwd) +ynh_mysql_setup_db --db_user=$db_user --db_name=$db_name --db_pwd=$db_pwd +ynh_mysql_connect_as --user=$db_user --password=$db_pwd --database=$db_name < ./db.sql + +#================================================= +# RESTORE VARIOUS FILES +#================================================= + +ynh_restore_file --origin_path="/etc/cron.d/$app" + +#================================================= +# RESTORE THE LOGROTATE CONFIGURATION +#================================================= + +ynh_restore_file --origin_path="/etc/logrotate.d/$app" + +#================================================= +# GENERIC FINALIZATION +#================================================= +# RELOAD NGINX AND PHP-FPM +#================================================= +ynh_script_progression --message="Reloading NGINX web server and PHP-FPM..." --time --weight=1 + +ynh_systemd_action --service_name=php$phpversion-fpm --action=reload +ynh_systemd_action --service_name=nginx --action=reload + +#================================================= +# END OF SCRIPT +#================================================= + +ynh_script_progression --message="Restoration completed for $app" --time --last diff --git a/scripts/upgrade b/scripts/upgrade index cf226ee..82dd48f 100644 --- a/scripts/upgrade +++ b/scripts/upgrade @@ -1,83 +1,232 @@ #!/bin/bash -# Exit on command errors and treat unset variables as an error -set -eu +#================================================= +# GENERIC START +#================================================= +# IMPORT GENERIC HELPERS +#================================================= + +source _common.sh +source /usr/share/yunohost/helpers + +#================================================= +# LOAD SETTINGS +#================================================= +ynh_script_progression --message="Loading installation settings..." --time --weight=1 app=$YNH_APP_INSTANCE_NAME -version=$(cat ../sources/version) -source='https://sourceforge.net/projects/humhub/files/' -# Source YunoHost helpers - source /usr/share/yunohost/helpers +domain=$(ynh_app_setting_get --app=$app --key=domain) +path_url=$(ynh_app_setting_get --app=$app --key=path) +admin=$(ynh_app_setting_get --app=$app --key=admin) +final_path=$(ynh_app_setting_get --app=$app --key=final_path) +language=$(ynh_app_setting_get --app=$app --key=language) +db_name=$(ynh_app_setting_get --app=$app --key=db_name) +db_pwd=$(ynh_app_setting_get "$app" mysqlpwd) -# Retrieve app settings - domain=$(ynh_app_setting_get "$app" domain) - path=$(ynh_app_setting_get "$app" path) - dbuser=$app - dbname=$app - dbpass=$(ynh_app_setting_get "$app" mysqlpwd) - src_path=/var/www/$app +#================================================= +# CHECK VERSION +#================================================= -# Correct path: puts a / at the start and nothing at the end - if [ "${path:0:1}" != "/" ]; then - path="/$path" - fi - if [ "${path:${#path}-1}" == "/" ] && [ ${#path} -gt 1 ]; then - path="${path:0:${#path}-1}" - fi +### This helper will compare the version of the currently installed app and the version of the upstream package. +### $upgrade_type can have 2 different values +### - UPGRADE_APP if the upstream app version has changed +### - UPGRADE_PACKAGE if only the YunoHost package has changed +### ynh_check_app_version_changed will stop the upgrade if the app is up to date. +### UPGRADE_APP should be used to upgrade the core app only if there's an upgrade to do. +upgrade_type=$(ynh_check_app_version_changed) -# Copy source files - sudo mv "$src_path" "$src_path.old" - sudo mkdir -p $src_path - sudo wget -q "${source}humhub-${version}.zip/download" -O humhub-${version}.zip - sudo unzip -qq humhub-${version}.zip - sudo cp -a humhub-$version/. $src_path +#================================================= +# ENSURE DOWNWARD COMPATIBILITY +#================================================= +ynh_script_progression --message="Ensuring downward compatibility..." --time --weight=1 -# Restore files - sudo cp -a "$src_path.old/uploads/." "$src_path/uploads/." - sudo cp -a "$src_path.old/protected/runtime" "$src_path/protected/runtime" - sudo cp -a "$src_path.old/protected/config/." "$src_path/protected/config/" - sudo cp -a "$src_path.old/protected/modules/." "$src_path/protected/modules/" - sudo cp -a "$src_path.old/themes/." "$src_path/themes/" +# +# N.B. : the followings setting migrations snippets are provided as *EXAMPLES* +# of what you may want to do in some cases (e.g. a setting was not defined on +# some legacy installs and you therefore want to initiaze stuff during upgrade) +# -# Hotfixes - # Fix LDAP email. See https://github.com/humhub/humhub/issues/1949 - sudo cp -a ../sources/fix/AuthClientHelpers.php $src_path/protected/humhub/modules/user/authclient/AuthClientHelpers.php - # Fix to allow passwordless LDAP login - sudo cp -a ../sources/fix/ZendLdapClient.php $src_path/protected/humhub/modules/user/authclient/ZendLdapClient.php - sudo sed -i "s@defined('YII_DEBUG') or define('YII_DEBUG', true);@//defined('YII_DEBUG') or define('YII_DEBUG', true);@g" $src_path/index.php - sudo sed -i "s@defined('YII_ENV') or define('YII_ENV', 'dev');@//defined('YII_ENV') or define('YII_ENV', 'dev');@g" $src_path/index.php +# If db_name doesn't exist, create it +#if [ -z "$db_name" ]; then +# db_name=$(ynh_sanitize_dbid --db_name=$app) +# ynh_app_setting_set --app=$app --key=db_name --value=$db_name +#fi -# Set permissions to app files - sudo chown -R www-data: $src_path +# If final_path doesn't exist, create it +#if [ -z "$final_path" ]; then +# final_path=/var/www/$app +# ynh_app_setting_set --app=$app --key=final_path --value=$final_path +#fi -# Upgrade - sudo sudo -u www-data php $src_path/protected/yii migrate/up --includeModuleMigrations=1 --interactive=0 > /dev/null 2>&1 +### If nobody installed your app before 4.1, +### then you may safely remove these lines -# Upgrade cron - echo "30 * * * * $src_path/protected/yii cron hourly >/dev/null 2>&1" > cron - echo "00 18 * * * $src_path/protected/yii cron daily >/dev/null 2>&1" > cron - sudo mv cron /etc/cron.d/${app} - sudo chown root /etc/cron.d/${app} +# Cleaning legacy permissions +if ynh_legacy_permissions_exists; then + ynh_legacy_permissions_delete_all -# Modify Nginx configuration file and copy it to Nginx conf directory - nginx_conf=../conf/nginx.conf - sed -i "s@YNH_WWW_PATH@${path:-/}@g" $nginx_conf - sed -i "s@YNH_WWW_ALIAS@$src_path/@g" $nginx_conf - sed -i "s@YNH_WWW_APP@$app@g" $nginx_conf - sudo cp $nginx_conf /etc/nginx/conf.d/$domain.d/$app.conf + ynh_app_setting_delete --app=$app --key=is_public +fi -# PHP - sed -i "s@YNH_WWW_APP@$app@g" ../conf/php-fpm.conf - sed -i "s@YNH_WWW_ALIAS@$src_path/@g" ../conf/php-fpm.conf - finalphpconf=/etc/php5/fpm/pool.d/$app.conf - sudo cp ../conf/php-fpm.conf $finalphpconf - sudo chown root: $finalphpconf - sudo chmod 644 $finalphpconf +if ! ynh_permission_exists --permission="admin"; then + # Create the required permissions + ynh_permission_create --permission="admin" --url="/admin" --allowed=$admin +fi -# Reload nginx service - sudo service php5-fpm reload - sudo service nginx reload +# Create a permission if needed +if ! ynh_permission_exists --permission="api"; then + ynh_permission_create --permission="api" --url "/api" --allowed="visitors" --show_tile="false" --protected="true" +fi -# Delete old source - sudo rm -rf "$src_path.old" +#================================================= +# BACKUP BEFORE UPGRADE THEN ACTIVE TRAP +#================================================= +ynh_script_progression --message="Backing up the app before upgrading (may take a while)..." --time --weight=1 + +# Backup the current version of the app +ynh_backup_before_upgrade +ynh_clean_setup () { + # Restore it if the upgrade fails + ynh_restore_upgradebackup +} +# Exit if an error occurs during the execution of the script +ynh_abort_if_errors + +#================================================= +# STANDARD UPGRADE STEPS +#================================================= +# DOWNLOAD, CHECK AND UNPACK SOURCE +#================================================= + +# Deactivate cron jobs +ynh_secure_remove --file="/etc/cron.d/$app" + +if [ "$upgrade_type" == "UPGRADE_APP" ] +then + ynh_script_progression --message="Upgrading source files..." --time --weight=1 + + # Backup user contents + mv "$final_path" "$final_path.old" + + # Download, check integrity, uncompress and patch the source from app.src + ynh_setup_source --dest_dir="$final_path" + + # Restore user contents + cp -a "$final_path.old/uploads/." "$final_path/uploads/." + cp -a "$final_path.old/protected/runtime" "$final_path/protected/runtime" + cp -a "$final_path.old/protected/config/." "$final_path/protected/config/" + cp -a "$final_path.old/protected/modules/." "$final_path/protected/modules/" + cp -a "$final_path.old/themes/." "$final_path/themes/" + + # Delete old source + rm -rf "$final_path.old" +fi + +#================================================= +# NGINX CONFIGURATION +#================================================= +ynh_script_progression --message="Upgrading NGINX web server configuration..." --time --weight=1 + +# Create a dedicated NGINX config +ynh_add_nginx_config + +#================================================= +# UPGRADE DEPENDENCIES +#================================================= +ynh_script_progression --message="Upgrading dependencies..." --time --weight=1 + +ynh_install_app_dependencies $pkg_dependencies + +#================================================= +# CREATE DEDICATED USER +#================================================= +ynh_script_progression --message="Making sure dedicated system user exists..." --time --weight=1 + +# Create a dedicated user (if not existing) +ynh_system_user_create --username=$app + +#================================================= +# PHP-FPM CONFIGURATION +#================================================= +ynh_script_progression --message="Upgrading PHP-FPM configuration..." --time --weight=1 + +# Create a dedicated PHP-FPM config +ynh_add_fpm_config + +#================================================= +# SPECIFIC UPGRADE +#================================================= +# APPLY LDAP PATCHES +#================================================= +ynh_script_progression --message="Applying LDAP patches..." --time --weight=1 + +# Fix LDAP email. See https://github.com/humhub/humhub/issues/1949 +# Fix to allow passwordless LDAP login + +#================================================= +# REINSTALL CRONTAB +#================================================= +ynh_script_progression --message="Upgrading crontab..." --time --weight=1 + +ynh_add_config --template="../conf/cron" --destination="/etc/cron.d/${app}" + +#================================================= +# MODIFY A CONFIG FILE +#================================================= + +### Verify the checksum of a file, stored by `ynh_store_file_checksum` in the install script. +### And create a backup of this file if the checksum is different. So the file will be backed up if the admin had modified it. +# ynh_backup_if_checksum_is_different --file="$final_path/CONFIG_FILE" + +# ynh_replace_string --match_string="match_string" --replace_string="replace_string" --target_file="$final_path/CONFIG_FILE" + +# Recalculate and store the checksum of the file for the next upgrade. +# ynh_store_file_checksum --file="$final_path/CONFIG_FILE" + +#================================================= +# GENERIC FINALIZATION +#================================================= +# SECURE FILES AND DIRECTORIES +#================================================= + +# Set permissions on app files +chown -R root: $final_path + +chown -R $app $final_path/assets +chown -R $app $final_path/protected/config +chown -R $app $final_path/protected/modules +chown -R $app $final_path/protected/runtime +chown -R $app $final_path/uploads/* + +# This file contains the db password +chmod g-rwx o-rwx $final_path/protected/config/dynamic.php + +#================================================= +# SETUP LOGROTATE +#================================================= +ynh_script_progression --message="Upgrading logrotate configuration..." --time --weight=1 + +# Use logrotate to manage app-specific logfile(s) +ynh_use_logrotate --non-append + +#================================================= +# UPGRADE FAIL2BAN +#================================================= +ynh_script_progression --message="Reconfiguring Fail2Ban..." --time --weight=1 + +# Create a dedicated Fail2Ban config +ynh_add_fail2ban_config --logpath="/var/log/nginx/${domain}-error.log" --failregex="Regex to match into the log for a failed login" + +#================================================= +# RELOAD NGINX +#================================================= +ynh_script_progression --message="Reloading NGINX web server..." --time --weight=1 + +ynh_systemd_action --service_name=nginx --action=reload + +#================================================= +# END OF SCRIPT +#================================================= + +ynh_script_progression --message="Upgrade of $app completed" --time --last diff --git a/sources/fix/AuthClientHelpers.php b/sources/fix/AuthClientHelpers.php deleted file mode 100644 index 9e0766b..0000000 --- a/sources/fix/AuthClientHelpers.php +++ /dev/null @@ -1,261 +0,0 @@ -getUserAttributes(); - - if ($authClient instanceof interfaces\PrimaryClient) { - /** - * @var interfaces\PrimaryClient $authClient - */ - return User::findOne([ - $authClient->getUserTableIdAttribute() => $attributes['id'], - 'auth_mode' => $authClient->getId() - ]); - } - - $auth = Auth::find()->where(['source' => $authClient->getId(), 'source_id' => $attributes['id']])->one(); - if ($auth !== null) { - return $auth->user; - } - } - - /** - * Stores an authClient to an user record - * - * @param \yii\authclient\BaseClient $authClient - * @param User $user - */ - public static function storeAuthClientForUser(ClientInterface $authClient, User $user) - { - $attributes = $authClient->getUserAttributes(); - - if ($authClient instanceof interfaces\PrimaryClient) { - $user->auth_mode = $authClient->getId(); - $user->save(); - } else { - $auth = Auth::findOne(['source' => $authClient->getId(), 'source_id' => $attributes['id']]); - - /** - * Make sure authClient is not double assigned - */ - if ($auth !== null && $auth->user_id != $user->id) { - $auth->delete(); - $auth = null; - } - - - if ($auth === null) { - $auth = new \humhub\modules\user\models\Auth([ - 'user_id' => $user->id, - 'source' => (string) $authClient->getId(), - 'source_id' => (string) $attributes['id'], - ]); - - $auth->save(); - } - } - } - - /** - * Removes Authclient for a user - * - * @param \yii\authclient\BaseClient $authClient - * @param User $user - */ - public static function removeAuthClientForUser(ClientInterface $authClient, User $user) - { - Auth::deleteAll([ - 'user_id' => $user->id, - 'source' => (string) $authClient->getId() - ]); - } - - /** - * Updates (or creates) a user in HumHub using AuthClients Attributes - * This method will be called after login or by cron sync. - * - * @param \yii\authclient\BaseClient $authClient - * @param User $user - * @return boolean succeed - */ - public static function updateUser(ClientInterface $authClient, User $user = null) - { - if ($user === null) { - $user = self::getUserByAuthClient($authClient); - if ($user === null) { - return false; - } - } - - $authClient->trigger(BaseClient::EVENT_UPDATE_USER, new \yii\web\UserEvent(['identity' => $user])); - - if ($authClient instanceof interfaces\SyncAttributes) { - $attributes = $authClient->getUserAttributes(); - foreach ($authClient->getSyncAttributes() as $attributeName) { - if (isset($attributes[$attributeName])) { - if (in_array($attributeName, ['email', 'username'])) { - $user->setAttribute($attributeName, $attributes[$attributeName]); - } else { - $user->profile->setAttribute($attributeName, $attributes[$attributeName]); - } - } else { - if ($user->profile->hasAttribute($attributeName)) { - $user->profile->setAttribute($attributeName, ''); - } - } - } - - if (count($user->getDirtyAttributes()) !== 0 && !$user->save()) { - Yii::error('Could not update user attributes by AuthClient (UserId: ' . $user->id . ") - Error: " . print_r($user->getErrors(), 1)); - return false; - } - - if (count($user->profile->getDirtyAttributes()) !== 0 && !$user->profile->save()) { - Yii::error('Could not update user attributes by AuthClient (UserId: ' . $user->id . ") - Error: " . print_r($user->profile->getErrors(), 1)); - return false; - } - } - - return true; - } - - /** - * Automatically creates user by auth client attributes - * - * @param \yii\authclient\BaseClient $authClient - * @return boolean success status - */ - public static function createUser(ClientInterface $authClient) - { - $attributes = $authClient->getUserAttributes(); - - if (!isset($attributes['id'])) { - return false; - } - - // Hotfix for YunoHost. Select the first LDAP email address when there are several in the mail attribute. See https://github.com/humhub/humhub/issues/1949 - if (is_array($attributes['mail'])) { - $attributes['mail'] = $attributes['mail'][0]; - } - if (is_array($attributes['email'])) { - $attributes['email'] = $attributes['email'][0]; - } - - $registration = new \humhub\modules\user\models\forms\Registration(); - $registration->enablePasswordForm = false; - $registration->enableEmailField = true; - - if ($authClient instanceof interfaces\ApprovalBypass) { - $registration->enableUserApproval = false; - } - - unset($attributes['id']); - $registration->getUser()->setAttributes($attributes, false); - $registration->getProfile()->setAttributes($attributes, false); - $registration->getGroupUser()->setAttributes($attributes, false); - - if ($registration->validate() && $registration->register($authClient)) { - return $registration->getUser(); - } - - return null; - } - - /** - * Returns all users which are using an given authclient - * - * @param ClientInterface $authClient - * @return \yii\db\ActiveQuery - */ - public static function getUsersByAuthClient(ClientInterface $authClient) - { - $query = User::find(); - - if ($authClient instanceof interfaces\PrimaryClient) { - $query->where([ - 'auth_mode' => $authClient->getId() - ]); - } else { - $query->where(['user_auth.source' => $authClient->getId()]); - } - - return $query; - } - - /** - * Returns AuthClients used by given User - * - * @param User $user - * @return ClientInterface[] the users authclients - */ - public static function getAuthClientsByUser(User $user) - { - $authClients = []; - - foreach (Yii::$app->authClientCollection->getClients() as $client) { - /** - * @var $client ClientInterface - */ - // Add primary authClient - if ($user->auth_mode == $client->getId()) { - $authClients[] = $client; - } - - // Add additional authClient - foreach ($user->auths as $auth) { - if ($auth->source == $client->getId()) { - $authClients[] = $client; - } - } - } - - return $authClients; - } - - /** - * Returns a list of all synchornized user attributes - * - * @param User $user - * @return array attribute names - */ - public static function getSyncAttributesByUser(User $user) - { - $attributes = []; - foreach (self::getAuthClientsByUser($user) as $authClient) { - if ($authClient instanceof interfaces\SyncAttributes) { - $attributes = array_merge($attributes, $authClient->getSyncAttributes()); - } - } - return $attributes; - } - -} diff --git a/sources/fix/ZendLdapClient.php b/sources/fix/ZendLdapClient.php deleted file mode 100644 index 2e75f09..0000000 --- a/sources/fix/ZendLdapClient.php +++ /dev/null @@ -1,380 +0,0 @@ -idAttribute; - } - - /** - * @inheritdoc - */ - public function getUserTableIdAttribute() - { - return $this->userTableIdAttribute; - } - - /** - * @inheritdoc - */ - public function auth() - { - - $node = $this->getUserNode(); - if ($node !== null) { - $this->setUserAttributes($node->getAttributes()); - return true; - } - - return false; - } - - /** - * @inheritdoc - */ - protected function defaultNormalizeUserAttributeMap() - { - $map = []; - - // Username field - $usernameAttribute = Yii::$app->getModule('user')->settings->get('auth.ldap.usernameAttribute'); - if ($usernameAttribute == '') { - $usernameAttribute = 'sAMAccountName'; - } - $map['username'] = strtolower($usernameAttribute); - - // E-Mail field - $emailAttribute = Yii::$app->getModule('user')->settings->get('auth.ldap.emailAttribute'); - if ($emailAttribute == '') { - $emailAttribute = 'mail'; - } - $map['email'] = strtolower($emailAttribute); - - // Profile Field Mapping - foreach (ProfileField::find()->andWhere(['!=', 'ldap_attribute', ''])->all() as $profileField) { - $map[$profileField->internal_name] = strtolower($profileField->ldap_attribute); - } - - return $map; - } - - /** - * @inheritdoc - */ - protected function normalizeUserAttributes($attributes) - { - $normalized = []; - - // Fix LDAP Attributes - foreach ($attributes as $name => $value) { - if (is_array($value) && count($value) == 1 && $name != 'memberof') { - $normalized[$name] = $value[0]; - } else { - $normalized[$name] = $value; - } - } - - if (isset($normalized['objectguid'])) { - $normalized['objectguid'] = \humhub\libs\StringHelper::binaryToGuid($normalized['objectguid']); - } - - // Handle date fields (formats are specified in config) - foreach ($normalized as $name => $value) { - if (isset(Yii::$app->params['ldap']['dateFields'][$name]) && $value != '') { - $dateFormat = Yii::$app->params['ldap']['dateFields'][$name]; - $date = \DateTime::createFromFormat($dateFormat, $value); - - if ($date !== false) { - $normalized[$name] = $date->format('Y-m-d 00:00:00'); - } else { - $normalized[$name] = ""; - } - } - } - return parent::normalizeUserAttributes($normalized); - } - - /** - * @return array list of user attributes - */ - public function getUserAttributes() - { - $attributes = parent::getUserAttributes(); - - // Try to automatically set id and usertable id attribute by available attributes - if ($this->getIdAttribute() === null || $this->getUserTableIdAttribute() === null) { - if (isset($attributes['objectguid'])) { - $this->idAttribute = 'objectguid'; - $this->userTableIdAttribute = 'guid'; - } elseif (isset($attributes['mail'])) { - $this->idAttribute = 'mail'; - $this->userTableIdAttribute = 'email'; - } else { - throw new \yii\base\Exception("Could not automatically determine unique user id from ldap node!"); - } - } - - // Make sure id attributes sits on id attribute key - if (isset($attributes[$this->getIdAttribute()])) { - $attributes['id'] = $attributes[$this->getIdAttribute()]; - } - - // Map usertable id attribute against ldap id attribute - $attributes[$this->getUserTableIdAttribute()] = $attributes[$this->getIdAttribute()]; - - return $attributes; - } - - /** - * Returns Users LDAP Node - * - * @return Node the users ldap node - */ - protected function getUserNode() - { - $dn = $this->getUserDn(); - if ($dn !== '') { - return $this->getLdap()->getNode($dn); - } - - return null; - } - - /** - * Returns the users LDAP DN - * - * @return string the user dn if found - */ - protected function getUserDn() - { - $userName = $this->login->username; - - // Translate given e-mail to username - if (strpos($userName, '@') !== false) { - $user = User::findOne(['email' => $userName]); - if ($user !== null) { - $userName = $user->username; - } - } - - try { - $this->getLdap()->bind($userName, $this->login->password); - return $this->getLdap()->getCanonicalAccountName($userName, Ldap::ACCTNAME_FORM_DN); - } catch (LdapException $ex) { - // User not found in LDAP - } - return ''; - } - - /** - * Returns Zend LDAP - * - * @return \Zend\Ldap\Ldap - */ - public function getLdap() - { - if ($this->_ldap === null) { - $options = array( - 'host' => Yii::$app->getModule('user')->settings->get('auth.ldap.hostname'), - 'port' => Yii::$app->getModule('user')->settings->get('auth.ldap.port'), - //'username' => Yii::$app->getModule('user')->settings->get('auth.ldap.username'), - //'password' => Yii::$app->getModule('user')->settings->get('auth.ldap.password'), - 'username' => '', - 'password' => '', - 'useStartTls' => (Yii::$app->getModule('user')->settings->get('auth.ldap.encryption') == 'tls'), - 'useSsl' => (Yii::$app->getModule('user')->settings->get('auth.ldap.encryption') == 'ssl'), - 'bindRequiresDn' => true, - 'baseDn' => Yii::$app->getModule('user')->settings->get('auth.ldap.baseDn'), - 'accountFilterFormat' => Yii::$app->getModule('user')->settings->get('auth.ldap.loginFilter'), - ); - - $this->_ldap = new \Zend\Ldap\Ldap($options); - $this->_ldap->bind(); - } - - return $this->_ldap; - } - - /** - * Sets an Zend LDAP Instance - * - * @param \Zend\Ldap\Ldap $ldap - */ - public function setLdap(\Zend\Ldap\Ldap $ldap) - { - $this->_ldap = $ldap; - } - - /** - * @inheritdoc - */ - public function getSyncAttributes() - { - $attributes = ['username', 'email']; - - foreach (ProfileField::find()->andWhere(['!=', 'ldap_attribute', ''])->all() as $profileField) { - $attributes[] = $profileField->internal_name; - } - - return $attributes; - } - - /** - * Refresh ldap users - * - * New users (found in ldap) will be automatically created if all required fiƩlds are set. - * Profile fields which are bind to LDAP will automatically updated. - */ - public function syncUsers() - { - if (!Yii::$app->getModule('user')->settings->get('auth.ldap.enabled') || !Yii::$app->getModule('user')->settings->get('auth.ldap.refreshUsers')) { - return; - } - - $userFilter = Yii::$app->getModule('user')->settings->get('auth.ldap.userFilter'); - $baseDn = Yii::$app->getModule('user')->settings->get('auth.ldap.baseDn'); - try { - $ldap = $this->getLdap(); - - $userCollection = $ldap->search($userFilter, $baseDn, Ldap::SEARCH_SCOPE_SUB); - - $authClient = null; - $ids = []; - foreach ($userCollection as $attributes) { - $authClient = clone $this; - $authClient->init(); - $authClient->setUserAttributes($attributes); - $attributes = $authClient->getUserAttributes(); - - $user = AuthClientHelpers::getUserByAuthClient($authClient); - if ($user === null) { - if (!AuthClientHelpers::createUser($authClient)) { - Yii::warning('Could not automatically create LDAP user - check required attributes! (' . print_r($attributes, 1) . ')'); - } - } else { - AuthClientHelpers::updateUser($authClient, $user); - } - - $ids[] = $attributes['id']; - } - - /** - * Since userTableAttribute can be automatically set on user attributes - * try to take it from initialized authclient instance. - */ - $userTableIdAttribute = $this->getUserTableIdAttribute(); - if ($authClient !== null) { - $userTableIdAttribute = $authClient->getUserTableIdAttribute(); - } - - foreach (AuthClientHelpers::getUsersByAuthClient($this)->each() as $user) { - $foundInLdap = in_array($user->getAttribute($userTableIdAttribute), $ids); - // Enable disabled users that have been found in ldap - if ($foundInLdap && $user->status === User::STATUS_DISABLED) { - $user->status = User::STATUS_ENABLED; - $user->save(); - Yii::info('Enabled user' . $user->username . ' (' . $user->id . ') - found in LDAP!'); - // Disable users that were not found in ldap - } elseif (!$foundInLdap && $user->status !== User::STATUS_DISABLED) { - $user->status = User::STATUS_DISABLED; - $user->save(); - Yii::warning('Disabled user' . $user->username . ' (' . $user->id . ') - not found in LDAP!'); - } - } - } catch (\Zend\Ldap\Exception\LdapException $ex) { - Yii::error('Could not connect to LDAP instance: ' . $ex->getMessage()); - } catch (\Exception $ex) { - Yii::error('An error occurred while user sync: ' . $ex->getMessage()); - } - } - - /** - * Checks if LDAP is supported - */ - public static function isLdapAvailable() - { - if (!class_exists('Zend\Ldap\Ldap')) { - return false; - } - - if (!function_exists('ldap_bind')) { - return false; - } - - return true; - } - -} diff --git a/sources/patches/app-00-no-password-ldap.patch b/sources/patches/app-00-no-password-ldap.patch new file mode 100644 index 0000000..645e65f --- /dev/null +++ b/sources/patches/app-00-no-password-ldap.patch @@ -0,0 +1,13 @@ +diff --git a/protected/humhub/modules/ldap/models/LdapSettings.php b/protected/humhub/modules/ldap/models/LdapSettings.php +index e6402e8b3..3b653d590 100644 +--- a/protected/humhub/modules/ldap/models/LdapSettings.php ++++ b/protected/humhub/modules/ldap/models/LdapSettings.php +@@ -120,7 +120,7 @@ class LdapSettings extends Model + return [ + [['enabled', 'refreshUsers', 'usernameAttribute', 'emailAttribute', 'username', 'passwordField', 'hostname', 'port', 'idAttribute'], 'string', 'max' => 255], + [['baseDn', 'loginFilter', 'userFilter'], 'string'], +- [['usernameAttribute', 'username', 'passwordField', 'hostname', 'port', 'baseDn', 'loginFilter', 'userFilter', 'idAttribute'], 'required'], ++ [['usernameAttribute', 'hostname', 'port', 'baseDn', 'loginFilter', 'userFilter', 'idAttribute'], 'required'], + ['encryption', 'in', 'range' => ['', 'ssl', 'tls']], + ]; + } diff --git a/sources/version b/sources/version index 26aaba0..f8a696c 100644 --- a/sources/version +++ b/sources/version @@ -1 +1 @@ -1.2.0 +1.7.2