Skip to content

Commit 55a7eb5

Browse files
user flag groups (#396)
Co-authored-by: bryank-cs <[email protected]>
1 parent fb8ddd0 commit 55a7eb5

27 files changed

+307
-147
lines changed

.pre-commit-config.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ repos:
3131
resources/lib/phpopenldaper/.*|
3232
vendor/.*|
3333
resources/lib/.*|
34+
resources/mail/.*|
3435
)$
3536
3637
- repo: https://github.com/rbubley/mirrors-prettier
@@ -47,6 +48,7 @@ repos:
4748
vendor/.*|
4849
resources/templates/.*|
4950
webroot/.*|
51+
resources/mail/.*|
5052
)$
5153
5254
# linters (work required) ########################################################################
@@ -81,6 +83,7 @@ repos:
8183
resources/lib/phpopenldaper/.*|
8284
vendor/.*|
8385
resources/lib/.*|
86+
resources/mail/.*|
8487
)$
8588
- id: php-l
8689
name: php -l

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
This will enable strict mode and throw an exception rather than issuing a warning.
2727
- `UnityHTTPD`'s user-facing error functionality (ex: `badRequest`) should only be called from `webroot/**/*.php`.
2828
`resources/**/*.php` should throw exceptions instead.
29-
- all pages under `webroot/admin/` must check for `$USER->isAdmin()` and call `UnityHTTPD::forbidden()` if not admin.
29+
- all pages under `webroot/admin/` must check for `$USER->getFlag(UserFlag::ADMIN)` and call `UnityHTTPD::forbidden()` if not admin.
3030

3131
This repository will automatically check PRs for linting compliance.
3232

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ rm "$prod" && ln -s "$old" "$prod"
120120
### 1.5.0 -> 1.5.1
121121

122122
- the `[site]getting_started_url` option should be defined
123+
- the `[ldap]admin_group` option has been renamed to `[ldap]user_flag_groups[admin]`
124+
- the `[ldap]qualified_user_group` option has been renamed to `[ldap]user_flag_groups[qualified]`
123125

124126
### 1.4 -> 1.5
125127

defaults/config.ini.default

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,18 @@ pass = "password" ; Admin bind password
2828
custom_user_mappings_dir = "deployment/custom_user_mappings" ; for internal use only
2929
basedn = "dc=unityhpc,dc=test" ; Base search DN
3030
user_ou = "ou=users,dc=unityhpc,dc=test" ; User organizational unit (may contain more than user group)
31-
qualified_user_group = "cn=unityusers,dc=unityhpc,dc=test" ; Qualified user group (in at least one PI group)
3231
group_ou = "ou=groups,dc=unityhpc,dc=test" ; Group organizational unit
3332
pigroup_ou = "ou=pi_groups,dc=unityhpc,dc=test" ; PI Group organizational unit
3433
orggroup_ou = "ou=org_groups,dc=unityhpc,dc=test" ; ORG group organizational unit
35-
admin_group = "cn=web_admins,dc=unityhpc,dc=test" ; admin dn (members of this group are admins on the web portal)
3634
def_user_shell = "/bin/bash" ; Default shell for new users
3735
offset_UIDGID = 1000000 ; start point when allocating new UID/GID pairs for a new user
3836
offset_PIGID = 2000000 ; start point when allocating new GID for a new PI group
3937
offset_ORGGID = 3000000 ; start point when allocating new GID for a new org group
38+
user_flag_groups[admin] = "cn=web_admins,dc=unityhpc,dc=test" ; admin user group dn
39+
user_flag_groups[ghost] = "cn=ghost,dc=unityhpc,dc=test" ; ghost user group dn
40+
user_flag_groups[idlelocked] = "cn=idlelocked,dc=unityhpc,dc=test" ; idlelocked user group dn
41+
user_flag_groups[locked] = "cn=locked,dc=unityhpc,dc=test" ; locked user group dn
42+
user_flag_groups[qualified] = "cn=unityusers,dc=unityhpc,dc=test" ; qualified user group (in at least one PI group)
4043

4144
[sql]
4245
host = "sql" ; mariadb hostname

resources/init.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use UnityWebPortal\lib\UnityWebhook;
1313
use UnityWebPortal\lib\UnityGithub;
1414
use UnityWebPortal\lib\UnityHTTPD;
15+
use UnityWebPortal\lib\UserFlag;
1516

1617
if (CONFIG["site"]["enable_exception_handler"]) {
1718
set_exception_handler(["UnityWebPortal\lib\UnityHTTPD", "exceptionHandler"]);
@@ -56,7 +57,7 @@
5657
$_SESSION["SSO"] = $SSO;
5758

5859
$OPERATOR = new UnityUser($SSO["user"], $LDAP, $SQL, $MAILER, $WEBHOOK);
59-
$_SESSION["is_admin"] = $OPERATOR->isAdmin();
60+
$_SESSION["is_admin"] = $OPERATOR->getFlag(UserFlag::ADMIN);
6061

6162
if (isset($_SESSION["viewUser"]) && $_SESSION["is_admin"]) {
6263
$USER = new UnityUser($_SESSION["viewUser"], $LDAP, $SQL, $MAILER, $WEBHOOK);

resources/lib/UnityGroup.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ public function approveGroup(?UnityUser $operator = null, bool $send_mail = true
8585
if ($send_mail) {
8686
$this->MAILER->sendMail($this->getOwner()->getMail(), "group_created");
8787
}
88-
$this->getOwner()->setIsQualified(true); // having your own group makes you qualified
88+
$this->getOwner()->setFlag(UserFlag::QUALIFIED, true); // having your own group makes you qualified
8989
}
9090

9191
/**
@@ -191,7 +191,8 @@ public function approveUser(UnityUser $new_user, bool $send_mail = true): void
191191
"org" => $new_user->getOrg(),
192192
]);
193193
}
194-
$new_user->setIsQualified(true); // being in a group makes you qualified
194+
// being in a group makes you qualified
195+
$new_user->setFlag(UserFlag::QUALIFIED, true, doSendMail: true, doSendMailAdmin: false);
195196
}
196197

197198
public function denyUser(UnityUser $new_user, bool $send_mail = true): void

resources/lib/UnityLDAP.php

Lines changed: 19 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,16 @@
55
use UnityWebPortal\lib\exceptions\EntryNotFoundException;
66
use PHPOpenLDAPer\LDAPConn;
77
use PHPOpenLDAPer\LDAPEntry;
8+
use UnityWebPortal\lib\PosixGroup;
9+
10+
enum UserFlag: string
11+
{
12+
case ADMIN = "admin";
13+
case GHOST = "ghost";
14+
case IDLELOCKED = "idlelocked";
15+
case LOCKED = "locked";
16+
case QUALIFIED = "qualified";
17+
}
818

919
/**
1020
* An LDAP connection class which extends LDAPConn tailored for the UnityHPC Platform
@@ -35,8 +45,8 @@ class UnityLDAP extends LDAPConn
3545
private LDAPEntry $groupOU;
3646
private LDAPEntry $pi_groupOU;
3747
private LDAPEntry $org_groupOU;
38-
private LDAPEntry $adminGroup;
39-
private LDAPEntry $qualifiedUserGroup;
48+
49+
public array $userFlagGroups;
4050

4151
public function __construct()
4252
{
@@ -46,8 +56,11 @@ public function __construct()
4656
$this->groupOU = $this->getEntry(CONFIG["ldap"]["group_ou"]);
4757
$this->pi_groupOU = $this->getEntry(CONFIG["ldap"]["pigroup_ou"]);
4858
$this->org_groupOU = $this->getEntry(CONFIG["ldap"]["orggroup_ou"]);
49-
$this->adminGroup = $this->getEntry(CONFIG["ldap"]["admin_group"]);
50-
$this->qualifiedUserGroup = $this->getEntry(CONFIG["ldap"]["qualified_user_group"]);
59+
$this->userFlagGroups = [];
60+
foreach (UserFlag::cases() as $flag) {
61+
$dn = CONFIG["ldap"]["user_flag_groups"][$flag->value];
62+
$this->userFlagGroups[$flag->value] = new PosixGroup(new LDAPEntry($this->conn, $dn));
63+
}
5164
}
5265

5366
public function getUserOU(): LDAPEntry
@@ -70,16 +83,6 @@ public function getOrgGroupOU(): LDAPEntry
7083
return $this->org_groupOU;
7184
}
7285

73-
public function getAdminGroup(): LDAPEntry
74-
{
75-
return $this->adminGroup;
76-
}
77-
78-
public function getQualifiedUserGroup(): LDAPEntry
79-
{
80-
return $this->qualifiedUserGroup;
81-
}
82-
8386
public function getDefUserShell(): string
8487
{
8588
return $this->def_user_shell;
@@ -187,31 +190,11 @@ private function getAllGIDNumbersInUse(): array
187190
);
188191
}
189192

190-
public function getQualifiedUsersUIDs(): array
191-
{
192-
// should not use $user_ou->getChildren or $base_ou->getChildren(objectClass=posixAccount)
193-
// qualified users might be outside user ou, and not all users in LDAP tree are qualified users
194-
return $this->qualifiedUserGroup->getAttribute("memberuid");
195-
}
196-
197-
public function getQualifiedUsers($UnitySQL, $UnityMailer, $UnityWebhook): array
198-
{
199-
$out = [];
200-
201-
$qualifiedUsers = $this->getQualifiedUsersUIDs();
202-
sort($qualifiedUsers);
203-
foreach ($qualifiedUsers as $user) {
204-
$params = [$user, $this, $UnitySQL, $UnityMailer, $UnityWebhook];
205-
array_push($out, new UnityUser(...$params));
206-
}
207-
return $out;
208-
}
209-
210193
public function getQualifiedUsersAttributes(
211194
array $attributes,
212195
array $default_values = [],
213196
): array {
214-
$include_uids = $this->getQualifiedUsersUIDs();
197+
$include_uids = $this->userFlagGroups[UserFlag::QUALIFIED->value]->getMemberUIDs();
215198
$user_attributes = $this->baseOU->getChildrenArrayStrict(
216199
$attributes,
217200
true, // recursive
@@ -308,7 +291,7 @@ public function getAllPIGroupOwnerAttributes(
308291
public function getQualifiedUID2PIGIDs(): array
309292
{
310293
// initialize output so each UID is a key with an empty array as its value
311-
$uids = $this->getQualifiedUsersUIDs();
294+
$uids = $this->userFlagGroups[UserFlag::QUALIFIED->value]->getMemberUIDs();
312295
$uid2pigids = array_combine($uids, array_fill(0, count($uids), []));
313296
// for each PI group, append that GID to the member list for each of its member UIDs
314297
foreach (

resources/lib/UnityUser.php

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -97,35 +97,51 @@ public function init(
9797
$this->SQL->addLog($this->uid, $_SERVER["REMOTE_ADDR"], "user_added", $this->uid);
9898
}
9999

100-
public function isQualified(): bool
100+
public function getFlag(UserFlag $flag): bool
101101
{
102-
return $this->LDAP->getQualifiedUserGroup()->attributeValueExists("memberUid", $this->uid);
102+
return $this->LDAP->userFlagGroups[$flag->value]->memberUIDExists($this->uid);
103103
}
104104

105-
public function setIsQualified(bool $newIsQualified, bool $doSendMail = true): void
106-
{
107-
$oldIsQualified = $this->isQualified();
108-
if ($oldIsQualified == $newIsQualified) {
105+
public function setFlag(
106+
UserFlag $flag,
107+
bool $newValue,
108+
bool $doSendMail = true,
109+
bool $doSendMailAdmin = true,
110+
): void {
111+
$oldValue = $this->getFlag($flag);
112+
if ($oldValue == $newValue) {
109113
return;
110114
}
111-
if ($newIsQualified) {
112-
$this->LDAP->getQualifiedUserGroup()->appendAttribute("memberuid", $this->uid);
113-
$this->LDAP->getQualifiedUserGroup()->write();
115+
if ($newValue) {
116+
$this->LDAP->userFlagGroups[$flag->value]->addMemberUID($this->uid);
114117
if ($doSendMail) {
115-
$this->MAILER->sendMail($this->getMail(), "user_qualified", [
118+
$this->MAILER->sendMail($this->getMail(), "user_flag_added", [
119+
"user" => $this->uid,
120+
"org" => $this->getOrg(),
121+
"flag" => $flag,
122+
]);
123+
}
124+
if ($doSendMailAdmin) {
125+
$this->MAILER->sendMail("admin", "user_flag_added_admin", [
116126
"user" => $this->uid,
117127
"org" => $this->getOrg(),
128+
"flag" => $flag,
118129
]);
119130
}
120131
} else {
121-
$this->LDAP
122-
->getQualifiedUserGroup()
123-
->removeAttributeEntryByValue("memberuid", $this->uid);
124-
$this->LDAP->getQualifiedUserGroup()->write();
132+
$this->LDAP->userFlagGroups[$flag->value]->removeMemberUID($this->uid);
125133
if ($doSendMail) {
126-
$this->MAILER->sendMail($this->getMail(), "user_dequalified", [
134+
$this->MAILER->sendMail($this->getMail(), "user_flag_removed", [
127135
"user" => $this->uid,
128136
"org" => $this->getOrg(),
137+
"flag" => $flag,
138+
]);
139+
}
140+
if ($doSendMailAdmin) {
141+
$this->MAILER->sendMail("admin", "user_flag_removed_admin", [
142+
"user" => $this->uid,
143+
"org" => $this->getOrg(),
144+
"flag" => $flag,
129145
]);
130146
}
131147
}
@@ -319,15 +335,6 @@ public function getHomeDir(): string
319335
return $this->entry->getAttribute("homedirectory");
320336
}
321337

322-
/**
323-
* Checks if the current account is an admin
324-
*/
325-
public function isAdmin(): bool
326-
{
327-
$admins = $this->LDAP->getAdminGroup()->getAttribute("memberuid");
328-
return in_array($this->uid, $admins);
329-
}
330-
331338
/**
332339
* Checks if current user is a PI
333340
*/

resources/mail/user_dequalified.php

Lines changed: 0 additions & 10 deletions
This file was deleted.

resources/mail/user_flag_added.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php use UnityWebPortal\lib\UserFlag; ?>
2+
<?php switch ($data["flag"]):
3+
case UserFlag::QUALIFIED: ?>
4+
<?php $this->Subject = "User Activated"; ?>
5+
<p>Hello,</p>
6+
<p>Your account on the UnityHPC Platform has been activated. Your account details are below:</p>
7+
<p>
8+
<strong>Username</strong> <?php echo $data["user"]; ?>
9+
<br>
10+
<strong>Organization</strong> <?php echo $data["org"]; ?>
11+
</p>
12+
<p>
13+
See the
14+
<a href="<?php echo CONFIG["site"]["getting_started_url"]; ?>">Getting Started</a>
15+
page in our documentation for next steps.
16+
</p>
17+
<p>If you believe this to be a mistake, please reply to this email as soon as possible.</p>
18+
<?php break; ?>
19+
20+
<?php /////////////////////////////////////////////////////////////////////////////////////////// ?>
21+
<?php case UserFlag::GHOST: ?>
22+
<?php $this->Subject = "User Deleted"; ?>
23+
<p>Hello,</p>
24+
<p>Your account on the UnityHPC Platform has been deleted.</p>
25+
<p>If you believe this to be a mistake, please reply to this email as soon as possible.</p>
26+
<?php break; ?>
27+
28+
<?php /////////////////////////////////////////////////////////////////////////////////////////// ?>
29+
<?php case UserFlag::LOCKED: ?>
30+
<?php $this->Subject = "User Locked"; ?>
31+
<p>Hello,</p>
32+
<p>Your account on the UnityHPC Platform has been locked.</p>
33+
<p>If you believe this to be a mistake, please reply to this email as soon as possible.</p>
34+
<?php break; ?>
35+
36+
<?php /////////////////////////////////////////////////////////////////////////////////////////// ?>
37+
<?php case UserFlag::IDLELOCKED: ?>
38+
<?php $this->Subject = "User Locked"; ?>
39+
<p>Hello,</p>
40+
<p>Your account on the UnityHPC Platform has been locked due to inactivity.</p>
41+
<p>If you believe this to be a mistake, please reply to this email as soon as possible.</p>
42+
<?php break; ?>
43+
44+
<?php /////////////////////////////////////////////////////////////////////////////////////////// ?>
45+
<?php case UserFlag::ADMIN: ?>
46+
<?php $this->Subject = "User Promoted"; ?>
47+
<p>Hello,</p>
48+
<p>Your account on the UnityHPC Platform has been promoted to admin.</p>
49+
<p>If you believe this to be a mistake, please reply to this email as soon as possible.</p>
50+
<?php break; ?>
51+
52+
<?php /////////////////////////////////////////////////////////////////////////////////////////// ?>
53+
<?php default: ?>
54+
<?php throw new \Exception("unknown flag: " . $data["flag"]); ?>
55+
<?php endswitch; ?>

0 commit comments

Comments
 (0)