Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/Service/AcquisitionAction.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

/**
* Actions that can result from credential acquisition attempt.
*
Expand Down
1 change: 1 addition & 0 deletions src/Service/CredentialAcquisitionResult.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

/**
* Result of credential acquisition attempt.
*
Expand Down
1 change: 1 addition & 0 deletions src/Service/CredentialProvisioningStrategy.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

/**
* Strategy interface for credential provisioning.
*
Expand Down
1 change: 1 addition & 0 deletions src/Service/CredentialStore.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

/**
* Repository interface for password credential storage.
*
Expand Down
1 change: 1 addition & 0 deletions src/Service/CredentialType.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

/**
* Credential types supported by unified manager.
*
Expand Down
3 changes: 2 additions & 1 deletion src/Service/Exception/OAuthTokenRefreshException.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

use Horde\Core\Service\TokenGrant;
use RuntimeException;
use Throwable;

/**
* Thrown when an OAuth token refresh fails (e.g. refresh token revoked).
Expand All @@ -32,7 +33,7 @@ public function __construct(
private readonly string $providerId,
private readonly ?TokenGrant $grant = null,
int $code = 0,
?\Throwable $previous = null
?Throwable $previous = null
) {
parent::__construct($message, $code, $previous);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

/**
* Factory for CredentialProvisioningStrategy.
*
Expand All @@ -11,11 +12,12 @@

use Horde\Core\Service\CredentialProvisioningStrategy;
use Horde\Core\Service\NullCredentialProvisioningStrategy;
use Horde\Injector\Injector;
use Horde_Injector;

class CredentialProvisioningStrategyFactory
{
public function create(Horde_Injector $injector): CredentialProvisioningStrategy
public function create(Horde_Injector|Injector $injector): CredentialProvisioningStrategy
{
return new NullCredentialProvisioningStrategy();
}
Expand Down
91 changes: 89 additions & 2 deletions src/Service/Factory/CredentialStoreFactory.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

/**
* Factory for CredentialStore.
*
Expand All @@ -9,14 +10,100 @@

namespace Horde\Core\Service\Factory;

use Horde\Core\Config\ConfigLoader;
use Horde\Core\Service\CredentialStore;
use Horde\Core\Service\NullCredentialStore;
use Horde\Injector\Injector;
use Horde_Injector;
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;
use Throwable;

/**
* Resolves the configured password-credential store.
*
* Core owns the {@see CredentialStore} contract but ships no concrete
* storage backend of its own (only {@see NullCredentialStore}). Real
* backends live in downstream packages — e.g. base provides an
* SQL-backed store. To avoid a Core -> base dependency, the concrete
* backend is selected by configuration rather than wired in here.
*
* `password_credentials.storage_factory` holds the fully-qualified class
* name of a daughter factory (any class exposing a
* `create(Injector): CredentialStore` method). This factory loads that
* class through the injector and delegates to it. When the key is empty,
* names a missing class, or the delegate cannot produce a store, it falls
* back to {@see NullCredentialStore} — warning first when a non-empty FQCN
* was configured but could not be used, so misconfiguration is visible.
*/
class CredentialStoreFactory
{
public function create(Horde_Injector $injector): CredentialStore
public function create(Horde_Injector|Injector $injector): CredentialStore
{
$hordeConfig = $injector->get(ConfigLoader::class)->load('horde');
$factoryClass = (string) $hordeConfig->get(
'password_credentials.storage_factory',
'',
);

// Empty or explicitly disabled: No store and no warning.
if ($factoryClass === '' || strtolower($factoryClass) === 'null') {
return new NullCredentialStore();
}

// Guard against a config value that causes recursive recursion on this factory.
if (ltrim($factoryClass, '\\') === self::class) {
$this->logger($injector)->warning(sprintf(
'Config Issue: password_credentials.storage_factory points at the Core '
. 'resolver itself (%s). Falling back to NullCredentialStore.',
$factoryClass,
));
return new NullCredentialStore();
}

if (!class_exists($factoryClass)) {
$this->logger($injector)->warning(sprintf(
'Config Issue: Configured password credential store factory "%s" does not '
. 'exist. Falling back to NullCredentialStore.',
$factoryClass,
));
return new NullCredentialStore();
}

try {
$factory = $injector->get($factoryClass);
$store = $factory->create($injector);
} catch (Throwable $e) {
print_r($e);
exit;
$this->logger($injector)->warning(sprintf(
'Config Issue: Password credential store factory "%s" failed to produce a '
. 'store (%s). Falling back to NullCredentialStore.',
$factoryClass,
$e->getMessage(),
));
return new NullCredentialStore();
}

if (!$store instanceof CredentialStore) {
$this->logger($injector)->warning(sprintf(
'Config Issue: Password credential store factory "%s" returned %s, not a '
. 'CredentialStore. Falling back to NullCredentialStore.',
$factoryClass,
get_debug_type($store),
));
return new NullCredentialStore();
}

return $store;
}

private function logger(Horde_Injector|Injector $injector): LoggerInterface
{
return new NullCredentialStore();
try {
return $injector->get(LoggerInterface::class);
} catch (Throwable) {
return new NullLogger();
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

/**
* Factory for PasswordServiceAuthorizationService.
*
Expand All @@ -11,11 +12,12 @@

use Horde\Core\Service\NullPasswordServiceAuthorizationService;
use Horde\Core\Service\PasswordServiceAuthorizationService;
use Horde\Injector\Injector;
use Horde_Injector;

class PasswordServiceAuthorizationServiceFactory
{
public function create(Horde_Injector $injector): PasswordServiceAuthorizationService
public function create(Horde_Injector|Injector $injector): PasswordServiceAuthorizationService
{
return new NullPasswordServiceAuthorizationService();
}
Expand Down
4 changes: 3 additions & 1 deletion src/Service/Factory/ServiceCredentialManagerFactory.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

/**
* Factory for ServiceCredentialManager.
*
Expand All @@ -11,11 +12,12 @@

use Horde\Core\Service\NullServiceCredentialManager;
use Horde\Core\Service\ServiceCredentialManager;
use Horde\Injector\Injector;
use Horde_Injector;

class ServiceCredentialManagerFactory
{
public function create(Horde_Injector $injector): ServiceCredentialManager
public function create(Horde_Injector|Injector $injector): ServiceCredentialManager
{
return new NullServiceCredentialManager();
}
Expand Down
1 change: 1 addition & 0 deletions src/Service/NullCredentialProvisioningStrategy.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

/**
* Null implementation of CredentialProvisioningStrategy.
*
Expand Down
7 changes: 5 additions & 2 deletions src/Service/NullCredentialStore.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

/**
* Null implementation of CredentialStore.
*
Expand All @@ -12,6 +13,8 @@

namespace Horde\Core\Service;

use RuntimeException;

final class NullCredentialStore implements CredentialStore
{
public function find(
Expand Down Expand Up @@ -40,14 +43,14 @@ public function store(
ServicePurpose $purpose,
array|string $credential
): PasswordCredential {
throw new \RuntimeException('Password credential storage not available');
throw new RuntimeException('Password credential storage not available');
}

public function update(
string $credentialId,
array|string $credential
): PasswordCredential {
throw new \RuntimeException('Password credential storage not available');
throw new RuntimeException('Password credential storage not available');
}

public function delete(string $credentialId): void
Expand Down
7 changes: 5 additions & 2 deletions src/Service/NullPasswordServiceAuthorizationService.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

/**
* Null implementation of PasswordServiceAuthorizationService.
*
Expand All @@ -12,6 +13,8 @@

namespace Horde\Core\Service;

use RuntimeException;

final class NullPasswordServiceAuthorizationService implements PasswordServiceAuthorizationService
{
public function get(
Expand All @@ -36,14 +39,14 @@ public function store(
ServicePurpose $purpose,
array|string $credential
): PasswordCredential {
throw new \RuntimeException('Password credential service not available');
throw new RuntimeException('Password credential service not available');
}

public function update(
string $credentialId,
array|string $credential
): PasswordCredential {
throw new \RuntimeException('Password credential service not available');
throw new RuntimeException('Password credential service not available');
}

public function revoke(
Expand Down
3 changes: 2 additions & 1 deletion src/Service/NullServiceAuthorizationService.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Horde\OAuth\Client\OAuthFlowData;
use Horde\OAuth\Client\ScopeSet;
use Psr\Http\Message\UriInterface;
use RuntimeException;

/** Null ServiceAuthorizationService - safe default when service authorization is not configured. */
class NullServiceAuthorizationService implements ServiceAuthorizationService
Expand Down Expand Up @@ -36,7 +37,7 @@ public function initiate(

public function handleCallback(string $code, OAuthFlowData $flowData): ServiceAuthorization
{
throw new \RuntimeException('Service authorization not configured');
throw new RuntimeException('Service authorization not configured');
}

public function revoke(
Expand Down
5 changes: 4 additions & 1 deletion src/Service/NullServiceCredentialManager.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

/**
* Null implementation of ServiceCredentialManager.
*
Expand All @@ -12,14 +13,16 @@

namespace Horde\Core\Service;

use RuntimeException;

final class NullServiceCredentialManager implements ServiceCredentialManager
{
public function get(
string $userId,
string $providerId,
ServicePurpose $purpose
): ServiceCredentialResult {
throw new \RuntimeException('Service credential manager not available');
throw new RuntimeException('Service credential manager not available');
}

public function initiate(
Expand Down
1 change: 1 addition & 0 deletions src/Service/PasswordCredential.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

/**
* Password-based credential value object.
*
Expand Down
8 changes: 6 additions & 2 deletions src/Service/PasswordCredentialNotFoundException.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

/**
* Exception thrown when password credential is not found.
*
Expand All @@ -9,15 +10,18 @@

namespace Horde\Core\Service;

class PasswordCredentialNotFoundException extends \RuntimeException
use RuntimeException;
use Throwable;

class PasswordCredentialNotFoundException extends RuntimeException
{
public function __construct(
private readonly string $userId,
private readonly string $providerId,
private readonly ServicePurpose $purpose,
string $message = '',
int $code = 0,
?\Throwable $previous = null
?Throwable $previous = null
) {
if ($message === '') {
$message = sprintf(
Expand Down
1 change: 1 addition & 0 deletions src/Service/PasswordServiceAuthorizationService.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

/**
* Service interface for password-based authorization.
*
Expand Down
1 change: 1 addition & 0 deletions src/Service/ProvisioningAction.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

/**
* Actions that can result from provisioning attempt.
*
Expand Down
1 change: 1 addition & 0 deletions src/Service/ProvisioningResult.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

/**
* Result of credential provisioning attempt.
*
Expand Down
2 changes: 2 additions & 0 deletions src/Service/ServiceAuthorization.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
<?php

declare(strict_types=1);

namespace Horde\Core\Service;

/**
* Revocation is performed through `ServiceAuthorizationService` rather than through this object.
* This avoids the object holding a self-reference to its repository.
Expand Down
1 change: 1 addition & 0 deletions src/Service/ServiceAuthorizationRepository.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

declare(strict_types=1);

namespace Horde\Core\Service;
Expand Down
1 change: 1 addition & 0 deletions src/Service/ServiceAuthorizationService.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

declare(strict_types=1);

namespace Horde\Core\Service;
Expand Down
Loading
Loading