Passed
Pull Request — master (#327)
by Tim
02:34
created

AuthnQuery   A

Complexity

Total Complexity 7

Size/Duplication

Total Lines 157
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 53
c 1
b 0
f 0
dl 0
loc 157
rs 10
wmc 7

5 Methods

Rating   Name   Duplication   Size   Complexity  
A toUnsignedXML() 0 12 2
A fromXML() 0 67 2
A __construct() 0 13 1
A getSessionIndex() 0 3 1
A getRequestedAuthnContext() 0 3 1
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\Exception\Protocol\RequestVersionTooHighException;
10
use SimpleSAML\SAML2\Exception\Protocol\RequestVersionTooLowException;
11
use SimpleSAML\SAML2\Exception\ProtocolViolationException;
12
use SimpleSAML\SAML2\XML\saml\Issuer;
13
use SimpleSAML\SAML2\XML\saml\Subject;
14
use SimpleSAML\SAML2\XML\samlp\RequestedAuthnContext;
15
use SimpleSAML\XML\Exception\InvalidDOMElementException;
16
use SimpleSAML\XML\Exception\MissingElementException;
17
use SimpleSAML\XML\Exception\TooManyElementsException;
18
use SimpleSAML\XML\Utils as XMLUtils;
19
use SimpleSAML\XMLSecurity\XML\ds\Signature;
20
21
use function array_pop;
22
use function in_array;
23
24
/**
25
 * Class for SAML 2 AuthnQuery query messages.
26
 *
27
 * @package simplesamlphp/saml2
28
 */
29
final class AuthnQuery extends AbstractSubjectQuery
30
{
31
    /**
32
     * Constructor for SAML 2 AuthnQuery.
33
     *
34
     * @param \SimpleSAML\SAML2\XML\saml\Subject $subject
35
     * @param \SimpleSAML\SAML2\XML\samlp\RequestedAuthnContext|null $requestedAuthnContext
36
     * @param string|null $sessionIndex
37
     * @param \SimpleSAML\SAML2\XML\saml\Issuer $issuer
38
     * @param string|null $id
39
     * @param string $version
40
     * @param int $issueInstant
41
     * @param string|null $destination
42
     * @param string|null $consent
43
     * @param \SimpleSAML\SAML2\XML\samlp\Extensions $extensions
44
     */
45
    public function __construct(
46
        Subject $subject,
47
        protected ?RequestedAuthnContext $requestedAuthnContext = null,
48
        protected ?string $sessionIndex = null,
49
        ?Issuer $issuer = null,
50
        ?string $id = null,
51
        string $version = '2.0',
52
        ?int $issueInstant = null,
53
        ?string $destination = null,
54
        ?string $consent = null,
55
        ?Extensions $extensions = null,
56
    ) {
57
        parent::__construct($subject, $issuer, $id, $version, $issueInstant, $destination, $consent, $extensions);
58
    }
59
60
61
    /**
62
     * Retrieve RequestedAuthnContext.
63
     *
64
     * @return \SimpleSAML\SAML2\XML\samlp\RequestedAuthnContext|null
65
     */
66
    public function getRequestedAuthnContext(): ?RequestedAuthnContext
67
    {
68
        return $this->requestedAuthnContext;
69
    }
70
71
72
    /**
73
     * Retrieve session index.
74
     *
75
     * @return string|null
76
     */
77
    public function getSessionIndex(): ?string
78
    {
79
        return $this->sessionIndex;
80
    }
81
82
83
    /**
84
     * Create a class from XML
85
     *
86
     * @param \DOMElement $xml
87
     * @return static
88
     *
89
     * @throws \SimpleSAML\XML\Exception\InvalidDOMElementException
90
     *   if the qualified name of the supplied element is wrong
91
     * @throws \SimpleSAML\XML\Exception\MissingAttributeException
92
     *   if the supplied element is missing one of the mandatory attributes
93
     * @throws \SimpleSAML\XML\Exception\MissingElementException
94
     *   if one of the mandatory child-elements is missing
95
     * @throws \SimpleSAML\XML\Exception\TooManyElementsException
96
     *   if too many child-elements of a type are specified
97
     */
98
    public static function fromXML(DOMElement $xml): static
99
    {
100
        Assert::same($xml->localName, 'AuthnQuery', InvalidDOMElementException::class);
101
        Assert::same($xml->namespaceURI, AuthnQuery::NS, InvalidDOMElementException::class);
102
103
        /** @psalm-var string $version */
104
        $version = self::getAttribute($xml, 'Version');
105
        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

105
        Assert::true(version_compare('2.0', /** @scrutinizer ignore-type */ $version, '<='), RequestVersionTooLowException::class);
Loading history...
106
        Assert::true(version_compare('2.0', $version, '>='), RequestVersionTooHighException::class);
107
108
        $id = self::getAttribute($xml, 'ID');
109
        $destination = self::getAttribute($xml, 'Destination', null);
110
        $consent = self::getAttribute($xml, 'Consent', null);
111
        $sessionIndex = self::getAttribute($xml, 'SessionIndex', null);
112
113
        /** @psalm-var string $issueInstant */
114
        $issueInstant = self::getAttribute($xml, 'IssueInstant');
115
        // Strip sub-seconds - See paragraph 1.3.3 of SAML core specifications
116
        $issueInstant = preg_replace('/([.][0-9]+Z)$/', 'Z', $issueInstant, 1);
117
118
        Assert::validDateTimeZulu($issueInstant, ProtocolViolationException::class);
119
        $issueInstant = XMLUtils::xsDateTimeToTimestamp($issueInstant);
120
121
        $requestedAuthnContext = RequestedAuthnContext::getChildrenOfClass($xml);
122
123
        $issuer = Issuer::getChildrenOfClass($xml);
124
        Assert::countBetween($issuer, 0, 1);
125
126
        $extensions = Extensions::getChildrenOfClass($xml);
127
        Assert::maxCount(
128
            $extensions,
129
            1,
130
            'Only one saml:Extensions element is allowed.',
131
            TooManyElementsException::class,
132
        );
133
134
        $subject = Subject::getChildrenOfClass($xml);
135
        Assert::notEmpty($subject, 'Missing subject in subject query.', MissingElementException::class);
136
        Assert::maxCount(
137
            $subject,
138
            1,
139
            'More than one <saml:Subject> in AttributeQuery',
140
            TooManyElementsException::class,
141
        );
142
143
        $signature = Signature::getChildrenOfClass($xml);
144
        Assert::maxCount($signature, 1, 'Only one ds:Signature element is allowed.', TooManyElementsException::class);
145
146
        $request = new static(
147
            array_pop($subject),
148
            array_pop($requestedAuthnContext),
149
            $sessionIndex,
150
            array_pop($issuer),
151
            $id,
152
            $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...thnQuery::__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

152
            /** @scrutinizer ignore-type */ $version,
Loading history...
153
            $issueInstant,
154
            $destination,
155
            $consent,
156
            array_pop($extensions),
157
        );
158
159
        if (!empty($signature)) {
160
            $request->setSignature($signature[0]);
161
            $request->setXML($xml);
162
        }
163
164
        return $request;
165
    }
166
167
168
    /**
169
     * Convert this message to an unsigned XML document.
170
     * This method does not sign the resulting XML document.
171
     *
172
     * @return \DOMElement The root element of the DOM tree
173
     */
174
    protected function toUnsignedXML(?DOMElement $parent = null): DOMElement
175
    {
176
        $e = parent::toUnsignedXML($parent);
177
178
        $sessionIndex = $this->getSessionIndex();
179
        if ($sessionIndex !== null) {
180
            $e->setAttribute('SessionIndex', $sessionIndex);
181
        }
182
183
        $this->getRequestedAuthnContext()?->toXML($e);
184
185
        return $e;
186
    }
187
}
188