#!/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/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"
ADMINISTRATOR_NAME="$(univention-ldapsearch -b "$tests_domainadmin_account" uid | grep uid | sed -ne 's/^uid: //p')"

min_pwd_age="$(samba-tool domain passwordsettings show | grep "Minimum password age" | sed s/[^0-9]*/""/)"
pwd_complexity="$(samba-tool domain passwordsettings show | grep complexity | sed "s/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

if ! user_create "$username"; then
	fail_fast 1 "User could not be created"
fi

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

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

USER_DN=$(udm-test users/user list --filter uid="$username" | sed -ne 's/^DN: //p')

#--test starting point
#----password change with samba-tool
echo "----password change with samba-tool"
sambaPwdLastSet="$(univention-ldapsearch -b "$USER_DN" sambaPwdLastSet | sed -n 's/^sambaPwdLastSet: //p')"
samba-tool user password -U"$username" --password="$first_password" --newpassword="$second_password"
echo "Setting new password: $second_password"
if ! [ $? -eq 0 ]; then
	fail_fast 1 "Password change with samba-tool failed"
fi

force_drs_replication -o
sleep $CONNECTOR_TIMEOUT

## first check trivial case: Samba4 password must work
i=0
while ! ldbsearch -U "$username%$second_password" -H ldap://localhost "sAMAccountName=$username" dn 2>&1 | grep -q '^dn:'
do
	i=$((i+1))
	if [ $i -gt $DRS_REPLICATION_TIMEOUT ]; then
		fail_fast 1 "Could not authenticate against LDAP after password change with samba after $i seconds."
	fi
done

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

i=0

while [ "$(univention-ldapsearch -b "$USER_DN" sambaPwdLastSet | sed -n 's/^sambaPwdLastSet: //p')" == "$sambaPwdLastSet" ]; do
	i=$((i+1))
	if [ $i -gt $DRS_REPLICATION_TIMEOUT ]; then
		echo "sambaPwdLastSet did not change in UDM after $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
	fi
	sleep 1
done
echo "sambaPwdLastSet change check succeeded after $((i+1)) seconds."

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

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

echo "----password change with kpasswd"
#----password change with kpassword
max_i=20
delta_t=5
i=0
while true
do
	retval="$(python3 kpasswd_change_pwd.py -u "$username" -n "$third_password" -p "$second_password")"
	echo "$retval" | grep "nSoft" || break
	let i="$i"+1
	if [ "$i" = "$max_i" ]; then
		echo "Password change with kpasswd: Soft error."
		break
	fi
	sleep "$delta_t"
done
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
i=0
while ! ldbsearch -U "$username%$third_password" -H ldap://localhost "sAMAccountName=$username" dn 2>&1 | grep -q '^dn:'
do
	i=$((i+1))
	if [ $i -gt $DRS_REPLICATION_TIMEOUT ]; then
		fail_fast 1 "Could not authenticate against samba after password change with kpasswd after $i seconds."
		break
	fi
	sleep 1
done
echo "Authentication against samba after password change with kpasswd succeeded after $((i+1)) seconds."

# In case the previous check used the local KDC we should here wait for the DRS replication
i=0
while [ "$(univention-ldapsearch -b "$USER_DN" sambaPwdLastSet | sed -n 's/^sambaPwdLastSet: //p')" == "$sambaPwdLastSet" ]; do
	i=$((i+1))
	if [ $i -gt $DRS_REPLICATION_TIMEOUT ]; then
		fail_fast 1 "sambaPwdLastSet did not change in UDM after $i seconds."
		break
	fi
	sleep 1
done
echo "sambaPwdLastSet change check succeeded after $((i+1)) seconds."

## second check complex case: UDM password must work after replication
i=0
while ! output="$(univention-ldapsearch -D "$USER_DN" -w "$third_password" -b "$USER_DN" dn 2>&1 )"
do
	i=$((i+1))
	echo $output
	if [ $i -gt $DRS_REPLICATION_TIMEOUT ]; then
		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 $i seconds."
		break
	fi
	sleep 1
done
echo "Authentication against LDAP after password change with kpasswd succeeded after $((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
