asdasd
This commit is contained in:
@@ -10,6 +10,8 @@ final class RegistrationService
|
||||
private RegistrationLdifBuilder $ldifBuilder;
|
||||
private RegistrationSecretBox $secretBox;
|
||||
private LdapProvisioner $ldapProvisioner;
|
||||
private RegistrationIdentityAllocator $identityAllocator;
|
||||
private PasswordResetService $passwordResetService;
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $config
|
||||
@@ -23,6 +25,9 @@ final class RegistrationService
|
||||
$this->ldifBuilder = new RegistrationLdifBuilder($this->config);
|
||||
$this->secretBox = new RegistrationSecretBox((string) ($this->config['password_crypto_key'] ?? ''));
|
||||
$this->ldapProvisioner = new LdapProvisioner($this->config);
|
||||
$counterPath = $this->resolveProjectPath((string) ($this->config['identity_counter_path'] ?? 'data/registration-identity-counter.json'));
|
||||
$this->identityAllocator = new RegistrationIdentityAllocator($counterPath, $this->config);
|
||||
$this->passwordResetService = new PasswordResetService($this->projectRoot, $this->config);
|
||||
}
|
||||
|
||||
public function isEnabled(): bool
|
||||
@@ -100,6 +105,10 @@ final class RegistrationService
|
||||
$errors[] = 'Für diesen Benutzernamen oder diese E-Mail existiert bereits eine offene oder freigegebene Registrierung.';
|
||||
}
|
||||
|
||||
if ($this->ldapProvisioner->usernameExists($username)) {
|
||||
$errors[] = 'Dieser Benutzername ist bereits im LDAP vergeben.';
|
||||
}
|
||||
|
||||
if ($errors !== []) {
|
||||
return [
|
||||
'success' => false,
|
||||
@@ -107,9 +116,26 @@ final class RegistrationService
|
||||
];
|
||||
}
|
||||
|
||||
$identities = $this->identityAllocator->allocate();
|
||||
$pendingGroup = trim((string) ($this->config['ldap']['pending_group_dn'] ?? ''));
|
||||
$provisioning = [
|
||||
'uid_number' => $identities['uid_number'],
|
||||
'gid_number' => $identities['gid_number'],
|
||||
'home_directory' => rtrim((string) ($this->config['ldap']['home_directory_prefix'] ?? '/home'), '/') . '/' . $username,
|
||||
'login_shell' => trim((string) ($this->config['ldap']['default_login_shell'] ?? '/bin/sh')),
|
||||
'member_of_list' => $pendingGroup,
|
||||
'samba_sid' => $identities['samba_sid'],
|
||||
'apple_generateduid' => '',
|
||||
'display_name' => $displayName,
|
||||
'cn' => $displayName !== '' ? $displayName : $username,
|
||||
'gecos' => $displayName,
|
||||
'admin_note' => '',
|
||||
'ldap_created_at' => gmdate('c'),
|
||||
];
|
||||
|
||||
$request = [
|
||||
'id' => bin2hex(random_bytes(8)),
|
||||
'status' => 'pending',
|
||||
'status' => 'pending_approval',
|
||||
'created_at' => gmdate('c'),
|
||||
'updated_at' => gmdate('c'),
|
||||
'username' => $username,
|
||||
@@ -125,8 +151,29 @@ final class RegistrationService
|
||||
'host' => (string) ($_SERVER['HTTP_HOST'] ?? ''),
|
||||
],
|
||||
'review' => null,
|
||||
'provisioning' => null,
|
||||
'provisioning' => $provisioning,
|
||||
];
|
||||
$passwordSecret = $this->secretBox->encrypt($password);
|
||||
|
||||
try {
|
||||
$ldapResult = $this->ldapProvisioner->createInactiveUser($request, $provisioning, $password);
|
||||
$request['password_secret'] = null;
|
||||
$request['provisioning']['ldap_dn'] = $ldapResult['dn'];
|
||||
$request['provisioning']['group_updates'] = $ldapResult['group_updates'];
|
||||
$request['provisioning']['status'] = 'ldap_created_inactive';
|
||||
$request['provisioning']['ldif_path'] = $this->writeLdifDraft($request['id'], $username, $this->ldifBuilder->build($request, $provisioning));
|
||||
} catch (\Throwable $exception) {
|
||||
$request['password_secret'] = $passwordSecret;
|
||||
$request['status'] = 'provisioning_failed';
|
||||
$request['provisioning']['status'] = 'provisioning_failed';
|
||||
$request['provisioning']['error'] = $exception->getMessage();
|
||||
|
||||
return [
|
||||
'success' => false,
|
||||
'errors' => ['LDAP-Provisionierung bei Registrierung fehlgeschlagen: ' . $exception->getMessage()],
|
||||
'request' => $this->store->create($request),
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
@@ -146,49 +193,45 @@ final class RegistrationService
|
||||
return ['success' => false, 'errors' => ['Die Registrierung wurde nicht gefunden.']];
|
||||
}
|
||||
|
||||
$uidNumber = trim((string) ($input['uid_number'] ?? ''));
|
||||
$gidNumber = trim((string) ($input['gid_number'] ?? ''));
|
||||
$homeDirectory = trim((string) ($input['home_directory'] ?? ''));
|
||||
$sambaSid = trim((string) ($input['samba_sid'] ?? ''));
|
||||
$memberOfList = trim((string) ($input['member_of_list'] ?? ''));
|
||||
$adminNote = trim((string) ($input['admin_note'] ?? ''));
|
||||
$errors = [];
|
||||
|
||||
if ($uidNumber === '' || !ctype_digit($uidNumber)) {
|
||||
$errors[] = 'uidNumber ist erforderlich und muss numerisch sein.';
|
||||
}
|
||||
|
||||
if ($gidNumber === '' || !ctype_digit($gidNumber)) {
|
||||
$errors[] = 'gidNumber ist erforderlich und muss numerisch sein.';
|
||||
}
|
||||
|
||||
if ($homeDirectory === '') {
|
||||
$errors[] = 'homeDirectory ist erforderlich.';
|
||||
if ($memberOfList === '') {
|
||||
$errors[] = 'Für die Freischaltung muss mindestens eine Zielgruppe ausgewählt werden.';
|
||||
}
|
||||
|
||||
if ($errors !== []) {
|
||||
return ['success' => false, 'errors' => $errors];
|
||||
}
|
||||
|
||||
$activate = $this->ldapProvisioner->activateUser((string) ($request['username'] ?? ''), preg_split('/\r\n|\r|\n/', $memberOfList) ?: []);
|
||||
|
||||
if (!($activate['success'] ?? false)) {
|
||||
return ['success' => false, 'errors' => [(string) ($activate['message'] ?? 'Aktivierung fehlgeschlagen.')]];
|
||||
}
|
||||
|
||||
$provisioning = [
|
||||
'uid_number' => $uidNumber,
|
||||
'gid_number' => $gidNumber,
|
||||
'home_directory' => $homeDirectory,
|
||||
'login_shell' => trim((string) ($input['login_shell'] ?? ($this->config['ldap']['default_login_shell'] ?? '/bin/sh'))),
|
||||
'uid_number' => (string) ($request['provisioning']['uid_number'] ?? ''),
|
||||
'gid_number' => (string) ($request['provisioning']['gid_number'] ?? ''),
|
||||
'home_directory' => (string) ($request['provisioning']['home_directory'] ?? ''),
|
||||
'login_shell' => (string) ($request['provisioning']['login_shell'] ?? ($this->config['ldap']['default_login_shell'] ?? '/bin/sh')),
|
||||
'member_of_list' => $memberOfList,
|
||||
'samba_sid' => $sambaSid,
|
||||
'apple_generateduid' => trim((string) ($input['apple_generateduid'] ?? '')),
|
||||
'display_name' => trim((string) ($input['display_name'] ?? (string) ($request['display_name'] ?? ''))),
|
||||
'cn' => trim((string) ($input['cn'] ?? (string) ($request['display_name'] ?? $request['username'] ?? ''))),
|
||||
'gecos' => trim((string) ($input['gecos'] ?? (string) ($request['display_name'] ?? ''))),
|
||||
'samba_sid' => (string) ($request['provisioning']['samba_sid'] ?? ''),
|
||||
'apple_generateduid' => (string) ($request['provisioning']['apple_generateduid'] ?? ''),
|
||||
'display_name' => (string) ($request['provisioning']['display_name'] ?? $request['display_name'] ?? ''),
|
||||
'cn' => (string) ($request['provisioning']['cn'] ?? $request['display_name'] ?? $request['username'] ?? ''),
|
||||
'gecos' => (string) ($request['provisioning']['gecos'] ?? $request['display_name'] ?? ''),
|
||||
'admin_note' => $adminNote,
|
||||
'ldif_generated_at' => gmdate('c'),
|
||||
'ldap_activated_at' => gmdate('c'),
|
||||
'ldap_dn' => (string) ($activate['dn'] ?? ($request['provisioning']['ldap_dn'] ?? '')),
|
||||
'status' => 'approved_active',
|
||||
];
|
||||
|
||||
$request = $this->store->update(
|
||||
$id,
|
||||
static function (array $item) use ($provisioning, $reviewer, $adminNote): array {
|
||||
$item['status'] = 'approved_pending_provisioning';
|
||||
$item['status'] = 'approved_active';
|
||||
$item['updated_at'] = gmdate('c');
|
||||
$item['review'] = [
|
||||
'reviewed_at' => gmdate('c'),
|
||||
@@ -206,54 +249,6 @@ final class RegistrationService
|
||||
return ['success' => false, 'errors' => ['Die Registrierung konnte nicht aktualisiert werden.']];
|
||||
}
|
||||
|
||||
$ldif = $this->ldifBuilder->build($request, $provisioning);
|
||||
$ldifPath = $this->writeLdifDraft((string) ($request['id'] ?? ''), (string) ($request['username'] ?? ''), $ldif);
|
||||
|
||||
try {
|
||||
$passwordSecret = (string) ($request['password_secret'] ?? '');
|
||||
|
||||
if ($passwordSecret === '') {
|
||||
throw new \RuntimeException('Für diese Registrierung ist kein Passwort mehr hinterlegt.');
|
||||
}
|
||||
|
||||
$plainPassword = $this->secretBox->decrypt($passwordSecret);
|
||||
$ldapResult = $this->ldapProvisioner->createInactiveUser($request, $provisioning, $plainPassword);
|
||||
|
||||
$request = $this->store->update(
|
||||
$id,
|
||||
static function (array $item) use ($ldifPath, $ldapResult): array {
|
||||
$item['status'] = 'ldap_created_inactive';
|
||||
$item['updated_at'] = gmdate('c');
|
||||
$item['password_secret'] = null;
|
||||
$item['provisioning']['ldif_path'] = $ldifPath;
|
||||
$item['provisioning']['status'] = 'ldap_created_inactive';
|
||||
$item['provisioning']['ldap_dn'] = $ldapResult['dn'];
|
||||
$item['provisioning']['group_updates'] = $ldapResult['group_updates'];
|
||||
|
||||
return $item;
|
||||
}
|
||||
);
|
||||
} catch (\Throwable $exception) {
|
||||
$request = $this->store->update(
|
||||
$id,
|
||||
static function (array $item) use ($ldifPath, $exception): array {
|
||||
$item['status'] = 'provisioning_failed';
|
||||
$item['updated_at'] = gmdate('c');
|
||||
$item['provisioning']['ldif_path'] = $ldifPath;
|
||||
$item['provisioning']['status'] = 'provisioning_failed';
|
||||
$item['provisioning']['error'] = $exception->getMessage();
|
||||
|
||||
return $item;
|
||||
}
|
||||
);
|
||||
|
||||
return [
|
||||
'success' => false,
|
||||
'errors' => ['LDAP-Provisionierung fehlgeschlagen: ' . $exception->getMessage()],
|
||||
'request' => $request,
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'request' => $request,
|
||||
@@ -297,6 +292,66 @@ final class RegistrationService
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{success: bool, message: string}
|
||||
*/
|
||||
public function sendPasswordReset(string $username, string $origin): array
|
||||
{
|
||||
return $this->passwordResetService->request($username, $origin);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{success: bool, message: string}
|
||||
*/
|
||||
public function deactivateUser(string $username): array
|
||||
{
|
||||
return $this->ldapProvisioner->deactivateUser($username);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{success: bool, message: string}
|
||||
*/
|
||||
public function activateExistingUser(string $username, array $groupDns): array
|
||||
{
|
||||
return $this->ldapProvisioner->activateUser($username, $groupDns);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{success: bool, message: string}
|
||||
*/
|
||||
public function setUserPassword(string $username, string $password): array
|
||||
{
|
||||
return $this->ldapProvisioner->updateUserPassword($username, $password);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, array<string, mixed>>
|
||||
*/
|
||||
public function pendingApprovals(): array
|
||||
{
|
||||
return array_values(array_filter(
|
||||
$this->all(),
|
||||
static fn (array $item): bool => in_array((string) ($item['status'] ?? ''), ['pending_approval', 'provisioning_failed'], true)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, array<string, string>>
|
||||
*/
|
||||
public function availableGroups(): array
|
||||
{
|
||||
return array_values(array_filter(
|
||||
array_map(
|
||||
static fn (array $group): array => [
|
||||
'dn' => (string) ($group['dn'] ?? ''),
|
||||
'label' => (string) ($group['label'] ?? ($group['dn'] ?? '')),
|
||||
],
|
||||
(array) ($this->config['ldap']['available_groups'] ?? [])
|
||||
),
|
||||
static fn (array $group): bool => $group['dn'] !== ''
|
||||
));
|
||||
}
|
||||
|
||||
private function writeLdifDraft(string $id, string $username, string $content): string
|
||||
{
|
||||
$directory = $this->resolveProjectPath((string) ($this->config['ldif_export_dir'] ?? 'data/registration-ldif'));
|
||||
|
||||
Reference in New Issue
Block a user