diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4cb2b061..7488fb88 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -31,6 +31,7 @@ repos: resources/lib/phpopenldaper/.*| vendor/.*| resources/lib/.*| + resources/mail/.*| )$ - repo: https://github.com/rbubley/mirrors-prettier @@ -47,6 +48,7 @@ repos: vendor/.*| resources/templates/.*| webroot/.*| + resources/mail/.*| )$ # linters (work required) ######################################################################## @@ -81,6 +83,7 @@ repos: resources/lib/phpopenldaper/.*| vendor/.*| resources/lib/.*| + resources/mail/.*| )$ - id: php-l name: php -l diff --git a/defaults/config.ini.default b/defaults/config.ini.default index a505140f..71376d44 100644 --- a/defaults/config.ini.default +++ b/defaults/config.ini.default @@ -26,15 +26,18 @@ pass = "password" ; Admin bind password custom_user_mappings_dir = "deployment/custom_user_mappings" ; for internal use only basedn = "dc=unityhpc,dc=test" ; Base search DN user_ou = "ou=users,dc=unityhpc,dc=test" ; User organizational unit (may contain more than user group) -qualified_user_group = "cn=unityusers,dc=unityhpc,dc=test" ; Qualified user group (in at least one PI group) group_ou = "ou=groups,dc=unityhpc,dc=test" ; Group organizational unit pigroup_ou = "ou=pi_groups,dc=unityhpc,dc=test" ; PI Group organizational unit orggroup_ou = "ou=org_groups,dc=unityhpc,dc=test" ; ORG group organizational unit -admin_group = "cn=web_admins,dc=unityhpc,dc=test" ; admin dn (members of this group are admins on the web portal) def_user_shell = "/bin/bash" ; Default shell for new users offset_UIDGID = 1000000 ; start point when allocating new UID/GID pairs for a new user offset_PIGID = 2000000 ; start point when allocating new GID for a new PI group offset_ORGGID = 3000000 ; start point when allocating new GID for a new org group +user_modifier_groups[admin] = "cn=web_admins,dc=unityhpc,dc=test" ; admin user group dn +user_modifier_groups[ghost] = "cn=ghost,dc=unityhpc,dc=test" ; ghost user group dn +user_modifier_groups[idlelocked] = "cn=idlelocked,dc=unityhpc,dc=test" ; idlelocked user group dn +user_modifier_groups[locked] = "cn=locked,dc=unityhpc,dc=test" ; locked user group dn +user_modifier_groups[qualified] = "cn=unityusers,dc=unityhpc,dc=test" ; qualified user group (in at least one PI group) [sql] host = "sql" ; mariadb hostname 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/init.php b/resources/init.php index f23f2c2d..0fa0e395 100644 --- a/resources/init.php +++ b/resources/init.php @@ -44,7 +44,7 @@ $_SESSION["SSO"] = $SSO; $OPERATOR = new UnityUser($SSO["user"], $LDAP, $SQL, $MAILER, $WEBHOOK); - $_SESSION["is_admin"] = $OPERATOR->isAdmin(); + $_SESSION["is_admin"] = $OPERATOR->getModifier("admin"); if (isset($_SESSION["viewUser"]) && $_SESSION["is_admin"]) { $USER = new UnityUser($_SESSION["viewUser"], $LDAP, $SQL, $MAILER, $WEBHOOK); 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..9c07cdbd 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()) { @@ -110,7 +85,7 @@ public function approveGroup(?UnityUser $operator = null, bool $send_mail = true if ($send_mail) { $this->MAILER->sendMail($this->getOwner()->getMail(), "group_created"); } - $this->getOwner()->setIsQualified(true); // having your own group makes you qualified + $this->getOwner()->setModifier("qualified", true); // having your own group makes you qualified } /** @@ -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", [ @@ -216,7 +191,8 @@ public function approveUser(UnityUser $new_user, bool $send_mail = true): void "org" => $new_user->getOrg(), ]); } - $new_user->setIsQualified(true); // being in a group makes you qualified + // being in a group makes you qualified + $new_user->setModifier("qualified", true, true, false); } public function denyUser(UnityUser $new_user, bool $send_mail = true): void @@ -240,14 +216,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 +240,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 +286,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 +301,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 +327,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 +370,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/UnityLDAP.php b/resources/lib/UnityLDAP.php index 292be4a1..bf6d4303 100644 --- a/resources/lib/UnityLDAP.php +++ b/resources/lib/UnityLDAP.php @@ -5,6 +5,7 @@ use UnityWebPortal\lib\exceptions\EntryNotFoundException; use PHPOpenLDAPer\LDAPConn; use PHPOpenLDAPer\LDAPEntry; +use UnityWebPortal\lib\PosixGroup; /** * An LDAP connection class which extends LDAPConn tailored for the Unity Cluster @@ -35,8 +36,8 @@ class UnityLDAP extends LDAPConn private LDAPEntry $groupOU; private LDAPEntry $pi_groupOU; private LDAPEntry $org_groupOU; - private LDAPEntry $adminGroup; - private LDAPEntry $qualifiedUserGroup; + + public array $userModifierGroups; public function __construct() { @@ -46,8 +47,10 @@ public function __construct() $this->groupOU = $this->getEntry(CONFIG["ldap"]["group_ou"]); $this->pi_groupOU = $this->getEntry(CONFIG["ldap"]["pigroup_ou"]); $this->org_groupOU = $this->getEntry(CONFIG["ldap"]["orggroup_ou"]); - $this->adminGroup = $this->getEntry(CONFIG["ldap"]["admin_group"]); - $this->qualifiedUserGroup = $this->getEntry(CONFIG["ldap"]["qualified_user_group"]); + $this->userModifierGroups = []; + foreach (CONFIG["ldap"]["user_modifier_groups"] as $gid => $dn) { + $this->userModifierGroups[$gid] = new PosixGroup(new LDAPEntry($this->conn, $dn)); + } } public function getUserOU(): LDAPEntry @@ -70,16 +73,6 @@ public function getOrgGroupOU(): LDAPEntry return $this->org_groupOU; } - public function getAdminGroup(): LDAPEntry - { - return $this->adminGroup; - } - - public function getQualifiedUserGroup(): LDAPEntry - { - return $this->qualifiedUserGroup; - } - public function getDefUserShell(): string { return $this->def_user_shell; @@ -191,7 +184,7 @@ public function getQualifiedUsersUIDs(): array { // should not use $user_ou->getChildren or $base_ou->getChildren(objectClass=posixAccount) // qualified users might be outside user ou, and not all users in LDAP tree are qualified users - return $this->qualifiedUserGroup->getAttribute("memberuid"); + return $this->userModifierGroups["qualified"]->getMemberUIDs(); } public function getQualifiedUsers($UnitySQL, $UnityMailer, $UnityWebhook): array 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..b3395841 100644 --- a/resources/lib/UnityUser.php +++ b/resources/lib/UnityUser.php @@ -90,42 +90,58 @@ 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); } - public function isQualified(): bool + public function getModifier($modifier): bool { - return $this->LDAP->getQualifiedUserGroup()->attributeValueExists("memberUid", $this->uid); + return $this->LDAP->userModifierGroups[$modifier]->memberUIDExists($this->uid); } - public function setIsQualified(bool $newIsQualified, bool $doSendMail = true): void - { - $oldIsQualified = $this->isQualified(); - if ($oldIsQualified == $newIsQualified) { + public function setModifier( + $modifier, + bool $newValue, + bool $doSendMail = true, + bool $doSendMailAdmin = true, + ): void { + $oldValue = $this->getModifier($modifier); + if ($oldValue == $newValue) { return; } - if ($newIsQualified) { - $this->LDAP->getQualifiedUserGroup()->appendAttribute("memberuid", $this->uid); - $this->LDAP->getQualifiedUserGroup()->write(); + if ($newValue) { + $this->LDAP->userModifierGroups[$modifier]->addMemberUID($this->uid); if ($doSendMail) { - $this->MAILER->sendMail($this->getMail(), "user_qualified", [ + $this->MAILER->sendMail($this->getMail(), "user_modifier_added", [ + "user" => $this->uid, + "org" => $this->getOrg(), + "modifier" => $modifier, + ]); + } + if ($doSendMailAdmin) { + $this->MAILER->sendMail($this->getMail(), "user_modifier_added_admin", [ "user" => $this->uid, "org" => $this->getOrg(), + "modifier" => $modifier, ]); } } else { - $this->LDAP - ->getQualifiedUserGroup() - ->removeAttributeEntryByValue("memberuid", $this->uid); - $this->LDAP->getQualifiedUserGroup()->write(); + $this->LDAP->userModifierGroups[$modifier]->removeMemberUID($this->uid); if ($doSendMail) { - $this->MAILER->sendMail($this->getMail(), "user_dequalified", [ + $this->MAILER->sendMail($this->getMail(), "user_modifier_removed", [ "user" => $this->uid, "org" => $this->getOrg(), + "modifier" => $modifier, + ]); + } + if ($doSendMailAdmin) { + $this->MAILER->sendMail($this->getMail(), "user_modifier_removed_admin", [ + "user" => $this->uid, + "org" => $this->getOrg(), + "modifier" => $modifier, ]); } } @@ -319,15 +335,6 @@ public function getHomeDir(): string return $this->entry->getAttribute("homedirectory"); } - /** - * Checks if the current account is an admin - */ - public function isAdmin(): bool - { - $admins = $this->LDAP->getAdminGroup()->getAttribute("memberuid"); - return in_array($this->uid, $admins); - } - /** * Checks if current user is a PI */ @@ -416,6 +423,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/resources/mail/user_dequalified.php b/resources/mail/user_dequalified.php deleted file mode 100644 index 36efcc04..00000000 --- a/resources/mail/user_dequalified.php +++ /dev/null @@ -1,10 +0,0 @@ -Subject = "User Deactivated"; ?> - -
Hello,
- -Your account on the Unity cluster has been deactivated.
- -If you believe this to be a mistake, please reply to this email as soon as possible.
diff --git a/resources/mail/user_modifier_added.php b/resources/mail/user_modifier_added.php new file mode 100644 index 00000000..ac25beb2 --- /dev/null +++ b/resources/mail/user_modifier_added.php @@ -0,0 +1,55 @@ + +Subject = "User Activated"; ?> +Hello,
+Your account on the Unity cluster has been activated. Your account details are below:
+
+Username
+
+Organization
+
+Please login to the web portal to access Unity. +If you need console access, you will need to set your SSH keys in the +account settings +page. +
+If you believe this to be a mistake, please reply to this email as soon as possible.
+ + + + +Subject = "User Deleted"; ?> +Hello,
+Your account on the Unity cluster has been deleted.
+If you believe this to be a mistake, please reply to this email as soon as possible.
+ + + + +Subject = "User Locked"; ?> +Hello,
+Your account on the Unity cluster has been locked.
+If you believe this to be a mistake, please reply to this email as soon as possible.
+ + + + +Subject = "User Locked"; ?> +Hello,
+Your account on the Unity cluster has been locked due to inactivity.
+If you believe this to be a mistake, please reply to this email as soon as possible.
+ + + + +Subject = "User Promoted"; ?> +Hello,
+Your account on the Unity cluster has been promoted to admin.
+If you believe this to be a mistake, please reply to this email as soon as possible.
+ + + + + + diff --git a/resources/mail/user_modifier_added_admin.php b/resources/mail/user_modifier_added_admin.php new file mode 100644 index 00000000..99cc8691 --- /dev/null +++ b/resources/mail/user_modifier_added_admin.php @@ -0,0 +1,39 @@ + +Subject = "User Qualified"; ?> +Hello,
+User "" has been qualified.
+ + + + +Subject = "User Ghosted"; ?> +Hello,
+User "" has been marked as ghost.
+ + + + +Subject = "User Locked"; ?> +Hello,
+User "" has been locked.
+ + + + +Subject = "User Idle Locked"; ?> +Hello,
+User "" has been idle locked.
+ + + + +Subject = "User Promoted"; ?> +Hello,
+User "" has been promoted to admin.
+ + + + + + diff --git a/resources/mail/user_modifier_removed.php b/resources/mail/user_modifier_removed.php new file mode 100644 index 00000000..37873a6b --- /dev/null +++ b/resources/mail/user_modifier_removed.php @@ -0,0 +1,44 @@ + +Subject = "User Deactivated"; ?> +Hello,
+Your account on the Unity cluster has been deactivated.
+If you believe this to be a mistake, please reply to this email as soon as possible.
+ + + + +Subject = "User Resurrected"; ?> +Hello,
+Your account on the Unity cluster has been resurrected.
+If you believe this to be a mistake, please reply to this email as soon as possible.
+ + + + +Subject = "User Unlocked"; ?> +Hello,
+Your account on the Unity cluster has been unlocked.
+If you believe this to be a mistake, please reply to this email as soon as possible.
+ + + + +Subject = "User Unlocked"; ?> +Hello,
+Your account on the Unity cluster has been unlocked.
+If you believe this to be a mistake, please reply to this email as soon as possible.
+ + + + +Subject = "User Demoted"; ?> +Hello,
+Your account on the Unity cluster has been demoted from admin.
+If you believe this to be a mistake, please reply to this email as soon as possible.
+ + + + + + diff --git a/resources/mail/user_modifier_removed_admin.php b/resources/mail/user_modifier_removed_admin.php new file mode 100644 index 00000000..1aac930d --- /dev/null +++ b/resources/mail/user_modifier_removed_admin.php @@ -0,0 +1,39 @@ + +Subject = "User Dequalified"; ?> +Hello,
+User "" has been dequalified.
+ + + + +Subject = "User Resurrected"; ?> +Hello,
+User "" has been resurrected (no longer marked as ghost).
+ + + + +Subject = "User Unlocked"; ?> +Hello,
+User "" has been unlocked.
+ + + + +Subject = "User Idle Unlocked"; ?> +Hello,
+User "" has been idle unlocked.
+ + + + +Subject = "User Demoted"; ?> +Hello,
+User "" has been demoted from admin.
+ + + + + + diff --git a/resources/mail/user_qualified.php b/resources/mail/user_qualified.php deleted file mode 100644 index 512930c3..00000000 --- a/resources/mail/user_qualified.php +++ /dev/null @@ -1,20 +0,0 @@ -Subject = "User Activated"; ?> - -Hello,
- -Your account on the Unity cluster has been activated. Your account details are below:
- -
-Username
-
-Organization
-
Please login to the web portal to access Unity. - If you need console access, you will need to set your SSH keys in the - account settings page.
- -If you believe this to be a mistake, please reply to this email as soon as possible.
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/PIBecomeApproveTest.php b/test/functional/PIBecomeApproveTest.php index afe7a9e3..451853e7 100644 --- a/test/functional/PIBecomeApproveTest.php +++ b/test/functional/PIBecomeApproveTest.php @@ -64,7 +64,7 @@ public function testApprovePI() $this->assertRequestedPIGroup(false); $this->assertTrue($pi_group->exists()); - $this->assertTrue($USER->isQualified()); + $this->assertTrue($USER->getModifier("qualified")); // $third_request_failed = false; // try { 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..06639843 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,8 +106,8 @@ public function testApproveMemberByPI() $this->assertTrue(!$pi_group->requestExists($USER)); $this->assertRequestedMembership(false, $gid); - $this->assertTrue($pi_group->memberExists($USER)); - $this->assertTrue($USER->isQualified()); + $this->assertTrue($pi_group->memberUIDExists($USER->uid)); + $this->assertTrue($USER->getModifier("qualified")); // $third_request_failed = false; // try { @@ -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,8 +166,8 @@ public function testApproveMemberByAdmin() $this->assertTrue(!$pi_group->requestExists($USER)); $this->assertRequestedMembership(false, $gid); - $this->assertTrue($pi_group->memberExists($USER)); - $this->assertTrue($USER->isQualified()); + $this->assertTrue($pi_group->memberUIDExists($USER->uid)); + $this->assertTrue($USER->getModifier("qualified")); // $third_request_failed = false; // try { 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/functional/ViewAsUserTest.php b/test/functional/ViewAsUserTest.php index 99383c1c..b3a20b01 100644 --- a/test/functional/ViewAsUserTest.php +++ b/test/functional/ViewAsUserTest.php @@ -10,7 +10,7 @@ public function _testViewAsUser(array $beforeUser, array $afterUser) switchUser(...$afterUser); $afterUid = $USER->uid; switchUser(...$beforeUser); - // $this->assertTrue($USER->isAdmin()); + // $this->assertTrue($USER->getModifier("admin")); $beforeUid = $USER->uid; // $this->assertNotEquals($afterUid, $beforeUid); http_post(__DIR__ . "/../../webroot/admin/user-mgmt.php", [ @@ -57,7 +57,7 @@ public function testNonAdminViewAsAdmin() global $USER; switchUser(...getAdminUser()); $adminUid = $USER->uid; - $this->assertTrue($USER->isAdmin()); + $this->assertTrue($USER->getModifier("admin")); switchUser(...getNormalUser()); http_post(__DIR__ . "/../../webroot/admin/user-mgmt.php", [ "form_type" => "viewAsUser", diff --git a/test/phpunit-bootstrap.php b/test/phpunit-bootstrap.php index c613602f..a31a1deb 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()); @@ -185,18 +186,8 @@ function ensureUserDoesNotExist() $USER->getGroupEntry()->delete(); ensure(!$USER->getGroupEntry()->exists()); } - $qualified_users_group = $LDAP->getQualifiedUserGroup(); - $all_member_uids = $qualified_users_group->getAttribute("memberuid"); - if (in_array($USER->uid, $all_member_uids)) { - $qualified_users_group->setAttribute( - "memberuid", - // array_diff will break the contiguity of the array indexes - // ldap_mod_replace requires contiguity, array_values restores contiguity - array_values(array_diff($all_member_uids, [$USER->uid])), - ); - $qualified_users_group->write(); - ensure(!in_array($USER->uid, $qualified_users_group->getAttribute("memberuid"))); - } + $USER->setModifier("qualified", false); + ensure(!$LDAP->userModifierGroups["qualified"]->memberUIDExists($USER->uid)); } function ensureOrgGroupDoesNotExist() @@ -220,9 +211,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 +356,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/admin/ajax/get_group_members.php b/webroot/admin/ajax/get_group_members.php index 7bd4c618..e3dcc8e2 100644 --- a/webroot/admin/ajax/get_group_members.php +++ b/webroot/admin/ajax/get_group_members.php @@ -5,7 +5,7 @@ use UnityWebPortal\lib\UnityGroup; use UnityWebPortal\lib\UnityHTTPD; -if (!$USER->isAdmin()) { +if (!$USER->getModifier("admin")) { UnityHTTPD::forbidden("not an admin"); } diff --git a/webroot/admin/ajax/get_page_contents.php b/webroot/admin/ajax/get_page_contents.php index b4f62292..c27b3971 100644 --- a/webroot/admin/ajax/get_page_contents.php +++ b/webroot/admin/ajax/get_page_contents.php @@ -4,7 +4,7 @@ use UnityWebPortal\lib\UnityHTTPD; -if (!$USER->isAdmin()) { +if (!$USER->getModifier("admin")) { UnityHTTPD::forbidden("not an admin"); } diff --git a/webroot/admin/content.php b/webroot/admin/content.php index 620a8fac..4001a2e6 100644 --- a/webroot/admin/content.php +++ b/webroot/admin/content.php @@ -4,7 +4,7 @@ use UnityWebPortal\lib\UnityHTTPD; -if (!$USER->isAdmin()) { +if (!$USER->getModifier("admin")) { UnityHTTPD::forbidden("not an admin"); } diff --git a/webroot/admin/notices.php b/webroot/admin/notices.php index 2c42cac9..3cb9d1f2 100644 --- a/webroot/admin/notices.php +++ b/webroot/admin/notices.php @@ -4,7 +4,7 @@ use UnityWebPortal\lib\UnityHTTPD; -if (!$USER->isAdmin()) { +if (!$USER->getModifier("admin")) { UnityHTTPD::forbidden("not an admin"); } diff --git a/webroot/admin/pi-mgmt.php b/webroot/admin/pi-mgmt.php index 7b161a4b..16d94976 100644 --- a/webroot/admin/pi-mgmt.php +++ b/webroot/admin/pi-mgmt.php @@ -7,7 +7,7 @@ use UnityWebPortal\lib\UnityHTTPD; use UnityWebPortal\lib\UnitySQL; -if (!$USER->isAdmin()) { +if (!$USER->getModifier("admin")) { UnityHTTPD::forbidden("not an admin"); } diff --git a/webroot/admin/user-mgmt.php b/webroot/admin/user-mgmt.php index 47b347fc..56c20754 100644 --- a/webroot/admin/user-mgmt.php +++ b/webroot/admin/user-mgmt.php @@ -4,7 +4,7 @@ use UnityWebPortal\lib\UnityHTTPD; -if (!$USER->isAdmin()) { +if (!$USER->getModifier("admin")) { UnityHTTPD::forbidden("not an admin"); } diff --git a/webroot/panel/account.php b/webroot/panel/account.php index 8c2cf1a2..a3003653 100644 --- a/webroot/panel/account.php +++ b/webroot/panel/account.php @@ -131,7 +131,7 @@ if ($isPI) { echo "You are curently a principal investigator on the Unity Cluster
"; -} elseif ($USER->isQualified()) { +} elseif ($USER->getModifier("qualified")) { echo "You are curently a qualified user on the Unity Cluster
"; } else { $tos_url = CONFIG["site"]["terms_of_service_url"]; 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; }