diff --git a/resources/autoload.php b/resources/autoload.php index 158db4bc..0531a750 100644 --- a/resources/autoload.php +++ b/resources/autoload.php @@ -14,6 +14,7 @@ // load libs require_once __DIR__ . "/lib/UnityLDAP.php"; require_once __DIR__ . "/lib/UnityUser.php"; +require_once __DIR__ . "/lib/PosixGroup.php"; require_once __DIR__ . "/lib/UnityGroup.php"; require_once __DIR__ . "/lib/UnityOrg.php"; require_once __DIR__ . "/lib/UnitySQL.php"; diff --git a/resources/lib/PosixGroup.php b/resources/lib/PosixGroup.php new file mode 100644 index 00000000..5850e326 --- /dev/null +++ b/resources/lib/PosixGroup.php @@ -0,0 +1,82 @@ +entry = $entry; + } + + public function getDN(): string + { + return $this->entry->getDN(); + } + + public function equals(PosixGroup $other_group): bool + { + if (!is_a($other_group, self::class)) { + throw new Exception( + "Unable to check equality because the parameter is not a " . + self::class . + " object", + ); + } + return $this->getDN() == $other_group->getDN(); + } + + public function exists(): bool + { + return $this->entry->exists(); + } + + public function getMemberUIDs(): array + { + $members = $this->entry->getAttribute("memberuid"); + sort($members); + return $members; + } + + public function addMemberUID(string $uid): void + { + $this->entry->appendAttribute("memberuid", $uid); + $this->entry->write(); + } + + public function addMemberUIDs(array $uids): void + { + foreach ($uids as $uid) { + $this->entry->appendAttribute("memberuid", $uid); + } + $this->entry->write(); + } + + public function removeMemberUID(string $uid): void + { + $this->entry->removeAttributeEntryByValue("memberuid", $uid); + $this->entry->write(); + } + + public function removeMemberUIDs(array $uids): void + { + foreach ($uids as $uid) { + $this->entry->removeAttributeEntryByValue("memberuid", $uid); + } + $this->entry->write(); + } + + public function memberUIDExists(string $uid): bool + { + return in_array($uid, $this->getMemberUIDs()); + } +} diff --git a/resources/lib/UnityGroup.php b/resources/lib/UnityGroup.php index 688d7106..8d24a61b 100644 --- a/resources/lib/UnityGroup.php +++ b/resources/lib/UnityGroup.php @@ -8,12 +8,10 @@ /** * Class that represents a single PI group in the Unity Cluster. */ -class UnityGroup +class UnityGroup extends PosixGroup { public const string PI_PREFIX = "pi_"; - public string $gid; - private LDAPEntry $entry; private UnityLDAP $LDAP; private UnitySQL $SQL; private UnityMailer $MAILER; @@ -26,42 +24,19 @@ public function __construct( UnityMailer $MAILER, UnityWebhook $WEBHOOK, ) { - $gid = trim($gid); + parent::__construct($LDAP->getPIGroupEntry(trim($gid))); $this->gid = $gid; - $this->entry = $LDAP->getPIGroupEntry($gid); - $this->LDAP = $LDAP; $this->SQL = $SQL; $this->MAILER = $MAILER; $this->WEBHOOK = $WEBHOOK; } - public function equals(UnityGroup $other_group): bool - { - if (!is_a($other_group, self::class)) { - throw new Exception( - "Unable to check equality because the parameter is not a " . - self::class . - " object", - ); - } - - return $this->gid == $other_group->gid; - } - public function __toString(): string { return $this->gid; } - /** - * Checks if the current PI is an approved and existent group - */ - public function exists(): bool - { - return $this->entry->exists(); - } - public function requestGroup(bool $send_mail_to_admins, bool $send_mail = true): void { if ($this->exists()) { @@ -202,7 +177,7 @@ public function approveUser(UnityUser $new_user, bool $send_mail = true): void { $request = $this->SQL->getRequest($new_user->uid, $this->gid); \ensure($new_user->exists()); - $this->addUserToGroup($new_user); + $this->addMemberUID($new_user->uid); $this->SQL->removeRequest($new_user->uid, $this->gid); if ($send_mail) { $this->MAILER->sendMail($new_user->getMail(), "group_user_added", [ @@ -240,14 +215,14 @@ public function denyUser(UnityUser $new_user, bool $send_mail = true): void public function removeUser(UnityUser $new_user, bool $send_mail = true): void { - if (!$this->memberExists($new_user)) { + if (!$this->memberUIDExists($new_user->uid)) { return; } if ($new_user->uid == $this->getOwner()->uid) { throw new Exception("Cannot delete group owner from group. Disband group instead"); } // remove request, this will fail silently if the request doesn't exist - $this->removeUserFromGroup($new_user); + $this->removeMemberUID($new_user->uid); if ($send_mail) { $this->MAILER->sendMail($new_user->getMail(), "group_user_removed", [ "group" => $this->gid, @@ -264,7 +239,7 @@ public function removeUser(UnityUser $new_user, bool $send_mail = true): void public function newUserRequest(UnityUser $new_user, bool $send_mail = true): void { - if ($this->memberExists($new_user)) { + if ($this->memberUIDExists($new_user->uid)) { UnityHTTPD::errorLog("warning", "user '$new_user' already in group"); return; } @@ -310,7 +285,7 @@ public function getRequests(): array public function getGroupMembers(): array { - $members = $this->getGroupMemberUIDs(); + $members = $this->getMemberUIDs(); $out = []; foreach ($members as $member) { $user_obj = new UnityUser( @@ -325,13 +300,6 @@ public function getGroupMembers(): array return $out; } - public function getGroupMemberUIDs(): array - { - $members = $this->entry->getAttribute("memberuid"); - sort($members); - return $members; - } - public function requestExists(UnityUser $user): bool { $requesters = $this->getRequests(); @@ -358,23 +326,6 @@ private function init(): void // we need to update the cache here with the memberuid } - private function addUserToGroup(UnityUser $new_user): void - { - $this->entry->appendAttribute("memberuid", $new_user->uid); - $this->entry->write(); - } - - private function removeUserFromGroup(UnityUser $old_user): void - { - $this->entry->removeAttributeEntryByValue("memberuid", $old_user->uid); - $this->entry->write(); - } - - public function memberExists(UnityUser $user): bool - { - return in_array($user->uid, $this->getGroupMemberUIDs()); - } - private function addRequest(string $uid): void { $this->SQL->addRequest($uid, $this->gid); @@ -418,7 +369,7 @@ public static function ownerMail2GID(string $email): string public function getGroupMembersAttributes(array $attributes, array $default_values = []): array { return $this->LDAP->getUsersAttributes( - $this->getGroupMemberUIDs(), + $this->getMemberUIDs(), $attributes, $default_values, ); diff --git a/resources/lib/UnityOrg.php b/resources/lib/UnityOrg.php index 07d12ec1..4ccedcc3 100644 --- a/resources/lib/UnityOrg.php +++ b/resources/lib/UnityOrg.php @@ -3,10 +3,9 @@ namespace UnityWebPortal\lib; use PHPOpenLDAPer\LDAPEntry; -class UnityOrg +class UnityOrg extends PosixGroup { public string $gid; - private LDAPEntry $entry; private UnityLDAP $LDAP; private UnitySQL $SQL; private UnityMailer $MAILER; @@ -19,16 +18,19 @@ public function __construct( UnityMailer $MAILER, UnityWebhook $WEBHOOK, ) { - $gid = trim($gid); + parent::__construct($LDAP->getOrgGroupEntry(trim($gid))); $this->gid = $gid; - $this->entry = $LDAP->getOrgGroupEntry($this->gid); - $this->LDAP = $LDAP; $this->SQL = $SQL; $this->MAILER = $MAILER; $this->WEBHOOK = $WEBHOOK; } + public function __toString(): string + { + return $this->gid; + } + public function init(): void { \ensure(!$this->entry->exists()); @@ -38,19 +40,9 @@ public function init(): void $this->entry->write(); } - public function exists(): bool - { - return $this->entry->exists(); - } - - public function inOrg(UnityUser $user): bool - { - return in_array($user->uid, $this->getOrgMemberUIDs()); - } - public function getOrgMembers(): array { - $members = $this->getOrgMemberUIDs(); + $members = $this->getMemberUIDs(); $out = []; foreach ($members as $member) { $user_obj = new UnityUser( @@ -64,23 +56,4 @@ public function getOrgMembers(): array } return $out; } - - public function getOrgMemberUIDs(): array - { - $members = $this->entry->getAttribute("memberuid"); - sort($members); - return $members; - } - - public function addUser(UnityUser $user): void - { - $this->entry->appendAttribute("memberuid", $user->uid); - $this->entry->write(); - } - - public function removeUser(UnityUser $user): void - { - $this->entry->removeAttributeEntryByValue("memberuid", $user->uid); - $this->entry->write(); - } } diff --git a/resources/lib/UnityUser.php b/resources/lib/UnityUser.php index 086f53af..16b4514f 100644 --- a/resources/lib/UnityUser.php +++ b/resources/lib/UnityUser.php @@ -90,8 +90,8 @@ public function init( $org->init(); } - if (!$org->inOrg($this)) { - $org->addUser($this); + if (!$org->memberUIDExists($this->uid)) { + $org->addMemberUID($this->uid); } $this->SQL->addLog($this->uid, $_SERVER["REMOTE_ADDR"], "user_added", $this->uid); @@ -416,6 +416,6 @@ public function isInGroup(string $uid, UnityGroup $group): bool $group_checked = $group; } - return in_array($uid, $group_checked->getGroupMemberUIDs()); + return in_array($uid, $group_checked->getMemberUIDs()); } } diff --git a/test/functional/AccountDeletionRequestTest.php b/test/functional/AccountDeletionRequestTest.php index 83177b25..8b595901 100644 --- a/test/functional/AccountDeletionRequestTest.php +++ b/test/functional/AccountDeletionRequestTest.php @@ -49,7 +49,7 @@ public function testRequestAccountDeletionUserHasRequest() switchUser(...$pi_args); $pi = $USER; $pi_group = $USER->getPIGroup(); - $this->assertEqualsCanonicalizing([$pi->uid], $pi_group->getGroupMemberUIDs()); + $this->assertEqualsCanonicalizing([$pi->uid], $pi_group->getMemberUIDs()); $user_args = getBlankUser(); switchUser(...$user_args); $this->assertEmpty($USER->getPIGroupGIDs()); diff --git a/test/functional/PIMemberRequestTest.php b/test/functional/PIMemberRequestTest.php index f42c600a..5d3975f1 100644 --- a/test/functional/PIMemberRequestTest.php +++ b/test/functional/PIMemberRequestTest.php @@ -38,7 +38,7 @@ public function testRequestMembership() $uid = $USER->uid; $this->assertFalse($USER->isPI()); $this->assertFalse($SQL->requestExists($uid, UnitySQL::REQUEST_BECOME_PI)); - $this->assertFalse($pi_group->memberExists($USER)); + $this->assertFalse($pi_group->memberUIDExists($USER->uid)); try { $this->requestMembership($gid); $this->assertTrue($SQL->requestExists($uid, $gid)); diff --git a/test/functional/PiMemberApproveTest.php b/test/functional/PiMemberApproveTest.php index db9cb2b0..51e90acb 100644 --- a/test/functional/PiMemberApproveTest.php +++ b/test/functional/PiMemberApproveTest.php @@ -54,7 +54,7 @@ public function testApproveNonexistentRequest() $this->assertTrue($piGroup->exists()); $this->assertGroupMembers($piGroup, [$piUID]); $this->assertEmpty($piGroup->getRequests()); - $this->assertFalse($piGroup->memberExists($user)); + $this->assertFalse($piGroup->memberUIDExists($user->uid)); $this->assertEmpty($piGroup->getRequests()); try { $this->expectException(Exception::class); // FIXME more specific exception type @@ -77,7 +77,7 @@ public function testApproveMemberByPI() $this->assertTrue($USER->exists()); $this->assertTrue($pi_group->exists()); $this->assertGroupMembers($pi_group, [$pi_uid]); - $this->assertTrue(!$pi_group->memberExists($USER)); + $this->assertTrue(!$pi_group->memberUIDExists($USER->uid)); $this->assertRequestedMembership(false, $gid); try { $this->requestGroupMembership($pi_group->gid); @@ -106,7 +106,7 @@ public function testApproveMemberByPI() $this->assertTrue(!$pi_group->requestExists($USER)); $this->assertRequestedMembership(false, $gid); - $this->assertTrue($pi_group->memberExists($USER)); + $this->assertTrue($pi_group->memberUIDExists($USER->uid)); $this->assertTrue($USER->isQualified()); // $third_request_failed = false; @@ -137,7 +137,7 @@ public function testApproveMemberByAdmin() $this->assertTrue($USER->exists()); $this->assertTrue($pi_group->exists()); $this->assertGroupMembers($pi_group, [$pi_uid]); - $this->assertTrue(!$pi_group->memberExists($USER)); + $this->assertTrue(!$pi_group->memberUIDExists($USER->uid)); $this->assertRequestedMembership(false, $gid); try { $this->requestGroupMembership($pi_group->gid); @@ -166,7 +166,7 @@ public function testApproveMemberByAdmin() $this->assertTrue(!$pi_group->requestExists($USER)); $this->assertRequestedMembership(false, $gid); - $this->assertTrue($pi_group->memberExists($USER)); + $this->assertTrue($pi_group->memberUIDExists($USER->uid)); $this->assertTrue($USER->isQualified()); // $third_request_failed = false; diff --git a/test/functional/PiMemberDenyTest.php b/test/functional/PiMemberDenyTest.php index f93a1fd5..b7a29c31 100644 --- a/test/functional/PiMemberDenyTest.php +++ b/test/functional/PiMemberDenyTest.php @@ -31,17 +31,17 @@ public function testDenyRequest() $pi = $USER; $piGroup = $USER->getPIGroup(); $this->assertTrue($piGroup->exists()); - $this->assertEqualsCanonicalizing([$pi->uid], $piGroup->getGroupMemberUIDs()); + $this->assertEqualsCanonicalizing([$pi->uid], $piGroup->getMemberUIDs()); $this->assertEmpty($piGroup->getRequests()); $requestedUser = new UnityUser(self::$requestUid, $LDAP, $SQL, $MAILER, $WEBHOOK); try { $piGroup->newUserRequest($requestedUser); - $this->assertFalse($piGroup->memberExists($requestedUser)); + $this->assertFalse($piGroup->memberUIDExists($requestedUser->uid)); $piGroup->denyUser($requestedUser); $this->assertEmpty($piGroup->getRequests()); - $this->assertEqualsCanonicalizing([$pi->uid], $piGroup->getGroupMemberUIDs()); - $this->assertFalse($piGroup->memberExists($requestedUser)); + $this->assertEqualsCanonicalizing([$pi->uid], $piGroup->getMemberUIDs()); + $this->assertFalse($piGroup->memberUIDExists($requestedUser->uid)); } finally { $SQL->removeRequest(self::$requestUid, $piGroup->gid); } diff --git a/test/functional/PiRemoveUserTest.php b/test/functional/PiRemoveUserTest.php index 7956d1c3..89110da8 100644 --- a/test/functional/PiRemoveUserTest.php +++ b/test/functional/PiRemoveUserTest.php @@ -21,7 +21,7 @@ public function testRemoveUser() $piUid = $USER->uid; $piGroup = $USER->getPIGroup(); $this->assertTrue($piGroup->exists()); - $memberUIDs = $piGroup->getGroupMemberUIDs(); + $memberUIDs = $piGroup->getMemberUIDs(); // the 0th member of the PI group is the PI $this->assertGreaterThan(1, count($memberUIDs)); // the ordering of the uids in getGroupMemberUIDs is different each time @@ -37,12 +37,12 @@ public function testRemoveUser() } } $this->assertNotEquals($pi->uid, $memberToDelete->uid); - $this->assertTrue($piGroup->memberExists($memberToDelete)); + $this->assertTrue($piGroup->memberUIDExists($memberToDelete->uid)); try { $this->removeUser($memberToDelete->uid); - $this->assertFalse($piGroup->memberExists($memberToDelete)); + $this->assertFalse($piGroup->memberUIDExists($memberToDelete->uid)); } finally { - if (!$piGroup->memberExists($memberToDelete)) { + if (!$piGroup->memberUIDExists($memberToDelete->uid)) { $piGroup->newUserRequest($memberToDelete); $piGroup->approveUser($memberToDelete); } @@ -56,13 +56,13 @@ public function testRemovePIFromTheirOwnGroup() $pi = $USER; $piGroup = $USER->getPIGroup(); $this->assertTrue($piGroup->exists()); - $this->assertTrue($piGroup->memberExists($pi)); + $this->assertTrue($piGroup->memberUIDExists($pi->uid)); $this->expectException(Exception::class); try { $this->removeUser($pi->uid); - $this->assertTrue($piGroup->memberExists($pi)); + $this->assertTrue($piGroup->memberUIDExists($pi->uid)); } finally { - if (!$piGroup->memberExists($pi)) { + if (!$piGroup->memberUIDExists($pi->uid)) { $piGroup->newUserRequest($pi); $piGroup->approveUser($pi); } diff --git a/test/phpunit-bootstrap.php b/test/phpunit-bootstrap.php index c613602f..ce3792ba 100644 --- a/test/phpunit-bootstrap.php +++ b/test/phpunit-bootstrap.php @@ -5,6 +5,7 @@ require_once __DIR__ . "/../resources/lib/UnityLDAP.php"; require_once __DIR__ . "/../resources/lib/UnityUser.php"; +require_once __DIR__ . "/../resources/lib/PosixGroup.php"; require_once __DIR__ . "/../resources/lib/UnityGroup.php"; require_once __DIR__ . "/../resources/lib/UnityOrg.php"; require_once __DIR__ . "/../resources/lib/UnitySQL.php"; @@ -174,9 +175,9 @@ function ensureUserDoesNotExist() $SQL->deleteRequestsByUser($USER->uid); if ($USER->exists()) { $org = $USER->getOrgGroup(); - if ($org->exists() and $org->inOrg($USER)) { - $org->removeUser($USER); - ensure(!$org->inOrg($USER)); + if ($org->exists() and $org->memberUIDExists($USER->uid)) { + $org->removeMemberUID($USER->uid); + ensure(!$org->memberUIDExists($USER->uid)); } $LDAP->getUserEntry($USER->uid)->delete(); ensure(!$USER->exists()); @@ -220,9 +221,9 @@ function ensureUserNotRequestedAccountDeletion() function ensureUserNotInPIGroup(UnityGroup $pi_group) { global $USER; - if ($pi_group->memberExists($USER)) { + if ($pi_group->memberUIDExists($USER->uid)) { $pi_group->removeUser($USER); - ensure(!$pi_group->memberExists($USER)); + ensure(!$pi_group->memberUIDExists($USER->uid)); } } @@ -365,7 +366,7 @@ public function assertMessageExists( public function assertGroupMembers(UnityGroup $group, array $expected_members) { sort($expected_members); - $found_members = $group->getGroupMemberUIDs(); + $found_members = $group->getMemberUIDs(); sort($found_members); $this->assertEqualsCanonicalizing($expected_members, $found_members); } diff --git a/webroot/panel/ajax/get_group_members.php b/webroot/panel/ajax/get_group_members.php index 177d31e0..15c0b08a 100644 --- a/webroot/panel/ajax/get_group_members.php +++ b/webroot/panel/ajax/get_group_members.php @@ -8,7 +8,7 @@ $gid = UnityHTTPD::getQueryParameter("gid"); $group = new UnityGroup($gid, $LDAP, $SQL, $MAILER, $WEBHOOK); -if (!$group->memberExists($USER)) { +if (!$group->memberUIDExists($USER->uid)) { UnityHTTPD::forbidden("not a group member"); } $members = $group->getGroupMembersAttributes(["gecos", "mail"]); diff --git a/webroot/panel/groups.php b/webroot/panel/groups.php index a04030d1..ce76ae12 100644 --- a/webroot/panel/groups.php +++ b/webroot/panel/groups.php @@ -39,7 +39,7 @@ ); UnityHTTPD::redirect(); } - if ($pi_account->memberExists($USER)) { + if ($pi_account->memberUIDExists($USER->uid)) { UnityHTTPD::messageError( "Invalid Group Membership Request", "You're already in this PI group" diff --git a/workers/remove-users-from-group.php b/workers/remove-users-from-group.php index 20fbb52e..198b9ee9 100755 --- a/workers/remove-users-from-group.php +++ b/workers/remove-users-from-group.php @@ -27,7 +27,7 @@ function _die($msg) while (($line = fgets($handle)) !== false) { $uid = trim($line); $user = new UnityUser($uid, $LDAP, $SQL, $MAILER, $WEBHOOK); - if (!$group->memberExists($user)) { + if (!$group->memberUIDExists($user->uid)) { print "Skipping '$uid' who doesn't appear to be in '$gid'\n"; continue; }