#!/usr/share/ucs-test/runner bash
# shellcheck shell=bash
## desc: "User initiated password change with samba and kerberos"
## exposure: dangerous
## packages:
##  - univention-samba4
## roles:
## - domaincontroller_master
## - domaincontroller_backup
## - domaincontroller_slave
## tags: [SKIP-UCSSCHOOL,basic,apptest]

# shellcheck source=../../lib/base.sh
. "$TESTLIBPATH/base.sh" || exit 137
# shellcheck source=../../lib/user.sh
. "$TESTLIBPATH/user.sh" || exit 137
# shellcheck source=../../lib/shares.sh
. "$TESTLIBPATH/shares.sh" || exit 137
# shellcheck source=../../lib/random.sh
. "$TESTLIBPATH/random.sh" || exit 137
# shellcheck source=../../lib/samba.sh
. "$TESTLIBPATH/samba.sh" || exit 137

#----create User
SAMBA="true"
MAIL="false"
KERBEROS="true"
PERSON="false"
POSIX="true"

CONNECTOR_TIMEOUT=16

username="$(user_randomname)"
first_password=univention
second_password="$(random_chars 8 ${_upperletters}${_lowerletters}${_ciphers}äöü)z1AÄÖÜ"
third_password="$(random_chars 8 ${_upperletters}${_lowerletters}${_ciphers}äöü)z1AÄÖÜ"

check_domainadmin_credentials || fail_fast 77 "UCR variables for admin credentials are not set"
# shellcheck disable=SC2034
ADMINISTRATOR_NAME="$(univention-ldapsearch -b "$tests_domainadmin_account" uid | VAL uid)"

min_pwd_age="$(samba-tool domain passwordsettings show | VAL 'Minimum password age[^:]*')"
pwd_complexity="$(samba-tool domain passwordsettings show | VAL 'Password complexity')"
samba-tool domain passwordsettings set --complexity=off --min-pwd-age=0
trap 'user_remove "$username"; samba-tool domain passwordsettings set --min-pwd-age="$min_pwd_age" --complexity="$pwd_complexity"' INT TERM EXIT

user_create "$username" ||
	fail_fast 1 "User could not be created"

wait_for_replication
wait_for_drs_replication "(sAMAccountName=$username)"
sleep $CONNECTOR_TIMEOUT

command_output=$(echo "$first_password" | kinit --password-file=STDIN "$username" 2>&1) ||
	fail_fast 1 "Could not authenticate against kinit: $command_output"
echo "Authentication against kinit succeeded."

USER_DN=$(udm-test users/user list --filter uid="$username" | DN1)

#--test starting point
#----password change with samba-tool
echo "----password change with samba-tool"
sambaPwdLastSet="$(univention-ldapsearch -b "$USER_DN" sambaPwdLastSet | VAL sambaPwdLastSet)"
echo "Setting new password: $second_password"
samba-tool user password -U"$username" --password="$first_password" --newpassword="$second_password" ||
	fail_fast 1 "Password change with samba-tool failed"

force_drs_replication -o
sleep $CONNECTOR_TIMEOUT

## first check trivial case: Samba4 password must work
check_ldap_search () {
	ldbsearch -U "$username%$second_password" -H ldap://localhost "sAMAccountName=$username" dn 2>&1 | grep -q '^dn:'
}
retry_delay=0 retry "$DRS_REPLICATION_TIMEOUT" check_ldap_search ||
	fail_fast 1 "Could not authenticate against LDAP after password change with samba after $retry_i seconds."

echo "Authentication against samba after password change with samba."

wait_ldap_spls_changed () {
	[ "$(univention-ldapsearch -b "$USER_DN" sambaPwdLastSet | VAL sambaPwdLastSet)" != "$sambaPwdLastSet" ]
}
retry "$DRS_REPLICATION_TIMEOUT" wait_ldap_spls_changed || {
		echo "sambaPwdLastSet did not change in UDM after $retry_i seconds."
		if output="$(univention-ldapsearch -D "$USER_DN" -w "$first_password" -b "$USER_DN" dn 2>&1 )"; then
			echo "FAIL: Previous password still valid in LDAP"
		fi
		fail_fast 1
}
echo "sambaPwdLastSet change check succeeded after $((retry_i+1)) seconds."

## second check complex case: UDM password must work after replication
output="$(univention-ldapsearch -D "$USER_DN" -w "$second_password" -b "$USER_DN" dn 2>&1 )" ||
	fail_fast 1 "Could not authenticate against LDAP after password change with samba: $output"
echo "Authentication against LDAP after password change with samba succeeded."

## cross check
command_output=$(echo "$second_password" | kinit --password-file=STDIN "$username" 2>&1) ||
	fail_fast 1 "Could not authenticate against kinit after password change with samba."
echo "Authentication against kinit after password change with samba succeeded."

echo "----password change with kpasswd"
#----password change with kpassword
check_kpw_changed () {
	! python3 kpasswd_change_pwd.py -u "$username" -n "$third_password" -p "$second_password" | grep nSoft
}
retry_delay=5 retry 20 check_kpw_changed ||
		echo "Password change with kpasswd: Soft error."
echo "Setting new password: $third_password"
sleep $CONNECTOR_TIMEOUT

## first check trivial case: Samba4 password must work, at least after the DRS repliction was successful
check_ldb_search () {
	ldbsearch -U "$username%$third_password" -H ldap://localhost "sAMAccountName=$username" dn 2>&1 | grep -q '^dn:'
}
retry $DRS_REPLICATION_TIMEOUT check_ldb_search ||
	fail_fast 1 "Could not authenticate against samba after password change with kpasswd after $retry_i seconds."
echo "Authentication against samba after password change with kpasswd succeeded after $((retry_i+1)) seconds."

# In case the previous check used the local KDC we should here wait for the DRS replication
retry "$DRS_REPLICATION_TIMEOUT" wait_ldap_spls_changed ||
	fail_fast 1 "sambaPwdLastSet did not change in UDM after $retry_i seconds."
echo "sambaPwdLastSet change check succeeded after $((retry_i+1)) seconds."

## second check complex case: UDM password must work after replication
test_ldap_auth () {
	output="$(univention-ldapsearch -D "$USER_DN" -w "$third_password" -b "$USER_DN" dn 2>&1)"
}
retry "$DRS_REPLICATION_TIMEOUT" test_ldap_auth || {
		if output="$(univention-ldapsearch -D "$USER_DN" -w "$second_password" -b "$USER_DN" dn 2>&1 )"; then
			echo "FAIL: Previous password still valid in LDAP"
		fi
		fail_fast 1 "Could not authenticate against UDM after password change with kpasswd after $retry_i seconds."
}
echo "Authentication against LDAP after password change with kpasswd succeeded after $((retry_i+1)) seconds."

## cross check
# this should now work directly
if ! output=$(echo "$third_password" | kinit --password-file=STDIN "$username")
then
	echo "$output"
	fail_fast 1 "Could not authenticate against kinit after password change with kpasswd."
fi
echo "Authentication against kinit after password change with kpasswd succeeded."

exit "$RETVAL"
