Issues (85)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  Header Injection
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/XML/saml/Assertion.php (3 issues)

1
<?php
2
3
declare(strict_types=1);
4
5
namespace SimpleSAML\SAML2\XML\saml;
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\ProtocolViolationException;
12
use SimpleSAML\SAML2\Utils\XPath;
13
use SimpleSAML\SAML2\XML\EncryptableElementTrait;
14
use SimpleSAML\SAML2\XML\SignableElementTrait;
15
use SimpleSAML\SAML2\XML\SignedElementTrait;
16
use SimpleSAML\XML\Exception\InvalidDOMElementException;
17
use SimpleSAML\XML\Exception\MissingElementException;
18
use SimpleSAML\XML\Exception\TooManyElementsException;
19
use SimpleSAML\XML\SchemaValidatableElementInterface;
20
use SimpleSAML\XML\SchemaValidatableElementTrait;
21
use SimpleSAML\XML\Utils\Random as RandomUtils;
22
use SimpleSAML\XMLSecurity\Backend\EncryptionBackend;
23
use SimpleSAML\XMLSecurity\XML\ds\Signature;
24
use SimpleSAML\XMLSecurity\XML\EncryptableElementInterface;
25
use SimpleSAML\XMLSecurity\XML\SignableElementInterface;
26
use SimpleSAML\XMLSecurity\XML\SignedElementInterface;
27
28
use function array_filter;
29
use function array_merge;
30
use function array_pop;
31
use function array_values;
32
33
/**
34
 * Class representing a SAML 2 assertion.
35
 *
36
 * @package simplesamlphp/saml2
37
 */
38
final class Assertion extends AbstractSamlElement implements
39
    EncryptableElementInterface,
40
    SchemaValidatableElementInterface,
41
    SignableElementInterface,
42
    SignedElementInterface
43
{
44
    use EncryptableElementTrait {
0 ignored issues
show
The trait SimpleSAML\SAML2\XML\EncryptableElementTrait requires the property $ownerDocument which is not provided by SimpleSAML\SAML2\XML\saml\Assertion.
Loading history...
45
        EncryptableElementTrait::getBlacklistedAlgorithms insteadof SignedElementTrait;
46
        EncryptableElementTrait::getBlacklistedAlgorithms insteadof SignableElementTrait;
47
    }
48
    use SchemaValidatableElementTrait;
49
    use SignableElementTrait;
0 ignored issues
show
The trait SimpleSAML\SAML2\XML\SignableElementTrait requires some properties which are not provided by SimpleSAML\SAML2\XML\saml\Assertion: $ownerDocument, $documentElement
Loading history...
50
    use SignedElementTrait;
0 ignored issues
show
The trait SimpleSAML\SAML2\XML\SignedElementTrait requires some properties which are not provided by SimpleSAML\SAML2\XML\saml\Assertion: $ownerDocument, $documentElement
Loading history...
51
52
53
    /**
54
     * @var bool
55
     */
56
    protected bool $wasSignedAtConstruction = false;
57
58
    /**
59
     * The original signed XML
60
     *
61
     * @var \DOMElement
62
     */
63
    protected DOMElement $xml;
64
65
66
    /**
67
     * Assertion constructor.
68
     *
69
     * @param \SimpleSAML\SAML2\XML\saml\Issuer $issuer
70
     * @param string|null $id
71
     * @param \DateTimeImmutable $issueInstant
72
     * @param \SimpleSAML\SAML2\XML\saml\Subject|null $subject
73
     * @param \SimpleSAML\SAML2\XML\saml\Conditions|null $conditions
74
     * @param \SimpleSAML\SAML2\XML\saml\AbstractStatementType[] $statements
75
     */
76
    public function __construct(
77
        protected Issuer $issuer,
78
        protected DateTimeImmutable $issueInstant,
79
        protected ?string $id = null,
80
        protected ?Subject $subject = null,
81
        protected ?Conditions $conditions = null,
82
        protected array $statements = [],
83
    ) {
84
        Assert::same($issueInstant->getTimeZone()->getName(), 'Z', ProtocolViolationException::class);
85
        Assert::nullOrValidNCName($id); // Covers the empty string
86
        Assert::true(
87
            $subject || !empty($statements),
88
            "Either a <saml:Subject> or some statement must be present in a <saml:Assertion>",
89
        );
90
        Assert::maxCount($statements, C::UNBOUNDED_LIMIT);
91
        Assert::allIsInstanceOf($statements, AbstractStatementType::class);
92
        Assert::nullOrNotWhitespaceOnly($id);
93
    }
94
95
96
    /**
97
     * Collect the value of the subject
98
     *
99
     * @return \SimpleSAML\SAML2\XML\saml\Subject|null
100
     */
101
    public function getSubject(): ?Subject
102
    {
103
        return $this->subject;
104
    }
105
106
107
    /**
108
     * Collect the value of the conditions-property
109
     *
110
     * @return \SimpleSAML\SAML2\XML\saml\Conditions|null
111
     */
112
    public function getConditions(): ?Conditions
113
    {
114
        return $this->conditions;
115
    }
116
117
118
    /**
119
     * @return \SimpleSAML\SAML2\XML\saml\AttributeStatement[]
120
     */
121
    public function getAttributeStatements(): array
122
    {
123
        return array_values(array_filter($this->statements, function ($statement) {
124
            return $statement instanceof AttributeStatement;
125
        }));
126
    }
127
128
129
    /**
130
     * @return \SimpleSAML\SAML2\XML\saml\AuthnStatement[]
131
     */
132
    public function getAuthnStatements(): array
133
    {
134
        return array_values(array_filter($this->statements, function ($statement) {
135
            return $statement instanceof AuthnStatement;
136
        }));
137
    }
138
139
140
    /**
141
     * @return \SimpleSAML\SAML2\XML\saml\AbstractStatement[]
142
     */
143
    public function getStatements(): array
144
    {
145
        return array_values(array_filter($this->statements, function ($statement) {
146
            return $statement instanceof AbstractStatement;
147
        }));
148
    }
149
150
151
    /**
152
     * Retrieve the identifier of this assertion.
153
     *
154
     * @return string The identifier of this assertion.
155
     */
156
    public function getId(): string
157
    {
158
        if ($this->id === null) {
159
            return (new RandomUtils())->generateId();
160
        }
161
162
        return $this->id;
163
    }
164
165
166
    /**
167
     * Retrieve the issue timestamp of this assertion.
168
     *
169
     * @return \DateTimeImmutable The issue timestamp of this assertion, as an UNIX timestamp.
170
     */
171
    public function getIssueInstant(): DateTimeImmutable
172
    {
173
        return $this->issueInstant;
174
    }
175
176
177
    /**
178
     * Retrieve the issuer if this assertion.
179
     *
180
     * @return \SimpleSAML\SAML2\XML\saml\Issuer The issuer of this assertion.
181
     */
182
    public function getIssuer(): Issuer
183
    {
184
        return $this->issuer;
185
    }
186
187
188
    /**
189
     * @return bool
190
     */
191
    public function wasSignedAtConstruction(): bool
192
    {
193
        return $this->wasSignedAtConstruction;
194
    }
195
196
197
    /**
198
     * Get the XML element.
199
     *
200
     * @return \DOMElement
201
     */
202
    public function getXML(): DOMElement
203
    {
204
        return $this->xml;
205
    }
206
207
208
    /**
209
     * Set the XML element.
210
     *
211
     * @param \DOMElement $xml
212
     */
213
    private function setXML(DOMElement $xml): void
214
    {
215
        $this->xml = $xml;
216
    }
217
218
219
    /**
220
     * @return \DOMElement
221
     */
222
    protected function getOriginalXML(): DOMElement
223
    {
224
        return $this->xml ?? $this->toUnsignedXML();
225
    }
226
227
228
    public function getEncryptionBackend(): ?EncryptionBackend
229
    {
230
        // return the encryption backend you want to use,
231
        // or null if you are fine with the default
232
        return null;
233
    }
234
235
236
    /**
237
     * Convert XML into an Assertion
238
     *
239
     * @param \DOMElement $xml The XML element we should load
240
     * @return static
241
     *
242
     * @throws \SimpleSAML\Assert\AssertionFailedException if assertions are false
243
     * @throws \SimpleSAML\XML\Exception\InvalidDOMElementException
244
     *   if the qualified name of the supplied element is wrong
245
     * @throws \SimpleSAML\XML\Exception\MissingAttributeException
246
     *   if the supplied element is missing one of the mandatory attributes
247
     * @throws \SimpleSAML\XML\Exception\MissingElementException if one of the mandatory child-elements is missing
248
     * @throws \SimpleSAML\XML\Exception\TooManyElementsException if too many child-elements of a type are specified
249
     * @throws \Exception
250
     */
251
    public static function fromXML(DOMElement $xml): static
252
    {
253
        Assert::same($xml->localName, 'Assertion', InvalidDOMElementException::class);
254
        Assert::same($xml->namespaceURI, Assertion::NS, InvalidDOMElementException::class);
255
        Assert::same(self::getAttribute($xml, 'Version'), '2.0', 'Unsupported version: %s');
256
257
        $id = self::getAttribute($xml, 'ID');
258
        Assert::validNCName($id); // Covers the empty string
259
260
        $issueInstant = self::getAttribute($xml, 'IssueInstant');
261
        // Strip sub-seconds - See paragraph 1.3.3 of SAML core specifications
262
        $issueInstant = preg_replace('/([.][0-9]+Z)$/', 'Z', $issueInstant, 1);
263
264
        Assert::validDateTime($issueInstant, ProtocolViolationException::class);
265
        $issueInstant = new DateTimeImmutable($issueInstant);
266
267
        $issuer = Issuer::getChildrenOfClass($xml);
268
        Assert::minCount($issuer, 1, 'Missing <saml:Issuer> in assertion.', MissingElementException::class);
269
        Assert::maxCount($issuer, 1, 'More than one <saml:Issuer> in assertion.', TooManyElementsException::class);
270
271
        $subject = Subject::getChildrenOfClass($xml);
272
        Assert::maxCount(
273
            $subject,
274
            1,
275
            'More than one <saml:Subject> in <saml:Assertion>',
276
            TooManyElementsException::class,
277
        );
278
279
        $conditions = Conditions::getChildrenOfClass($xml);
280
        Assert::maxCount(
281
            $conditions,
282
            1,
283
            'More than one <saml:Conditions> in <saml:Assertion>.',
284
            TooManyElementsException::class,
285
        );
286
287
        $signature = Signature::getChildrenOfClass($xml);
288
        Assert::maxCount($signature, 1, 'Only one <ds:Signature> element is allowed.', TooManyElementsException::class);
289
290
        $authnStatement = AuthnStatement::getChildrenOfClass($xml);
291
        $attrStatement = AttributeStatement::getChildrenOfClass($xml);
292
        $statements = AbstractStatement::getChildrenOfClass($xml);
293
294
        $assertion = new static(
295
            array_pop($issuer),
296
            $issueInstant,
297
            $id,
298
            array_pop($subject),
299
            array_pop($conditions),
300
            array_merge($authnStatement, $attrStatement, $statements),
301
        );
302
303
        if (!empty($signature)) {
304
            $assertion->setSignature($signature[0]);
305
            $assertion->wasSignedAtConstruction = true;
306
            $assertion->setXML($xml);
307
        }
308
309
        return $assertion;
310
    }
311
312
313
    /**
314
     * Convert this assertion to an unsigned XML document.
315
     * This method does not sign the resulting XML document.
316
     *
317
     * @return \DOMElement The root element of the DOM tree
318
     */
319
    protected function toUnsignedXML(?DOMElement $parent = null): DOMElement
320
    {
321
        $e = $this->instantiateParentElement($parent);
322
323
        $e->setAttribute('Version', '2.0');
324
        $e->setAttribute('ID', $this->getId());
325
        $e->setAttribute('IssueInstant', $this->getIssueInstant()->format(C::DATETIME_FORMAT));
326
327
        $this->getIssuer()->toXML($e);
328
        $this->getSubject()?->toXML($e);
329
        $this->getConditions()?->toXML($e);
330
331
        foreach ($this->statements as $statement) {
332
            $statement->toXML($e);
333
        }
334
335
        return $e;
336
    }
337
338
339
    /**
340
     * Convert this assertion to a signed XML element, if a signer was set.
341
     *
342
     * @param \DOMElement|null $parent The DOM node the assertion should be created in.
343
     *
344
     * @return \DOMElement This assertion.
345
     * @throws \Exception
346
     */
347
    public function toXML(?DOMElement $parent = null): DOMElement
348
    {
349
        if ($this->isSigned() === true && $this->signer === null) {
350
            // We already have a signed document and no signer was set to re-sign it
351
            if ($parent === null) {
352
                return $this->getXML();
353
            }
354
355
            $node = $parent->ownerDocument?->importNode($this->getXML(), true);
356
            $parent->appendChild($node);
357
            return $parent;
358
        }
359
360
        $e = $this->toUnsignedXML($parent);
361
362
        if ($this->signer !== null) {
363
            $signedXML = $this->doSign($e);
364
365
            // Test for an Issuer
366
            $messageElements = XPath::xpQuery($signedXML, './saml_assertion:Issuer', XPath::getXPath($signedXML));
367
            $issuer = array_pop($messageElements);
368
369
            $signedXML->insertBefore($this->signature?->toXML($signedXML), $issuer->nextSibling);
370
            return $signedXML;
371
        }
372
373
        return $e;
374
    }
375
}
376