Response::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 25
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

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