Completed
Push — master ( 484ff8...780e48 )
by Jaime Pérez
15s queued 12s
created

AbstractAlgorithmFactory::__construct()   B

Complexity

Conditions 7
Paths 10

Size

Total Lines 22
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 9
c 1
b 0
f 0
nc 10
nop 2
dl 0
loc 22
rs 8.8333
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SimpleSAML\XMLSecurity\Alg;
6
7
use SimpleSAML\Assert\Assert;
8
use SimpleSAML\XMLSecurity\Exception\BlacklistedAlgorithmException;
9
use SimpleSAML\XMLSecurity\Exception\UnsupportedAlgorithmException;
10
use SimpleSAML\XMLSecurity\Key\AbstractKey;
11
12
/**
13
 * An abstract class implementing an algorithm factory.
14
 *
15
 * Extending classes MUST declare two static properties:
16
 *
17
 * - $cache: an associative array holding algorithm IDs as the keys, and class names implementing those algorithms as
18
 *   the value.
19
 * - $initialized: a boolean telling whether this factory has been initialized (a constructor has been called) or not.
20
 *
21
 * @package simplesamlphp/xml-security
22
 */
23
abstract class AbstractAlgorithmFactory
24
{
25
    /**
26
     * An array of blacklisted algorithms.
27
     *
28
     * @var string[]
29
     */
30
    protected array $blacklist = [];
31
32
33
    /**
34
     * Build a factory that creates algorithms.
35
     *
36
     * @param string[]|null $blacklist A list of algorithms forbidden for their use.
37
     * @param string[]|null $defaults A list of known implementations.
38
     */
39
    public function __construct(array $blacklist = null, array $defaults = null)
40
    {
41
        if ($blacklist !== null) {
42
            $this->blacklist = $blacklist;
43
        }
44
45
        // initialize the cache for supported algorithms per known implementation
46
        if (!static::$initialized && $defaults !== null) {
47
            foreach ($defaults as $algorithm) {
48
                /** @var \SimpleSAML\XMLSecurity\Alg\AlgorithmInterface $algorithm */
49
                foreach ($algorithm::getSupportedAlgorithms() as $algId) {
50
                    if (array_key_exists($algId, static::$cache)) {
51
                        /*
52
                         * If the key existed before initialization, that means someone registered a handler for this
53
                         * algorithm, so we should respect that and skip registering the default here.
54
                         */
55
                        continue;
56
                    }
57
                    static::$cache[$algId] = $algorithm;
0 ignored issues
show
Bug Best Practice introduced by
The property cache does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
58
                }
59
            }
60
            static::$initialized = true;
0 ignored issues
show
Bug Best Practice introduced by
The property initialized does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
61
        }
62
    }
63
64
65
    /**
66
     * Get a new object implementing the given algorithm.
67
     *
68
     * @param string $algId The identifier of the algorithm desired.
69
     * @param \SimpleSAML\XMLSecurity\Key\AbstractKey $key The key to use with the given algorithm.
70
     *
71
     * @return \SimpleSAML\XMLSecurity\Alg\AlgorithmInterface An object implementing the given algorithm.
72
     *
73
     * @throws \SimpleSAML\XMLSecurity\Exception\InvalidArgumentException If an error occurs, e.g. the given algorithm
74
     * is blacklisted, unknown or the given key is not suitable for it.
75
     */
76
    public function getAlgorithm(string $algId, AbstractKey $key): AlgorithmInterface
77
    {
78
        Assert::true(
79
            !in_array($algId, $this->blacklist, true),
80
            sprintf('Blacklisted algorithm: \'%s\'.', $algId),
81
            BlacklistedAlgorithmException::class
82
        );
83
        Assert::keyExists(
84
            static::$cache,
85
            $algId,
86
            sprintf('Unknown or unsupported algorithm: \'%s\'.', $algId),
87
            UnsupportedAlgorithmException::class
88
        );
89
90
        return new static::$cache[$algId]($key, $algId);
91
    }
92
93
94
    /**
95
     * Get the name of the abstract class our algorithm implementations must extend.
96
     *
97
     * @return string
98
     */
99
    abstract protected static function getExpectedParent(): string;
100
101
102
    /**
103
     * Register an implementation of some algorithm(s) for its use.
104
     *
105
     * @param string $className
106
     */
107
    public static function registerAlgorithm(string $className): void
108
    {
109
        $parent = static::getExpectedParent();
110
        Assert::subclassOf(
111
            $className,
112
            $parent,
113
            'Cannot register algorithm "' . $className . '", must implement ' . $parent . '.'
114
        );
115
116
        /** @var \SimpleSAML\XMLSecurity\Alg\AlgorithmInterface $className */
117
        foreach ($className::getSupportedAlgorithms() as $algId) {
118
            static::$cache[$algId] = $className;
0 ignored issues
show
Bug Best Practice introduced by
The property cache does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
119
        }
120
    }
121
}
122