Passed
Pull Request — master (#280)
by Tim
02:22
created

LogoutRequest::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 18
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 10
dl 0
loc 18
rs 10
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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\IdentifierTrait;
13
use SimpleSAML\SAML2\XML\saml\IdentifierInterface;
14
use SimpleSAML\SAML2\XML\saml\BaseID;
15
use SimpleSAML\SAML2\XML\saml\EncryptedID;
16
use SimpleSAML\SAML2\XML\saml\NameID;
17
use SimpleSAML\SAML2\XML\saml\Issuer;
18
use SimpleSAML\XML\Exception\InvalidDOMElementException;
19
use SimpleSAML\XML\Exception\MissingElementException;
20
use SimpleSAML\XML\Exception\TooManyElementsException;
21
use SimpleSAML\XML\Utils as XMLUtils;
22
use SimpleSAML\XMLSecurity\Key\PrivateKey;
23
use SimpleSAML\XMLSecurity\XML\ds\Signature;
24
25
use function array_pop;
26
use function gmdate;
27
28
/**
29
 * Class for SAML 2 logout request messages.
30
 *
31
 * @package simplesamlphp/saml2
32
 */
33
class LogoutRequest extends AbstractRequest
34
{
35
    use IdentifierTrait;
36
37
    /**
38
     * The expiration time of this request.
39
     *
40
     * @var int|null
41
     */
42
    protected ?int $notOnOrAfter = null;
43
44
    /**
45
     * The SessionIndexes of the sessions that should be terminated.
46
     *
47
     * @var \SimpleSAML\SAML2\XML\samlp\SessionIndex[]
48
     */
49
    protected array $sessionIndexes = [];
50
51
    /**
52
     * The optional reason for the logout, typically a URN
53
     * See \SimpleSAML\SAML2\Constants::LOGOUT_REASON_*
54
     * From the standard section 3.7.3: "other values MAY be agreed on between participants"
55
     *
56
     * @var string|null
57
     */
58
    protected ?string $reason = null;
59
60
61
    /**
62
     * Constructor for SAML 2 AttributeQuery.
63
     *
64
     * @param \SimpleSAML\SAML2\XML\saml\IdentifierInterface $identifier
65
     * @param int|null $notOnOrAfter
66
     * @param string|null $reason
67
     * @param \SimpleSAML\SAML2\XML\samlp\SessionIndex[] $sessionIndexes
68
     * @param \SimpleSAML\SAML2\XML\saml\Issuer|null $issuer
69
     * @param string|null $id
70
     * @param int|null $issueInstant
71
     * @param string|null $destination
72
     * @param string|null $consent
73
     * @param \SimpleSAML\SAML2\XML\samlp\Extensions $extensions
74
     * @throws \Exception
75
     */
76
    public function __construct(
77
        IdentifierInterface $identifier,
78
        ?int $notOnOrAfter = null,
79
        ?string $reason = null,
80
        array $sessionIndexes = [],
81
        ?Issuer $issuer = null,
82
        ?string $id = null,
83
        ?int $issueInstant = null,
84
        ?string $destination = null,
85
        ?string $consent = null,
86
        ?Extensions $extensions = null
87
    ) {
88
        parent::__construct($issuer, $id, $issueInstant, $destination, $consent, $extensions);
89
90
        $this->setIdentifier($identifier);
91
        $this->setNotOnOrAfter($notOnOrAfter);
92
        $this->setReason($reason);
93
        $this->setSessionIndexes($sessionIndexes);
94
    }
95
96
97
    /**
98
     * Retrieve the expiration time of this request.
99
     *
100
     * @return int|null The expiration time of this request.
101
     */
102
    public function getNotOnOrAfter(): ?int
103
    {
104
        return $this->notOnOrAfter;
105
    }
106
107
108
    /**
109
     * Set the expiration time of this request.
110
     *
111
     * @param int|null $notOnOrAfter The expiration time of this request.
112
     */
113
    public function setNotOnOrAfter(?int $notOnOrAfter = null): void
114
    {
115
        $this->notOnOrAfter = $notOnOrAfter;
116
    }
117
118
    /**
119
     * Retrieve the reason for this request.
120
     *
121
     * @return string|null The reason for this request.
122
     */
123
    public function getReason(): ?string
124
    {
125
        return $this->reason;
126
    }
127
128
129
    /**
130
     * Set the reason for this request.
131
     *
132
     * @param string|null $reason The optional reason for this request in URN format
133
     */
134
    public function setReason(?string $reason = null): void
135
    {
136
        $this->reason = $reason;
137
    }
138
139
140
    /**
141
     * Retrieve the SessionIndexes of the sessions that should be terminated.
142
     *
143
     * @return \SimpleSAML\SAML2\XML\samlp\SessionIndex[] The SessionIndexes, or an empty array if all sessions should be terminated.
144
     */
145
    public function getSessionIndexes(): array
146
    {
147
        return $this->sessionIndexes;
148
    }
149
150
151
    /**
152
     * Set the SessionIndexes of the sessions that should be terminated.
153
     *
154
     * @param \SimpleSAML\SAML2\XML\samlp\SessionIndex[] $sessionIndexes The SessionIndexes, or an empty array if all sessions should be terminated.
155
     */
156
    public function setSessionIndexes(array $sessionIndexes): void
157
    {
158
        Assert::allIsInstanceOf($sessionIndexes, SessionIndex::class);
159
        $this->sessionIndexes = $sessionIndexes;
160
    }
161
162
163
    /**
164
     * Convert XML into a LogoutRequest
165
     *
166
     * @param \DOMElement $xml The XML element we should load
167
     * @return \SimpleSAML\SAML2\XML\samlp\LogoutRequest
168
     *
169
     * @throws \SimpleSAML\XML\Exception\InvalidDOMElementException if the qualified name of the supplied element is wrong
170
     * @throws \SimpleSAML\XML\Exception\MissingAttributeException if the supplied element is missing one of the mandatory attributes
171
     * @throws \SimpleSAML\XML\Exception\MissingElementException if one of the mandatory child-elements is missing
172
     * @throws \SimpleSAML\XML\Exception\TooManyElementsException if too many child-elements of a type are specified
173
     */
174
    public static function fromXML(DOMElement $xml): object
175
    {
176
        Assert::same($xml->localName, 'LogoutRequest', InvalidDOMElementException::class);
177
        Assert::same($xml->namespaceURI, LogoutRequest::NS, InvalidDOMElementException::class);
178
179
        $version = self::getAttribute($xml, 'Version');
180
        Assert::true(version_compare('2.0', $version, '<='), RequestVersionTooLowException::class);
181
        Assert::true(version_compare('2.0', $version, '>='), RequestVersionTooHighException::class);
182
183
        $issueInstant = self::getAttribute($xml, 'IssueInstant');
184
        Assert::validDateTimeZulu($issueInstant, ProtocolViolationException::class);
185
        $issueInstant = XMLUtils::xsDateTimeToTimestamp($issueInstant);
186
187
        $notOnOrAfter = self::getAttribute($xml, 'NotOnOrAfter', null);
188
        if ($notOnOrAfter !== null) {
189
            Assert::validDateTimeZulu($notOnOrAfter, ProtocolViolationException::class);
190
            $notOnOrAfter = XMLUtils::xsDateTimeToTimestamp($notOnOrAfter);
191
        }
192
193
        $issuer = Issuer::getChildrenOfClass($xml);
194
        Assert::countBetween($issuer, 0, 1);
195
196
        $extensions = Extensions::getChildrenOfClass($xml);
197
        Assert::maxCount($extensions, 1, 'Only one saml:Extensions element is allowed.', TooManyElementsException::class);
198
199
        $identifier = self::getIdentifierFromXML($xml);
200
        Assert::notNull(
201
            $identifier,
202
            'Missing <saml:NameID>, <saml:BaseID> or <saml:EncryptedID> in <samlp:LogoutRequest>.',
203
            MissingElementException::class
204
        );
205
        Assert::isInstanceOfAny($identifier, [BaseID::class, NameID::class, EncryptedID::class]);
206
207
        $signature = Signature::getChildrenOfClass($xml);
208
        Assert::maxCount($signature, 1, 'Only one ds:Signature element is allowed.');
209
210
        $sessionIndex = SessionIndex::getChildrenOfClass($xml);
211
212
        $request = new self(
213
            $identifier,
214
            $notOnOrAfter,
215
            self::getAttribute($xml, 'Reason', null),
216
            $sessionIndex,
217
            array_pop($issuer),
218
            self::getAttribute($xml, 'ID'),
219
            $issueInstant,
220
            self::getAttribute($xml, 'Destination', null),
221
            self::getAttribute($xml, 'Consent', null),
222
            array_pop($extensions)
223
        );
224
225
        if (!empty($signature)) {
226
            $request->setSignature($signature[0]);
227
            $request->messageContainedSignatureUponConstruction = true;
228
        }
229
230
        $request->setXML($xml);
231
        return $request;
232
    }
233
234
235
    /**
236
     * Convert this message to an unsigned XML document.
237
     * This method does not sign the resulting XML document.
238
     *
239
     * @param \DOMElement|null $parent
240
     * @return \DOMElement The root element of the DOM tree
241
     */
242
    protected function toUnsignedXML(?DOMElement $parent = null): DOMElement
243
    {
244
        /** @psalm-var \DOMDocument $e->ownerDocument */
245
        $e = parent::toUnsignedXML($parent);
246
247
        if ($this->notOnOrAfter !== null) {
248
            $e->setAttribute('NotOnOrAfter', gmdate('Y-m-d\TH:i:s\Z', $this->notOnOrAfter));
249
        }
250
251
        if ($this->reason !== null) {
252
            $e->setAttribute('Reason', $this->reason);
253
        }
254
255
        /** @var \SimpleSAML\SAML2\XML\saml\IdentifierInterface $this->identifier */
256
        $this->identifier->toXML($e);
0 ignored issues
show
Bug introduced by
The method toXML() does not exist on null. ( Ignorable by Annotation )

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

256
        $this->identifier->/** @scrutinizer ignore-call */ 
257
                           toXML($e);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
257
258
        foreach ($this->sessionIndexes as $sessionIndex) {
259
            $sessionIndex->toXML($e);
260
        }
261
262
        return $e;
263
    }
264
}
265