Conditions::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 6
nc 1
nop 6
dl 0
loc 14
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SimpleSAML\SAML2\XML\saml;
6
7
use DateTimeImmutable;
8
use DOMElement;
9
use SimpleSAML\Assert\Assert;
10
use SimpleSAML\SAML2\Assert\Assert as SAMLAssert;
11
use SimpleSAML\SAML2\Constants as C;
12
use SimpleSAML\SAML2\Exception\ProtocolViolationException;
13
use SimpleSAML\XML\Exception\InvalidDOMElementException;
14
use SimpleSAML\XML\SchemaValidatableElementInterface;
15
use SimpleSAML\XML\SchemaValidatableElementTrait;
16
17
use function array_pop;
18
19
/**
20
 * Class representing SAML 2 Conditions element.
21
 *
22
 * @package simplesamlphp/saml2
23
 */
24
final class Conditions extends AbstractSamlElement implements SchemaValidatableElementInterface
25
{
26
    use SchemaValidatableElementTrait;
27
28
    /**
29
     * Initialize a Conditions element.
30
     *
31
     * @param \DateTimeImmutable|null $notBefore
32
     * @param \DateTimeImmutable|null $notOnOrAfter
33
     * @param \SimpleSAML\SAML2\XML\saml\AbstractCondition[] $condition
34
     * @param \SimpleSAML\SAML2\XML\saml\AudienceRestriction[] $audienceRestriction
35
     * @param \SimpleSAML\SAML2\XML\saml\OneTimeUse|null $oneTimeUse
36
     * @param \SimpleSAML\SAML2\XML\saml\ProxyRestriction|null $proxyRestriction
37
     */
38
    public function __construct(
39
        protected ?DateTimeImmutable $notBefore = null,
40
        protected ?DateTimeImmutable $notOnOrAfter = null,
41
        protected array $condition = [],
42
        protected array $audienceRestriction = [],
43
        protected ?OneTimeUse $oneTimeUse = null,
44
        protected ?ProxyRestriction $proxyRestriction = null,
45
    ) {
46
        Assert::nullOrSame($notBefore?->getTimeZone()->getName(), 'Z', ProtocolViolationException::class);
47
        Assert::nullOrSame($notOnOrAfter?->getTimeZone()->getName(), 'Z', ProtocolViolationException::class);
48
        Assert::maxCount($condition, C::UNBOUNDED_LIMIT);
49
        Assert::allIsInstanceOf($condition, AbstractCondition::class);
50
        Assert::maxCount($audienceRestriction, C::UNBOUNDED_LIMIT);
51
        Assert::allIsInstanceOf($audienceRestriction, AudienceRestriction::class);
52
    }
53
54
55
    /**
56
     * Collect the value of the notBefore-property
57
     *
58
     * @return \DateTimeImmutable|null
59
     */
60
    public function getNotBefore(): ?DateTimeImmutable
61
    {
62
        return $this->notBefore;
63
    }
64
65
66
    /**
67
     * Collect the value of the notOnOrAfter-property
68
     *
69
     * @return \DateTimeImmutable|null
70
     */
71
    public function getNotOnOrAfter(): ?DateTimeImmutable
72
    {
73
        return $this->notOnOrAfter;
74
    }
75
76
77
    /**
78
     * Collect the value of the condition-property
79
     *
80
     * @return \SimpleSAML\SAML2\XML\saml\AbstractCondition[]
81
     */
82
    public function getCondition(): array
83
    {
84
        return $this->condition;
85
    }
86
87
88
    /**
89
     * Collect the value of the audienceRestriction-property
90
     *
91
     * @return \SimpleSAML\SAML2\XML\saml\AudienceRestriction[]
92
     */
93
    public function getAudienceRestriction(): array
94
    {
95
        return $this->audienceRestriction;
96
    }
97
98
99
    /**
100
     * Collect the value of the oneTimeUse-property
101
     *
102
     * @return \SimpleSAML\SAML2\XML\saml\OneTimeUse|null
103
     */
104
    public function getOneTimeUse(): ?OneTimeUse
105
    {
106
        return $this->oneTimeUse;
107
    }
108
109
110
    /**
111
     * Collect the value of the proxyRestriction-property
112
     *
113
     * @return \SimpleSAML\SAML2\XML\saml\ProxyRestriction|null
114
     */
115
    public function getProxyRestriction(): ?ProxyRestriction
116
    {
117
        return $this->proxyRestriction;
118
    }
119
120
121
    /**
122
     * Test if an object, at the state it's in, would produce an empty XML-element
123
     *
124
     * @return bool
125
     */
126
    public function isEmptyElement(): bool
127
    {
128
        return empty($this->notBefore)
129
            && empty($this->notOnOrAfter)
130
            && empty($this->condition)
131
            && empty($this->audienceRestriction)
132
            && empty($this->oneTimeUse)
133
            && empty($this->proxyRestriction);
134
    }
135
136
137
    /**
138
     * Convert XML into a Conditions object
139
     *
140
     * @param \DOMElement $xml The XML element we should load
141
     * @return static
142
     *
143
     * @throws \SimpleSAML\XML\Exception\InvalidDOMElementException
144
     *   if the qualified name of the supplied element is wrong
145
     */
146
    public static function fromXML(DOMElement $xml): static
147
    {
148
        Assert::same($xml->localName, 'Conditions', InvalidDOMElementException::class);
149
        Assert::same($xml->namespaceURI, Conditions::NS, InvalidDOMElementException::class);
150
151
        $notBefore = self::getOptionalAttribute($xml, 'NotBefore', null);
152
        if ($notBefore !== null) {
153
            // Strip sub-seconds - See paragraph 1.3.3 of SAML core specifications
154
            $notBefore = preg_replace('/([.][0-9]+Z)$/', 'Z', $notBefore, 1);
155
156
            SAMLAssert::validDateTime($notBefore, ProtocolViolationException::class);
157
        }
158
159
        $notOnOrAfter = self::getOptionalAttribute($xml, 'NotOnOrAfter', null);
160
        if ($notOnOrAfter !== null) {
161
            // Strip sub-seconds - See paragraph 1.3.3 of SAML core specifications
162
            $notOnOrAfter = preg_replace('/([.][0-9]+Z)$/', 'Z', $notOnOrAfter, 1);
163
164
            SAMLAssert::validDateTime($notOnOrAfter, ProtocolViolationException::class);
165
        }
166
167
        $condition = AbstractCondition::getChildrenOfClass($xml);
168
        $audienceRestriction = AudienceRestriction::getChildrenOfClass($xml);
169
        $oneTimeUse = OneTimeUse::getChildrenOfClass($xml);
170
        $proxyRestriction = ProxyRestriction::getChildrenOfClass($xml);
171
172
        Assert::maxCount(
173
            $oneTimeUse,
174
            1,
175
            'There MUST occur at most one <saml:OneTimeUse> element inside a <saml:Conditions>',
176
            ProtocolViolationException::class,
177
        );
178
        Assert::maxCount(
179
            $proxyRestriction,
180
            1,
181
            'There MUST occur at most one <saml:ProxyRestriction> element inside a <saml:Conditions>',
182
            ProtocolViolationException::class,
183
        );
184
185
        return new static(
186
            $notBefore !== null ? new DateTimeImmutable($notBefore) : null,
187
            $notOnOrAfter !== null ? new DateTimeImmutable($notOnOrAfter) : null,
188
            $condition,
189
            $audienceRestriction,
190
            array_pop($oneTimeUse),
191
            array_pop($proxyRestriction),
192
        );
193
    }
194
195
196
    /**
197
     * Convert this element to XML.
198
     *
199
     * @param  \DOMElement|null $parent The parent element we should append this element to.
200
     * @return \DOMElement This element, as XML.
201
     */
202
    public function toXML(?DOMElement $parent = null): DOMElement
203
    {
204
        $e = $this->instantiateParentElement($parent);
205
206
        if ($this->getNotBefore() !== null) {
207
            $e->setAttribute('NotBefore', $this->getNotBefore()->format(C::DATETIME_FORMAT));
208
        }
209
210
        if ($this->getNotOnOrAfter() !== null) {
211
            $e->setAttribute('NotOnOrAfter', $this->getNotOnOrAfter()->format(C::DATETIME_FORMAT));
212
        }
213
214
        foreach ($this->getCondition() as $condition) {
215
            $condition->toXML($e);
216
        }
217
218
        foreach ($this->getAudienceRestriction() as $audienceRestriction) {
219
            $audienceRestriction->toXML($e);
220
        }
221
222
        $this->getOneTimeUse()?->toXML($e);
223
        $this->getProxyRestriction()?->toXML($e);
224
225
        return $e;
226
    }
227
}
228