Passed
Push — master ( 545cbd...74acb4 )
by Tim
02:16
created

AuthzDecisionQuery::getDecision()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SimpleSAML\SAML2\XML\samlp;
6
7
use DOMElement;
8
use SimpleSAML\Assert\Assert;
9
use SimpleSAML\SAML2\Constants as C;
10
use SimpleSAML\SAML2\Exception\ProtocolViolationException;
11
use SimpleSAML\SAML2\Exception\Protocol\RequestVersionTooHighException;
12
use SimpleSAML\SAML2\Exception\Protocol\RequestVersionTooLowException;
13
use SimpleSAML\SAML2\XML\saml\Action;
14
use SimpleSAML\SAML2\XML\saml\Evidence;
15
use SimpleSAML\SAML2\XML\saml\Issuer;
16
use SimpleSAML\SAML2\XML\saml\Subject;
17
use SimpleSAML\XML\Exception\InvalidDOMElementException;
18
use SimpleSAML\XML\Exception\MissingElementException;
19
use SimpleSAML\XML\Exception\SchemaViolationException;
20
use SimpleSAML\XML\Exception\TooManyElementsException;
21
use SimpleSAML\XML\Utils as XMLUtils;
22
use SimpleSAML\XMLSecurity\XML\ds\Signature;
23
24
use function preg_match;
25
use function version_compare;
26
27
/**
28
 * Class representing a SAML2 AuthzDecisionQuery
29
 *
30
 * @package simplesamlphp/saml2
31
 */
32
final class AuthzDecisionQuery extends AbstractSubjectQuery
33
{
34
    /**
35
     * Constructor for SAML 2 AuthzDecisionQuery.
36
     *
37
     * @param \SimpleSAML\SAML2\XML\saml\Subject $subject
38
     * @param string $resource
39
     * @param \SimpleSAML\SAML2\XML\saml\Action[] $action
40
     * @param \SimpleSAML\SAML2\XML\saml\Evidence $evidence
41
     * @param \SimpleSAML\SAML2\XML\saml\Issuer $issuer
42
     * @param string|null $id
43
     * @param string $version
44
     * @param int $issueInstant
45
     * @param string|null $destination
46
     * @param string|null $consent
47
     * @param \SimpleSAML\SAML2\XML\samlp\Extensions $extensions
48
     */
49
    public function __construct(
50
        Subject $subject,
51
        protected string $resource,
52
        protected array $action,
53
        protected ?Evidence $evidence = null,
54
        ?Issuer $issuer = null,
55
        ?string $id = null,
56
        string $version = '2.0',
57
        ?int $issueInstant = null,
58
        ?string $destination = null,
59
        ?string $consent = null,
60
        ?Extensions $extensions = null,
61
    ) {
62
        Assert::validURI($resource);
63
        Assert::allIsInstanceOf($action, Action::class, SchemaViolationException::class);
64
65
        parent::__construct($subject, $issuer, $id, $version, $issueInstant, $destination, $consent, $extensions);
66
    }
67
68
69
    /**
70
     * Collect the value of the resource-property
71
     *
72
     * @return string
73
     */
74
    public function getResource(): string
75
    {
76
        return $this->resource;
77
    }
78
79
80
    /**
81
     * Collect the value of the action-property
82
     *
83
     * @return array
84
     */
85
    public function getAction(): array
86
    {
87
        return $this->action;
88
    }
89
90
91
    /**
92
     * Collect the value of the evidence-property
93
     *
94
     * @return \SimpleSAML\SAML2\XML\saml\Evidence|null
95
     */
96
    public function getEvidence(): ?Evidence
97
    {
98
        return $this->evidence;
99
    }
100
101
102
    /**
103
     * Convert XML into an AuthzDecisionQuery
104
     *
105
     * @param \DOMElement $xml The XML element we should load
106
     *
107
     * @return static
108
     * @throws \SimpleSAML\XML\Exception\InvalidDOMElementException
109
     *   if the qualified name of the supplied element is wrong
110
     * @throws \SimpleSAML\XML\Exception\MissingElementException
111
     *   if one of the mandatory child-elements is missing
112
     * @throws \Exception if the authentication instant is not a valid timestamp.
113
     */
114
    public static function fromXML(DOMElement $xml): static
115
    {
116
        Assert::same($xml->localName, 'AuthzDecisionQuery', InvalidDOMElementException::class);
117
        Assert::same($xml->namespaceURI, AuthzDecisionQuery::NS, InvalidDOMElementException::class);
118
119
        $version = self::getAttribute($xml, 'Version');
120
        Assert::true(version_compare('2.0', $version, '<='), RequestVersionTooLowException::class);
0 ignored issues
show
Bug introduced by
It seems like $version can also be of type null; however, parameter $version2 of version_compare() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

120
        Assert::true(version_compare('2.0', /** @scrutinizer ignore-type */ $version, '<='), RequestVersionTooLowException::class);
Loading history...
121
        Assert::true(version_compare('2.0', $version, '>='), RequestVersionTooHighException::class);
122
123
        $id = self::getAttribute($xml, 'ID');
124
        Assert::validNCName($id); // Covers the empty string
0 ignored issues
show
Bug introduced by
It seems like $id can also be of type null; however, parameter $value of SimpleSAML\Assert\Assert::validNCName() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

124
        Assert::validNCName(/** @scrutinizer ignore-type */ $id); // Covers the empty string
Loading history...
125
126
        $destination = self::getAttribute($xml, 'Destination', null);
127
        $consent = self::getAttribute($xml, 'Consent', null);
128
129
        $issueInstant = self::getAttribute($xml, 'IssueInstant');
130
        // Strip sub-seconds - See paragraph 1.3.3 of SAML core specifications
131
        $issueInstant = preg_replace('/([.][0-9]+Z)$/', 'Z', $issueInstant, 1);
132
133
        Assert::validDateTimeZulu($issueInstant, ProtocolViolationException::class);
134
        $issueInstant = XMLUtils::xsDateTimeToTimestamp($issueInstant);
135
136
        $issuer = Issuer::getChildrenOfClass($xml);
137
        Assert::countBetween($issuer, 0, 1);
138
139
        $extensions = Extensions::getChildrenOfClass($xml);
140
        Assert::maxCount(
141
            $extensions,
142
            1,
143
            'Only one saml:Extensions element is allowed.',
144
            TooManyElementsException::class,
145
        );
146
147
        $subject = Subject::getChildrenOfClass($xml);
148
        Assert::notEmpty($subject, 'Missing subject in subject query.', MissingElementException::class);
149
        Assert::maxCount(
150
            $subject,
151
            1,
152
            'More than one <saml:Subject> in AuthzDecisionQuery',
153
            TooManyElementsException::class,
154
        );
155
156
        $action = Action::getChildrenOfClass($xml);
157
        Assert::minCount(
158
            $action,
159
            1,
160
            'Missing <saml:Action> in <saml:AuthzDecisionQuery>',
161
            MissingElementException::class,
162
        );
163
164
        $evidence = Evidence::getChildrenOfClass($xml);
165
        Assert::maxCount(
166
            $evidence,
167
            1,
168
            'Too many <saml:Evidence> in <saml:AuthzDecisionQuery>',
169
            TooManyElementsException::class,
170
        );
171
172
        $signature = Signature::getChildrenOfClass($xml);
173
        Assert::maxCount($signature, 1, 'Only one ds:Signature element is allowed.', TooManyElementsException::class);
174
175
        $request = new static(
176
            array_pop($subject),
177
            self::getAttribute($xml, 'Resource'),
0 ignored issues
show
Bug introduced by
It seems like self::getAttribute($xml, 'Resource') can also be of type null; however, parameter $resource of SimpleSAML\SAML2\XML\sam...ionQuery::__construct() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

177
            /** @scrutinizer ignore-type */ self::getAttribute($xml, 'Resource'),
Loading history...
178
            $action,
179
            array_pop($evidence),
180
            array_pop($issuer),
181
            $id,
182
            $version,
0 ignored issues
show
Bug introduced by
It seems like $version can also be of type null; however, parameter $version of SimpleSAML\SAML2\XML\sam...ionQuery::__construct() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

182
            /** @scrutinizer ignore-type */ $version,
Loading history...
183
            $issueInstant,
184
            $destination,
185
            $consent,
186
            array_pop($extensions),
187
        );
188
189
        if (!empty($signature)) {
190
            $request->setSignature($signature[0]);
191
            $request->setXML($xml);
192
        }
193
194
        return $request;
195
    }
196
197
198
    /**
199
     * Convert this message to an unsigned XML document.
200
     * This method does not sign the resulting XML document.
201
     *
202
     * @return \DOMElement The root element of the DOM tree
203
     */
204
    protected function toUnsignedXML(?DOMElement $parent = null): DOMElement
205
    {
206
        $e = parent::toUnsignedXML($parent);
207
        $e->setAttribute('Resource', $this->getResource());
208
209
        foreach ($this->getAction() as $action) {
210
            $action->toXML($e);
211
        }
212
213
        if ($this->getEvidence() !== null && !$this->getEvidence()->isEmptyElement()) {
214
            $this->getEvidence()->toXML($e);
215
        }
216
217
        return $e;
218
    }
219
}
220