# Copyright (c) 2021-2024 Andrew Ruthven <andrew@etc.gen.nz>
# Portions Copyright (c) Best Practical Solutions, LLC
#   <sales@bestpractical.com>, licensed under the GPL v2.
#
# In this test we create LDAP records that are slightly different from
# the previous test to make sure that changes are reflected.
#
# Database will start with:
#   pg_ldap_group1: pg_ldap1
#   pg_ldap_group2: pg_ldap2
#   pg_ldap_group3: <empty>
#   pg_ldap_group4: pg_ldap1
#
# We will change that to:
#   pg_ldap_group1: pg_ldap2
#   pg_ldap_group2: pg_ldap1, pg_ldap2
#   pg_ldap_group3: pg_ldap1
#   pg_ldap_group4: <empty>
#
# The fullanme for each group should change from "pg LDAP Group $n" to
# "pg_ldap_group_$n".
#
BEGINPERL
if ($debug) { $ENV{'LDAP_DEBUG'} = 1 };

use Net::LDAP::Server::Test;
use Net::LDAP;
use IO::Socket::INET;

my $ldap_port = 21394;
my $ldap_socket = IO::Socket::INET->new(
    Listen    => 5,
    Proto     => 'tcp',
    Reuse     => 1,
    LocalPort => $ldap_port,
);

# Keep it around after this block exits.
$evaled{'ldap_server'} = Net::LDAP::Server::Test->new( $ldap_socket, auto_schema => 1 );

my $ldap = Net::LDAP->new("localhost:$ldap_port") || die "Failed to instantiate Net::LDAP: $!";
$ldap->bind();
my $base   = "dc=example,dc=com";
my $users  = "ou=users,$base";
my $groups = "ou=groups,$base";
$ldap->add( $base );

# pg = posixGroup
for my $username (qw/pg_ldap1 pg_ldap2/) {
    my $dn       = "uid=$username,$users";
    (my $cn = $username) =~ s/_ldap(\d+)/LDAP $1/;
    my $entry    = {
        cn           => $cn,
        mail         => "$username\@example.com",
        uid          => $username,
        objectClass  => 'person',
        userPassword => $username,
        modifyTimestamp => 20240203001020,
    };
    $ldap->add( $dn, attr => [%$entry] );
}

make_group($ldap, 'pg_ldap_group1', 'pg_ldap2');
make_group($ldap, 'pg_ldap_group2', 'pg_ldap1', 'pg_ldap2');
make_group($ldap, 'pg_ldap_group3', 'pg_ldap1');
make_group($ldap, 'pg_ldap_group4');

# We need to keep the client around, otherwise the test server will exit.
$evaled{'ldap_client'} = $ldap;
sleep 60;

sub make_group {
    my $ldap = shift;
    my $name = shift;
    my @users = @_;

    my $dn    = "cn=$name,$groups";
    my $entry = {
        cn           => $name,
        objectClass  => 'posixGroup',
        description  => $name,
        (@users
            ? (memberUid => [ @users ])
            : ()
        ),
        modifyTimestamp => 20240203001020,
    };
    $ldap->add( $dn, attr => [%$entry] );
}
ENDPERL

SCRIPT=../scripts/cron-sync-ldap.php regression_ldap.host

# Testing logging in as one of the users - should work.
TYPE=PROPFIND
URL=http://regression_ldap.host/caldav.php/
HEADER=Content-Type: text/xml
HEADER=Depth: 1
AUTH=pg_ldap1:pg_ldap1
HEAD

BEGINDATA
<?xml version="1.0" encoding="utf-8" ?>
<D:propfind xmlns:D="DAV:">
  <D:prop>
    <D:resourcetype/>
  </D:prop>
</D:propfind>
ENDDATA

# Check that a usr record has been created for all users and groups
QUERY
SELECT active, email, fullname, last_used, password, username
FROM usr
WHERE username LIKE 'pg_ldap%'
ORDER BY username;
ENDQUERY

# Check that group membership matches what was created above.
QUERY
SELECT grp_u.username AS group_name, usr_u.username AS user_name
FROM principal AS grp_p
  left join group_member ON       (grp_p.principal_id = group_member.group_id)
  left join principal AS usr_p ON (group_member.member_id = usr_p.principal_id)
  left join usr AS usr_u ON       (usr_p.user_no = usr_u.user_no)
  left join usr AS grp_u ON       (grp_p.user_no = grp_u.user_no)
WHERE grp_u.username LIKE 'pg_ldap_group%'
ORDER BY group_name, user_name;
ENDQUERY
