Response::fromXML()   A
last analyzed

Complexity

Conditions 4
Paths 2

Size

Total Lines 61
Code Lines 42

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 42
nc 2
nop 1
dl 0
loc 61
rs 9.248
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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