Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions defaults/config.ini.default
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,10 @@ 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
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
offset_user_uidnumber = 1000000 ; start point when allocating new UIDnumber for a new user
offset_user_gidnumber = 1000000 ; start point when allocating new GIDnumber for a new user
offset_pi_gidnumber = 2000000 ; start point when allocating new GIDnumber for a new PI group
offset_org_gidnumber = 3000000 ; start point when allocating new GIDnumber for a new org group
user_flag_groups[admin] = "cn=web_admins,dc=unityhpc,dc=test" ; admin user group dn
user_flag_groups[ghost] = "cn=ghost,dc=unityhpc,dc=test" ; ghost user group dn
user_flag_groups[idlelocked] = "cn=idlelocked,dc=unityhpc,dc=test" ; idlelocked user group dn
Expand Down
5 changes: 3 additions & 2 deletions deployment/overrides/course-creator/config/config.ini
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# we have hacked in course groups using normal PI accounts but using a different IDnumber range
[ldap]
offset_UIDGID = 20000
offset_PIGID = 20000
offset_user_uidnumber = 20000
offset_user_gidnumber = 20000
offset_pi_gidnumber = 20000

[site]
enable_exception_handler = false
83 changes: 56 additions & 27 deletions resources/lib/UnityLDAP.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace UnityWebPortal\lib;

use RuntimeException;
use UnityWebPortal\lib\exceptions\ArrayKeyException;
use UnityWebPortal\lib\exceptions\EntryNotFoundException;
use PHPOpenLDAPer\LDAPConn;
use PHPOpenLDAPer\LDAPEntry;
Expand Down Expand Up @@ -35,9 +37,10 @@ class UnityLDAP extends LDAPConn
private string $custom_mappings_path =
__DIR__ . "/../../" . CONFIG["ldap"]["custom_user_mappings_dir"];
private string $def_user_shell = CONFIG["ldap"]["def_user_shell"];
private int $offset_UIDGID = CONFIG["ldap"]["offset_UIDGID"];
private int $offset_PIGID = CONFIG["ldap"]["offset_PIGID"];
private int $offset_ORGGID = CONFIG["ldap"]["offset_ORGGID"];
private int $offset_user_uidnumber = CONFIG["ldap"]["offset_user_uidnumber"];
private int $offset_user_gidnumber = CONFIG["ldap"]["offset_user_gidnumber"];
private int $offset_pi_gidnumber = CONFIG["ldap"]["offset_pi_gidnumber"];
private int $offset_org_gidnumber = CONFIG["ldap"]["offset_org_gidnumber"];

// Instance vars for various ldapEntry objects
private LDAPEntry $baseOU;
Expand Down Expand Up @@ -68,40 +71,66 @@ public function getDefUserShell(): string
return $this->def_user_shell;
}

public function getNextUIDGIDNumber(string $uid): int
public function getNextUserUIDNumber(string $uid): int
{
$IDNumsInUse = array_merge($this->getAllUIDNumbersInUse(), $this->getAllGIDNumbersInUse());
$IDNumsInUse = $this->getAllUIDNumbersInUse();
$customIDMappings = $this->getCustomIDMappings();
$customMappedID = $customIDMappings[$uid] ?? null;
if (!is_null($customMappedID) && !in_array($customMappedID, $IDNumsInUse)) {
return $customMappedID;
if (array_key_exists($uid, $customIDMappings)) {
$customMappedID = $customIDMappings[$uid][0];
if (in_array($customMappedID, $IDNumsInUse)) {
UnityHTTPD::errorLog(
"warning",
sprintf(
"user '%s' has a custom mapped GIDNumber %s but it's already in use!",
$uid,
$customMappedID,
),
);
} else {
return $customMappedID;
}
}
if (!is_null($customMappedID) && in_array($customMappedID, $IDNumsInUse)) {
UnityHTTPD::errorLog(
"warning",
"user '$uid' has a custom mapped IDNumber $customMappedID but it's already in use!",
);
$customMappedUIDNumbers = array_map(fn($x) => $x[0], $this->getCustomIDMappings());
$IDNumbersToSkip = array_merge($this->getAllUIDNumbersInUse(), $customMappedUIDNumbers);
return $this->getNextIDNumber($this->offset_user_uidnumber, $IDNumbersToSkip);
}

public function getNextUserGIDNumber(string $uid): int
{
$IDNumsInUse = $this->getAllGIDNumbersInUse();
$customIDMappings = $this->getCustomIDMappings();
if (array_key_exists($uid, $customIDMappings)) {
$customMappedID = $customIDMappings[$uid][1];
if (in_array($customMappedID, $IDNumsInUse)) {
UnityHTTPD::errorLog(
"warning",
sprintf(
"user '%s' has a custom mapped GIDNumber %s but it's already in use!",
$uid,
$customMappedID,
),
);
} else {
return $customMappedID;
}
}
return $this->getNextIDNumber(
$this->offset_UIDGID,
array_merge($IDNumsInUse, array_values($this->getCustomIDMappings())),
);
$customMappedGIDNumbers = array_map(fn($x) => $x[1], $this->getCustomIDMappings());
$IDNumbersToSkip = array_merge($this->getAllGIDNumbersInUse(), $customMappedGIDNumbers);
return $this->getNextIDNumber($this->offset_user_gidnumber, $IDNumbersToSkip);
}

public function getNextPIGIDNumber(): int
{
return $this->getNextIDNumber(
$this->offset_PIGID,
array_merge($this->getAllGIDNumbersInUse(), array_values($this->getCustomIDMappings())),
);
$customMappedGIDNumbers = array_map(fn($x) => $x[1], $this->getCustomIDMappings());
$IDNumbersToSkip = array_merge($this->getAllGIDNumbersInUse(), $customMappedGIDNumbers);
return $this->getNextIDNumber($this->offset_pi_gidnumber, $IDNumbersToSkip);
}

public function getNextOrgGIDNumber(): int
{
return $this->getNextIDNumber(
$this->offset_ORGGID,
array_merge($this->getAllGIDNumbersInUse(), array_values($this->getCustomIDMappings())),
);
$customMappedGIDNumbers = array_map(fn($x) => $x[1], $this->getCustomIDMappings());
$IDNumbersToSkip = array_merge($this->getAllGIDNumbersInUse(), $customMappedGIDNumbers);
return $this->getNextIDNumber($this->offset_org_gidnumber, $IDNumbersToSkip);
}

private function isIDNumberForbidden($id): bool
Expand Down Expand Up @@ -142,8 +171,8 @@ private function getCustomIDMappings(): array
}
}
$output_map = [];
foreach ($output as [$uid, $uidNumber_str]) {
$output_map[$uid] = digits2int($uidNumber_str);
foreach ($output as [$uid, $uidNumber_str, $gidNumber_str]) {
$output_map[$uid] = [digits2int($uidNumber_str), digits2int($gidNumber_str)];
}
return $output_map;
}
Expand Down
9 changes: 5 additions & 4 deletions resources/lib/UnityUser.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,12 @@ public function init(
bool $send_mail = true,
): void {
$ldapGroupEntry = $this->getGroupEntry();
$id = $this->LDAP->getNextUIDGIDNumber($this->uid);
$uidnumber = $this->LDAP->getNextUserUIDNumber($this->uid);
$gidnumber = $this->LDAP->getNextUserGIDNumber($this->uid);
\ensure(!$ldapGroupEntry->exists());
$ldapGroupEntry->create([
"objectclass" => UnityLDAP::POSIX_GROUP_CLASS,
"gidnumber" => strval($id),
"gidnumber" => strval($gidnumber),
]);
\ensure(!$this->entry->exists());
$this->entry->create([
Expand All @@ -74,8 +75,8 @@ public function init(
"o" => $org,
"homedirectory" => self::HOME_DIR . $this->uid,
"loginshell" => $this->LDAP->getDefUserShell(),
"uidnumber" => strval($id),
"gidnumber" => strval($id),
"uidnumber" => strval($uidnumber),
"gidnumber" => strval($gidnumber),
]);
$org = $this->getOrgGroup();
if (!$org->exists()) {
Expand Down
12 changes: 6 additions & 6 deletions test/custom_user_mappings/test.csv
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
user2002_org998_test,555
foobar0,1000000
foobar1,1000001
foobar2,1000002
foobar3,1000003
foobar4,1000004
user2002_org998_test,555,556
foobar0,1000000,1000000
foobar1,1000001,1000001
foobar2,1000002,1000002
foobar3,1000003,1000003
foobar4,1000004,1000004
22 changes: 14 additions & 8 deletions test/functional/RegisterUserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ class RegisterUserTest extends UnityWebPortalTestCase
public static function provider()
{
return [
// defaults/config.ini.default: ldap.offset_UIDGID=1000000
// defaults/config.ini.default: ldap.offset_user_(uid|gid)number=1000000
// test/custom_user_mappings/test.csv has reservations for 1000000-1000004
["NonExistent", 1000005],
// test/custom_user_mappings/test.csv: {user2001: 555}
["CustomMapped555", 555],
["NonExistent", "1000005", "1000005"],
// test/custom_user_mappings/test.csv: {user2001: [555, 556]}
["CustomMapped555", "555", "556"],
];
}

Expand All @@ -22,8 +22,11 @@ private function register()
}

#[DataProvider("provider")]
public function testRegisterUserAndCreateOrg($nickname, $expected_uid_gid)
{
public function testRegisterUserAndCreateOrg(
string $nickname,
string $expected_uidnumber,
string $expected_gidnumber,
): void {
global $USER, $SSO, $LDAP, $SQL, $MAILER, $WEBHOOK;
$this->switchUser($nickname);
$uid = $USER->uid;
Expand All @@ -39,8 +42,11 @@ public function testRegisterUserAndCreateOrg($nickname, $expected_uid_gid)
$this->assertTrue($user_entry->exists());
$this->assertTrue($user_group_entry->exists());
$this->assertTrue($org_entry->exists());
$this->assertEquals($expected_uid_gid, $user_entry->getAttribute("uidnumber")[0]);
$this->assertEquals($expected_uid_gid, $user_group_entry->getAttribute("gidnumber")[0]);
$this->assertEquals($expected_uidnumber, $user_entry->getAttribute("uidnumber")[0]);
$this->assertEquals(
$expected_gidnumber,
$user_group_entry->getAttribute("gidnumber")[0],
);
} finally {
ensureOrgGroupDoesNotExist($org_gid);
ensureUserDoesNotExist($uid);
Expand Down