resource provider and service improvements
This commit is contained in:
@@ -6,7 +6,9 @@ namespace KTXC\Service;
|
|||||||
|
|
||||||
use KTXC\Http\Request\Request;
|
use KTXC\Http\Request\Request;
|
||||||
use KTXC\Models\Identity\User;
|
use KTXC\Models\Identity\User;
|
||||||
|
use KTXC\Resource\ProviderManager;
|
||||||
use KTXC\SessionTenant;
|
use KTXC\SessionTenant;
|
||||||
|
use KTXF\Security\Authentication\AuthenticationProviderInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Security Service
|
* Security Service
|
||||||
@@ -21,9 +23,10 @@ class SecurityService
|
|||||||
private string $securityCode;
|
private string $securityCode;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
|
private readonly SessionTenant $sessionTenant,
|
||||||
private readonly TokenService $tokenService,
|
private readonly TokenService $tokenService,
|
||||||
private readonly UserAccountsService $userService,
|
private readonly UserAccountsService $userService,
|
||||||
private readonly SessionTenant $sessionTenant
|
private readonly ProviderManager $providerManager,
|
||||||
) {
|
) {
|
||||||
$this->securityCode = $this->sessionTenant->configuration()->security()->code();
|
$this->securityCode = $this->sessionTenant->configuration()->security()->code();
|
||||||
}
|
}
|
||||||
@@ -55,7 +58,7 @@ class SecurityService
|
|||||||
if ($decoded !== false) {
|
if ($decoded !== false) {
|
||||||
[$identity, $secret] = array_pad(explode(':', $decoded, 2), 2, null);
|
[$identity, $secret] = array_pad(explode(':', $decoded, 2), 2, null);
|
||||||
if ($identity !== null && $secret !== 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)
|
* Authenticate HTTP Basic header (for API access)
|
||||||
* Note: This is for request authentication, not login
|
* 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
|
// For Basic auth headers, we need to validate against the provider
|
||||||
// This is a simplified flow for API access
|
// This is a simplified flow for API access
|
||||||
$provider = $this->providerRegistry->resolve('default');
|
$providers = $this->providerManager->providers(AuthenticationProviderInterface::TYPE_AUTHENTICATION);
|
||||||
if ($provider === null) {
|
if ($providers === []) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = $provider->authenticate($identity, $credentials);
|
foreach ($providers as $provider) {
|
||||||
if (!$result->isSuccess()) {
|
if ($provider instanceof AuthenticationProviderInterface === false) {
|
||||||
return null;
|
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);
|
if (isset($result) && $result->isSuccess()) {
|
||||||
}
|
return $this->userService->fetchByIdentity($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($payload['type']) || $payload['type'] !== 'refresh') {
|
return null;
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -26,8 +26,6 @@ namespace KTXF\Mail\Provider;
|
|||||||
*/
|
*/
|
||||||
interface ProviderServiceDiscoverInterface extends ProviderBaseInterface {
|
interface ProviderServiceDiscoverInterface extends ProviderBaseInterface {
|
||||||
|
|
||||||
public const CAPABILITY_SERVICE_DISCOVER = 'ServiceDiscover';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Discover service configuration
|
* Discover service configuration
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ use KTXF\Resource\Provider\ResourceProviderServiceMutateInterface;
|
|||||||
*/
|
*/
|
||||||
interface ProviderServiceMutateInterface extends ProviderBaseInterface, ResourceProviderServiceMutateInterface {
|
interface ProviderServiceMutateInterface extends ProviderBaseInterface, ResourceProviderServiceMutateInterface {
|
||||||
|
|
||||||
|
public const JSON_TYPE = ProviderBaseInterface::JSON_TYPE;
|
||||||
|
|
||||||
// Methods inherited from ResourceProviderServiceMutateInterface
|
// Methods inherited from ResourceProviderServiceMutateInterface
|
||||||
// Implementations should return/accept ServiceMutableInterface instances
|
// Implementations should return/accept ServiceMutableInterface instances
|
||||||
|
|
||||||
|
|||||||
@@ -27,8 +27,6 @@ use KTXF\Mail\Service\ServiceBaseInterface;
|
|||||||
*/
|
*/
|
||||||
interface ProviderServiceTestInterface extends ProviderBaseInterface {
|
interface ProviderServiceTestInterface extends ProviderBaseInterface {
|
||||||
|
|
||||||
public const CAPABILITY_SERVICE_TEST = 'ServiceTest';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test a service connection
|
* Test a service connection
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -34,31 +34,28 @@ interface ServiceBaseInterface extends ResourceServiceBaseInterface {
|
|||||||
public const CAPABILITY_COLLECTION_LIST_SORT = 'CollectionListSort';
|
public const CAPABILITY_COLLECTION_LIST_SORT = 'CollectionListSort';
|
||||||
public const CAPABILITY_COLLECTION_EXTANT = 'CollectionExtant';
|
public const CAPABILITY_COLLECTION_EXTANT = 'CollectionExtant';
|
||||||
public const CAPABILITY_COLLECTION_FETCH = 'CollectionFetch';
|
public const CAPABILITY_COLLECTION_FETCH = 'CollectionFetch';
|
||||||
|
|
||||||
// Message capabilities
|
// Message capabilities
|
||||||
public const CAPABILITY_MESSAGE_LIST = 'MessageList';
|
public const CAPABILITY_ENTITY_LIST = 'EntityList';
|
||||||
public const CAPABILITY_MESSAGE_LIST_FILTER = 'MessageListFilter';
|
public const CAPABILITY_ENTITY_LIST_FILTER = 'EntityListFilter';
|
||||||
public const CAPABILITY_MESSAGE_LIST_SORT = 'MessageListSort';
|
public const CAPABILITY_ENTITY_LIST_SORT = 'EntityListSort';
|
||||||
public const CAPABILITY_MESSAGE_LIST_RANGE = 'MessageListRange';
|
public const CAPABILITY_ENTITY_LIST_RANGE = 'EntityListRange';
|
||||||
public const CAPABILITY_MESSAGE_DELTA = 'MessageDelta';
|
public const CAPABILITY_ENTITY_DELTA = 'EntityDelta';
|
||||||
public const CAPABILITY_MESSAGE_EXTANT = 'MessageExtant';
|
public const CAPABILITY_ENTITY_EXTANT = 'EntityExtant';
|
||||||
public const CAPABILITY_MESSAGE_FETCH = 'MessageFetch';
|
public const CAPABILITY_ENTITY_FETCH = 'EntityFetch';
|
||||||
|
|
||||||
// Filter capabilities
|
// Filter capabilities
|
||||||
public const CAPABILITY_FILTER_ID = 'FilterId';
|
public const CAPABILITY_FILTER_ID = 'id';
|
||||||
public const CAPABILITY_FILTER_SUBJECT = 'FilterSubject';
|
public const CAPABILITY_FILTER_SUBJECT = 'subject';
|
||||||
public const CAPABILITY_FILTER_FROM = 'FilterFrom';
|
public const CAPABILITY_FILTER_FROM = 'from';
|
||||||
public const CAPABILITY_FILTER_TO = 'FilterTo';
|
public const CAPABILITY_FILTER_TO = 'to';
|
||||||
public const CAPABILITY_FILTER_DATE = 'FilterDate';
|
public const CAPABILITY_FILTER_DATE = 'date';
|
||||||
public const CAPABILITY_FILTER_FLAG = 'FilterFlag';
|
public const CAPABILITY_FILTER_FLAG = 'flag';
|
||||||
public const CAPABILITY_FILTER_SIZE = 'FilterSize';
|
public const CAPABILITY_FILTER_SIZE = 'size';
|
||||||
public const CAPABILITY_FILTER_BODY = 'FilterBody';
|
public const CAPABILITY_FILTER_BODY = 'body';
|
||||||
|
|
||||||
// Sort capabilities
|
// Sort capabilities
|
||||||
public const CAPABILITY_SORT_DATE = 'SortDate';
|
public const CAPABILITY_SORT_DATE = 'date';
|
||||||
public const CAPABILITY_SORT_SUBJECT = 'SortSubject';
|
public const CAPABILITY_SORT_SUBJECT = 'subject';
|
||||||
public const CAPABILITY_SORT_FROM = 'SortFrom';
|
public const CAPABILITY_SORT_FROM = 'from';
|
||||||
public const CAPABILITY_SORT_SIZE = 'SortSize';
|
public const CAPABILITY_SORT_SIZE = 'size';
|
||||||
|
|
||||||
public const JSON_TYPE = 'mail.service';
|
public const JSON_TYPE = 'mail.service';
|
||||||
public const JSON_PROPERTY_PRIMARY_ADDRESS = 'primaryAddress';
|
public const JSON_PROPERTY_PRIMARY_ADDRESS = 'primaryAddress';
|
||||||
|
|||||||
@@ -22,12 +22,12 @@ use KTXF\Mail\Entity\IMessageMutable;
|
|||||||
*/
|
*/
|
||||||
interface ServiceMessageMutableInterface extends ServiceBaseInterface {
|
interface ServiceMessageMutableInterface extends ServiceBaseInterface {
|
||||||
|
|
||||||
public const CAPABILITY_MESSAGE_CREATE = 'MessageCreate';
|
public const CAPABILITY_ENTITY_CREATE = 'EntityCreate';
|
||||||
public const CAPABILITY_MESSAGE_MODIFY = 'MessageModify';
|
public const CAPABILITY_ENTITY_MODIFY = 'EntityModify';
|
||||||
public const CAPABILITY_MESSAGE_DESTROY = 'MessageDestroy';
|
public const CAPABILITY_ENTITY_DESTROY = 'EntityDestroy';
|
||||||
public const CAPABILITY_MESSAGE_COPY = 'MessageCopy';
|
public const CAPABILITY_ENTITY_COPY = 'EntityCopy';
|
||||||
public const CAPABILITY_MESSAGE_MOVE = 'MessageMove';
|
public const CAPABILITY_ENTITY_MOVE = 'EntityMove';
|
||||||
public const CAPABILITY_MESSAGE_FLAG = 'MessageFlag';
|
public const CAPABILITY_ENTITY_FLAG = 'EntityFlag';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a fresh message instance for composition
|
* Creates a fresh message instance for composition
|
||||||
|
|||||||
@@ -11,9 +11,14 @@ use KTXF\Json\JsonSerializable;
|
|||||||
*/
|
*/
|
||||||
interface ResourceProviderBaseInterface extends ProviderInterface, 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_FETCH = 'ServiceFetch';
|
||||||
public const CAPABILITY_SERVICE_EXTANT = 'ServiceExtant';
|
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_TYPE = 'resource.provider';
|
||||||
public const JSON_PROPERTY_TYPE = '@type';
|
public const JSON_PROPERTY_TYPE = '@type';
|
||||||
|
|||||||
@@ -13,37 +13,32 @@ use KTXF\Json\JsonDeserializable;
|
|||||||
|
|
||||||
interface ResourceProviderServiceMutateInterface extends ResourceProviderBaseInterface, 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
|
* construct and new blank service instance
|
||||||
*
|
*
|
||||||
* @since 2025.05.01
|
* @since 2025.05.01
|
||||||
*/
|
*/
|
||||||
public function serviceFresh(string $tenantId, ?string $userId): ResourceServiceMutateInterface;
|
public function serviceFresh(): ResourceServiceMutateInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* create a service configuration for a specific user
|
* create a service configuration for a specific user
|
||||||
*
|
*
|
||||||
* @since 2025.05.01
|
* @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
|
* modify a service configuration for a specific user
|
||||||
*
|
*
|
||||||
* @since 2025.05.01
|
* @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
|
* delete a service configuration for a specific user
|
||||||
*
|
*
|
||||||
* @since 2025.05.01
|
* @since 2025.05.01
|
||||||
*/
|
*/
|
||||||
public function serviceDestroy(string $tenantId, ?string $userId, ResourceServiceMutateInterface $service): bool;
|
public function serviceDestroy(string $tenantId, string $userId, ResourceServiceMutateInterface $service): bool;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ interface ResourceServiceBaseInterface extends JsonSerializable {
|
|||||||
// JSON Constants
|
// JSON Constants
|
||||||
public const JSON_TYPE = 'resource.service';
|
public const JSON_TYPE = 'resource.service';
|
||||||
public const JSON_PROPERTY_TYPE = '@type';
|
public const JSON_PROPERTY_TYPE = '@type';
|
||||||
public const JSON_PROPERTY_PROVIDER = 'provider';
|
|
||||||
public const JSON_PROPERTY_ID = 'id';
|
public const JSON_PROPERTY_ID = 'id';
|
||||||
public const JSON_PROPERTY_LABEL = 'label';
|
public const JSON_PROPERTY_LABEL = 'label';
|
||||||
public const JSON_PROPERTY_ENABLED = 'enabled';
|
public const JSON_PROPERTY_ENABLED = 'enabled';
|
||||||
|
|||||||
Reference in New Issue
Block a user