From 965d839a8cdedf1359f51bde23e463cd22a0a5db Mon Sep 17 00:00:00 2001 From: root Date: Sun, 4 Jan 2026 21:43:20 -0500 Subject: [PATCH] resource provider and service improvements --- core/lib/Service/SecurityService.php | 111 +++++------------- .../ProviderServiceDiscoverInterface.php | 2 - .../ProviderServiceMutateInterface.php | 2 + .../Provider/ProviderServiceTestInterface.php | 2 - .../lib/Mail/Service/ServiceBaseInterface.php | 41 +++---- .../ServiceMessageMutableInterface.php | 12 +- .../ResourceProviderBaseInterface.php | 7 +- ...ResourceProviderServiceMutateInterface.php | 13 +- .../Provider/ResourceServiceBaseInterface.php | 1 - 9 files changed, 64 insertions(+), 127 deletions(-) diff --git a/core/lib/Service/SecurityService.php b/core/lib/Service/SecurityService.php index 7291a21..beaba8d 100644 --- a/core/lib/Service/SecurityService.php +++ b/core/lib/Service/SecurityService.php @@ -6,7 +6,9 @@ namespace KTXC\Service; use KTXC\Http\Request\Request; use KTXC\Models\Identity\User; +use KTXC\Resource\ProviderManager; use KTXC\SessionTenant; +use KTXF\Security\Authentication\AuthenticationProviderInterface; /** * Security Service @@ -21,9 +23,10 @@ class SecurityService private string $securityCode; public function __construct( + private readonly SessionTenant $sessionTenant, private readonly TokenService $tokenService, private readonly UserAccountsService $userService, - private readonly SessionTenant $sessionTenant + private readonly ProviderManager $providerManager, ) { $this->securityCode = $this->sessionTenant->configuration()->security()->code(); } @@ -55,7 +58,7 @@ class SecurityService if ($decoded !== false) { [$identity, $secret] = array_pad(explode(':', $decoded, 2), 2, null); if ($identity !== null && $secret !== null) { - return $this->authenticateBasicHeader($identity, $secret); + return $this->authenticateBasic($identity, $secret); } } } @@ -98,98 +101,38 @@ class SecurityService * Authenticate HTTP Basic header (for API access) * Note: This is for request authentication, not login */ - private function authenticateBasicHeader(string $identity, string $credentials): ?User + private function authenticateBasic(string $identity, string $credentials): ?User { // For Basic auth headers, we need to validate against the provider // This is a simplified flow for API access - $provider = $this->providerRegistry->resolve('default'); - if ($provider === null) { + $providers = $this->providerManager->providers(AuthenticationProviderInterface::TYPE_AUTHENTICATION); + if ($providers === []) { return null; } - $result = $provider->authenticate($identity, $credentials); - if (!$result->isSuccess()) { - return null; + foreach ($providers as $provider) { + if ($provider instanceof AuthenticationProviderInterface === false) { + continue; + } + if ($provider->method() !== AuthenticationProviderInterface::METHOD_CREDENTIAL) { + continue; + } + $context = new \KTXF\Security\Authentication\ProviderContext( + tenantId: $this->sessionTenant->identifier(), + userIdentity: $identity, + ); + $result = $provider->verify($context, $credentials); + + if ($result->isSuccess()) { + break; + } } - return $this->getUserByIdentity($identity); - } - - // ========================================================================= - // Token Operations (delegated to AuthenticationManager for new flows) - // These are kept for backwards compatibility during transition - // ========================================================================= - - /** - * @deprecated Use AuthenticationManager::createTokens() instead - */ - public function createAccessToken(array $payload): string - { - return $this->tokenService->createToken($payload, $this->securityCode, 900); - } - - /** - * @deprecated Use AuthenticationManager::createTokens() instead - */ - public function createRefreshToken(array $payload): string - { - $refreshPayload = [ - 'tenant' => $payload['tenant'] ?? null, - 'identifier' => $payload['identifier'], - 'identity' => $payload['identity'], - 'type' => 'refresh' - ]; - - return $this->tokenService->createToken($refreshPayload, $this->securityCode, 604800); - } - - /** - * @deprecated Use AuthenticationManager::refreshAccessToken() instead - */ - public function validateRefreshToken(string $refreshToken): ?User - { - $payload = $this->tokenService->validateToken($refreshToken, $this->securityCode); - - if (!$payload) { - return null; + if (isset($result) && $result->isSuccess()) { + return $this->userService->fetchByIdentity($identity); } - if (!isset($payload['type']) || $payload['type'] !== 'refresh') { - return null; - } - - $identifier = $payload['identifier'] ?? null; - if (!$identifier || $this->providerRegistry->validateUser($identifier) === false) { - return null; - } - - $user = new User(); - $user->populate([ - 'identifier' => $payload['identifier'], - 'identity' => $payload['identity'], - 'tenant' => $payload['tenant'] ?? null, - ], 'jwt'); - - return $user; - } - - /** - * @deprecated Use AuthenticationManager::logout() instead - */ - public function logout(?string $jti = null, ?int $exp = null): void - { - if ($jti !== null) { - $expiresAt = $exp ?? (time() + 86400); - $this->tokenService->blacklist($jti, $expiresAt); - } - } - - /** - * @deprecated Use AuthenticationManager::logoutAll() instead - */ - public function logoutAllDevices(string $identity): void - { - $this->tokenService->blacklistUserTokensBefore($identity, time()); + return null; } /** diff --git a/shared/lib/Mail/Provider/ProviderServiceDiscoverInterface.php b/shared/lib/Mail/Provider/ProviderServiceDiscoverInterface.php index e5fbd2d..1f5da97 100644 --- a/shared/lib/Mail/Provider/ProviderServiceDiscoverInterface.php +++ b/shared/lib/Mail/Provider/ProviderServiceDiscoverInterface.php @@ -26,8 +26,6 @@ namespace KTXF\Mail\Provider; */ interface ProviderServiceDiscoverInterface extends ProviderBaseInterface { - public const CAPABILITY_SERVICE_DISCOVER = 'ServiceDiscover'; - /** * Discover service configuration * diff --git a/shared/lib/Mail/Provider/ProviderServiceMutateInterface.php b/shared/lib/Mail/Provider/ProviderServiceMutateInterface.php index 550f7f6..7bf5e92 100644 --- a/shared/lib/Mail/Provider/ProviderServiceMutateInterface.php +++ b/shared/lib/Mail/Provider/ProviderServiceMutateInterface.php @@ -27,6 +27,8 @@ use KTXF\Resource\Provider\ResourceProviderServiceMutateInterface; */ interface ProviderServiceMutateInterface extends ProviderBaseInterface, ResourceProviderServiceMutateInterface { + public const JSON_TYPE = ProviderBaseInterface::JSON_TYPE; + // Methods inherited from ResourceProviderServiceMutateInterface // Implementations should return/accept ServiceMutableInterface instances diff --git a/shared/lib/Mail/Provider/ProviderServiceTestInterface.php b/shared/lib/Mail/Provider/ProviderServiceTestInterface.php index b6d186c..82196b9 100644 --- a/shared/lib/Mail/Provider/ProviderServiceTestInterface.php +++ b/shared/lib/Mail/Provider/ProviderServiceTestInterface.php @@ -27,8 +27,6 @@ use KTXF\Mail\Service\ServiceBaseInterface; */ interface ProviderServiceTestInterface extends ProviderBaseInterface { - public const CAPABILITY_SERVICE_TEST = 'ServiceTest'; - /** * Test a service connection * diff --git a/shared/lib/Mail/Service/ServiceBaseInterface.php b/shared/lib/Mail/Service/ServiceBaseInterface.php index e833daa..129a3d4 100644 --- a/shared/lib/Mail/Service/ServiceBaseInterface.php +++ b/shared/lib/Mail/Service/ServiceBaseInterface.php @@ -34,31 +34,28 @@ interface ServiceBaseInterface extends ResourceServiceBaseInterface { public const CAPABILITY_COLLECTION_LIST_SORT = 'CollectionListSort'; public const CAPABILITY_COLLECTION_EXTANT = 'CollectionExtant'; public const CAPABILITY_COLLECTION_FETCH = 'CollectionFetch'; - // Message capabilities - public const CAPABILITY_MESSAGE_LIST = 'MessageList'; - public const CAPABILITY_MESSAGE_LIST_FILTER = 'MessageListFilter'; - public const CAPABILITY_MESSAGE_LIST_SORT = 'MessageListSort'; - public const CAPABILITY_MESSAGE_LIST_RANGE = 'MessageListRange'; - public const CAPABILITY_MESSAGE_DELTA = 'MessageDelta'; - public const CAPABILITY_MESSAGE_EXTANT = 'MessageExtant'; - public const CAPABILITY_MESSAGE_FETCH = 'MessageFetch'; - + public const CAPABILITY_ENTITY_LIST = 'EntityList'; + public const CAPABILITY_ENTITY_LIST_FILTER = 'EntityListFilter'; + public const CAPABILITY_ENTITY_LIST_SORT = 'EntityListSort'; + public const CAPABILITY_ENTITY_LIST_RANGE = 'EntityListRange'; + public const CAPABILITY_ENTITY_DELTA = 'EntityDelta'; + public const CAPABILITY_ENTITY_EXTANT = 'EntityExtant'; + public const CAPABILITY_ENTITY_FETCH = 'EntityFetch'; // Filter capabilities - public const CAPABILITY_FILTER_ID = 'FilterId'; - public const CAPABILITY_FILTER_SUBJECT = 'FilterSubject'; - public const CAPABILITY_FILTER_FROM = 'FilterFrom'; - public const CAPABILITY_FILTER_TO = 'FilterTo'; - public const CAPABILITY_FILTER_DATE = 'FilterDate'; - public const CAPABILITY_FILTER_FLAG = 'FilterFlag'; - public const CAPABILITY_FILTER_SIZE = 'FilterSize'; - public const CAPABILITY_FILTER_BODY = 'FilterBody'; - + public const CAPABILITY_FILTER_ID = 'id'; + public const CAPABILITY_FILTER_SUBJECT = 'subject'; + public const CAPABILITY_FILTER_FROM = 'from'; + public const CAPABILITY_FILTER_TO = 'to'; + public const CAPABILITY_FILTER_DATE = 'date'; + public const CAPABILITY_FILTER_FLAG = 'flag'; + public const CAPABILITY_FILTER_SIZE = 'size'; + public const CAPABILITY_FILTER_BODY = 'body'; // Sort capabilities - public const CAPABILITY_SORT_DATE = 'SortDate'; - public const CAPABILITY_SORT_SUBJECT = 'SortSubject'; - public const CAPABILITY_SORT_FROM = 'SortFrom'; - public const CAPABILITY_SORT_SIZE = 'SortSize'; + public const CAPABILITY_SORT_DATE = 'date'; + public const CAPABILITY_SORT_SUBJECT = 'subject'; + public const CAPABILITY_SORT_FROM = 'from'; + public const CAPABILITY_SORT_SIZE = 'size'; public const JSON_TYPE = 'mail.service'; public const JSON_PROPERTY_PRIMARY_ADDRESS = 'primaryAddress'; diff --git a/shared/lib/Mail/Service/ServiceMessageMutableInterface.php b/shared/lib/Mail/Service/ServiceMessageMutableInterface.php index 59775a7..ea202de 100644 --- a/shared/lib/Mail/Service/ServiceMessageMutableInterface.php +++ b/shared/lib/Mail/Service/ServiceMessageMutableInterface.php @@ -22,12 +22,12 @@ use KTXF\Mail\Entity\IMessageMutable; */ interface ServiceMessageMutableInterface extends ServiceBaseInterface { - public const CAPABILITY_MESSAGE_CREATE = 'MessageCreate'; - public const CAPABILITY_MESSAGE_MODIFY = 'MessageModify'; - public const CAPABILITY_MESSAGE_DESTROY = 'MessageDestroy'; - public const CAPABILITY_MESSAGE_COPY = 'MessageCopy'; - public const CAPABILITY_MESSAGE_MOVE = 'MessageMove'; - public const CAPABILITY_MESSAGE_FLAG = 'MessageFlag'; + public const CAPABILITY_ENTITY_CREATE = 'EntityCreate'; + public const CAPABILITY_ENTITY_MODIFY = 'EntityModify'; + public const CAPABILITY_ENTITY_DESTROY = 'EntityDestroy'; + public const CAPABILITY_ENTITY_COPY = 'EntityCopy'; + public const CAPABILITY_ENTITY_MOVE = 'EntityMove'; + public const CAPABILITY_ENTITY_FLAG = 'EntityFlag'; /** * Creates a fresh message instance for composition diff --git a/shared/lib/Resource/Provider/ResourceProviderBaseInterface.php b/shared/lib/Resource/Provider/ResourceProviderBaseInterface.php index 25950f0..dfbd4f8 100644 --- a/shared/lib/Resource/Provider/ResourceProviderBaseInterface.php +++ b/shared/lib/Resource/Provider/ResourceProviderBaseInterface.php @@ -11,9 +11,14 @@ use KTXF\Json\JsonSerializable; */ interface ResourceProviderBaseInterface extends ProviderInterface, JsonSerializable { - public const CAPABILITY_SERVICE_LIST = 'ServiceList'; + public const CAPABILITY_SERVICE_LIST = 'ServiceList'; public const CAPABILITY_SERVICE_FETCH = 'ServiceFetch'; public const CAPABILITY_SERVICE_EXTANT = 'ServiceExtant'; + public const CAPABILITY_SERVICE_CREATE = 'ServiceCreate'; + public const CAPABILITY_SERVICE_MODIFY = 'ServiceModify'; + public const CAPABILITY_SERVICE_DESTROY = 'ServiceDestroy'; + public const CAPABILITY_SERVICE_DISCOVER = 'ServiceDiscover'; + public const CAPABILITY_SERVICE_TEST = 'ServiceTest'; public const JSON_TYPE = 'resource.provider'; public const JSON_PROPERTY_TYPE = '@type'; diff --git a/shared/lib/Resource/Provider/ResourceProviderServiceMutateInterface.php b/shared/lib/Resource/Provider/ResourceProviderServiceMutateInterface.php index 45d1c3e..4a22b71 100644 --- a/shared/lib/Resource/Provider/ResourceProviderServiceMutateInterface.php +++ b/shared/lib/Resource/Provider/ResourceProviderServiceMutateInterface.php @@ -13,37 +13,32 @@ use KTXF\Json\JsonDeserializable; interface ResourceProviderServiceMutateInterface extends ResourceProviderBaseInterface, JsonDeserializable { - public const CAPABILITY_SERVICE_FRESH = 'ServiceFresh'; - public const CAPABILITY_SERVICE_CREATE = 'ServiceCreate'; - public const CAPABILITY_SERVICE_UPDATE = 'ServiceUpdate'; - public const CAPABILITY_SERVICE_DESTROY = 'ServiceDestroy'; - /** * construct and new blank service instance * * @since 2025.05.01 */ - public function serviceFresh(string $tenantId, ?string $userId): ResourceServiceMutateInterface; + public function serviceFresh(): ResourceServiceMutateInterface; /** * create a service configuration for a specific user * * @since 2025.05.01 */ - public function serviceCreate(string $tenantId, ?string $userId, ResourceServiceMutateInterface $service): string; + public function serviceCreate(string $tenantId, string $userId, ResourceServiceMutateInterface $service): string; /** * modify a service configuration for a specific user * * @since 2025.05.01 */ - public function serviceModify(string $tenantId, ?string $userId, ResourceServiceMutateInterface $service): string; + public function serviceModify(string $tenantId, string $userId, ResourceServiceMutateInterface $service): string; /** * delete a service configuration for a specific user * * @since 2025.05.01 */ - public function serviceDestroy(string $tenantId, ?string $userId, ResourceServiceMutateInterface $service): bool; + public function serviceDestroy(string $tenantId, string $userId, ResourceServiceMutateInterface $service): bool; } diff --git a/shared/lib/Resource/Provider/ResourceServiceBaseInterface.php b/shared/lib/Resource/Provider/ResourceServiceBaseInterface.php index e097819..f0111a8 100644 --- a/shared/lib/Resource/Provider/ResourceServiceBaseInterface.php +++ b/shared/lib/Resource/Provider/ResourceServiceBaseInterface.php @@ -11,7 +11,6 @@ interface ResourceServiceBaseInterface extends JsonSerializable { // JSON Constants public const JSON_TYPE = 'resource.service'; public const JSON_PROPERTY_TYPE = '@type'; - public const JSON_PROPERTY_PROVIDER = 'provider'; public const JSON_PROPERTY_ID = 'id'; public const JSON_PROPERTY_LABEL = 'label'; public const JSON_PROPERTY_ENABLED = 'enabled';