tenantContext->identifier(); $identifier = $this->identityContext->mailAddress(); if ($tenantId === null || $identifier === null) { return new JsonResponse(['error' => 'Invalid session state'], 400); } $credential = $this->credentialStore->fetchByIdentifier($tenantId, $identifier); if (!$credential) { return new JsonResponse(['error' => 'No password set'], 400); } if (!$this->crypto->verifyPassword($current_password, $credential['secret'])) { return new JsonResponse(['error' => 'Invalid current password'], 400); } $newHash = $this->crypto->hashPassword($new_password); $this->credentialStore->updateSecret($tenantId, $identifier, $newHash); return new JsonResponse(['success' => true]); } /** * Admin endpoint: Get credential status for a user */ #[AuthenticatedRoute('/status', name: 'password.admin.status', methods: ['POST'], permissions: ['authentication_provider_password.admin.view', 'authentication_provider_password.admin.manage'])] public function getStatus(string $uid): JsonResponse { $tenantId = $this->tenantContext->identifier(); if ($tenantId === null) { return new JsonResponse(['error' => 'Invalid session state'], 400); } $user = $this->userAccountsService->fetchByIdentifier($uid); if (!$user) { return new JsonResponse(['error' => 'User not found'], 404); } // Credentials are keyed by identity (email/username), not uid $hasCredentials = $this->provider->hasCredentials($tenantId, $user['identity']); return new JsonResponse([ 'enrolled' => $hasCredentials, 'provider' => 'password', ]); } /** * Admin endpoint: Set/reset user password */ #[AuthenticatedRoute('/reset', name: 'password.admin.reset', methods: ['POST'], permissions: ['authentication_provider_password.admin.manage'])] public function adminReset(string $uid, string $password): JsonResponse { $tenantId = $this->tenantContext->identifier(); if ($tenantId === null) { return new JsonResponse(['error' => 'Invalid session state'], 400); } if (strlen($password) < 8) { return new JsonResponse(['error' => 'Password must be at least 8 characters'], 400); } $user = $this->userAccountsService->fetchByIdentifier($uid); if (!$user) { return new JsonResponse(['error' => 'User not found'], 404); } // Credentials are keyed by identity (email/username), not uid $success = $this->provider->setCredential($tenantId, $user['identity'], $password); if (!$success) { return new JsonResponse(['error' => 'Failed to set password'], 500); } return new JsonResponse(['success' => true]); } /** * Admin endpoint: Remove user password */ #[AuthenticatedRoute('/remove', name: 'password.admin.remove', methods: ['POST'], permissions: ['authentication_provider_password.admin.manage'])] public function adminRemove(string $uid): JsonResponse { $tenantId = $this->tenantContext->identifier(); if ($tenantId === null) { return new JsonResponse(['error' => 'Invalid session state'], 400); } $user = $this->userAccountsService->fetchByIdentifier($uid); if (!$user) { return new JsonResponse(['error' => 'User not found'], 404); } // Credentials are keyed by identity (email/username), not uid $this->credentialStore->delete($tenantId, $user['identity']); return new JsonResponse(['success' => true]); } }