Skip to content

Commit

Permalink
Refactor algorithm factories
Browse files Browse the repository at this point in the history
  • Loading branch information
tvdijen committed Jan 22, 2024
1 parent 91bf47e commit 1c0b0d8
Show file tree
Hide file tree
Showing 11 changed files with 285 additions and 204 deletions.
124 changes: 0 additions & 124 deletions src/Alg/AbstractAlgorithmFactory.php

This file was deleted.

2 changes: 1 addition & 1 deletion src/Alg/Encryption/AES.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public function __construct(SymmetricKey $key, string $algId = C::BLOCK_ENC_AES2


/**
* @inheritDoc
* @return string[]
*/
public static function getSupportedAlgorithms(): array
{
Expand Down
107 changes: 86 additions & 21 deletions src/Alg/Encryption/EncryptionAlgorithmFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,36 @@
namespace SimpleSAML\XMLSecurity\Alg\Encryption;

use SimpleSAML\Assert\Assert;
use SimpleSAML\XMLSecurity\Alg\AbstractAlgorithmFactory;
use SimpleSAML\XMLSecurity\Constants as C;
use SimpleSAML\XMLSecurity\Exception\BlacklistedAlgorithmException;
use SimpleSAML\XMLSecurity\Exception\UnsupportedAlgorithmException;
use SimpleSAML\XMLSecurity\Key\KeyInterface;

use function array_key_exists;
use function in_array;
use function sprintf;

/**
* Factory class to create and configure encryption algorithms.
*
* @package simplesamlphp/xml-security
*/
final class EncryptionAlgorithmFactory extends AbstractAlgorithmFactory
final class EncryptionAlgorithmFactory
{
/**
* A cache of algorithm implementations indexed by algorithm ID.
*
* @var array<string, \SimpleSAML\XMLSecurity\Alg\Encryption\EncryptionAlgorithmInterface>
*/
protected static array $cache = [];

/**
* Whether the factory has been initialized or not.
*
* @var bool
*/
protected static bool $initialized = false;

/**
* An array of blacklisted algorithms.
*
Expand All @@ -30,44 +47,92 @@ final class EncryptionAlgorithmFactory extends AbstractAlgorithmFactory
];

/**
* A cache of algorithm implementations indexed by algorithm ID.
* An array of default algorithms that can be used.
*
* @var array<string, \SimpleSAML\XMLSecurity\Alg\Encryption\EncryptionAlgorithmInterface>
* @var class-string[]
*/
protected static array $cache = [];
private const SUPPORTED_DEFAULTS = [
TripleDES::class,
AES::class,
];


/**
* Whether the factory has been initialized or not.
* Build a factory that creates algorithms.
*
* @var bool
* @param string[]|null $blacklist A list of algorithms forbidden for their use.
*/
protected static bool $initialized = false;
public function __construct(
protected ?array $blacklist = self::DEFAULT_BLACKLIST,
) {
// initialize the cache for supported algorithms per known implementation
if (!self::$initialized && $blacklist !== null) {
foreach (self::SUPPORTED_DEFAULTS as $algorithm) {
foreach ($algorithm::getSupportedAlgorithms() as $algId) {
if (array_key_exists($algId, self::$cache)) {
/*
* If the key existed before initialization, that means someone registered a handler for this
* algorithm, so we should respect that and skip registering the default here.
*/
continue;
}
self::$cache[$algId] = $algorithm;
}
}
self::$initialized = true;
}
}


/**
* Build a factory that creates encryption algorithms.
* Get a new object implementing the given digital signature algorithm.
*
* @param string[]|null $blacklist A list of algorithms forbidden for their use.
* @param string $algId The identifier of the algorithm desired.
* @param \SimpleSAML\XMLSecurity\Key\KeyInterface $key The key to use with the given algorithm.
*
* @return \SimpleSAML\XMLSecurity\Alg\Encryption\EncryptionAlgorithmInterface An object implementing the given
* algorithm.
*
* @throws \SimpleSAML\XMLSecurity\Exception\UnsupportedAlgorithmException If an error occurs, e.g. the given
* algorithm is blacklisted, unknown or the given key is not suitable for it.
*/
public function __construct(array $blacklist = null)
public function getAlgorithm(string $algId, KeyInterface $key): EncryptionAlgorithmInterface
{
parent::__construct(
$blacklist ?? self::DEFAULT_BLACKLIST,
[
TripleDES::class,
AES::class,
],
Assert::false(
($this->blacklist !== null) && in_array($algId, $this->blacklist, true),
sprintf('Blacklisted algorithm: \'%s\'.', $algId),
BlacklistedAlgorithmException::class,
);
Assert::keyExists(
self::$cache,
$algId,
sprintf('Unknown or unsupported algorithm: \'%s\'.', $algId),
UnsupportedAlgorithmException::class,
);

return new self::$cache[$algId]($key, $algId);
}


/**
* Get the name of the abstract class our algorithm implementations must extend.
* Register an implementation of some algorithm(s) for its use.
*
* @return string
* @param class-string $className
*/
protected static function getExpectedParent(): string
public static function registerAlgorithm(string $className): void
{
return EncryptionAlgorithmInterface::class;
Assert::implementsInterface(
$className,
EncryptionAlgorithmInterface::class,
sprintf(
'Cannot register algorithm "%s", must implement %s.',
$className,
EncryptionAlgorithmInterface::class,
),
);

foreach ($className::getSupportedAlgorithms() as $algId) {
self::$cache[$algId] = $className;
}
}
}
2 changes: 1 addition & 1 deletion src/Alg/Encryption/TripleDES.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public function __construct(SymmetricKey $key)


/**
* @inheritDoc
* @return string[]
*/
public static function getSupportedAlgorithms(): array
{
Expand Down
3 changes: 1 addition & 2 deletions src/Alg/KeyTransport/AbstractKeyTransporter.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
namespace SimpleSAML\XMLSecurity\Alg\KeyTransport;

use SimpleSAML\Assert\Assert;
use SimpleSAML\XMLSecurity\Alg\Encryption\EncryptionAlgorithmInterface;
use SimpleSAML\XMLSecurity\Backend;
use SimpleSAML\XMLSecurity\Backend\EncryptionBackend;
use SimpleSAML\XMLSecurity\Exception\UnsupportedAlgorithmException;
Expand All @@ -16,7 +15,7 @@
*
* @package simplesamlphp/xml-security
*/
abstract class AbstractKeyTransporter implements EncryptionAlgorithmInterface
abstract class AbstractKeyTransporter implements KeyTransportAlgorithmInterface
{
/** @var string */
protected const DEFAULT_BACKEND = Backend\OpenSSL::class;
Expand Down
Loading

0 comments on commit 1c0b0d8

Please sign in to comment.