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

Response::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 23
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 10
nc 1
nop 9
dl 0
loc 23
rs 9.9332
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\Constants;
10
use SimpleSAML\SAML2\Exception\ProtocolViolationException;
11
use SimpleSAML\SAML2\Utils\XPath;
12
use SimpleSAML\SAML2\XML\saml\Assertion;
13
use SimpleSAML\SAML2\XML\saml\EncryptedAssertion;
14
use SimpleSAML\SAML2\XML\saml\Issuer;
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\Utils\Security;
20
use SimpleSAML\XMLSecurity\XML\ds\Signature;
21
22
use function array_pop;
23
24
/**
25
 * Class for SAML 2 Response messages.
26
 *
27
 * @package simplesamlphp/saml2
28
 */
29
class Response extends AbstractStatusResponse
30
{
31
    /**
32
     * The assertions in this response.
33
     *
34
     * @var (\SimpleSAML\SAML2\XML\saml\Assertion|\SimpleSAML\SAML2\XML\saml\EncryptedAssertion)[]
35
     */
36
    protected array $assertions = [];
37
38
39
    /**
40
     * Constructor for SAML 2 response messages.
41
     *
42
     * @param \SimpleSAML\SAML2\XML\samlp\Status $status
43
     * @param \SimpleSAML\SAML2\XML\saml\Issuer $issuer
44
     * @param string $id
45
     * @param int $issueInstant
46
     * @param string $inResponseTo
47
     * @param string|null $destination
48
     * @param string|null $consent
49
     * @param \SimpleSAML\SAML2\XML\samlp\Extensions $extensions
50
     * @param (\SimpleSAML\SAML2\XML\saml\Assertion|\SimpleSAML\SAML2\XML\saml\EncryptedAssertion)[] $assertions
51
     */
52
    public function __construct(
53
        Status $status,
54
        ?Issuer $issuer = null,
55
        ?string $id = null,
56
        ?int $issueInstant = null,
57
        ?string $inResponseTo = null,
58
        ?string $destination = null,
59
        ?string $consent = null,
60
        ?Extensions $extensions = null,
61
        array $assertions = []
62
    ) {
63
        parent::__construct(
64
            $status,
65
            $issuer,
66
            $id,
67
            $issueInstant,
68
            $inResponseTo,
69
            $destination,
70
            $consent,
71
            $extensions
72
        );
73
74
        $this->setAssertions($assertions);
75
    }
76
77
78
    /**
79
     * Retrieve the assertions in this response.
80
     *
81
     * @return \SimpleSAML\SAML2\XML\saml\Assertion[]|\SimpleSAML\SAML2\XML\saml\EncryptedAssertion[]
82
     */
83
    public function getAssertions(): array
84
    {
85
        return $this->assertions;
86
    }
87
88
89
    /**
90
     * Set the assertions that should be included in this response.
91
     *
92
     * @param (\SimpleSAML\SAML2\XML\saml\Assertion|\SimpleSAML\SAML2\XML\saml\EncryptedAssertion)[] $assertions The assertions.
93
     */
94
    protected function setAssertions(array $assertions): void
95
    {
96
        Assert::allIsInstanceOfAny($assertions, [Assertion::class, EncryptedAssertion::class]);
97
98
        $this->assertions = $assertions;
99
    }
100
101
102
    /**
103
     * Convert XML into a Response element.
104
     *
105
     * @param \DOMElement $xml The input message.
106
     * @return self
107
     *
108
     * @throws \SimpleSAML\XML\Exception\InvalidDOMElementException if the qualified name of the supplied element is wrong
109
     * @throws \SimpleSAML\XML\Exception\MissingAttributeException if the supplied element is missing one of the mandatory attributes
110
     * @throws \SimpleSAML\XML\Exception\MissingElementException if one of the mandatory child-elements is missing
111
     */
112
    public static function fromXML(DOMElement $xml): object
113
    {
114
        Assert::same($xml->localName, 'Response', InvalidDOMElementException::class);
115
        Assert::same($xml->namespaceURI, Response::NS, InvalidDOMElementException::class);
116
        Assert::same('2.0', self::getAttribute($xml, 'Version'));
117
118
        $signature = Signature::getChildrenOfClass($xml);
119
        Assert::maxCount($signature, 1, 'Only one ds:Signature element is allowed.', TooManyElementsException::class);
120
121
        $id = self::getAttribute($xml, 'ID');
122
        $inResponseTo = self::getAttribute($xml, 'InResponseTo', null);
123
        $destination = self::getAttribute($xml, 'Destination', null);
124
        $consent = self::getAttribute($xml, 'Consent', null);
125
126
        /** @psalm-suppress PossiblyNullArgument */
127
        $issueInstant = self::getAttribute($xml, 'IssueInstant');
128
        Assert::validDateTimeZulu($issueInstant, ProtocolViolationException::class);
129
        $issueInstant = XMLUtils::xsDateTimeToTimestamp($issueInstant);
130
131
        $issuer = Issuer::getChildrenOfClass($xml);
132
        Assert::countBetween($issuer, 0, 1);
133
134
        $status = Status::getChildrenOfClass($xml);
135
        Assert::minCount($status, 1, MissingElementException::class);
136
        Assert::maxCount($status, 1, TooManyElementsException::class);
137
138
        $extensions = Extensions::getChildrenOfClass($xml);
139
        Assert::maxCount($extensions, 1, 'Only one saml:Extensions element is allowed.', TooManyElementsException::class);
140
141
        $assertions = [];
142
        foreach ($xml->childNodes as $node) {
143
            if ($node->namespaceURI !== Constants::NS_SAML) {
144
                continue;
145
            } elseif (!($node instanceof DOMElement)) {
146
                continue;
147
            }
148
149
            if ($node->localName === 'Assertion') {
150
                $assertions[] = Assertion::fromXML($node);
151
            } elseif ($node->localName === 'EncryptedAssertion') {
152
                $assertions[] = EncryptedAssertion::fromXML($node);
153
            }
154
        }
155
156
        $response = new self(
157
            array_pop($status),
158
            empty($issuer) ? null : array_pop($issuer),
159
            $id,
160
            $issueInstant,
161
            $inResponseTo,
162
            $destination,
163
            $consent,
164
            empty($extensions) ? null : array_pop($extensions),
165
            $assertions
166
        );
167
168
        if (!empty($signature)) {
169
            $response->setSignature($signature[0]);
170
            $response->messageContainedSignatureUponConstruction = true;
171
        }
172
173
        $response->setXML($xml);
174
        return $response;
175
    }
176
177
178
    /**
179
     * Convert the response message to an XML element.
180
     *
181
     * @return \DOMElement This response.
182
     */
183
    protected function toUnsignedXML(?DOMElement $parent = null): DOMElement
184
    {
185
        $e = parent::toUnsignedXML($parent);
186
187
        foreach ($this->assertions as $assertion) {
188
            $assertion->toXML($e);
189
        }
190
191
        return $e;
192
    }
193
}
194