Passed
Branch feature/php83 (e52173)
by Tim
33:00 queued 16:50
created

KeyTransportAlgorithmFactory   A

Complexity

Total Complexity 9

Size/Duplication

Total Lines 118
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 9
eloc 33
c 1
b 0
f 0
dl 0
loc 118
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SimpleSAML\XMLSecurity\Alg\KeyTransport;
6
7
use SimpleSAML\Assert\Assert;
8
use SimpleSAML\XMLSecurity\Constants as C;
9
use SimpleSAML\XMLSecurity\Exception\BlacklistedAlgorithmException;
10
use SimpleSAML\XMLSecurity\Exception\UnsupportedAlgorithmException;
11
use SimpleSAML\XMLSecurity\Key\KeyInterface;
12
13
use function array_key_exists;
14
use function sprintf;
15
16
/**
17
 * Factory class to create and configure key transport algorithms.
18
 */
19
class KeyTransportAlgorithmFactory
20
{
21
    /**
22
     * An array of blacklisted algorithms.
23
     *
24
     * Defaults to RSA 1.5.
25
     *
26
     * @var string[]
27
     */
28
    public const array DEFAULT_BLACKLIST = [
0 ignored issues
show
Bug introduced by
A parse error occurred: Syntax error, unexpected T_STRING, expecting '=' on line 28 at column 23
Loading history...
29
        C::KEY_TRANSPORT_RSA_1_5,
30
    ];
31
32
    /**
33
     * An array of default algorithms that can be used.
34
     *
35
     * @var class-string[]
36
     */
37
    private const array SUPPORTED_DEFAULTS = [
38
        RSA::class,
39
    ];
40
41
42
    /**
43
     * A cache of algorithm implementations indexed by algorithm ID.
44
     *
45
     * @var array<string, \SimpleSAML\XMLSecurity\Alg\KeyTransport\KeyTransportAlgorithmInterface>
46
     */
47
    protected static array $cache = [];
48
49
    /**
50
     * Whether the factory has been initialized or not.
51
     */
52
    protected static bool $initialized = false;
53
54
55
    /**
56
     * Build a factory that creates algorithms.
57
     *
58
     * @param string[] $blacklist A list of algorithms forbidden for their use.
59
     */
60
    public function __construct(
61
        protected array $blacklist = self::DEFAULT_BLACKLIST,
62
    ) {
63
        // initialize the cache for supported algorithms per known implementation
64
        if (!self::$initialized) {
65
            foreach (self::SUPPORTED_DEFAULTS as $algorithm) {
66
                foreach ($algorithm::getSupportedAlgorithms() as $algId) {
67
                    if (array_key_exists($algId, self::$cache) && !array_key_exists($algId, $this->blacklist)) {
68
                        /*
69
                         * If the key existed before initialization, that means someone registered a handler for this
70
                         * algorithm, so we should respect that and skip registering the default here.
71
                         */
72
                        continue;
73
                    }
74
                    self::$cache[$algId] = $algorithm;
75
                }
76
            }
77
            self::$initialized = true;
78
        }
79
    }
80
81
82
    /**
83
     * Get a new object implementing the given digital signature algorithm.
84
     *
85
     * @param string $algId The identifier of the algorithm desired.
86
     * @param \SimpleSAML\XMLSecurity\Key\KeyInterface $key The key to use with the given algorithm.
87
     *
88
     * @return \SimpleSAML\XMLSecurity\Alg\KeyTransport\KeyTransportAlgorithmInterface An object implementing the given
89
     * algorithm.
90
     *
91
     * @throws \SimpleSAML\XMLSecurity\Exception\UnsupportedAlgorithmException If an error occurs, e.g. the given
92
     * algorithm is blacklisted, unknown or the given key is not suitable for it.
93
     */
94
    public function getAlgorithm(
95
        string $algId,
96
        #[\SensitiveParameter]
97
        KeyInterface $key,
98
    ): KeyTransportAlgorithmInterface {
99
        Assert::notInArray(
100
            $algId,
101
            $this->blacklist,
102
            sprintf('Blacklisted algorithm: \'%s\'.', $algId),
103
            BlacklistedAlgorithmException::class,
104
        );
105
        Assert::keyExists(
106
            self::$cache,
107
            $algId,
108
            sprintf('Unknown or unsupported algorithm: \'%s\'.', $algId),
109
            UnsupportedAlgorithmException::class,
110
        );
111
112
        return new self::$cache[$algId]($key, $algId);
113
    }
114
115
116
    /**
117
     * Register an implementation of some algorithm(s) for its use.
118
     *
119
     * @param class-string $className
120
     */
121
    public static function registerAlgorithm(string $className): void
122
    {
123
        Assert::implementsInterface(
124
            $className,
125
            KeyTransportAlgorithmInterface::class,
126
            sprintf(
127
                'Cannot register algorithm "%s", must implement %s.',
128
                $className,
129
                KeyTransportAlgorithmInterface::class,
130
            ),
131
        );
132
133
        foreach ($className::getSupportedAlgorithms() as $algId) {
134
            self::$cache[$algId] = $className;
135
        }
136
    }
137
}
138