#!/usr/share/ucs-test/runner bash
# shellcheck shell=bash
## desc: Test faillog/lock_global via ssh and ldap
## roles: [domaincontroller_master]
## tags: [basic, univention]
## packages: [univention-directory-manager-tools, openssh-server]
## exposure: dangerous
## versions:
##  1.0-0: skip
##  2.4-0: fixed

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

RETVAL=100
NAME=$(user_randomname)

ucr set \
	auth/faillog=no \
	auth/faillog/lock_global=no \
	sshd/challengeresponse=yes \
	sshd/passwordauthentication=no

invoke-rc.d ssh restart

tdir=$(mktemp -d)
trap "rm -rf '$tdir' ; udm mail/domain remove --dn 'cn=$domainname,$ldap_base' ; user_remove '$NAME' ; ucr_restore ; invoke-rc.d ssh restart" EXIT
fake_passwd="$tdir/fake_passwd"
echo "foobar1234" >"$fake_passwd"

ssh_login () {
	univention-ssh -timeout 10 "$1" -o NumberOfPasswordPrompts=3 "$NAME@$hostname.$domainname" /usr/sbin/ucr get hostname
}

user_disabled () {
	udm-test users/user list --filter "uid=$NAME" | grep -q "^  disabled: 1"
}

udm mail/domain create --set name="$domainname"
user_create "$NAME" \
	--set password="$(<$tests_domainadmin_pwdfile)" \
	--set primaryGroup="$(get_domain_admins_dn)"

attempts=20
i=0
while ((i < attempts)) && ! /usr/lib/univention-pam/ldap-group-to-file.py; do
	((i+=1))
	sleep 1
done
if ((i==attempts)); then
	warning "ldap-group-to-file.py failed $i times"
fi

userdn=$(user_dn "$NAME")

# univention-ssh tries it 3 times
info "Login with wrong password via ssh"
ssh_login "$fake_passwd"
ssh_login "$fake_passwd"
ssh_login "$fake_passwd"
ssh_hostname="$(ssh_login "$tests_domainadmin_pwdfile")"
if [ "$ssh_hostname" != "$hostname" ]; then
	fail_test 110 "E: The login wasn't successful, but faillog is disabled"
fi

info "Activate global lock"
ucr set auth/faillog=yes auth/faillog/limit=6 auth/faillog/lock_global=yes
ssh_login "$fake_passwd"
ssh_hostname="$(ssh_login "$tests_domainadmin_pwdfile")"
if [ "$ssh_hostname" != "$hostname" ]; then
	fail_fast 110 "E: The login wasn't successful, but the users faillog is lower than the maximum"
fi
ssh_login "$fake_passwd" #3
ssh_login "$fake_passwd" #6
retry 30 user_disabled
wait_for_replication_and_postrun
ssh_hostname="$(ssh_login "$tests_domainadmin_pwdfile")"
if [ "$ssh_hostname" = "$hostname" ]; then
	fail_fast 110 "E: The login was successful, but the user should be locked"
fi

test_output=$(ldapsearch -LLL -D "$userdn" -y "$tests_domainadmin_pwdfile" -s base 1.1 | dn1)
if [ -n "$test_output" ]; then
	fail_test 110 "E: user can still do LDAP search but should be disabled in UDM"
	univention-directory-manager users/user list --filter "uid=$NAME"
	exit $RETVAL
fi

test_output=$(ldapwhoami -D "$userdn" -y "$tests_domainadmin_pwdfile")
if [ -n "$test_output" ]; then
	fail_test 110 "E: user can still do LDAP whoami but should be disabled in UDM"
	univention-directory-manager users/user list --filter "uid=$NAME"
	exit $RETVAL
fi

### Just locking would be good, but requires ppolicy LDAP overlay active and configured properly to temporarily block LDAP authentication too,
### so the /usr/lib/univention-pam/lock-user (which is called for auth/faillog/lock_global=yes) currently simply disables the account
# udm_locked=$(univention-directory-manager users/user list --filter "uid=$NAME" | grep "^  locked: 1")
# if [ "$udm_locked" != "  locked: 1" ]; then
# 	fail_test 110 "E: user was not locked in UDM"
# 	univention-directory-manager users/user list --filter "uid=$NAME"
#	exit $RETVAL
# fi

udm_disabled=$(univention-directory-manager users/user list --filter "uid=$NAME" | grep "^  disabled: 1")
if [ "$udm_disabled" != "  disabled: 1" ]; then
	fail_test 110 "E: user was not disabled in UDM"
	univention-directory-manager users/user list --filter "uid=$NAME"
	exit $RETVAL
fi

udm-test users/user modify --dn="$userdn" --set disabled=0 # --set locked=0

wait_for_replication_and_postrun

ssh_hostname="$(ssh_login "$tests_domainadmin_pwdfile")"
if [ "$ssh_hostname" != "$hostname" ]; then
	fail_test 110 "E: The login wasn't successful, but the fail counter should be reset"
	faillog -u "$NAME"
	exit $RETVAL
fi

test_output=$(ldapsearch -LLL -D "$userdn" -y "$tests_domainadmin_pwdfile" -s base 1.1 | dn1)
if [ -z "$test_output" ]; then
	fail_test 110 "E: The cannot do LDAP search, but the account should be re-enabled and un-locked again"
	univention-directory-manager users/user list --filter "uid=$NAME"
	exit $RETVAL
fi

test_output=$(ldapwhoami -D "$userdn" -y "$tests_domainadmin_pwdfile")
if [ -z "$test_output" ]; then
	fail_test 110 "E: The cannot do LDAP whoami, but the account should be re-enabled and un-locked again"
	univention-directory-manager users/user list --filter "uid=$NAME"
	exit $RETVAL
fi

exit $RETVAL
# vim: set ft=sh :
