Passed
Pull Request — master (#26)
by Jaime Pérez
01:59
created

AbstractAlgorithmFactory   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 95
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 27
c 1
b 0
f 0
dl 0
loc 95
rs 10
wmc 10

3 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 22 7
A registerAlgorithm() 0 12 2
A getAlgorithm() 0 14 1
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::true(
84
            array_key_exists($algId, static::$cache),
85
            sprintf('Unknown or unsupported algorithm: \'%s\'.', $algId),
86
            UnsupportedAlgorithmException::class
87
        );
88
89
        return new static::$cache[$algId]($key, $algId);
90
    }
91
92
93
    /**
94
     * Get the name of the abstract class our algorithm implementations must extend.
95
     *
96
     * @return string
97
     */
98
    abstract protected static function getExpectedParent(): string;
99
100
101
    /**
102
     * Register an implementation of some algorithm(s) for its use.
103
     *
104
     * @param string $className
105
     */
106
    public static function registerAlgorithm(string $className): void
107
    {
108
        $parent = static::getExpectedParent();
109
        Assert::subclassOf(
110
            $className,
111
            $parent,
112
            'Cannot register algorithm "' . $className . '", must implement ' . $parent . '.'
113
        );
114
115
        /** @var \SimpleSAML\XMLSecurity\Alg\AlgorithmInterface $className */
116
        foreach ($className::getSupportedAlgorithms() as $algId) {
117
            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...
118
        }
119
    }
120
}
121