#!/bin/bash # @copyright Copyright (c) 2020 Arthur Schiwon # # @author Arthur Schiwon # # @license GNU AGPL version 3 or any later version # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as # published by the Free Software Foundation, either version 3 of the # License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . VERSION=3 SERVICE="Nextcloud" ARGS=("$@") getarg() { # by Univention local found=0 for arg in "${ARGS[@]}"; do if [ "$found" -eq 1 ]; then echo "$arg" break fi if [ "$arg" = "$1" ]; then found=1 fi done } ERROR_FILE=$(getarg "--error-file") . /usr/share/univention-join/joinscripthelper.lib . /usr/share/univention-appcenter/joinscripthelper.sh . /usr/share/univention-lib/ldap.sh joinscript_init eval "$(ucr shell)" NC_PERMCONFDIR="/var/lib/univention-appcenter/apps/nextcloud/data/integration" NC_ADMIN_PWD_FILE="$NC_PERMCONFDIR/admin.secret" NC_MEMBER_OF=0 HOST="https://${hostname}.${domainname}/nextcloud" IS_UPDATE=false NC_LDAP_BIND_DN="$appcenter_apps_nextcloud_hostdn" NC_LDAP_BIND_PW_FILE="$(joinscript_container_file /etc/machine.secret)" NC_LDAP_BIND_PW="$(< $NC_LDAP_BIND_PW_FILE)" NC_ADDITIONAL_CURL_ARGS= NC_OFFICE_SUITE="oo_community" # fallback nextcloud_main() { if [ -e "$NC_PERMCONFDIR/initial_config_done" ] ; then IS_UPDATE=true fi ucs_addServiceToLocalhost "${SERVICE}" "$@" nextcloud_appliance_detection if [ "$JS_LAST_EXECUTED_VERSION" = 1 ]; then nextcloud_update_ldap_bind_account fi nextcloud_ensure_ucr nextcloud_attempt_memberof_support nextcloud_configure_saml "$@" nextcloud_configure_ldap_backend nextcloud_modify_users "$@" nextcloud_add_Administrator_to_admin_group nextcloud_mark_initial_conig_done detect_collabora detect_onlyoffice joinscript_save_current_version exit 0 } error_msg() { if [ -n "$1" ]; then IN="$@" else read IN # from stdin fi if [ -n "$ERROR_FILE" ]; then echo "$IN" | tee -a "$ERROR_FILE" >&2 else echo "$IN" >&2 fi } die() { error_msg "$@" exit 1 } nextcloud_appliance_detection() { appliance_id=$(ucr get umc/web/appliance/id) if [ "$appliance_id" = "nextcloud" ] || [ "$appliance_id" = "collabora" ] || [ "$appliance_id" = "collabora-online" ] || [ "$appliance_id" = "onlyoffice-ds" ]; then # On appliance mode, the server works with a preliminary, unknown cert NC_ADDITIONAL_CURL_ARGS="--insecure" echo "Appliance mode has been detected for $appliance_id." fi } # ensures that UCR variables are set. They can be used to pre-set Nextcloud settings before install nextcloud_ensure_ucr() { ucr set nextcloud/ucs/modifyUsersFilter?"(&(|(&(objectClass=posixAccount) (objectClass=shadowAccount)) (objectClass=univentionMail) (objectClass=sambaSamAccount) (objectClass=simpleSecurityObject) (&(objectClass=person) (objectClass=organizationalPerson) (objectClass=inetOrgPerson))) (!(uidNumber=0)) (!(|(uid=*$) (uid=nextcloud-systemuser) (uid=join-backup) (uid=join-slave))) (!(objectClass=nextcloudUser)))" \ nextcloud/ucs/userEnabled?"1" \ nextcloud/ucs/userQuota?"" \ nextcloud/ucs/debug?"0" \ nextcloud/ldap/cacheTTL?"600" \ nextcloud/ldap/homeFolderAttribute?"" \ nextcloud/ldap/userSearchAttributes?"uid;givenName;sn;employeeNumber;mailPrimaryAddress" \ nextcloud/ldap/userDisplayName?"displayName" \ nextcloud/ldap/groupDisplayName?"cn" \ nextcloud/ldap/base?"$ldap_base" \ nextcloud/ldap/baseUsers?"$ldap_base" \ nextcloud/ldap/baseGroups?"$ldap_base" \ nextcloud/ldap/filterLogin?"(&(objectclass=nextcloudUser)(nextcloudEnabled=1)(uid=%uid))" \ nextcloud/ldap/filterUsers?"(&(objectclass=nextcloudUser)(nextcloudEnabled=1))" \ nextcloud/ldap/filterGroups?"(&(objectclass=nextcloudGroup)(nextcloudEnabled=1))" \ eval "$(ucr shell)" } # installs the memberof-overlay and saves the state in NC_MEMBER_OF nextcloud_attempt_memberof_support() { NC_MEMBER_OF=`dpkg-query -W -f='${Status}\n' univention-ldap-overlay-memberof | grep -i installed | grep "^i" -c` } # update ldap bind account to nextcloud user nextcloud_update_ldap_bind_account() { local data local admin_password=`cat "$NC_ADMIN_PWD_FILE"` local configid="s01" # reasonable fall back. in v1 of the join script the configid was not saved. if [ -e "$NC_PERMCONFDIR/ldap-config-id" ]; then configid=`cat "$NC_PERMCONFDIR/ldap-config-id"` fi data="configData[ldapAgentName]="`nextcloud_urlEncode "$NC_LDAP_BIND_DN"` data+="&configData[ldapAgentPassword]="`nextcloud_urlEncode "$NC_LDAP_BIND_PW"` nextcloud_curl -X PUT -d "$data" \ -H "OCS-APIREQUEST: true" -u "nc_admin:$admin_password" $NC_ADDITIONAL_CURL_ARGS \ "$HOST/ocs/v2.php/apps/user_ldap/api/v1/config/$configid" } # configures the LDAP backend at Nextcloud using its OCS API nextcloud_configure_ldap_backend() { if [ $IS_UPDATE = true ] ; then echo "Not attempting to set LDAP configuration, because NC is already installed and set up." nextcloud_update_ldap_backend_password_if_necessary return fi local NC_ADMIN_PWD=`cat "$NC_ADMIN_PWD_FILE"` data="configData[ldapHost]="`nextcloud_urlEncode "$ldap_server_name"` data+="&configData[ldapPort]="`nextcloud_urlEncode "$ldap_server_port"` data+="&configData[ldapTLS]=1" data+="&configData[ldapAgentName]="`nextcloud_urlEncode "$NC_LDAP_BIND_DN"` data+="&configData[ldapAgentPassword]="`nextcloud_urlEncode "$NC_LDAP_BIND_PW"` data+="&configData[ldapBase]="`nextcloud_urlEncode "$nextcloud_ldap_base"` data+="&configData[ldapBaseUsers]="`nextcloud_urlEncode "$nextcloud_ldap_baseUsers"` data+="&configData[ldapBaseGroups]="`nextcloud_urlEncode "$nextcloud_ldap_baseGroups"` data+="&configData[ldapUserFilter]="`nextcloud_urlEncode "$nextcloud_ldap_filterUsers"` data+="&configData[ldapUserFilterMode]=1" data+="&configData[ldapLoginFilter]="`nextcloud_urlEncode "$nextcloud_ldap_filterLogin"` data+="&configData[ldapLoginFilterMode]=1" data+="&configData[ldapLoginFilterUsername]=1" data+="&configData[ldapGroupFilter]="`nextcloud_urlEncode "$nextcloud_ldap_filterGroups"` data+="&configData[ldapGroupFilterMode]=1" data+="&configData[ldapGroupFilterObjectclass]=nextcloudGroup" data+="&configData[ldapUserDisplayName]="`nextcloud_urlEncode "$nextcloud_ldap_userDisplayName"` data+="&configData[ldapGroupDisplayName]="`nextcloud_urlEncode "$nextcloud_ldap_groupDisplayName"` data+="&configData[ldapEmailAttribute]=mail" data+="&configData[ldapQuotaAttribute]=nextcloudQuota" data+="&configData[homeFolderNamingRule]="`nextcloud_urlEncode "$nextcloud_ldap_homeFolderAttribute"` data+="&configData[ldapGroupMemberAssocAttr]=uniqueMember" data+="&configData[ldapCacheTTL]="`nextcloud_urlEncode "$nextcloud_ldap_cacheTTL"` data+="&configData[ldapConfigurationActive]=1" data+="&configData[ldapAttributesForUserSearch]="`nextcloud_urlEncode "$nextcloud_ldap_userSearchAttributes"` data+="&configData[ldapExpertUsernameAttr]=uid" data+="&configData[ldapExpertUUIDUserAttr]=" data+="&configData[useMemberOfToDetectMembership]=$NC_MEMBER_OF" data+="&configData[ldapNestedGroups]=0" data+="&configData[turnOnPasswordChange]=0" data+="&configData[ldapExperiencedAdmin]=1" RESULT=`nextcloud_curl -X POST -H "OCS-APIREQUEST: true" -u "nc_admin:$NC_ADMIN_PWD" \ $NC_ADDITIONAL_CURL_ARGS \ "$HOST/ocs/v2.php/apps/user_ldap/api/v1/config"` \ || die "Failed to request an LDAP config id from Nextcloud" STATUS=`echo $RESULT | grep "200" -c` if [ ! $STATUS -eq 1 ] ; then die "Could not create LDAP Config at Nextcloud" fi CONFIGID=`echo $RESULT | grep -oP '(?<=).*?(?=)'` echo "$CONFIGID" > "$NC_PERMCONFDIR/ldap-config-id" nextcloud_curl -X PUT -d "$data" -H "OCS-APIREQUEST: true" -u "nc_admin:$NC_ADMIN_PWD" \ $NC_ADDITIONAL_CURL_ARGS \ "$HOST/ocs/v2.php/apps/user_ldap/api/v1/config/$CONFIGID" \ || die "Configuring LDAP Backend failed" } nextcloud_update_ldap_backend_password_if_necessary() { # when the original user is configured, update the password to ensure it is set correctly even on a reinstall # that kept the data and config from the previous installation CONFIGID=$(< "$NC_PERMCONFDIR/ldap-config-id") if [[ -z "$CONFIGID" ]]; then return fi LDAP_CON_STATE=$(univention-app shell nextcloud sudo -u www-data php /var/www/html/occ ldap:test-config $CONFIGID) if [[ "$LDAP_CON_STATE" != "The configuration is valid and the connection could be established!" ]] ; then echo "Updating LDAP bind credentials" univention-app shell nextcloud sudo -u www-data php /var/www/html/occ ldap:set-config "$CONFIGID" ldapAgentName "$NC_LDAP_BIND_DN" univention-app shell nextcloud sudo -u www-data php /var/www/html/occ ldap:set-config "$CONFIGID" ldapAgentPassword "$NC_LDAP_BIND_PW" fi } nextcloud_add_Administrator_to_admin_group() { if [ $IS_UPDATE = true ] ; then echo "Not attempting to add Administrator to admin group, because NC is already installed and set up." return fi . /usr/share/univention-lib/base.sh local NC_ADMIN_PWD=`cat "$NC_ADMIN_PWD_FILE"` local ADMIN_NAME="$(custom_username Administrator)" # triggers the mapping RESULT=`nextcloud_curl -X GET -H "OCS-APIREQUEST: true" -u "nc_admin:$NC_ADMIN_PWD" $NC_ADDITIONAL_CURL_ARGS \ "$HOST/ocs/v2.php/cloud/users?search=$ADMIN_NAME"` \ || die "Failed to fetch Administrator user in Nextcloud" STATUS=`echo $RESULT | grep "$ADMIN_NAME" -c` if [ ! $STATUS -eq 1 ] ; then echo "Could not add Administrator to admin group, because user was not found:" echo $RESULT return fi RESULT=`nextcloud_curl -X POST -d "groupid=admin" -H "OCS-APIREQUEST: true" -u "nc_admin:$NC_ADMIN_PWD" $NC_ADDITIONAL_CURL_ARGS \ "$HOST/ocs/v2.php/cloud/users/$ADMIN_NAME/groups"` \ || die "Failed to add Administrator to admin group at Nextcloud" STATUS=`echo $RESULT | grep "200" -c` if [ ! $STATUS -eq 1 ] ; then echo "Could not add Administrator to admin group, because adding as group member failed:" echo $RESULT return fi } nextcloud_urlEncode() { python3 -c 'import urllib.parse, sys; print(urllib.parse.quote(sys.argv[1], sys.argv[2]))' \ "$1" "" } nextcloud_configure_saml() { udm saml/serviceprovider create "$@" \ --ignore_exists \ --position "cn=saml-serviceprovider,cn=univention,$ldap_base" \ --set isActivated=TRUE \ --set Identifier="https://$hostname.$domainname/nextcloud/apps/user_saml/saml/metadata" \ --set NameIDFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified" \ --set simplesamlAttributes=TRUE \ --set AssertionConsumerService="https://$hostname.$domainname/nextcloud/apps/user_saml/saml/acs" \ --set simplesamlNameIDAttribute="uid" \ --set singleLogoutService="https://$hostname.$domainname/nextcloud/apps/user_saml/saml/sls" || die IDP_CERT=$(curl -s https://"${ucs_server_sso_fqdn:-ucs-sso.$domainname}"/simplesamlphp/saml2/idp/certificate | sed -ne ' /-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p # got the range, ok /-END CERTIFICATE-/q # bailing out soon as the cert end seen ') SETCMD="univention-app shell nextcloud sudo -u www-data php /var/www/html/occ config:app:set user_saml" $SETCMD type --value="saml" $SETCMD general-require_provisioned_account --value="1" $SETCMD general-allow_multiple_user_back_ends --value="1" univention-app shell nextcloud sudo -u www-data php /var/www/html/occ saml:config:set \ --idp-x509cert="${IDP_CERT}" \ --general-uid_mapping="uid" \ --idp-singleLogoutService.url="https://${ucs_server_sso_fqdn}/simplesamlphp/saml2/idp/SingleLogoutService.php" \ --idp-singleSignOnService.url="https://${ucs_server_sso_fqdn}/simplesamlphp/saml2/idp/SSOService.php" \ --idp-entityId="https://${ucs_server_sso_fqdn}/simplesamlphp/saml2/idp/metadata.php" \ 1 } # Enables all Users that fit the filter to access Nextcloud nextcloud_modify_users() { if [ $IS_UPDATE = true ] || [ -z "$nextcloud_ucs_modifyUsersFilter" ] ; then echo "Not attempting to modify users." return fi SP_DN=$(univention-ldapsearch -LLL SAMLServiceProviderIdentifier=https://$hostname.$domainname/nextcloud/apps/user_saml/saml/metadata dn | cut -d ' ' -f 2) for dn in $(udm users/user list "$@" --filter "$nextcloud_ucs_modifyUsersFilter" | sed -ne 's/^DN: //p') ; do echo "modifying $dn .." udm users/user modify "$@" --dn "$dn" \ --set nextcloudEnabled="$nextcloud_ucs_userEnabled" \ --set nextcloudQuota="$nextcloud_ucs_userQuota" \ --append serviceprovider="$SP_DN" done } nextcloud_mark_initial_conig_done() { touch "$NC_PERMCONFDIR/initial_config_done" || die "Could not touch initial config flag" } nextcloud_curl() { local result local curlCode result=$(curl -s "$@") curlCode=$? #echo "curl exit code $curlCode params $@" > /dev/stderr if [ ! ${curlCode} -eq 0 ]; then debugOutput="" if [ "$nextcloud_ucs_debug" -eq 1 ]; then debugOutput=", parameters were\n\t$@" fi error_msg "curl failed with error $curlCode$debugOutput" exit ${curlCode} fi echo "$result" } detect_collabora () { # When Collabora (CODE) or Collabora Online is already installed on the UCS system when Nextcloud is going to be installed, # the richdocuments app is enabled and the WOPI URL is configured to the local system, if not already configured. # If the app is not present, the richdocuments app is disabled FQDN="$(ucr get hostname).$(ucr get domainname)" echo "Check for richdocuments app" if [ "$(ucr get appcenter/apps/collabora/status)" = "installed" ] || [ "$(ucr get appcenter/apps/collabora-online/status)" = "installed" ] ; then NC_OFFICE_SUITE=collabora univention-app shell nextcloud sudo -u www-data php /var/www/html/occ app:enable richdocuments occCode=$? if [ ${occCode} -eq 0 ] && [ "$(univention-app shell nextcloud sudo -u www-data php /var/www/html/occ config:app:get richdocuments wopi_url)" = "" ] ; then univention-app shell nextcloud sudo -u www-data php /var/www/html/occ config:app:set richdocuments wopi_url --value="https://$FQDN/" fi fi } detect_onlyoffice () { # When ONLYOFFICE is already installed on the UCS system when Nextcloud is going to be installed, # the onlyoffice app is enabled and the DocumentServerUrl is configured to the local system, if not already configured. # If the app is not present, the onlyoffice app is disabled FQDN="$(ucr get hostname).$(ucr get domainname)" echo "Check for onlyoffice app" if [ "$(ucr get appcenter/apps/onlyoffice-ds/status)" = "installed" ] || [ "$(ucr get appcenter/apps/onlyoffice-ds-integration/status)" = "installed" ] ; then NC_OFFICE_SUITE=onlyoffice univention-app shell nextcloud sudo -u www-data php /var/www/html/occ app:enable onlyoffice occCode=$? if [ ${occCode} -eq 0 ] && [ "$(univention-app shell nextcloud sudo -u www-data php /var/www/html/occ config:app:get onlyoffice DocumentServerUrl)" = "" ] ; then univention-app shell nextcloud sudo -u www-data php /var/www/html/occ config:app:set onlyoffice DocumentServerUrl --value="https://$FQDN/onlyoffice-documentserver" fi fi } if [ "$JS_LAST_EXECUTED_VERSION" = 2 ]; then ucr commit /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/default-ssl.conf joinscript_save_current_version else nextcloud_main "$@" fi