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

250
        $this->identifier->/** @scrutinizer ignore-call */ 
251
                           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...
251
252
        foreach ($this->sessionIndexes as $sessionIndex) {
253
            $sessionIndex->toXML($e);
254
        }
255
256
        return $e;
257
    }
258
}
259