Passed
Push — master ( 66592a...152b2f )
by Tim
02:08
created

RegistrationInfo::processArrayContents()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 28
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 17
nc 4
nop 1
dl 0
loc 28
rs 9.7
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SimpleSAML\SAML2\XML\mdrpi;
6
7
use DateTimeImmutable;
8
use DOMElement;
9
use SimpleSAML\Assert\Assert;
10
use SimpleSAML\SAML2\Constants as C;
11
use SimpleSAML\SAML2\Exception\ArrayValidationException;
12
use SimpleSAML\SAML2\Exception\ProtocolViolationException;
13
use SimpleSAML\SAML2\XML\md\AbstractLocalizedURI;
14
use SimpleSAML\XML\ArrayizableElementInterface;
15
use SimpleSAML\XML\Exception\InvalidDOMElementException;
16
17
use function preg_replace;
18
19
/**
20
 * Class for handling the mdrpi:RegistrationInfo element.
21
 *
22
 * @link: http://docs.oasis-open.org/security/saml/Post2.0/saml-metadata-rpi/v1.0/saml-metadata-rpi-v1.0.pdf
23
 * @package simplesamlphp/saml2
24
 */
25
final class RegistrationInfo extends AbstractMdrpiElement implements ArrayizableElementInterface
26
{
27
    /**
28
     * Create/parse a mdrpi:RegistrationInfo element.
29
     *
30
     * @param string $registrationAuthority
31
     * @param \DateTimeImmutable|null $registrationInstant
32
     * @param \SimpleSAML\SAML2\XML\mdrpi\RegistrationPolicy[] $RegistrationPolicy
33
     */
34
    public function __construct(
35
        protected string $registrationAuthority,
36
        protected ?DateTimeImmutable $registrationInstant = null,
37
        protected array $registrationPolicy = [],
38
    ) {
39
        Assert::nullOrSame($registrationInstant?->getTimeZone()->getName(), 'Z', ProtocolViolationException::class);
40
        Assert::allIsInstanceOf($registrationPolicy, RegistrationPolicy::class);
41
42
        /**
43
         * 2.1.1:  There MUST NOT be more than one <mdrpi:RegistrationPolicy>,
44
         *         within a given <mdrpi:RegistrationInfo>, for a given language
45
         */
46
        $languages = array_map(
47
            function ($rp) {
48
                return $rp->getLanguage();
49
            },
50
            $registrationPolicy,
51
        );
52
        Assert::uniqueValues(
53
            $languages,
54
            'There MUST NOT be more than one <mdrpi:RegistrationPolicy>,'
55
            . ' within a given <mdrpi:RegistrationInfo>, for a given language',
56
            ProtocolViolationException::class,
57
        );
58
    }
59
60
61
    /**
62
     * Collect the value of the RegistrationAuthority property
63
     *
64
     * @return string
65
     */
66
    public function getRegistrationAuthority(): string
67
    {
68
        return $this->registrationAuthority;
69
    }
70
71
72
    /**
73
     * Collect the value of the registrationInstant property
74
     *
75
     * @return \DateTimeImmutable|null
76
     */
77
    public function getRegistrationInstant(): ?DateTimeImmutable
78
    {
79
        return $this->registrationInstant;
80
    }
81
82
83
    /**
84
     * Collect the value of the RegistrationPolicy property
85
     *
86
     * @return \SimpleSAML\SAML2\XML\mdrpi\RegistrationPolicy[]
87
     */
88
    public function getRegistrationPolicy(): array
89
    {
90
        return $this->registrationPolicy;
91
    }
92
93
94
    /**
95
     * Convert XML into a RegistrationInfo
96
     *
97
     * @param \DOMElement $xml The XML element we should load
98
     * @return static
99
     *
100
     * @throws \SimpleSAML\XML\Exception\InvalidDOMElementException
101
     *   if the qualified name of the supplied element is wrong
102
     * @throws \SimpleSAML\XML\Exception\MissingAttributeException
103
     *   if the supplied element is missing one of the mandatory attributes
104
     */
105
    public static function fromXML(DOMElement $xml): static
106
    {
107
        Assert::same($xml->localName, 'RegistrationInfo', InvalidDOMElementException::class);
108
        Assert::same($xml->namespaceURI, RegistrationInfo::NS, InvalidDOMElementException::class);
109
110
        $registrationAuthority = self::getAttribute($xml, 'registrationAuthority');
111
        $registrationInstant = self::getOptionalAttribute($xml, 'registrationInstant', null);
112
113
        // 2.1.1:  Time values MUST be expressed in the UTC timezone using the 'Z' timezone identifier
114
        if ($registrationInstant !== null) {
115
            // Strip sub-seconds - See paragraph 1.3.3 of SAML core specifications
116
            $registrationInstant = preg_replace('/([.][0-9]+Z)$/', 'Z', $registrationInstant, 1);
117
118
            Assert::validDateTimeZulu($registrationInstant, ProtocolViolationException::class);
119
            $registrationInstant = new DateTimeImmutable($registrationInstant);
120
        }
121
        $RegistrationPolicy = RegistrationPolicy::getChildrenOfClass($xml);
122
123
        return new static($registrationAuthority, $registrationInstant, $RegistrationPolicy);
124
    }
125
126
127
    /**
128
     * Convert this element to XML.
129
     *
130
     * @param \DOMElement|null $parent The element we should append to.
131
     * @return \DOMElement
132
     */
133
    public function toXML(DOMElement $parent = null): DOMElement
134
    {
135
        $e = $this->instantiateParentElement($parent);
136
        $e->setAttribute('registrationAuthority', $this->getRegistrationAuthority());
137
138
        if ($this->getRegistrationInstant() !== null) {
139
            $e->setAttribute('registrationInstant', $this->getRegistrationInstant()->format(C::DATETIME_FORMAT));
140
        }
141
142
        foreach ($this->getRegistrationPolicy() as $rp) {
143
            $rp->toXML($e);
144
        }
145
146
        return $e;
147
    }
148
149
150
    /**
151
     * Create a class from an array
152
     *
153
     * @param array $data
154
     * @return static
155
     */
156
    public static function fromArray(array $data): static
157
    {
158
        $data = self::processArrayContents($data);
159
160
        return new static(
161
            $data['registrationAuthority'],
162
            $data['registrationInstant'] ?? null,
163
            $data['RegistrationPolicy'] ?? [],
164
        );
165
    }
166
167
168
    /**
169
     * Validates an array representation of this object and returns the same array with
170
     * rationalized keys (casing) and parsed sub-elements.
171
     *
172
     * @param array $data
173
     * @return array $data
174
     */
175
    private static function processArrayContents(array $data): array
176
    {
177
        $data = array_change_key_case($data, CASE_LOWER);
178
179
        Assert::allOneOf(
180
            array_keys($data),
181
            ['registrationauthority', 'registrationinstant', 'registrationpolicy'],
182
            ArrayValidationException::class,
183
        );
184
185
        Assert::keyExists($data, 'registrationauthority', ArrayValidationException::class);
186
        Assert::string($data['registrationauthority'], ArrayValidationException::class);
187
        $retval = ['registrationAuthority' => $data['registrationauthority']];
188
189
        if (array_key_exists('registrationinstant', $data)) {
190
            Assert::string($data['registrationinstant'], ArrayValidationException::class);
191
            Assert::validDateTimeZulu($data['registrationinstant'], ArrayValidationException::class);
192
            $retval['registrationInstant'] = new DateTimeImmutable($data['registrationinstant']);
193
        }
194
195
        if (array_key_exists('registrationpolicy', $data)) {
196
            Assert::isArray($data['registrationpolicy'], ArrayValidationException::class);
197
            foreach ($data['registrationpolicy'] as $lang => $rp) {
198
                $retval['RegistrationPolicy'][] = RegistrationPolicy::fromArray([$lang => $rp]);
199
            }
200
        }
201
202
        return $retval;
203
    }
204
205
206
    /**
207
     * Create an array from this class
208
     *
209
     * @return array
210
     */
211
    public function toArray(): array
212
    {
213
        $data = [];
214
        $data['registrationAuthority'] = $this->getRegistrationAuthority();
215
216
        if ($this->getRegistrationInstant() !== null) {
217
            $data['registrationInstant'] = $this->getRegistrationInstant()->format(C::DATETIME_FORMAT);
218
        }
219
220
        if (!empty($this->getRegistrationPolicy())) {
221
            $data['RegistrationPolicy'] = [];
222
            foreach ($this->getRegistrationPolicy() as $rp) {
223
                $data['RegistrationPolicy'] = array_merge($data['RegistrationPolicy'], $rp->toArray());
224
            }
225
        }
226
227
        return $data;
228
    }
229
}
230