138 lines
4.0 KiB
PHP
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;
|
|
}
|
|
|
|
}
|