#! /bin/sh
# $OpenLDAP$
## This work is part of OpenLDAP Software <http://www.openldap.org/>.
##
## Copyright 2022-2024 The OpenLDAP Foundation.
## All rights reserved.
##
## Redistribution and use in source and binary forms, with or without
## modification, are permitted only as authorized by the OpenLDAP
## Public License.
##
## A copy of this license is available in the file LICENSE in the
## top-level directory of the distribution or, alternatively, at
## <http://www.OpenLDAP.org/license.html>.

echo "running defines.sh"
. $SRCDIR/scripts/defines.sh

ITS=9863
ITSDIR=$DATADIR/regressions/its$ITS

if test $BACKLDAP = "ldapno" ; then
	echo "LDAP backend not available, test skipped"
	exit 0
fi
if test $SYNCPROV = "syncprovno" ; then
	echo "syncprov overlay not available, test skipped"
	exit 0
fi
if test $AUDITLOG = "auditlogno" ; then
	echo "auditlog overlay not available, test skipped"
	exit 0
fi
if test $UNIQUE = "uniqueno" ; then
	echo "unique overlay not available, test skipped"
	exit 0
fi
if test $CONSTRAINT = "constraintno" ; then
	echo "constraint overlay not available, test skipped"
	exit 0
fi

echo "This test checks slapo-chain behavior when forwarding lastbind"
echo "information to a provider as the rootdn when using a SASL mechanism"
echo "and authzto to allow identity assumption"
echo "Test #1 ensures that authzid in IDAssertBind is working correctly."
echo "Test #2 ensures that ACLbind works correctly."

PDIR=$TESTDIR/prov
CDIR=$TESTDIR/cons
mkdir -p $TESTDIR $PDIR/db $PDIR/slapd.d
mkdir -p $CDIR/db $CDIR/slapd.d

$SLAPPASSWD -g -n >$CONFIGPWF

cp -r $DATADIR/tls $TESTDIR
cp $ITSDIR/db.ldif $TESTDIR

#
# Start slapd that acts as a remote LDAP server that will be proxied
#
echo "Running slapadd to build database on the provider..."
. $CONFFILTER $BACKEND <  $ITSDIR/slapd-provider.ldif > $CONFLDIF
$SLAPADD -F $PDIR/slapd.d -n 0 -l $CONFLDIF
$SLAPADD -F $PDIR/slapd.d -q -b $BASEDN -l $TESTDIR/db.ldif
RC=$?
if test $RC != 0 ; then
	echo "slapadd failed ($RC)!"
	exit $RC
fi

echo "Starting slapd provider on TCP/IP port $PORT1 and ${PORT2}..."
$SLAPD -F $PDIR/slapd.d -h "$URI1 $SURI2" -d $LVL > $LOG1 2>&1 &
PROVPID=$!
if test $WAIT != 0 ; then
	echo PROVPID $PROVPID
	read foo
fi
KILLPIDS="$KILLPIDS $PROVPID"

echo "Using ldapsearch to check that slapd is running..."
for i in 0 1 2 3 4 5; do
	$LDAPSEARCH -s base -b "$MONITORDN" -H $URI1 \
		-D $MANAGERDN \
		-w $PASSWD \
		'objectclass=*' > /dev/null 2>&1
	RC=$?
	if test $RC = 0 ; then
		break
	fi
	echo "Waiting $SLEEP0 seconds for slapd to start..."
	sleep $SLEEP0
done

if test $RC != 0 ; then
	echo "ldapsearch failed ($RC)!"
	test $KILLSERVERS != no && kill -HUP $PROVPID
	exit $RC
fi

#
# Start slapd consumer
#
echo "Starting slapd consumer on TCP/IP port $PORT3 and ${PORT4}..."
. $CONFFILTER $BACKEND < $ITSDIR/slapd-consumer.ldif > $CONF2
$SLAPADD -F $CDIR/slapd.d -n 0 -l $CONF2
$SLAPD -F $CDIR/slapd.d -h "$URI3 $SURI4" -d $LVL > $LOG2 2>&1 &
CONSPID=$!
if test $WAIT != 0 ; then
	echo CONSPID $CONSPID
	read foo
fi
KILLPIDS="$KILLPIDS $CONSPID"

echo "Using ldapsearch to check that slapd is running..."
for i in 0 1 2 3 4 5; do
	$LDAPSEARCH -s base -b "$MONITORDN" -H $URI3 \
		-D $MANAGERDN \
		-w $PASSWD \
		'objectclass=*' > /dev/null 2>&1
	RC=$?
	if test $RC = 0 ; then
		break
	fi
	echo "Waiting $SLEEP0 seconds for slapd to start..."
	sleep $SLEEP0
done

if test $RC != 0 ; then
	echo "ldapsearch failed ($RC)!"
	test $KILLSERVERS != no && kill -HUP $KILLPIDS
	exit $RC
fi

$LDAPWHOAMI -H $URI3 -x -D "cn=replicator,dc=example,dc=com" -w secret >/dev/null
RC=$?
if test $RC != 0 ; then
	echo "ldapwhoami failed ($RC)!"
	test $KILLSERVERS != no && kill -HUP $KILLPIDS
	exit $RC
fi

echo "Sleeping $SLEEP1 seconds for replication of pwdLastSuccess attribute..."
sleep $SLEEP1

$LDAPSEARCH -H $URI3 -D "$MANAGERDN" -w $PASSWD -b "$BASEDN" "(cn=replicator)" pwdLastSuccess > $SEARCHOUT 2>&1
PWDLASTSUCCESS=`grep "pwdLastSuccess:" $SEARCHOUT | wc -l`

if test $PWDLASTSUCCESS != 1 ; then
	echo "Failure: pwdLastSuccess failed to replicate"
	test $KILLSERVERS != no && kill -HUP $KILLPIDS
	exit 1
fi

echo "Reconfiguring for ACL bind test..."
$LDAPMODIFY -H $URI3 -D cn=config -y $CONFIGPWF <<EOF >>$TESTOUT 2>&1
dn: olcDatabase={0}ldap,olcOverlay={0}chain,olcDatabase={-1}frontend,cn=config
changetype: modify
replace: olcDbIDAssertBind
olcDbIDAssertBind: mode=self flags=override,prescriptive,proxy-authz-critical 
 bindmethod=sasl saslmech=external tls_cert=$TESTDIR/tls/certs/ldap-server.crt 
 tls_key=$TESTDIR/tls/private/ldap-server.key 
 tls_cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt
-
add: olcDbACLBind
olcDbACLBind: bindmethod=sasl saslmech=external tls_cert=$TESTDIR/tls/certs/ldap-server.crt 
 tls_key=$TESTDIR/tls/private/ldap-server.key 
 tls_cacert=$TESTDIR/tls/ca/certs/testsuiteCA.crt 
 authzid="dn:cn=manager,dc=example,dc=com"
EOF

RC=$?
if test $RC != 0; then
        echo "ldapmodify failed ($RC)!"
        test $KILLSERVERS != no && kill -HUP $KILLPIDS
        exit $RC
fi

echo "Stopping consumer to test recovery..."
kill -HUP $CONSPID
wait $CONSPID

KILLPIDS="$PROVPID"

echo "Starting slapd consumer on TCP/IP port $PORT3 and ${PORT4}..."
$SLAPD -F $CDIR/slapd.d -h "$URI3 $SURI4" -d $LVL > $LOG2 2>&1 &
CONSPID=$!
if test $WAIT != 0 ; then
	echo CONSPID $CONSPID
	read foo
fi
KILLPIDS="$KILLPIDS $CONSPID"

echo "Using ldapsearch to check that slapd is running..."
for i in 0 1 2 3 4 5; do
	$LDAPSEARCH -s base -b "$MONITORDN" -H $URI3 \
		-D $MANAGERDN \
		-w $PASSWD \
		'objectclass=*' > /dev/null 2>&1
	RC=$?
	if test $RC = 0 ; then
		break
	fi
	echo "Waiting $SLEEP0 seconds for slapd to start..."
	sleep $SLEEP0
done

if test $RC != 0 ; then
	echo "ldapsearch failed ($RC)!"
	test $KILLSERVERS != no && kill -HUP $KILLPIDS
	exit $RC
fi

$LDAPMODIFY -H $URI1 -D "$MANAGERDN" -w $PASSWD -e \!relax <<EOF >>$TESTOUT 2>&1
dn: cn=replicator,dc=example,dc=com
changetype: modify
delete: pwdLastSuccess
EOF

RC=$?
if test $RC != 0; then
        echo "ldapmodify failed ($RC)!"
        test $KILLSERVERS != no && kill -HUP $KILLPIDS
        exit $RC
fi

echo "Sleeping $SLEEP1 seconds for replication of delete for pwdLastSuccess attribute..."
sleep $SLEEP1

$LDAPSEARCH -H $URI3 -D "$MANAGERDN" -w $PASSWD -b "$BASEDN" "(cn=replicator)" pwdLastSuccess > $SEARCHOUT 2>&1
PWDLASTSUCCESS=`grep "pwdLastSuccess:" $SEARCHOUT | wc -l`

if test $PWDLASTSUCCESS != 0 ; then
	echo "Failure: pwdLastSuccess failed to delete"
	test $KILLSERVERS != no && kill -HUP $KILLPIDS
	exit 1
fi

$LDAPWHOAMI -H $URI3 -x -D "cn=replicator,dc=example,dc=com" -w secret >/dev/null
RC=$?
if test $RC != 0 ; then
	echo "ldapwhoami failed ($RC)!"
	test $KILLSERVERS != no && kill -HUP $KILLPIDS
	exit $RC
fi

echo "Sleeping $SLEEP1 seconds for replication of pwdLastSuccess attribute..."
sleep $SLEEP1

$LDAPSEARCH -H $URI3 -D "$MANAGERDN" -w $PASSWD -b "$BASEDN" "(cn=replicator)" pwdLastSuccess > $SEARCHOUT 2>&1
PWDLASTSUCCESS=`grep "pwdLastSuccess:" $SEARCHOUT | wc -l`

if test $PWDLASTSUCCESS != 1 ; then
	echo "Failure: pwdLastSuccess failed to replicate"
	test $KILLSERVERS != no && kill -HUP $KILLPIDS
	exit 1
fi

USER="uid=test,ou=people,dc=example,dc=com"
echo "Changing password for $USER to test proxied user modifications work..."
$LDAPPASSWD -H $URI3 \
    -w secret -s secret \
    -D "$USER" >> $TESTOUT 2>&1
RC=$?
if test $RC != 0 ; then
    echo "ldappasswd failed ($RC)!"
    test $KILLSERVERS != no && kill -HUP $KILLPIDS
    exit $RC
fi

echo "Changing cn for $USER to test disallowed proxied user modifications should fail..."
$LDAPMODIFY -H $URI3 -D "$USER" -w $PASSWD <<EOF >>$TESTOUT 2>&1
dn: $USER
changetype: modify
replace: cn
cn: blahblahblah
EOF

RC=$?
if test $RC != 50; then
        echo "ldapmodify should have failed with result code 50, got ($RC)!"
        test $KILLSERVERS != no && kill -HUP $KILLPIDS
        exit $RC
fi

test $KILLSERVERS != no && kill -HUP $KILLPIDS 2>/dev/null

echo ">>>>> Test succeeded"

test $KILLSERVERS != no && wait

exit 0
