Passed
Push — master ( f21217...7f49bc )
by Tim
15:21 queued 13:12
created

AuthzDecisionQuery::toUnsignedXML()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 7
c 1
b 0
f 0
nc 4
nop 1
dl 0
loc 14
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 decision-property
82
     *
83
     * @return string
84
     */
85
    public function getDecision(): string
86
    {
87
        return $this->decision;
88
    }
89
90
91
    /**
92
     * Collect the value of the action-property
93
     *
94
     * @return array
95
     */
96
    public function getAction(): array
97
    {
98
        return $this->action;
99
    }
100
101
102
    /**
103
     * Collect the value of the evidence-property
104
     *
105
     * @return \SimpleSAML\SAML2\XML\saml\Evidence|null
106
     */
107
    public function getEvidence(): ?Evidence
108
    {
109
        return $this->evidence;
110
    }
111
112
113
    /**
114
     * Convert XML into an AuthzDecisionQuery
115
     *
116
     * @param \DOMElement $xml The XML element we should load
117
     *
118
     * @return static
119
     * @throws \SimpleSAML\XML\Exception\InvalidDOMElementException
120
     *   if the qualified name of the supplied element is wrong
121
     * @throws \SimpleSAML\XML\Exception\MissingElementException
122
     *   if one of the mandatory child-elements is missing
123
     * @throws \Exception if the authentication instant is not a valid timestamp.
124
     */
125
    public static function fromXML(DOMElement $xml): static
126
    {
127
        Assert::same($xml->localName, 'AuthzDecisionQuery', InvalidDOMElementException::class);
128
        Assert::same($xml->namespaceURI, AuthzDecisionQuery::NS, InvalidDOMElementException::class);
129
130
        $version = self::getAttribute($xml, 'Version');
131
        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

131
        Assert::true(version_compare('2.0', /** @scrutinizer ignore-type */ $version, '<='), RequestVersionTooLowException::class);
Loading history...
132
        Assert::true(version_compare('2.0', $version, '>='), RequestVersionTooHighException::class);
133
134
        $id = self::getAttribute($xml, 'ID');
135
        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

135
        Assert::validNCName(/** @scrutinizer ignore-type */ $id); // Covers the empty string
Loading history...
136
137
        $destination = self::getAttribute($xml, 'Destination', null);
138
        $consent = self::getAttribute($xml, 'Consent', null);
139
140
        $issueInstant = self::getAttribute($xml, 'IssueInstant');
141
        // Strip sub-seconds - See paragraph 1.3.3 of SAML core specifications
142
        $issueInstant = preg_replace('/([.][0-9]+Z)$/', 'Z', $issueInstant, 1);
143
144
        Assert::validDateTimeZulu($issueInstant, ProtocolViolationException::class);
145
        $issueInstant = XMLUtils::xsDateTimeToTimestamp($issueInstant);
146
147
        $issuer = Issuer::getChildrenOfClass($xml);
148
        Assert::countBetween($issuer, 0, 1);
149
150
        $extensions = Extensions::getChildrenOfClass($xml);
151
        Assert::maxCount(
152
            $extensions,
153
            1,
154
            'Only one saml:Extensions element is allowed.',
155
            TooManyElementsException::class,
156
        );
157
158
        $subject = Subject::getChildrenOfClass($xml);
159
        Assert::notEmpty($subject, 'Missing subject in subject query.', MissingElementException::class);
160
        Assert::maxCount(
161
            $subject,
162
            1,
163
            'More than one <saml:Subject> in AuthzDecisionQuery',
164
            TooManyElementsException::class,
165
        );
166
167
        $action = Action::getChildrenOfClass($xml);
168
        Assert::minCount(
169
            $action,
170
            1,
171
            'Missing <saml:Action> in <saml:AuthzDecisionQuery>',
172
            MissingElementException::class,
173
        );
174
175
        $evidence = Evidence::getChildrenOfClass($xml);
176
        Assert::maxCount(
177
            $evidence,
178
            1,
179
            'Too many <saml:Evidence> in <saml:AuthzDecisionQuery>',
180
            TooManyElementsException::class,
181
        );
182
183
        $signature = Signature::getChildrenOfClass($xml);
184
        Assert::maxCount($signature, 1, 'Only one ds:Signature element is allowed.', TooManyElementsException::class);
185
186
        $request = new static(
187
            array_pop($subject),
188
            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 $decision 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

188
            /** @scrutinizer ignore-type */ self::getAttribute($xml, 'Resource'),
Loading history...
189
            $action,
190
            array_pop($evidence),
191
            array_pop($issuer),
0 ignored issues
show
Unused Code introduced by
The call to SimpleSAML\SAML2\XML\sam...ionQuery::__construct() has too many arguments starting with array_pop($issuer). ( Ignorable by Annotation )

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

191
        $request = /** @scrutinizer ignore-call */ new static(

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

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