Issues (538)

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/mdui/UIInfo.php (1 issue)

Labels
Severity
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SimpleSAML\SAML2\XML\mdui;
6
7
use DOMElement;
8
use SimpleSAML\SAML2\Assert\Assert;
9
use SimpleSAML\SAML2\Exception\ArrayValidationException;
10
use SimpleSAML\SAML2\Exception\ProtocolViolationException;
11
use SimpleSAML\XML\ArrayizableElementInterface;
12
use SimpleSAML\XML\Constants as C;
13
use SimpleSAML\XML\ExtendableElementTrait;
14
use SimpleSAML\XML\SchemaValidatableElementInterface;
15
use SimpleSAML\XML\SchemaValidatableElementTrait;
16
use SimpleSAML\XML\SerializableElementInterface;
17
use SimpleSAML\XMLSchema\Exception\InvalidDOMElementException;
18
use SimpleSAML\XMLSchema\XML\Constants\NS;
19
20
use function array_filter;
21
use function array_key_exists;
22
use function array_keys;
23
use function array_map;
24
use function array_merge;
25
use function array_unique;
26
27
/**
28
 * Class for handling the metadata extensions for login and discovery user interface
29
 *
30
 * @link: http://docs.oasis-open.org/security/saml/Post2.0/sstc-saml-metadata-ui/v1.0/sstc-saml-metadata-ui-v1.0.pdf
31
 *
32
 * @package simplesamlphp/saml2
33
 */
34
final class UIInfo extends AbstractMduiElement implements
35
    ArrayizableElementInterface,
36
    SchemaValidatableElementInterface
37
{
38
    use ExtendableElementTrait;
39
    use SchemaValidatableElementTrait;
40
41
42
    /** The namespace-attribute for the xs:any element */
43
    public const string XS_ANY_ELT_NAMESPACE = NS::OTHER;
0 ignored issues
show
A parse error occurred: Syntax error, unexpected T_STRING, expecting '=' on line 43 at column 24
Loading history...
44
45
46
    /**
47
     * Create a UIInfo element.
48
     *
49
     * @param \SimpleSAML\SAML2\XML\mdui\DisplayName[] $displayName
50
     * @param \SimpleSAML\SAML2\XML\mdui\Description[] $description
51
     * @param \SimpleSAML\SAML2\XML\mdui\InformationURL[] $informationURL
52
     * @param \SimpleSAML\SAML2\XML\mdui\PrivacyStatementURL[] $privacyStatementURL
53
     * @param \SimpleSAML\SAML2\XML\mdui\Keywords[] $keywords
54
     * @param \SimpleSAML\SAML2\XML\mdui\Logo[] $logo
55
     * @param \SimpleSAML\XML\SerializableElementInterface[] $children
56
     */
57
    public function __construct(
58
        protected array $displayName = [],
59
        protected array $description = [],
60
        protected array $informationURL = [],
61
        protected array $privacyStatementURL = [],
62
        protected array $keywords = [],
63
        protected array $logo = [],
64
        array $children = [],
65
    ) {
66
        Assert::maxCount($displayName, C::UNBOUNDED_LIMIT);
67
        Assert::allIsInstanceOf($displayName, DisplayName::class);
68
        /**
69
         * 2.1.2:  There MUST NOT be more than one <mdui:DisplayName>,
70
         *         within a given <mdui:UIInfo>, for a given language
71
         */
72
        $this->testLocalizedElements($displayName);
73
74
        Assert::maxCount($description, C::UNBOUNDED_LIMIT);
75
        Assert::allIsInstanceOf($description, Description::class);
76
        /**
77
         * 2.1.3:  There MUST NOT be more than one <mdui:Description>,
78
         *         within a given <mdui:UIInfo>, for a given language
79
         */
80
        $this->testLocalizedElements($description);
81
82
        Assert::maxCount($keywords, C::UNBOUNDED_LIMIT);
83
        Assert::allIsInstanceOf($keywords, Keywords::class);
84
        /**
85
         * 2.1.4:  There MUST NOT be more than one <mdui:Keywords>,
86
         *         within a given <mdui:UIInfo>, for a given language
87
         */
88
        $this->testLocalizedElements($keywords);
89
90
        Assert::maxCount($informationURL, C::UNBOUNDED_LIMIT);
91
        Assert::allIsInstanceOf($informationURL, InformationURL::class);
92
        /**
93
         * 2.1.6:  There MUST NOT be more than one <mdui:InformationURL>,
94
         *         within a given <mdui:UIInfo>, for a given language
95
         */
96
        $this->testLocalizedElements($informationURL);
97
98
        Assert::maxCount($privacyStatementURL, C::UNBOUNDED_LIMIT);
99
        Assert::allIsInstanceOf($privacyStatementURL, PrivacyStatementURL::class);
100
        /**
101
         * 2.1.7:  There MUST NOT be more than one <mdui:PrivacyStatementURL>,
102
         *         within a given <mdui:UIInfo>, for a given language
103
         */
104
        $this->testLocalizedElements($privacyStatementURL);
105
106
        Assert::maxCount($logo, C::UNBOUNDED_LIMIT);
107
        Assert::allIsInstanceOf($logo, Logo::class);
108
109
        $this->setElements($children);
110
    }
111
112
113
    /**
114
     * Collect the value of the Keywords-property
115
     *
116
     * @return \SimpleSAML\SAML2\XML\mdui\Keywords[]
117
     */
118
    public function getKeywords(): array
119
    {
120
        return $this->keywords;
121
    }
122
123
124
    /**
125
     * Add the value to the Keywords-property
126
     *
127
     * @param \SimpleSAML\SAML2\XML\mdui\Keywords $keyword
128
     */
129
    public function addKeyword(Keywords $keyword): void
130
    {
131
        /**
132
         * 2.1.4:  There MUST NOT be more than one <mdui:Keywords>,
133
         *         within a given <mdui:UIInfo>, for a given language
134
         */
135
        $keywords = array_merge($this->keywords, [$keyword]);
136
        $this->testLocalizedElements($keywords);
137
        $this->keywords = $keywords;
138
    }
139
140
141
    /**
142
     * Collect the value of the DisplayName-property
143
     *
144
     * @return \SimpleSAML\SAML2\XML\mdui\DisplayName[]
145
     */
146
    public function getDisplayName(): array
147
    {
148
        return $this->displayName;
149
    }
150
151
152
    /**
153
     * Collect the value of the Description-property
154
     *
155
     * @return \SimpleSAML\SAML2\XML\mdui\Description[]
156
     */
157
    public function getDescription(): array
158
    {
159
        return $this->description;
160
    }
161
162
163
    /**
164
     * Collect the value of the InformationURL-property
165
     * @return \SimpleSAML\SAML2\XML\mdui\InformationURL[]
166
     */
167
    public function getInformationURL(): array
168
    {
169
        return $this->informationURL;
170
    }
171
172
173
    /**
174
     * Collect the value of the PrivacyStatementURL-property
175
     *
176
     * @return \SimpleSAML\SAML2\XML\mdui\PrivacyStatementURL[]
177
     */
178
    public function getPrivacyStatementURL(): array
179
    {
180
        return $this->privacyStatementURL;
181
    }
182
183
184
    /**
185
     * Collect the value of the Logo-property
186
     *
187
     * @return \SimpleSAML\SAML2\XML\mdui\Logo[]
188
     */
189
    public function getLogo(): array
190
    {
191
        return $this->logo;
192
    }
193
194
195
    /**
196
     * Add the value to the Logo-property
197
     *
198
     * @param \SimpleSAML\SAML2\XML\mdui\Logo $logo
199
     */
200
    public function addLogo(Logo $logo): void
201
    {
202
        $this->logo[] = $logo;
203
    }
204
205
206
    /**
207
     * Add the value to the elements-property
208
     *
209
     * @param \SimpleSAML\XML\SerializableElementInterface $child
210
     */
211
    public function addChild(SerializableElementInterface $child): void
212
    {
213
        $this->elements[] = $child;
214
    }
215
216
217
    /**
218
     * Test if an object, at the state it's in, would produce an empty XML-element
219
     *
220
     * @return bool
221
     */
222
    public function isEmptyElement(): bool
223
    {
224
        return empty($this->getDisplayName())
225
            && empty($this->getDescription())
226
            && empty($this->getInformationURL())
227
            && empty($this->getPrivacyStatementURL())
228
            && empty($this->getKeywords())
229
            && empty($this->getLogo())
230
            && empty($this->getElements());
231
    }
232
233
234
    /**
235
     * Test localized elements for multiple items with the same language
236
     *
237
     * @param (
238
     *   \SimpleSAML\SAML2\XML\md\AbstractLocalizedURI|
239
     *   \SimpleSAML\SAML2\XML\md\AbstractLocalizedName|
240
     *   \SimpleSAML\SAML2\XML\mdui\Keywords
241
     * )[] $elements
242
     */
243
    private function testLocalizedElements(array $elements)
244
    {
245
        if (!empty($elements)) {
246
            $types = array_map('get_class', $elements);
247
            Assert::maxCount(array_unique($types), 1, 'Multiple class types cannot be used.');
248
249
            $languages = array_map(
250
                function ($elt) {
251
                    return $elt->getLanguage();
252
                },
253
                $elements,
254
            );
255
            Assert::uniqueValues(
256
                $languages,
257
                'There MUST NOT be more than one <' . $elements[0]->getQualifiedName() . '>,'
258
                . ' within a given <mdui:UIInfo>, for a given language',
259
                ProtocolViolationException::class,
260
            );
261
        }
262
    }
263
264
265
    /**
266
     * Convert XML into a UIInfo
267
     *
268
     * @throws \SimpleSAML\XMLSchema\Exception\InvalidDOMElementException
269
     *   if the qualified name of the supplied element is wrong
270
     */
271
    public static function fromXML(DOMElement $xml): static
272
    {
273
        Assert::same($xml->localName, 'UIInfo', InvalidDOMElementException::class);
274
        Assert::same($xml->namespaceURI, UIInfo::NS, InvalidDOMElementException::class);
275
276
        $DisplayName = DisplayName::getChildrenOfClass($xml);
277
        $Description = Description::getChildrenOfClass($xml);
278
        $InformationURL = InformationURL::getChildrenOfClass($xml);
279
        $PrivacyStatementURL = PrivacyStatementURL::getChildrenOfClass($xml);
280
        $Keywords = Keywords::getChildrenOfClass($xml);
281
        $Logo = Logo::getChildrenOfClass($xml);
282
        $children = self::getChildElementsFromXML($xml);
283
284
        return new static(
285
            $DisplayName,
286
            $Description,
287
            $InformationURL,
288
            $PrivacyStatementURL,
289
            $Keywords,
290
            $Logo,
291
            $children,
292
        );
293
    }
294
295
296
    /**
297
     * Convert this UIInfo to XML.
298
     */
299
    public function toXML(?DOMElement $parent = null): DOMElement
300
    {
301
        $e = $this->instantiateParentElement($parent);
302
303
        foreach ($this->getDisplayName() as $child) {
304
            $child->toXML($e);
305
        }
306
307
        foreach ($this->getDescription() as $child) {
308
            $child->toXML($e);
309
        }
310
311
        foreach ($this->getInformationURL() as $child) {
312
            $child->toXML($e);
313
        }
314
315
        foreach ($this->getPrivacyStatementURL() as $child) {
316
            $child->toXML($e);
317
        }
318
319
        foreach ($this->getKeywords() as $child) {
320
            $child->toXML($e);
321
        }
322
323
        foreach ($this->getLogo() as $child) {
324
            $child->toXML($e);
325
        }
326
327
        /** @var \SimpleSAML\XML\SerializableElementInterface $child */
328
        foreach ($this->getElements() as $child) {
329
            $child->toXML($e);
330
        }
331
332
        return $e;
333
    }
334
335
336
    /**
337
     * Create a class from an array
338
     *
339
     * @param array{
340
     *   'DisplayName'?: array,
341
     *   'Description'?: array,
342
     *   'InformationURL'?: array,
343
     *   'PrivacyStatementURL'?: array,
344
     *   'Keywords'?: array,
345
     *   'Logo'?: array,
346
     *   'children'?: array,
347
     * } $data
348
     */
349
    public static function fromArray(array $data): static
350
    {
351
        $data = self::processArrayContents($data);
352
353
        return new static(
354
            $data['DisplayName'] ?? [],
355
            $data['Description'] ?? [],
356
            $data['InformationURL'] ?? [],
357
            $data['PrivacyStatementURL'] ?? [],
358
            $data['Keywords'] ?? [],
359
            $data['Logo'] ?? [],
360
            $data['children'] ?? [],
361
        );
362
    }
363
364
365
    /**
366
     * Validates an array representation of this object and returns the same array with
367
     * rationalized keys (casing) and parsed sub-elements.
368
     *
369
     * @param array{
370
     *   'DisplayName'?: array,
371
     *   'Description'?: array,
372
     *   'InformationURL'?: array,
373
     *   'PrivacyStatementURL'?: array,
374
     *   'Keywords'?: array,
375
     *   'Logo'?: array,
376
     *   'children'?: array,
377
     * } $data
378
     * @return array{
379
     *   'DisplayName'?: array,
380
     *   'Description'?: array,
381
     *   'InformationURL'?: array,
382
     *   'PrivacyStatementURL'?: array,
383
     *   'Keywords'?: array,
384
     *   'Logo'?: array,
385
     *   'children'?: array,
386
     * }
387
     */
388
    private static function processArrayContents(array $data): array
389
    {
390
        $data = array_change_key_case($data, CASE_LOWER);
391
392
        // Make sure the array keys are known for this kind of object
393
        Assert::allOneOf(
394
            array_keys($data),
395
            [
396
                'displayname',
397
                'description',
398
                'informationurl',
399
                'privacystatementurl',
400
                'keywords',
401
                'logo',
402
                'children',
403
            ],
404
            ArrayValidationException::class,
405
        );
406
407
        $retval = [];
408
409
        if (array_key_exists('displayname', $data)) {
410
            foreach ($data['displayname'] as $l => $displayName) {
411
                $retval['DisplayName'][] = DisplayName::fromArray([$l => $displayName]);
412
            }
413
        }
414
415
        if (array_key_exists('description', $data)) {
416
            foreach ($data['description'] as $l => $description) {
417
                $retval['Description'][] = Description::fromArray([$l => $description]);
418
            }
419
        }
420
421
        if (array_key_exists('informationurl', $data)) {
422
            foreach ($data['informationurl'] as $l => $iu) {
423
                $retval['InformationURL'][] = InformationURL::fromArray([$l => $iu]);
424
            }
425
        }
426
427
        if (array_key_exists('privacystatementurl', $data)) {
428
            foreach ($data['privacystatementurl'] as $l => $psu) {
429
                $retval['PrivacyStatementURL'][] = PrivacyStatementURL::fromArray([$l => $psu]);
430
            }
431
        }
432
433
        if (array_key_exists('keywords', $data)) {
434
            foreach ($data['keywords'] as $l => $keywords) {
435
                $retval['Keywords'][] = Keywords::fromArray([$l => $keywords]);
436
            }
437
        }
438
439
        if (array_key_exists('logo', $data)) {
440
            foreach ($data['logo'] as $logo) {
441
                $retval['Logo'][] = Logo::fromArray($logo);
442
            }
443
        }
444
445
        if (array_key_exists('children', $data)) {
446
            Assert::isArray($data['children'], ArrayValidationException::class);
447
            Assert::allIsInstanceOf(
448
                $data['children'],
449
                SerializableElementInterface::class,
450
                ArrayValidationException::class,
451
            );
452
            $retval['children'] = $data['children'];
453
        }
454
455
        return array_filter($retval);
456
    }
457
458
459
    /**
460
     * Create an array from this class
461
     *
462
     * @return array{
463
     *   'DisplayName'?: array,
464
     *   'Description'?: array,
465
     *   'InformationURL'?: array,
466
     *   'PrivacyStatementURL'?: array,
467
     *   'Keywords'?: array,
468
     *   'Logo'?: array,
469
     *   'children'?: array,
470
     * }
471
     */
472
    public function toArray(): array
473
    {
474
        $displayName = [];
475
        foreach ($this->getDisplayName() as $child) {
476
            $displayName = array_merge($displayName, $child->toArray());
477
        }
478
479
        $description = [];
480
        foreach ($this->getDescription() as $child) {
481
            $description = array_merge($description, $child->toArray());
482
        }
483
484
        $infoUrl = [];
485
        foreach ($this->getInformationURL() as $child) {
486
            $infoUrl = array_merge($infoUrl, $child->toArray());
487
        }
488
489
        $privacyUrl = [];
490
        foreach ($this->getPrivacyStatementURL() as $child) {
491
            $privacyUrl = array_merge($privacyUrl, $child->toArray());
492
        }
493
494
        $keywords = [];
495
        foreach ($this->getKeywords() as $child) {
496
            $keywords = array_merge($keywords, $child->toArray());
497
        }
498
499
        $logo = [];
500
        foreach ($this->getLogo() as $child) {
501
            $logo[] = $child->toArray();
502
        }
503
504
        $children = $this->getElements();
505
506
        return [] +
507
            (empty($displayName) ? [] : ['DisplayName' => $displayName]) +
508
            (empty($description) ? [] : ['Description' => $description]) +
509
            (empty($infoUrl) ? [] : ['InformationURL' => $infoUrl]) +
510
            (empty($privacyUrl) ? [] : ['PrivacyStatementURL' => $privacyUrl]) +
511
            (empty($keywords) ? [] : ['Keywords' => $keywords]) +
512
            (empty($logo) ? [] : ['Logo' => $logo]) +
513
            (empty($children) ? [] : ['children' => $children]);
514
    }
515
}
516