Passed
Pull Request — master (#226)
by Jaime Pérez
03:17
created

Response   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 153
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 59
dl 0
loc 153
rs 10
c 0
b 0
f 0
wmc 14

5 Methods

Rating   Name   Duplication   Size   Complexity  
A toXML() 0 9 2
A getAssertions() 0 3 1
A setAssertions() 0 4 1
B fromXML() 0 57 9
A __construct() 0 23 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SAML2\XML\samlp;
6
7
use DOMElement;
8
use SAML2\Constants;
9
use SAML2\Utils;
10
use SAML2\XML\ds\Signature;
11
use SAML2\XML\saml\Assertion;
12
use SAML2\XML\saml\EncryptedAssertion;
13
use SAML2\XML\saml\Issuer;
14
use Webmozart\Assert\Assert;
15
16
/**
17
 * Class for SAML 2 Response messages.
18
 *
19
 * @package SimpleSAMLphp
20
 */
21
class Response extends AbstractStatusResponse
22
{
23
    /**
24
     * The assertions in this response.
25
     *
26
     * @var (\SAML2\XML\saml\Assertion|\SAML2\XML\saml\EncryptedAssertion)[]
27
     */
28
    protected $assertions = [];
29
30
31
    /**
32
     * Constructor for SAML 2 response messages.
33
     *
34
     * @param \SAML2\XML\samlp\Status $status
35
     * @param \SAML2\XML\saml\Issuer $issuer
36
     * @param string $id
37
     * @param int $issueInstant
38
     * @param string $inResponseTo
39
     * @param string|null $destination
40
     * @param string|null $consent
41
     * @param \SAML2\XML\samlp\Extensions $extensions
42
     * @param (\SAML2\XML\saml\Assertion|\SAML2\XML\saml\EncryptedAssertion) $assertions
43
     */
44
    public function __construct(
45
        Status $status,
46
        ?Issuer $issuer = null,
47
        ?string $id = null,
48
        ?int $issueInstant = null,
49
        ?string $inResponseTo = null,
50
        ?string $destination = null,
51
        ?string $consent = null,
52
        ?Extensions $extensions = null,
53
        array $assertions = []
54
    ) {
55
        parent::__construct(
56
            $status,
57
            $issuer,
58
            $id,
59
            $issueInstant,
60
            $inResponseTo,
61
            $destination,
62
            $consent,
63
            $extensions
64
        );
65
66
        $this->setAssertions($assertions);
67
    }
68
69
70
    /**
71
     * Retrieve the assertions in this response.
72
     *
73
     * @return \SAML2\XML\saml\Assertion[]|\SAML2\XML\saml\EncryptedAssertion[]
74
     */
75
    public function getAssertions(): array
76
    {
77
        return $this->assertions;
78
    }
79
80
81
    /**
82
     * Set the assertions that should be included in this response.
83
     *
84
     * @param \SAML2\XML\saml\Assertion[]|\SAML2\XML\saml\EncryptedAssertion[] $assertions The assertions.
85
     * @return void
86
     */
87
    protected function setAssertions(array $assertions): void
88
    {
89
        Assert::allIsInstanceOfAny($assertions, [Assertion::class, EncryptedAssertion::class]);
90
        $this->assertions = $assertions;
91
    }
92
93
94
    /**
95
     * Convert XML into a Response element.
96
     *
97
     * @param \DOMElement $xml The input message.
98
     * @return self
99
     */
100
    public static function fromXML(DOMElement $xml): object
101
    {
102
        Assert::same($xml->localName, 'Response');
103
        Assert::same($xml->namespaceURI, Response::NS);
104
        Assert::same('2.0', self::getAttribute($xml, 'Version'));
105
106
        $id = self::getAttribute($xml, 'ID');
107
        $issueInstant = Utils::xsDateTimeToTimestamp(self::getAttribute($xml, 'IssueInstant'));
108
        $inResponseTo = self::getAttribute($xml, 'InResponseTo', null);
109
        $destination = self::getAttribute($xml, 'Destination', null);
110
        $consent = self::getAttribute($xml, 'Consent', null);
111
112
        $issuer = Issuer::getChildrenOfClass($xml);
113
        Assert::countBetween($issuer, 0, 1);
114
115
        $status = Status::getChildrenOfClass($xml);
116
        Assert::count($status, 1);
117
118
        $extensions = Extensions::getChildrenOfClass($xml);
119
        Assert::maxCount($extensions, 1, 'Only one saml:Extensions element is allowed.');
120
121
        $assertions = [];
122
        foreach ($xml->childNodes as $node) {
123
            if ($node->namespaceURI !== Constants::NS_SAML) {
124
                continue;
125
            } elseif (!($node instanceof DOMElement)) {
126
                continue;
127
            }
128
129
            if ($node->localName === 'Assertion') {
130
                $assertions[] = new Assertion($node);
131
            } elseif ($node->localName === 'EncryptedAssertion') {
132
                $assertions[] = EncryptedAssertion::fromXML($node);
133
            }
134
        }
135
136
        $signature = Signature::getChildrenOfClass($xml);
137
        Assert::maxCount($signature, 1, 'Only one ds:Signature element is allowed.');
138
139
        $response = new self(
140
            array_pop($status),
141
            empty($issuer) ? null : array_pop($issuer),
142
            $id,
143
            $issueInstant,
144
            $inResponseTo,
145
            $destination,
146
            $consent,
147
            empty($extensions) ? null : array_pop($extensions),
148
            $assertions
149
        );
150
151
        if (!empty($signature)) {
152
            $response->setSignature($signature[0]);
153
            $response->messageContainedSignatureUponConstruction = true;
154
        }
155
156
        return $response;
157
    }
158
159
160
    /**
161
     * Convert the response message to an XML element.
162
     *
163
     * @return \DOMElement This response.
164
     */
165
    public function toXML(?DOMElement $parent = null): DOMElement
166
    {
167
        $e = parent::toXML($parent);
168
169
        foreach ($this->assertions as $assertion) {
170
            $assertion->toXML($e);
171
        }
172
173
        return $this->signElement($e);
174
    }
175
}
176