Files
desktop/src/App/RegistrationLdifBuilder.php
Lars Gebhardt-Kusche 27c0825111
All checks were successful
Deploy / deploy-staging (push) Successful in 24s
Deploy / deploy-production (push) Has been skipped
asdasdasd
2026-06-15 21:50:41 +02:00

184 lines
6.6 KiB
PHP

<?php
declare(strict_types=1);
namespace App;
final class RegistrationLdifBuilder
{
/**
* @param array<string, mixed> $config
*/
public function __construct(
private readonly array $config,
) {
}
/**
* @param array<string, mixed> $request
* @param array<string, mixed> $provisioning
*/
public function build(array $request, array $provisioning): string
{
$username = (string) ($request['username'] ?? '');
$usersDn = (string) ($this->config['ldap']['users_dn'] ?? '');
$uidNumber = trim((string) ($provisioning['uid_number'] ?? ''));
$gidNumber = trim((string) ($provisioning['gid_number'] ?? ''));
$homeDirectory = trim((string) ($provisioning['home_directory'] ?? ''));
$loginShell = trim((string) ($provisioning['login_shell'] ?? ($this->config['ldap']['default_login_shell'] ?? '/bin/sh')));
$memberOf = $this->parseGroupDns((string) ($provisioning['member_of_list'] ?? ''));
$displayName = trim((string) ($provisioning['display_name'] ?? $request['display_name'] ?? ''));
$givenName = trim((string) ($request['given_name'] ?? ''));
$familyName = trim((string) ($request['family_name'] ?? ''));
$cn = trim((string) ($provisioning['cn'] ?? ($displayName !== '' ? $displayName : $username)));
$gecos = trim((string) ($provisioning['gecos'] ?? ($displayName !== '' ? $displayName : trim($givenName . ' ' . $familyName))));
$mail = trim((string) ($request['email'] ?? ''));
$appleGeneratedUid = trim((string) ($provisioning['apple_generateduid'] ?? $this->generateUuidV4()));
$sambaSid = trim((string) ($provisioning['samba_sid'] ?? ''));
$appleSchemaEnabled = (bool) ($this->config['ldap']['apple_schema_enabled'] ?? false);
$shadowExpire = (string) ($this->config['ldap']['shadow_expire'] ?? 1);
$shadowFlag = (string) ($this->config['ldap']['shadow_flag'] ?? 0);
$shadowInactive = (string) ($this->config['ldap']['shadow_inactive'] ?? 0);
$shadowMax = (string) ($this->config['ldap']['shadow_max'] ?? 99999);
$shadowMin = (string) ($this->config['ldap']['shadow_min'] ?? 0);
$shadowWarning = (string) ($this->config['ldap']['shadow_warning'] ?? 7);
$placeholderPassword = $this->generatePlaceholderPassword();
$passwordHash = $this->cryptSha512($placeholderPassword);
$warnings = [];
if ($uidNumber === '') {
$warnings[] = '# WARNUNG: uidNumber fehlt und muss vor dem LDAP-Import gesetzt werden.';
}
if ($gidNumber === '') {
$warnings[] = '# WARNUNG: gidNumber fehlt und muss vor dem LDAP-Import gesetzt werden.';
}
if ($sambaSid === '') {
$warnings[] = '# WARNUNG: sambaSID fehlt. Viele NAS-Setups erwarten diesen Wert.';
}
if ($memberOf === []) {
$memberOf = array_values(array_map('strval', (array) ($this->config['ldap']['default_groups'] ?? [])));
}
$lines = [
'version: 1',
'',
];
foreach ($warnings as $warning) {
$lines[] = $warning;
}
if ($warnings !== []) {
$lines[] = '# Das Passwort unten ist ein zufälliger Platzhalter für den inaktiven Zustand.';
$lines[] = '# Platzhalter-Passwort: ' . $placeholderPassword;
$lines[] = '';
}
$lines[] = 'dn: uid=' . $username . ',' . $usersDn;
$lines[] = 'objectClass: inetOrgPerson';
$lines[] = 'objectClass: organizationalPerson';
$lines[] = 'objectClass: person';
$lines[] = 'objectClass: posixAccount';
$lines[] = 'objectClass: sambaSamAccount';
$lines[] = 'objectClass: shadowAccount';
$lines[] = 'objectClass: top';
if ($appleSchemaEnabled) {
$lines[] = 'objectClass: apple-user';
$lines[] = 'objectClass: extensibleObject';
}
$lines[] = 'cn: ' . $cn;
if ($gidNumber !== '') {
$lines[] = 'gidNumber: ' . $gidNumber;
}
$lines[] = 'homeDirectory: ' . $homeDirectory;
if ($sambaSid !== '') {
$lines[] = 'sambaSID: ' . $sambaSid;
}
$lines[] = 'sn: ' . ($familyName !== '' ? $familyName : $username);
$lines[] = 'uid: ' . $username;
if ($uidNumber !== '') {
$lines[] = 'uidNumber: ' . $uidNumber;
}
$lines[] = 'displayName: ' . ($displayName !== '' ? $displayName : $username);
if ($appleSchemaEnabled) {
$lines[] = 'apple-generateduid: ' . strtoupper($appleGeneratedUid);
$lines[] = 'authAuthority: ;basic;';
}
if ($gecos !== '') {
$lines[] = 'gecos: ' . $gecos;
}
if ($givenName !== '') {
$lines[] = 'givenName: ' . $givenName;
}
$lines[] = 'loginShell: ' . $loginShell;
$lines[] = 'mail: ' . $mail;
foreach ($memberOf as $groupDn) {
$lines[] = 'memberOf: ' . $groupDn;
}
$lines[] = 'pwdLastSet: 0';
$lines[] = 'sambaAcctFlags: [U ]';
$lines[] = 'sambaLMPassword: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
$lines[] = 'sambaPasswordHistory: 0000000000000000000000000000000000000000000000000000000000000000';
$lines[] = 'sambaPwdLastSet: 0';
$lines[] = 'shadowExpire: ' . $shadowExpire;
$lines[] = 'shadowFlag: ' . $shadowFlag;
$lines[] = 'shadowInactive: ' . $shadowInactive;
$lines[] = 'shadowLastChange: 1';
$lines[] = 'shadowMax: ' . $shadowMax;
$lines[] = 'shadowMin: ' . $shadowMin;
$lines[] = 'shadowWarning: ' . $shadowWarning;
$lines[] = 'userPassword: ' . $passwordHash;
return implode(PHP_EOL, $lines) . PHP_EOL;
}
/**
* @return array<int, string>
*/
private function parseGroupDns(string $value): array
{
$lines = preg_split('/\r\n|\r|\n/', $value) ?: [];
return array_values(array_filter(array_map('trim', $lines)));
}
private function generateUuidV4(): string
{
$bytes = random_bytes(16);
$bytes[6] = chr((ord($bytes[6]) & 0x0f) | 0x40);
$bytes[8] = chr((ord($bytes[8]) & 0x3f) | 0x80);
return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($bytes), 4));
}
private function generatePlaceholderPassword(): string
{
return bin2hex(random_bytes(12));
}
private function cryptSha512(string $password): string
{
$salt = '$6$' . bin2hex(random_bytes(8)) . '$';
$hash = crypt($password, $salt);
return str_starts_with($hash, '$6$') ? '{CRYPT}' . $hash : $hash;
}
}