Files
server/core/lib/Service/UserManagerService.php
2025-12-21 10:09:54 -05:00

138 lines
4.0 KiB
PHP

<?php
namespace KTXC\Service;
use KTXC\Identity\Provider\DefaultIdentityProvider;
use KTXC\Models\Identity\User;
use KTXC\Server;
use KTXC\SessionTenant;
/**
* User Manager Service
* Manages authentication providers and user operations across domains
*/
class UserManagerService
{
private array $availableIdentityProviders = [];
private array $cachedIdentityProviders = [];
public function __construct(
private readonly SessionTenant $tenant,
private readonly UserService $userService
) {
// Register the default identity provider
$this->providerRegister('default', DefaultIdentityProvider::class);
}
/**
* Register an authentication provider
*/
public function providerRegister(string $identifier, string $class): void
{
$this->availableIdentityProviders[$identifier] = $class;
}
public function providerList(?array $filter = null): array
{
$requestedProviders = $filter ? $filter : array_keys($this->availableIdentityProviders);
$result = [];
foreach ($requestedProviders as $identifier) {
// Check if provider is available
if (!isset($this->availableIdentityProviders[$identifier])) {
continue;
}
// Check cache first
if (isset($this->cachedIdentityProviders[$identifier])) {
$result[$identifier] = $this->cachedIdentityProviders[$identifier];
} else {
// Instantiate the provider and cache it
$providerClass = $this->availableIdentityProviders[$identifier];
try {
// Server::get automatically detects context from calling object
$providerInstance = Server::runtimeContainer()->get($providerClass);
// Cache the instance
$this->cachedIdentityProviders[$identifier] = $providerInstance;
$result[$identifier] = $providerInstance;
} catch (\Exception $e) {
// Skip providers that can't be resolved
error_log("Failed to resolve identity provider {$providerClass}: " . $e->getMessage());
continue;
}
}
}
return $result;
}
/**
* Authenticate user against enabled providers
*/
public function authenticate(string $identity, string $credential): User | null
{
// validate identity and credential
if (empty($identity) || empty($credential)) {
return null;
}
// retrieve user by identity
$user = $this->userService->fetchByIdentity($identity);
// determine if user has logged in before
if (!$user) {
return null;
}
// determine if user has a identity provider assigned
if ($user->getProvider() === null) {
return null;
}
$authenticated = $this->authenticateExtant($user->getProvider(), $identity, $credential);
if ($authenticated) {
return $user;
}
return null;
}
public function authenticateExtant(string $provider, string $identity, string $credential): bool {
// determine if provider is enabled
$providers = $this->providerList([$provider]);
if (empty($providers)) {
return false;
}
// Get the first (and should be only) provider
$provider = reset($providers);
// authenticate user against provider
$user = $provider->authenticate($identity, $credential);
return $user;
}
public function validate(string $identifier): Bool
{
$data = $this->userService->fetchByIdentifier($identifier);
if (!$data) {
return false;
}
if ($data['enabled'] !== true) {
return false;
}
if ($data['tid'] !== $this->tenant->identifier()) {
return false;
}
return true;
}
}