Passed
Pull Request — master (#374)
by Tim
02:47
created

AbstractMessage::getVersion()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SimpleSAML\SAML2\XML\samlp;
6
7
use DOMElement;
8
use SimpleSAML\SAML2\Constants as C;
9
use SimpleSAML\SAML2\Type\{SAMLAnyURIValue, SAMLDateTimeValue};
10
use SimpleSAML\SAML2\Utils\XPath;
11
use SimpleSAML\SAML2\XML\ExtendableElementTrait;
12
use SimpleSAML\SAML2\XML\saml\Issuer;
13
use SimpleSAML\SAML2\XML\{SignableElementTrait, SignedElementTrait};
14
use SimpleSAML\XML\Type\IDValue;
15
use SimpleSAML\XMLSecurity\XML\{SignableElementInterface, SignedElementInterface};
16
17
use function array_pop;
18
19
/**
20
 * Base class for all SAML 2 messages.
21
 *
22
 * Implements what is common between the samlp:RequestAbstractType and
23
 * samlp:StatusResponseType element types.
24
 *
25
 * @package simplesamlphp/saml2
26
 */
27
abstract class AbstractMessage extends AbstractSamlpElement implements SignableElementInterface, SignedElementInterface
28
{
29
    use ExtendableElementTrait;
30
    use SignableElementTrait;
0 ignored issues
show
introduced by
The trait SimpleSAML\SAML2\XML\SignableElementTrait requires some properties which are not provided by SimpleSAML\SAML2\XML\samlp\AbstractMessage: $ownerDocument, $documentElement
Loading history...
31
    use SignedElementTrait {
0 ignored issues
show
introduced by
The trait SimpleSAML\SAML2\XML\SignedElementTrait requires some properties which are not provided by SimpleSAML\SAML2\XML\samlp\AbstractMessage: $ownerDocument, $documentElement
Loading history...
32
        SignedElementTrait::getBlacklistedAlgorithms insteadof SignableElementTrait;
33
    }
34
35
36
    /** @var bool */
37
    protected bool $messageContainedSignatureUponConstruction = false;
38
39
    /**
40
     * The original signed XML
41
     *
42
     * @var \DOMElement
43
     * @psalm-suppress PropertyNotSetInConstructor
44
     */
45
    protected DOMElement $xml;
46
47
48
    /**
49
     * Initialize a message.
50
     *
51
     * @param \SimpleSAML\SAML2\XML\saml\Issuer|null $issuer
52
     * @param \SimpleSAML\XML\Type\IDValue $id
53
     * @param \SimpleSAML\SAML2\Type\SAMLDateTimeValue|null $issueInstant
54
     * @param \SipmleSAML\SAML2\Type\SAMLAnyURIValue|null $destination
0 ignored issues
show
Bug introduced by
The type SipmleSAML\SAML2\Type\SAMLAnyURIValue was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
55
     * @param \SimpleSAML\SAML2\Type\SAMLAnyURIValue|null $consent
56
     * @param \SimpleSAML\SAML2\XML\samlp\Extensions $extensions
57
     *
58
     * @throws \Exception
59
     */
60
    protected function __construct(
61
        protected IDValue $id,
62
        protected ?Issuer $issuer = null,
63
        protected ?SAMLDateTimeValue $issueInstant = null,
64
        protected ?SAMLAnyURIValue $destination = null,
65
        protected ?SAMLAnyURIValue $consent = null,
66
        ?Extensions $extensions = null,
67
    ) {
68
        $this->setExtensions($extensions);
69
    }
70
71
72
    /**
73
     * Retrieve the identifier of this message.
74
     *
75
     * @return \SimpleSAML\XML\Type\IDValue The identifier of this message
76
     */
77
    public function getId(): IDValue
78
    {
79
        return $this->id;
80
    }
81
82
83
    /**
84
     * Retrieve the issue timestamp of this message.
85
     *
86
     * @return \SimpleSAML\SAML2\Type\SAMLDateTimeValue The issue timestamp of this message, as an UNIX timestamp
87
     */
88
    public function getIssueInstant(): SAMLDateTimeValue
89
    {
90
        return $this->issueInstant;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->issueInstant could return the type null which is incompatible with the type-hinted return SimpleSAML\SAML2\Type\SAMLDateTimeValue. Consider adding an additional type-check to rule them out.
Loading history...
91
    }
92
93
94
    /**
95
     * Retrieve the destination of this message.
96
     *
97
     * @return \SimpleSAML\SAML\Type\SAMLAnyURIValue|null The destination of this message,
0 ignored issues
show
Bug introduced by
The type SimpleSAML\SAML\Type\SAMLAnyURIValue was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
98
     *   or NULL if no destination is given
99
     */
100
    public function getDestination(): ?SAMLAnyURIValue
101
    {
102
        return $this->destination;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->destination also could return the type SimpleSAML\SAML2\Type\SAMLAnyURIValue which is incompatible with the documented return type SimpleSAML\SAML\Type\SAMLAnyURIValue|null.
Loading history...
103
    }
104
105
106
    /**
107
     * Get the given consent for this message.
108
     * Most likely (though not required) a value of urn:oasis:names:tc:SAML:2.0:consent.
109
     *
110
     * @see \SimpleSAML\SAML2\Constants
111
     * @return \SimpleSAML\SAML2\Type\SAMLAnyURIValue|null Consent
112
     */
113
    public function getConsent(): ?SAMLAnyURIValue
114
    {
115
        return $this->consent;
116
    }
117
118
119
    /**
120
     * Retrieve the issuer if this message.
121
     *
122
     * @return \SimpleSAML\SAML2\XML\saml\Issuer|null The issuer of this message, or NULL if no issuer is given
123
     */
124
    public function getIssuer(): ?Issuer
125
    {
126
        return $this->issuer;
127
    }
128
129
130
    /**
131
     * Query whether or not the message contained a signature at the root level when the object was constructed.
132
     *
133
     * @return bool
134
     */
135
    public function isMessageConstructedWithSignature(): bool
136
    {
137
        return $this->messageContainedSignatureUponConstruction;
138
    }
139
140
141
    /**
142
     * Get the XML element.
143
     *
144
     * @return \DOMElement
145
     */
146
    public function getXML(): DOMElement
147
    {
148
        return $this->xml;
149
    }
150
151
152
    /**
153
     * Set the XML element.
154
     *
155
     * @param \DOMElement $xml
156
     */
157
    protected function setXML(DOMElement $xml): void
158
    {
159
        $this->xml = $xml;
160
    }
161
162
163
    /**
164
     * @return \DOMElement
165
     */
166
    protected function getOriginalXML(): DOMElement
167
    {
168
        return $this->xml ?? $this->toUnsignedXML();
169
    }
170
171
172
    /**
173
     * Convert this message to an unsigned XML document.
174
     * This method does not sign the resulting XML document.
175
     *
176
     * @return \DOMElement The root element of the DOM tree
177
     */
178
    protected function toUnsignedXML(?DOMElement $parent = null): DOMElement
179
    {
180
        $root = $this->instantiateParentElement($parent);
181
182
        /* Ugly hack to add another namespace declaration to the root element. */
183
//        $root->setAttributeNS(C::NS_SAML, 'saml:tmp', 'tmp');
184
//        $root->removeAttributeNS(C::NS_SAML, 'tmp');
185
186
        $root->setAttribute('Version', '2.0');
187
        $root->setAttribute('ID', $this->getId()->getValue());
188
        $root->setAttribute('IssueInstant', $this->getIssueInstant()->getValue());
189
190
        if ($this->getDestination() !== null) {
191
            $root->setAttribute('Destination', $this->getDestination()->getValue());
192
        }
193
194
        if ($this->getConsent() !== null && $this->getConsent()->getValue() !== C::CONSENT_UNSPECIFIED) {
195
            $root->setAttribute('Consent', $this->getConsent()->getValue());
196
        }
197
198
        $this->getIssuer()?->toXML($root);
199
200
        $extensions = $this->getExtensions();
201
        if ($extensions !== null && !$extensions->isEmptyElement()) {
202
            $extensions->toXML($root);
203
        }
204
205
        return $root;
206
    }
207
208
209
    /**
210
     * Create XML from this class
211
     *
212
     * @param \DOMElement|null $parent
213
     * @return \DOMElement
214
     */
215
    public function toXML(?DOMElement $parent = null): DOMElement
216
    {
217
        if ($this->isSigned() === true && $this->signer === null) {
218
            // We already have a signed document and no signer was set to re-sign it
219
            if ($parent === null) {
220
                return $this->xml;
221
            }
222
223
            $node = $parent->ownerDocument?->importNode($this->getXML(), true);
224
            $parent->appendChild($node);
225
            return $parent;
226
        }
227
228
        $e = $this->toUnsignedXML($parent);
229
230
        if ($this->signer !== null) {
231
            $signedXML = $this->doSign($e);
232
233
            // Test for an Issuer
234
            $messageElements = XPath::xpQuery($signedXML, './saml_assertion:Issuer', XPath::getXPath($signedXML));
235
            $issuer = array_pop($messageElements);
236
237
            $signedXML->insertBefore($this->signature?->toXML($signedXML), $issuer->nextSibling);
238
            return $signedXML;
239
        }
240
241
        return $e;
242
    }
243
}
244