Passed
Push — master ( b399c9...7b0af8 )
by Tim
02:06
created
www/get.php 2 patches
Indentation   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -1,18 +1,18 @@  discard block
 block discarded – undo
1 1
 <?php
2 2
 
3 3
 if (!isset($_REQUEST['id'])) {
4
-    throw new \SimpleSAML\Error\BadRequest('Missing required parameter "id".');
4
+	throw new \SimpleSAML\Error\BadRequest('Missing required parameter "id".');
5 5
 }
6 6
 $id = strval($_REQUEST['id']);
7 7
 
8 8
 $set = null;
9 9
 if (isset($_REQUEST['set'])) {
10
-    $set = explode(',', $_REQUEST['set']);
10
+	$set = explode(',', $_REQUEST['set']);
11 11
 }
12 12
 
13 13
 $excluded_entities = null;
14 14
 if (isset($_REQUEST['exclude'])) {
15
-    $excluded_entities = explode(',', $_REQUEST['exclude']);
15
+	$excluded_entities = explode(',', $_REQUEST['exclude']);
16 16
 }
17 17
 
18 18
 $aggregator = \SimpleSAML\Module\aggregator2\Aggregator::getAggregator($id);
@@ -22,17 +22,17 @@  discard block
 block discarded – undo
22 22
 
23 23
 $mimetype = 'application/samlmetadata+xml';
24 24
 $allowedmimetypes = [
25
-    'text/plain',
26
-    'application/samlmetadata-xml',
27
-    'application/xml',
25
+	'text/plain',
26
+	'application/samlmetadata-xml',
27
+	'application/xml',
28 28
 ];
29 29
 
30 30
 if (isset($_GET['mimetype']) && in_array($_GET['mimetype'], $allowedmimetypes)) {
31
-    $mimetype = $_GET['mimetype'];
31
+	$mimetype = $_GET['mimetype'];
32 32
 }
33 33
 
34 34
 if ($mimetype === 'text/plain') {
35
-    $xml = \SimpleSAML\Utils\XML::::formatXMLString($xml);
35
+	$xml = \SimpleSAML\Utils\XML::::formatXMLString($xml);
36 36
 }
37 37
 
38 38
 header('Content-Type: '.$mimetype);
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -35,13 +35,13 @@
 block discarded – undo
35 35
     $xml = \SimpleSAML\Utils\XML::::formatXMLString($xml);
36 36
 }
37 37
 
38
-header('Content-Type: '.$mimetype);
38
+header('Content-Type: ' . $mimetype);
39 39
 header('Content-Length: ' . strlen($xml));
40 40
 
41 41
 /*
42 42
  * At this point, if the ID was forged, getMetadata() would
43 43
  * have failed to find a valid metadata set, so we can trust it.
44 44
  */
45
-header('Content-Disposition: filename='.$id.'.xml');
45
+header('Content-Disposition: filename=' . $id . '.xml');
46 46
 
47 47
 echo $xml;
Please login to merge, or discard this patch.
lib/Aggregator.php 2 patches
Indentation   +714 added lines, -714 removed lines patch added patch discarded remove patch
@@ -22,718 +22,718 @@
 block discarded – undo
22 22
  */
23 23
 class Aggregator
24 24
 {
25
-    /**
26
-     * The list of signature algorithms supported by the aggregator.
27
-     *
28
-     * @var array
29
-     */
30
-    public static $SUPPORTED_SIGNATURE_ALGORITHMS = [
31
-        XMLSecurityKey::RSA_SHA1,
32
-        XMLSecurityKey::RSA_SHA256,
33
-        XMLSecurityKey::RSA_SHA384,
34
-        XMLSecurityKey::RSA_SHA512,
35
-    ];
36
-
37
-    /**
38
-     * The ID of this aggregator.
39
-     *
40
-     * @var string
41
-     */
42
-    protected $id;
43
-
44
-    /**
45
-     * Our log "location".
46
-     *
47
-     * @var string
48
-     */
49
-    protected $logLoc;
50
-
51
-    /**
52
-     * Which cron-tag this should be updated in.
53
-     *
54
-     * @var string|null
55
-     */
56
-    protected $cronTag;
57
-
58
-    /**
59
-     * Absolute path to a cache directory.
60
-     *
61
-     * @var string|null
62
-     */
63
-    protected $cacheDirectory;
64
-
65
-    /**
66
-     * The entity sources.
67
-     *
68
-     * Array of sspmod_aggregator2_EntitySource objects.
69
-     *
70
-     * @var array
71
-     */
72
-    protected $sources = [];
73
-
74
-    /**
75
-     * How long the generated metadata should be valid, as a number of seconds.
76
-     *
77
-     * This is used to set the validUntil attribute on the generated EntityDescriptor.
78
-     *
79
-     * @var int
80
-     */
81
-    protected $validLength;
82
-
83
-    /**
84
-     * Duration we should cache generated metadata.
85
-     *
86
-     * @var int
87
-     */
88
-    protected $cacheGenerated;
89
-
90
-    /**
91
-     * An array of entity IDs to exclude from the aggregate.
92
-     *
93
-     * @var string[]|null
94
-     */
95
-    protected $excluded;
96
-
97
-    /**
98
-     * An indexed array of protocols to filter the aggregate by. keys can be any of:
99
-     *
100
-     * - urn:oasis:names:tc:SAML:1.1:protocol
101
-     * - urn:oasis:names:tc:SAML:2.0:protocol
102
-     *
103
-     * Values will be true if enabled, false otherwise.
104
-     *
105
-     * @var string[]|null
106
-     */
107
-    protected $protocols;
108
-
109
-    /**
110
-     * An array of roles to filter the aggregate by. Keys can be any of:
111
-     *
112
-     * - SAML2_XML_md_IDPSSODescriptor
113
-     * - SAML2_XML_md_SPSSODescriptor
114
-     * - SAML2_XML_md_AttributeAuthorityDescriptor
115
-     *
116
-     * Values will be true if enabled, false otherwise.
117
-     *
118
-     * @var string[]|null
119
-     */
120
-    protected $roles;
121
-
122
-    /**
123
-     * The key we should use to sign the metadata.
124
-     *
125
-     * @var string|null
126
-     */
127
-    protected $signKey;
128
-
129
-    /**
130
-     * The password for the private key.
131
-     *
132
-     * @var string|null
133
-     */
134
-    protected $signKeyPass;
135
-
136
-    /**
137
-     * The certificate of the key we sign the metadata with.
138
-     *
139
-     * @var string|null
140
-     */
141
-    protected $signCert;
142
-
143
-    /**
144
-     * The algorithm to use for metadata signing.
145
-     *
146
-     * @var string|null
147
-     */
148
-    protected $signAlg;
149
-
150
-    /**
151
-     * The CA certificate file that should be used to validate https-connections.
152
-     *
153
-     * @var string|null
154
-     */
155
-    protected $sslCAFile;
156
-
157
-    /**
158
-     * The cache ID for our generated metadata.
159
-     *
160
-     * @var string
161
-     */
162
-    protected $cacheId;
163
-
164
-    /**
165
-     * The cache tag for our generated metadata.
166
-     *
167
-     * This tag is used to make sure that a config change
168
-     * invalidates our cached metadata.
169
-     *
170
-     * @var string
171
-     */
172
-    protected $cacheTag;
173
-
174
-    /**
175
-     * The registration information for our generated metadata.
176
-     *
177
-     * @var array
178
-     */
179
-    protected $regInfo;
180
-
181
-
182
-    /**
183
-     * Initialize this aggregator.
184
-     *
185
-     * @param string $id  The id of this aggregator.
186
-     * @param \SimpleSAML\Configuration $config  The configuration for this aggregator.
187
-     */
188
-    protected function __construct($id, Configuration $config)
189
-    {
190
-        assert('is_string($id)');
191
-
192
-        $this->id = $id;
193
-        $this->logLoc = 'aggregator2:'.$this->id.': ';
194
-
195
-        $this->cronTag = $config->getString('cron.tag', null);
196
-
197
-        $this->cacheDirectory = $config->getString('cache.directory', null);
198
-        if ($this->cacheDirectory !== null) {
199
-            $this->cacheDirectory = System::resolvePath($this->cacheDirectory);
200
-        }
201
-
202
-        $this->cacheGenerated = $config->getInteger('cache.generated', null);
203
-        if ($this->cacheGenerated !== null) {
204
-            $this->cacheId = sha1($this->id);
205
-            $this->cacheTag = sha1(serialize($config));
206
-        }
207
-
208
-        // configure entity IDs excluded by default
209
-        $this->excludeEntities($config->getArrayize('exclude', null));
210
-
211
-        // configure filters
212
-        $this->setFilters($config->getArrayize('filter', null));
213
-
214
-        $this->validLength = $config->getInteger('valid.length', 7*24*60*60);
215
-
216
-        $globalConfig = Configuration::getInstance();
217
-        $certDir = $globalConfig->getPathValue('certdir', 'cert/');
218
-
219
-        $signKey = $config->getString('sign.privatekey', null);
220
-        if ($signKey !== null) {
221
-            $signKey = System::resolvePath($signKey, $certDir);
222
-            $this->signKey = @file_get_contents($signKey);
223
-            if ($this->signKey === null) {
224
-                throw new Exception('Unable to load private key from '.var_export($signKey, true));
225
-            }
226
-        }
227
-
228
-        $this->signKeyPass = $config->getString('sign.privatekey_pass', null);
229
-
230
-        $signCert = $config->getString('sign.certificate', null);
231
-        if ($signCert !== null) {
232
-            $signCert = System::resolvePath($signCert, $certDir);
233
-            $this->signCert = @file_get_contents($signCert);
234
-            if ($this->signCert === null) {
235
-                throw new Exception('Unable to load certificate file from '.var_export($signCert, true));
236
-            }
237
-        }
238
-
239
-        $this->signAlg = $config->getString('sign.algorithm', XMLSecurityKey::RSA_SHA1);
240
-        if (!in_array($this->signAlg, self::$SUPPORTED_SIGNATURE_ALGORITHMS)) {
241
-            throw new Exception('Unsupported signature algorithm '.var_export($this->signAlg, true));
242
-        }
243
-
244
-        $this->sslCAFile = $config->getString('ssl.cafile', null);
245
-
246
-        $this->regInfo = $config->getArray('RegistrationInfo', null);
247
-
248
-        $this->initSources($config->getConfigList('sources'));
249
-    }
250
-
251
-
252
-    /**
253
-     * Populate the sources array.
254
-     *
255
-     * This is called from the constructor, and can be overridden in subclasses.
256
-     *
257
-     * @param array $sources  The sources as an array of SimpleSAML_Configuration objects.
258
-     */
259
-    protected function initSources(array $sources)
260
-    {
261
-        foreach ($sources as $source) {
262
-            $this->sources[] = new EntitySource($this, $source);
263
-        }
264
-    }
265
-
266
-
267
-    /**
268
-     * Return an instance of the aggregator with the given id.
269
-     *
270
-     * @param string $id  The id of the aggregator.
271
-     */
272
-    public static function getAggregator($id)
273
-    {
274
-        assert('is_string($id)');
275
-
276
-        $config = Configuration::getConfig('module_aggregator2.php');
277
-        return new Aggregator($id, $config->getConfigItem($id));
278
-    }
279
-
280
-
281
-    /**
282
-     * Retrieve the ID of the aggregator.
283
-     *
284
-     * @return string  The ID of this aggregator.
285
-     */
286
-    public function getId()
287
-    {
288
-        return $this->id;
289
-    }
290
-
291
-
292
-    /**
293
-     * Add an item to the cache.
294
-     *
295
-     * @param string $id  The identifier of this data.
296
-     * @param string $data  The data.
297
-     * @param int $expires  The timestamp the data expires.
298
-     * @param string|null $tag  An extra tag that can be used to verify the validity of the cached data.
299
-     */
300
-    public function addCacheItem($id, $data, $expires, $tag = null)
301
-    {
302
-        assert('is_string($id)');
303
-        assert('is_string($data)');
304
-        assert('is_int($expires)');
305
-        assert('is_null($tag) || is_string($tag)');
306
-
307
-        $cacheFile = $this->cacheDirectory.'/'.$id;
308
-        try {
309
-            System::writeFile($cacheFile, $data);
310
-        } catch (\Exception $e) {
311
-            Logger::warning($this->logLoc.'Unable to write to cache file '.var_export($cacheFile, true));
312
-            return;
313
-        }
314
-
315
-        $expireInfo = (string)$expires;
316
-        if ($tag !== null) {
317
-            $expireInfo .= ':'.$tag;
318
-        }
319
-
320
-        $expireFile = $cacheFile.'.expire';
321
-        try {
322
-            System::writeFile($expireFile, $expireInfo);
323
-        } catch (\Exception $e) {
324
-            Logger::warning($this->logLoc.'Unable to write expiration info to '.var_export($expireFile, true));
325
-        }
326
-    }
327
-
328
-
329
-    /**
330
-     * Check validity of cached data.
331
-     *
332
-     * @param string $id  The identifier of this data.
333
-     * @param string $tag  The tag that was passed to addCacheItem.
334
-     * @return bool  TRUE if the data is valid, FALSE if not.
335
-     */
336
-    public function isCacheValid($id, $tag = null)
337
-    {
338
-        assert('is_string($id)');
339
-        assert('is_null($tag) || is_string($tag)');
340
-
341
-        $cacheFile = $this->cacheDirectory.'/'.$id;
342
-        if (!file_exists($cacheFile)) {
343
-            return false;
344
-        }
345
-
346
-        $expireFile = $cacheFile.'.expire';
347
-        if (!file_exists($expireFile)) {
348
-            return false;
349
-        }
350
-
351
-        $expireData = @file_get_contents($expireFile);
352
-        if ($expireData === false) {
353
-            return false;
354
-        }
355
-
356
-        $expireData = explode(':', $expireData, 2);
357
-
358
-        $expireTime = intval($expireData[0]);
359
-        if ($expireTime <= time()) {
360
-            return false;
361
-        }
362
-
363
-        if (count($expireData) === 1) {
364
-            $expireTag = null;
365
-        } else {
366
-            $expireTag = $expireData[1];
367
-        }
368
-        if ($expireTag !== $tag) {
369
-            return false;
370
-        }
371
-
372
-        return true;
373
-    }
374
-
375
-
376
-    /**
377
-     * Get the cache item.
378
-     *
379
-     * @param string $id  The identifier of this data.
380
-     * @param string $tag  The tag that was passed to addCacheItem.
381
-     * @return string|null  The cache item, or NULL if it isn't cached or if it is expired.
382
-     */
383
-    public function getCacheItem($id, $tag = null)
384
-    {
385
-        assert('is_string($id)');
386
-        assert('is_null($tag) || is_string($tag)');
387
-
388
-        if (!$this->isCacheValid($id, $tag)) {
389
-            return null;
390
-        }
391
-
392
-        $cacheFile = $this->cacheDirectory.'/'.$id;
393
-        return @file_get_contents($cacheFile);
394
-    }
395
-
396
-
397
-    /**
398
-     * Get the cache filename for the specific id.
399
-     *
400
-     * @param string $id  The identifier of the cached data.
401
-     * @return string|null  The filename, or NULL if the cache file doesn't exist.
402
-     */
403
-    public function getCacheFile($id)
404
-    {
405
-        assert('is_string($id)');
406
-
407
-        $cacheFile = $this->cacheDirectory.'/'.$id;
408
-        if (!file_exists($cacheFile)) {
409
-            return null;
410
-        }
411
-
412
-        return $cacheFile;
413
-    }
414
-
415
-
416
-    /**
417
-     * Retrieve the SSL CA file path, if it is set.
418
-     *
419
-     * @return string|null  The SSL CA file path.
420
-     */
421
-    public function getCAFile()
422
-    {
423
-        return $this->sslCAFile;
424
-    }
425
-
426
-
427
-    /**
428
-     * Sign the generated EntitiesDescriptor.
429
-     */
430
-    protected function addSignature(SignedElement $element)
431
-    {
432
-        if ($this->signKey === null) {
433
-            return;
434
-        }
435
-
436
-        $privateKey = new XMLSecurityKey($this->signAlg, ['type' => 'private']);
437
-        if ($this->signKeyPass !== null) {
438
-            $privateKey->passphrase = $this->signKeyPass;
439
-        }
440
-        $privateKey->loadKey($this->signKey, false);
441
-
442
-        $element->setSignatureKey($privateKey);
443
-
444
-        if ($this->signCert !== null) {
445
-            $element->setCertificates([$this->signCert]);
446
-        }
447
-    }
448
-
449
-
450
-    /**
451
-     * Recursively browse the children of an EntitiesDescriptor element looking for EntityDescriptor elements, and
452
-     * return an array containing all of them.
453
-     *
454
-     * @param \SAML2\XML\md\EntitiesDescriptor $entity The source EntitiesDescriptor that holds the entities to extract.
455
-     *
456
-     * @return array An array containing all the EntityDescriptors found.
457
-     */
458
-    private static function extractEntityDescriptors($entity)
459
-    {
460
-        assert('$entity instanceof EntitiesDescriptor');
461
-
462
-        if (!($entity instanceof EntitiesDescriptor)) {
463
-            return [];
464
-        }
465
-
466
-        $results = [];
467
-        foreach ($entity->children as $child) {
468
-            if ($child instanceof EntityDescriptor) {
469
-                $results[] = $child;
470
-                continue;
471
-            }
472
-
473
-            $results = array_merge($results, self::extractEntityDescriptors($child));
474
-        }
475
-        return $results;
476
-    }
477
-
478
-
479
-    /**
480
-     * Retrieve all entities as an EntitiesDescriptor.
481
-     *
482
-     * @return \SAML2\XML\md\EntitiesDescriptor  The entities.
483
-     */
484
-    protected function getEntitiesDescriptor()
485
-    {
486
-        $ret = new EntitiesDescriptor();
487
-        $now = time();
488
-
489
-        // add RegistrationInfo extension if enabled
490
-        if ($this->regInfo !== null) {
491
-            $ri = new RegistrationInfo();
492
-            $ri->registrationInstant = $now;
493
-            foreach ($this->regInfo as $riName => $riValues) {
494
-                switch ($riName) {
495
-                    case 'authority':
496
-                        $ri->registrationAuthority = $riValues;
497
-                        break;
498
-                    case 'instant':
499
-                        $ri->registrationInstant = Utils::xsDateTimeToTimestamp($riValues);
500
-                        break;
501
-                    case 'policies':
502
-                        $ri->RegistrationPolicy = $riValues;
503
-                        break;
504
-                }
505
-            }
506
-            $ret->Extensions[] = $ri;
507
-        }
508
-
509
-        foreach ($this->sources as $source) {
510
-            $m = $source->getMetadata();
511
-            if ($m === NULL) {
512
-                continue;
513
-            }
514
-            if ($m instanceof EntityDescriptor) {
515
-                $ret->children[] = $m;
516
-            } elseif ($m instanceof EntitiesDescriptor) {
517
-                $ret->children = array_merge($ret->children, self::extractEntityDescriptors($m));
518
-            }
519
-        }
520
-
521
-        $ret->children = array_unique($ret->children, SORT_REGULAR);
522
-        $ret->validUntil = $now + $this->validLength;
523
-
524
-        return $ret;
525
-    }
526
-
527
-
528
-    /**
529
-     * Recursively traverse the children of an EntitiesDescriptor, removing those entities listed in the $entities
530
-     * property. Returns the EntitiesDescriptor with the entities filtered out.
531
-     *
532
-     * @param \SAML2\XML\md\EntitiesDescriptor $descriptor The EntitiesDescriptor from where to exclude entities.
533
-     *
534
-     * @return \SAML2\XML\md\EntitiesDescriptor The EntitiesDescriptor with excluded entities filtered out.
535
-     */
536
-    protected function exclude(EntitiesDescriptor $descriptor)
537
-    {
538
-        if (empty($this->excluded)) {
539
-            return $descriptor;
540
-        }
541
-
542
-        $filtered = [];
543
-        foreach ($descriptor->children as $child) {
544
-            if ($child instanceof EntityDescriptor) {
545
-                if (in_array($child->entityID, $this->excluded)) {
546
-                    continue;
547
-                }
548
-                $filtered[] = $child;
549
-            }
550
-
551
-            if ($child instanceof EntitiesDescriptor) {
552
-                $filtered[] = $this->exclude($child);
553
-            }
554
-        }
555
-
556
-        $descriptor->children = $filtered;
557
-        return $descriptor;
558
-    }
559
-
560
-
561
-    /**
562
-     * Recursively traverse the children of an EntitiesDescriptor, keeping only those entities with the roles listed in
563
-     * the $roles property, and support for the protocols listed in the $protocols property. Returns the
564
-     * EntitiesDescriptor containing only those entities.
565
-     *
566
-     * @param \SAML2\XML\md\EntitiesDescriptor $descriptor The EntitiesDescriptor to filter.
567
-     *
568
-     * @return SAML2_XML_md_EntitiesDescriptor The EntitiesDescriptor with only the entities filtered.
569
-     */
570
-    protected function filter(SAML2_XML_md_EntitiesDescriptor $descriptor)
571
-    {
572
-        if ($this->roles === null || $this->protocols === null) {
573
-            return $descriptor;
574
-        }
575
-
576
-        $enabled_roles = array_keys($this->roles, true);
577
-        $enabled_protos = array_keys($this->protocols, true);
578
-
579
-        $filtered = [];
580
-        foreach ($descriptor->children as $child) {
581
-            if ($child instanceof EntityDescriptor) {
582
-                foreach ($child->RoleDescriptor as $role) {
583
-                    if (in_array(get_class($role), $enabled_roles)) {
584
-                        // we found a role descriptor that is enabled by our filters, check protocols
585
-                        if (array_intersect($enabled_protos, $role->protocolSupportEnumeration) !== []) {
586
-                            // it supports some protocol we have enabled, add it
587
-                            $filtered[] = $child;
588
-                            break;
589
-                        }
590
-                    }
591
-                }
592
-
593
-            }
594
-
595
-            if ($child instanceof EntitiesDescriptor) {
596
-                $filtered[] = $this->filter($child);
597
-            }
598
-        }
599
-
600
-        $descriptor->children = $filtered;
601
-        return $descriptor;
602
-    }
603
-
604
-
605
-    /**
606
-     * Set this aggregator to exclude a set of entities from the resulting aggregate.
607
-     *
608
-     * @param array|null $entities The entity IDs of the entities to exclude.
609
-     */
610
-    public function excludeEntities($entities)
611
-    {
612
-        assert('is_array($entities) || is_null($entities)');
613
-
614
-        if ($entities === null) {
615
-            return;
616
-        }
617
-        $this->excluded = $entities;
618
-        sort($this->excluded);
619
-        $this->cacheId = sha1($this->cacheId.serialize($this->excluded));
620
-    }
621
-
622
-
623
-    /**
624
-     * Set the internal filters according to one or more options:
625
-     *
626
-     * - 'saml2': all SAML2.0-capable entities.
627
-     * - 'shib13': all SHIB1.3-capable entities.
628
-     * - 'saml20-idp': all SAML2.0-capable identity providers.
629
-     * - 'saml20-sp': all SAML2.0-capable service providers.
630
-     * - 'saml20-aa': all SAML2.0-capable attribute authorities.
631
-     * - 'shib13-idp': all SHIB1.3-capable identity providers.
632
-     * - 'shib13-sp': all SHIB1.3-capable service providers.
633
-     * - 'shib13-aa': all SHIB1.3-capable attribute authorities.
634
-     *
635
-     * @param array|null $set An array of the different roles and protocols to filter by.
636
-     */
637
-    public function setFilters($set)
638
-    {
639
-        assert('is_array($set) || is_null($set)');
640
-
641
-        if ($set === null) {
642
-            return;
643
-        }
644
-
645
-        // configure filters
646
-        $this->protocols = [
647
-            SAML2_Const::NS_SAMLP                  => true,
648
-            'urn:oasis:names:tc:SAML:1.1:protocol' => true,
649
-        ];
650
-        $this->roles = [
651
-            'SAML2_XML_md_IDPSSODescriptor'             => true,
652
-            'SAML2_XML_md_SPSSODescriptor'              => true,
653
-            'SAML2_XML_md_AttributeAuthorityDescriptor' => true,
654
-        ];
655
-
656
-        // now translate from the options we have, to specific protocols and roles
657
-
658
-        // check SAML 2.0 protocol
659
-        $options = ['saml2', 'saml20-idp', 'saml20-sp', 'saml20-aa'];
660
-        $this->protocols[SAML2_Const::NS_SAMLP] = (array_intersect($set, $options) !== []);
661
-
662
-        // check SHIB 1.3 protocol
663
-        $options = ['shib13', 'shib13-idp', 'shib13-sp', 'shib13-aa'];
664
-        $this->protocols['urn:oasis:names:tc:SAML:1.1:protocol'] = (array_intersect($set, $options) !== []);
665
-
666
-        // check IdP
667
-        $options = ['saml2', 'shib13', 'saml20-idp', 'shib13-idp'];
668
-        $this->roles['SAML2_XML_md_IDPSSODescriptor'] = (array_intersect($set, $options) !== []);
669
-
670
-        // check SP
671
-        $options = ['saml2', 'shib13', 'saml20-sp', 'shib13-sp'];
672
-        $this->roles['SAML2_XML_md_SPSSODescriptor'] = (array_intersect($set, $options) !== []);
673
-
674
-        // check AA
675
-        $options = ['saml2', 'shib13', 'saml20-aa', 'shib13-aa'];
676
-        $this->roles['SAML2_XML_md_AttributeAuthorityDescriptor'] = (array_intersect($set, $options) !== []);
677
-
678
-        $this->cacheId = sha1($this->cacheId.serialize($this->protocols).serialize($this->roles));
679
-    }
680
-
681
-
682
-    /**
683
-     * Retrieve the complete, signed metadata as text.
684
-     *
685
-     * This function will write the new metadata to the cache file, but will not return
686
-     * the cached metadata.
687
-     *
688
-     * @return string  The metadata, as text.
689
-     */
690
-    public function updateCachedMetadata()
691
-    {
692
-        $ed = $this->getEntitiesDescriptor();
693
-        $ed = $this->exclude($ed);
694
-        $ed = $this->filter($ed);
695
-        $this->addSignature($ed);
696
-
697
-        $xml = $ed->toXML();
698
-        $xml = $xml->ownerDocument->saveXML($xml);
699
-
700
-        if ($this->cacheGenerated !== null) {
701
-            Logger::debug($this->logLoc.'Saving generated metadata to cache.');
702
-            $this->addCacheItem($this->cacheId, $xml, time() + $this->cacheGenerated, $this->cacheTag);
703
-        }
704
-
705
-        return $xml;
706
-    }
707
-
708
-
709
-    /**
710
-     * Retrieve the complete, signed metadata as text.
711
-     *
712
-     * @return string  The metadata, as text.
713
-     */
714
-    public function getMetadata()
715
-    {
716
-        if ($this->cacheGenerated !== null) {
717
-            $xml = $this->getCacheItem($this->cacheId, $this->cacheTag);
718
-            if ($xml !== null) {
719
-                Logger::debug($this->logLoc.'Loaded generated metadata from cache.');
720
-                return $xml;
721
-            }
722
-        }
723
-
724
-        return $this->updateCachedMetadata();
725
-    }
726
-
727
-
728
-    /**
729
-     * Update the cached copy of our metadata.
730
-     */
731
-    public function updateCache()
732
-    {
733
-        foreach ($this->sources as $source) {
734
-            $source->updateCache();
735
-        }
736
-
737
-        $this->updateCachedMetadata();
738
-    }
25
+	/**
26
+	 * The list of signature algorithms supported by the aggregator.
27
+	 *
28
+	 * @var array
29
+	 */
30
+	public static $SUPPORTED_SIGNATURE_ALGORITHMS = [
31
+		XMLSecurityKey::RSA_SHA1,
32
+		XMLSecurityKey::RSA_SHA256,
33
+		XMLSecurityKey::RSA_SHA384,
34
+		XMLSecurityKey::RSA_SHA512,
35
+	];
36
+
37
+	/**
38
+	 * The ID of this aggregator.
39
+	 *
40
+	 * @var string
41
+	 */
42
+	protected $id;
43
+
44
+	/**
45
+	 * Our log "location".
46
+	 *
47
+	 * @var string
48
+	 */
49
+	protected $logLoc;
50
+
51
+	/**
52
+	 * Which cron-tag this should be updated in.
53
+	 *
54
+	 * @var string|null
55
+	 */
56
+	protected $cronTag;
57
+
58
+	/**
59
+	 * Absolute path to a cache directory.
60
+	 *
61
+	 * @var string|null
62
+	 */
63
+	protected $cacheDirectory;
64
+
65
+	/**
66
+	 * The entity sources.
67
+	 *
68
+	 * Array of sspmod_aggregator2_EntitySource objects.
69
+	 *
70
+	 * @var array
71
+	 */
72
+	protected $sources = [];
73
+
74
+	/**
75
+	 * How long the generated metadata should be valid, as a number of seconds.
76
+	 *
77
+	 * This is used to set the validUntil attribute on the generated EntityDescriptor.
78
+	 *
79
+	 * @var int
80
+	 */
81
+	protected $validLength;
82
+
83
+	/**
84
+	 * Duration we should cache generated metadata.
85
+	 *
86
+	 * @var int
87
+	 */
88
+	protected $cacheGenerated;
89
+
90
+	/**
91
+	 * An array of entity IDs to exclude from the aggregate.
92
+	 *
93
+	 * @var string[]|null
94
+	 */
95
+	protected $excluded;
96
+
97
+	/**
98
+	 * An indexed array of protocols to filter the aggregate by. keys can be any of:
99
+	 *
100
+	 * - urn:oasis:names:tc:SAML:1.1:protocol
101
+	 * - urn:oasis:names:tc:SAML:2.0:protocol
102
+	 *
103
+	 * Values will be true if enabled, false otherwise.
104
+	 *
105
+	 * @var string[]|null
106
+	 */
107
+	protected $protocols;
108
+
109
+	/**
110
+	 * An array of roles to filter the aggregate by. Keys can be any of:
111
+	 *
112
+	 * - SAML2_XML_md_IDPSSODescriptor
113
+	 * - SAML2_XML_md_SPSSODescriptor
114
+	 * - SAML2_XML_md_AttributeAuthorityDescriptor
115
+	 *
116
+	 * Values will be true if enabled, false otherwise.
117
+	 *
118
+	 * @var string[]|null
119
+	 */
120
+	protected $roles;
121
+
122
+	/**
123
+	 * The key we should use to sign the metadata.
124
+	 *
125
+	 * @var string|null
126
+	 */
127
+	protected $signKey;
128
+
129
+	/**
130
+	 * The password for the private key.
131
+	 *
132
+	 * @var string|null
133
+	 */
134
+	protected $signKeyPass;
135
+
136
+	/**
137
+	 * The certificate of the key we sign the metadata with.
138
+	 *
139
+	 * @var string|null
140
+	 */
141
+	protected $signCert;
142
+
143
+	/**
144
+	 * The algorithm to use for metadata signing.
145
+	 *
146
+	 * @var string|null
147
+	 */
148
+	protected $signAlg;
149
+
150
+	/**
151
+	 * The CA certificate file that should be used to validate https-connections.
152
+	 *
153
+	 * @var string|null
154
+	 */
155
+	protected $sslCAFile;
156
+
157
+	/**
158
+	 * The cache ID for our generated metadata.
159
+	 *
160
+	 * @var string
161
+	 */
162
+	protected $cacheId;
163
+
164
+	/**
165
+	 * The cache tag for our generated metadata.
166
+	 *
167
+	 * This tag is used to make sure that a config change
168
+	 * invalidates our cached metadata.
169
+	 *
170
+	 * @var string
171
+	 */
172
+	protected $cacheTag;
173
+
174
+	/**
175
+	 * The registration information for our generated metadata.
176
+	 *
177
+	 * @var array
178
+	 */
179
+	protected $regInfo;
180
+
181
+
182
+	/**
183
+	 * Initialize this aggregator.
184
+	 *
185
+	 * @param string $id  The id of this aggregator.
186
+	 * @param \SimpleSAML\Configuration $config  The configuration for this aggregator.
187
+	 */
188
+	protected function __construct($id, Configuration $config)
189
+	{
190
+		assert('is_string($id)');
191
+
192
+		$this->id = $id;
193
+		$this->logLoc = 'aggregator2:'.$this->id.': ';
194
+
195
+		$this->cronTag = $config->getString('cron.tag', null);
196
+
197
+		$this->cacheDirectory = $config->getString('cache.directory', null);
198
+		if ($this->cacheDirectory !== null) {
199
+			$this->cacheDirectory = System::resolvePath($this->cacheDirectory);
200
+		}
201
+
202
+		$this->cacheGenerated = $config->getInteger('cache.generated', null);
203
+		if ($this->cacheGenerated !== null) {
204
+			$this->cacheId = sha1($this->id);
205
+			$this->cacheTag = sha1(serialize($config));
206
+		}
207
+
208
+		// configure entity IDs excluded by default
209
+		$this->excludeEntities($config->getArrayize('exclude', null));
210
+
211
+		// configure filters
212
+		$this->setFilters($config->getArrayize('filter', null));
213
+
214
+		$this->validLength = $config->getInteger('valid.length', 7*24*60*60);
215
+
216
+		$globalConfig = Configuration::getInstance();
217
+		$certDir = $globalConfig->getPathValue('certdir', 'cert/');
218
+
219
+		$signKey = $config->getString('sign.privatekey', null);
220
+		if ($signKey !== null) {
221
+			$signKey = System::resolvePath($signKey, $certDir);
222
+			$this->signKey = @file_get_contents($signKey);
223
+			if ($this->signKey === null) {
224
+				throw new Exception('Unable to load private key from '.var_export($signKey, true));
225
+			}
226
+		}
227
+
228
+		$this->signKeyPass = $config->getString('sign.privatekey_pass', null);
229
+
230
+		$signCert = $config->getString('sign.certificate', null);
231
+		if ($signCert !== null) {
232
+			$signCert = System::resolvePath($signCert, $certDir);
233
+			$this->signCert = @file_get_contents($signCert);
234
+			if ($this->signCert === null) {
235
+				throw new Exception('Unable to load certificate file from '.var_export($signCert, true));
236
+			}
237
+		}
238
+
239
+		$this->signAlg = $config->getString('sign.algorithm', XMLSecurityKey::RSA_SHA1);
240
+		if (!in_array($this->signAlg, self::$SUPPORTED_SIGNATURE_ALGORITHMS)) {
241
+			throw new Exception('Unsupported signature algorithm '.var_export($this->signAlg, true));
242
+		}
243
+
244
+		$this->sslCAFile = $config->getString('ssl.cafile', null);
245
+
246
+		$this->regInfo = $config->getArray('RegistrationInfo', null);
247
+
248
+		$this->initSources($config->getConfigList('sources'));
249
+	}
250
+
251
+
252
+	/**
253
+	 * Populate the sources array.
254
+	 *
255
+	 * This is called from the constructor, and can be overridden in subclasses.
256
+	 *
257
+	 * @param array $sources  The sources as an array of SimpleSAML_Configuration objects.
258
+	 */
259
+	protected function initSources(array $sources)
260
+	{
261
+		foreach ($sources as $source) {
262
+			$this->sources[] = new EntitySource($this, $source);
263
+		}
264
+	}
265
+
266
+
267
+	/**
268
+	 * Return an instance of the aggregator with the given id.
269
+	 *
270
+	 * @param string $id  The id of the aggregator.
271
+	 */
272
+	public static function getAggregator($id)
273
+	{
274
+		assert('is_string($id)');
275
+
276
+		$config = Configuration::getConfig('module_aggregator2.php');
277
+		return new Aggregator($id, $config->getConfigItem($id));
278
+	}
279
+
280
+
281
+	/**
282
+	 * Retrieve the ID of the aggregator.
283
+	 *
284
+	 * @return string  The ID of this aggregator.
285
+	 */
286
+	public function getId()
287
+	{
288
+		return $this->id;
289
+	}
290
+
291
+
292
+	/**
293
+	 * Add an item to the cache.
294
+	 *
295
+	 * @param string $id  The identifier of this data.
296
+	 * @param string $data  The data.
297
+	 * @param int $expires  The timestamp the data expires.
298
+	 * @param string|null $tag  An extra tag that can be used to verify the validity of the cached data.
299
+	 */
300
+	public function addCacheItem($id, $data, $expires, $tag = null)
301
+	{
302
+		assert('is_string($id)');
303
+		assert('is_string($data)');
304
+		assert('is_int($expires)');
305
+		assert('is_null($tag) || is_string($tag)');
306
+
307
+		$cacheFile = $this->cacheDirectory.'/'.$id;
308
+		try {
309
+			System::writeFile($cacheFile, $data);
310
+		} catch (\Exception $e) {
311
+			Logger::warning($this->logLoc.'Unable to write to cache file '.var_export($cacheFile, true));
312
+			return;
313
+		}
314
+
315
+		$expireInfo = (string)$expires;
316
+		if ($tag !== null) {
317
+			$expireInfo .= ':'.$tag;
318
+		}
319
+
320
+		$expireFile = $cacheFile.'.expire';
321
+		try {
322
+			System::writeFile($expireFile, $expireInfo);
323
+		} catch (\Exception $e) {
324
+			Logger::warning($this->logLoc.'Unable to write expiration info to '.var_export($expireFile, true));
325
+		}
326
+	}
327
+
328
+
329
+	/**
330
+	 * Check validity of cached data.
331
+	 *
332
+	 * @param string $id  The identifier of this data.
333
+	 * @param string $tag  The tag that was passed to addCacheItem.
334
+	 * @return bool  TRUE if the data is valid, FALSE if not.
335
+	 */
336
+	public function isCacheValid($id, $tag = null)
337
+	{
338
+		assert('is_string($id)');
339
+		assert('is_null($tag) || is_string($tag)');
340
+
341
+		$cacheFile = $this->cacheDirectory.'/'.$id;
342
+		if (!file_exists($cacheFile)) {
343
+			return false;
344
+		}
345
+
346
+		$expireFile = $cacheFile.'.expire';
347
+		if (!file_exists($expireFile)) {
348
+			return false;
349
+		}
350
+
351
+		$expireData = @file_get_contents($expireFile);
352
+		if ($expireData === false) {
353
+			return false;
354
+		}
355
+
356
+		$expireData = explode(':', $expireData, 2);
357
+
358
+		$expireTime = intval($expireData[0]);
359
+		if ($expireTime <= time()) {
360
+			return false;
361
+		}
362
+
363
+		if (count($expireData) === 1) {
364
+			$expireTag = null;
365
+		} else {
366
+			$expireTag = $expireData[1];
367
+		}
368
+		if ($expireTag !== $tag) {
369
+			return false;
370
+		}
371
+
372
+		return true;
373
+	}
374
+
375
+
376
+	/**
377
+	 * Get the cache item.
378
+	 *
379
+	 * @param string $id  The identifier of this data.
380
+	 * @param string $tag  The tag that was passed to addCacheItem.
381
+	 * @return string|null  The cache item, or NULL if it isn't cached or if it is expired.
382
+	 */
383
+	public function getCacheItem($id, $tag = null)
384
+	{
385
+		assert('is_string($id)');
386
+		assert('is_null($tag) || is_string($tag)');
387
+
388
+		if (!$this->isCacheValid($id, $tag)) {
389
+			return null;
390
+		}
391
+
392
+		$cacheFile = $this->cacheDirectory.'/'.$id;
393
+		return @file_get_contents($cacheFile);
394
+	}
395
+
396
+
397
+	/**
398
+	 * Get the cache filename for the specific id.
399
+	 *
400
+	 * @param string $id  The identifier of the cached data.
401
+	 * @return string|null  The filename, or NULL if the cache file doesn't exist.
402
+	 */
403
+	public function getCacheFile($id)
404
+	{
405
+		assert('is_string($id)');
406
+
407
+		$cacheFile = $this->cacheDirectory.'/'.$id;
408
+		if (!file_exists($cacheFile)) {
409
+			return null;
410
+		}
411
+
412
+		return $cacheFile;
413
+	}
414
+
415
+
416
+	/**
417
+	 * Retrieve the SSL CA file path, if it is set.
418
+	 *
419
+	 * @return string|null  The SSL CA file path.
420
+	 */
421
+	public function getCAFile()
422
+	{
423
+		return $this->sslCAFile;
424
+	}
425
+
426
+
427
+	/**
428
+	 * Sign the generated EntitiesDescriptor.
429
+	 */
430
+	protected function addSignature(SignedElement $element)
431
+	{
432
+		if ($this->signKey === null) {
433
+			return;
434
+		}
435
+
436
+		$privateKey = new XMLSecurityKey($this->signAlg, ['type' => 'private']);
437
+		if ($this->signKeyPass !== null) {
438
+			$privateKey->passphrase = $this->signKeyPass;
439
+		}
440
+		$privateKey->loadKey($this->signKey, false);
441
+
442
+		$element->setSignatureKey($privateKey);
443
+
444
+		if ($this->signCert !== null) {
445
+			$element->setCertificates([$this->signCert]);
446
+		}
447
+	}
448
+
449
+
450
+	/**
451
+	 * Recursively browse the children of an EntitiesDescriptor element looking for EntityDescriptor elements, and
452
+	 * return an array containing all of them.
453
+	 *
454
+	 * @param \SAML2\XML\md\EntitiesDescriptor $entity The source EntitiesDescriptor that holds the entities to extract.
455
+	 *
456
+	 * @return array An array containing all the EntityDescriptors found.
457
+	 */
458
+	private static function extractEntityDescriptors($entity)
459
+	{
460
+		assert('$entity instanceof EntitiesDescriptor');
461
+
462
+		if (!($entity instanceof EntitiesDescriptor)) {
463
+			return [];
464
+		}
465
+
466
+		$results = [];
467
+		foreach ($entity->children as $child) {
468
+			if ($child instanceof EntityDescriptor) {
469
+				$results[] = $child;
470
+				continue;
471
+			}
472
+
473
+			$results = array_merge($results, self::extractEntityDescriptors($child));
474
+		}
475
+		return $results;
476
+	}
477
+
478
+
479
+	/**
480
+	 * Retrieve all entities as an EntitiesDescriptor.
481
+	 *
482
+	 * @return \SAML2\XML\md\EntitiesDescriptor  The entities.
483
+	 */
484
+	protected function getEntitiesDescriptor()
485
+	{
486
+		$ret = new EntitiesDescriptor();
487
+		$now = time();
488
+
489
+		// add RegistrationInfo extension if enabled
490
+		if ($this->regInfo !== null) {
491
+			$ri = new RegistrationInfo();
492
+			$ri->registrationInstant = $now;
493
+			foreach ($this->regInfo as $riName => $riValues) {
494
+				switch ($riName) {
495
+					case 'authority':
496
+						$ri->registrationAuthority = $riValues;
497
+						break;
498
+					case 'instant':
499
+						$ri->registrationInstant = Utils::xsDateTimeToTimestamp($riValues);
500
+						break;
501
+					case 'policies':
502
+						$ri->RegistrationPolicy = $riValues;
503
+						break;
504
+				}
505
+			}
506
+			$ret->Extensions[] = $ri;
507
+		}
508
+
509
+		foreach ($this->sources as $source) {
510
+			$m = $source->getMetadata();
511
+			if ($m === NULL) {
512
+				continue;
513
+			}
514
+			if ($m instanceof EntityDescriptor) {
515
+				$ret->children[] = $m;
516
+			} elseif ($m instanceof EntitiesDescriptor) {
517
+				$ret->children = array_merge($ret->children, self::extractEntityDescriptors($m));
518
+			}
519
+		}
520
+
521
+		$ret->children = array_unique($ret->children, SORT_REGULAR);
522
+		$ret->validUntil = $now + $this->validLength;
523
+
524
+		return $ret;
525
+	}
526
+
527
+
528
+	/**
529
+	 * Recursively traverse the children of an EntitiesDescriptor, removing those entities listed in the $entities
530
+	 * property. Returns the EntitiesDescriptor with the entities filtered out.
531
+	 *
532
+	 * @param \SAML2\XML\md\EntitiesDescriptor $descriptor The EntitiesDescriptor from where to exclude entities.
533
+	 *
534
+	 * @return \SAML2\XML\md\EntitiesDescriptor The EntitiesDescriptor with excluded entities filtered out.
535
+	 */
536
+	protected function exclude(EntitiesDescriptor $descriptor)
537
+	{
538
+		if (empty($this->excluded)) {
539
+			return $descriptor;
540
+		}
541
+
542
+		$filtered = [];
543
+		foreach ($descriptor->children as $child) {
544
+			if ($child instanceof EntityDescriptor) {
545
+				if (in_array($child->entityID, $this->excluded)) {
546
+					continue;
547
+				}
548
+				$filtered[] = $child;
549
+			}
550
+
551
+			if ($child instanceof EntitiesDescriptor) {
552
+				$filtered[] = $this->exclude($child);
553
+			}
554
+		}
555
+
556
+		$descriptor->children = $filtered;
557
+		return $descriptor;
558
+	}
559
+
560
+
561
+	/**
562
+	 * Recursively traverse the children of an EntitiesDescriptor, keeping only those entities with the roles listed in
563
+	 * the $roles property, and support for the protocols listed in the $protocols property. Returns the
564
+	 * EntitiesDescriptor containing only those entities.
565
+	 *
566
+	 * @param \SAML2\XML\md\EntitiesDescriptor $descriptor The EntitiesDescriptor to filter.
567
+	 *
568
+	 * @return SAML2_XML_md_EntitiesDescriptor The EntitiesDescriptor with only the entities filtered.
569
+	 */
570
+	protected function filter(SAML2_XML_md_EntitiesDescriptor $descriptor)
571
+	{
572
+		if ($this->roles === null || $this->protocols === null) {
573
+			return $descriptor;
574
+		}
575
+
576
+		$enabled_roles = array_keys($this->roles, true);
577
+		$enabled_protos = array_keys($this->protocols, true);
578
+
579
+		$filtered = [];
580
+		foreach ($descriptor->children as $child) {
581
+			if ($child instanceof EntityDescriptor) {
582
+				foreach ($child->RoleDescriptor as $role) {
583
+					if (in_array(get_class($role), $enabled_roles)) {
584
+						// we found a role descriptor that is enabled by our filters, check protocols
585
+						if (array_intersect($enabled_protos, $role->protocolSupportEnumeration) !== []) {
586
+							// it supports some protocol we have enabled, add it
587
+							$filtered[] = $child;
588
+							break;
589
+						}
590
+					}
591
+				}
592
+
593
+			}
594
+
595
+			if ($child instanceof EntitiesDescriptor) {
596
+				$filtered[] = $this->filter($child);
597
+			}
598
+		}
599
+
600
+		$descriptor->children = $filtered;
601
+		return $descriptor;
602
+	}
603
+
604
+
605
+	/**
606
+	 * Set this aggregator to exclude a set of entities from the resulting aggregate.
607
+	 *
608
+	 * @param array|null $entities The entity IDs of the entities to exclude.
609
+	 */
610
+	public function excludeEntities($entities)
611
+	{
612
+		assert('is_array($entities) || is_null($entities)');
613
+
614
+		if ($entities === null) {
615
+			return;
616
+		}
617
+		$this->excluded = $entities;
618
+		sort($this->excluded);
619
+		$this->cacheId = sha1($this->cacheId.serialize($this->excluded));
620
+	}
621
+
622
+
623
+	/**
624
+	 * Set the internal filters according to one or more options:
625
+	 *
626
+	 * - 'saml2': all SAML2.0-capable entities.
627
+	 * - 'shib13': all SHIB1.3-capable entities.
628
+	 * - 'saml20-idp': all SAML2.0-capable identity providers.
629
+	 * - 'saml20-sp': all SAML2.0-capable service providers.
630
+	 * - 'saml20-aa': all SAML2.0-capable attribute authorities.
631
+	 * - 'shib13-idp': all SHIB1.3-capable identity providers.
632
+	 * - 'shib13-sp': all SHIB1.3-capable service providers.
633
+	 * - 'shib13-aa': all SHIB1.3-capable attribute authorities.
634
+	 *
635
+	 * @param array|null $set An array of the different roles and protocols to filter by.
636
+	 */
637
+	public function setFilters($set)
638
+	{
639
+		assert('is_array($set) || is_null($set)');
640
+
641
+		if ($set === null) {
642
+			return;
643
+		}
644
+
645
+		// configure filters
646
+		$this->protocols = [
647
+			SAML2_Const::NS_SAMLP                  => true,
648
+			'urn:oasis:names:tc:SAML:1.1:protocol' => true,
649
+		];
650
+		$this->roles = [
651
+			'SAML2_XML_md_IDPSSODescriptor'             => true,
652
+			'SAML2_XML_md_SPSSODescriptor'              => true,
653
+			'SAML2_XML_md_AttributeAuthorityDescriptor' => true,
654
+		];
655
+
656
+		// now translate from the options we have, to specific protocols and roles
657
+
658
+		// check SAML 2.0 protocol
659
+		$options = ['saml2', 'saml20-idp', 'saml20-sp', 'saml20-aa'];
660
+		$this->protocols[SAML2_Const::NS_SAMLP] = (array_intersect($set, $options) !== []);
661
+
662
+		// check SHIB 1.3 protocol
663
+		$options = ['shib13', 'shib13-idp', 'shib13-sp', 'shib13-aa'];
664
+		$this->protocols['urn:oasis:names:tc:SAML:1.1:protocol'] = (array_intersect($set, $options) !== []);
665
+
666
+		// check IdP
667
+		$options = ['saml2', 'shib13', 'saml20-idp', 'shib13-idp'];
668
+		$this->roles['SAML2_XML_md_IDPSSODescriptor'] = (array_intersect($set, $options) !== []);
669
+
670
+		// check SP
671
+		$options = ['saml2', 'shib13', 'saml20-sp', 'shib13-sp'];
672
+		$this->roles['SAML2_XML_md_SPSSODescriptor'] = (array_intersect($set, $options) !== []);
673
+
674
+		// check AA
675
+		$options = ['saml2', 'shib13', 'saml20-aa', 'shib13-aa'];
676
+		$this->roles['SAML2_XML_md_AttributeAuthorityDescriptor'] = (array_intersect($set, $options) !== []);
677
+
678
+		$this->cacheId = sha1($this->cacheId.serialize($this->protocols).serialize($this->roles));
679
+	}
680
+
681
+
682
+	/**
683
+	 * Retrieve the complete, signed metadata as text.
684
+	 *
685
+	 * This function will write the new metadata to the cache file, but will not return
686
+	 * the cached metadata.
687
+	 *
688
+	 * @return string  The metadata, as text.
689
+	 */
690
+	public function updateCachedMetadata()
691
+	{
692
+		$ed = $this->getEntitiesDescriptor();
693
+		$ed = $this->exclude($ed);
694
+		$ed = $this->filter($ed);
695
+		$this->addSignature($ed);
696
+
697
+		$xml = $ed->toXML();
698
+		$xml = $xml->ownerDocument->saveXML($xml);
699
+
700
+		if ($this->cacheGenerated !== null) {
701
+			Logger::debug($this->logLoc.'Saving generated metadata to cache.');
702
+			$this->addCacheItem($this->cacheId, $xml, time() + $this->cacheGenerated, $this->cacheTag);
703
+		}
704
+
705
+		return $xml;
706
+	}
707
+
708
+
709
+	/**
710
+	 * Retrieve the complete, signed metadata as text.
711
+	 *
712
+	 * @return string  The metadata, as text.
713
+	 */
714
+	public function getMetadata()
715
+	{
716
+		if ($this->cacheGenerated !== null) {
717
+			$xml = $this->getCacheItem($this->cacheId, $this->cacheTag);
718
+			if ($xml !== null) {
719
+				Logger::debug($this->logLoc.'Loaded generated metadata from cache.');
720
+				return $xml;
721
+			}
722
+		}
723
+
724
+		return $this->updateCachedMetadata();
725
+	}
726
+
727
+
728
+	/**
729
+	 * Update the cached copy of our metadata.
730
+	 */
731
+	public function updateCache()
732
+	{
733
+		foreach ($this->sources as $source) {
734
+			$source->updateCache();
735
+		}
736
+
737
+		$this->updateCachedMetadata();
738
+	}
739 739
 }
Please login to merge, or discard this patch.
Spacing   +18 added lines, -18 removed lines patch added patch discarded remove patch
@@ -190,7 +190,7 @@  discard block
 block discarded – undo
190 190
         assert('is_string($id)');
191 191
 
192 192
         $this->id = $id;
193
-        $this->logLoc = 'aggregator2:'.$this->id.': ';
193
+        $this->logLoc = 'aggregator2:' . $this->id . ': ';
194 194
 
195 195
         $this->cronTag = $config->getString('cron.tag', null);
196 196
 
@@ -221,7 +221,7 @@  discard block
 block discarded – undo
221 221
             $signKey = System::resolvePath($signKey, $certDir);
222 222
             $this->signKey = @file_get_contents($signKey);
223 223
             if ($this->signKey === null) {
224
-                throw new Exception('Unable to load private key from '.var_export($signKey, true));
224
+                throw new Exception('Unable to load private key from ' . var_export($signKey, true));
225 225
             }
226 226
         }
227 227
 
@@ -232,13 +232,13 @@  discard block
 block discarded – undo
232 232
             $signCert = System::resolvePath($signCert, $certDir);
233 233
             $this->signCert = @file_get_contents($signCert);
234 234
             if ($this->signCert === null) {
235
-                throw new Exception('Unable to load certificate file from '.var_export($signCert, true));
235
+                throw new Exception('Unable to load certificate file from ' . var_export($signCert, true));
236 236
             }
237 237
         }
238 238
 
239 239
         $this->signAlg = $config->getString('sign.algorithm', XMLSecurityKey::RSA_SHA1);
240 240
         if (!in_array($this->signAlg, self::$SUPPORTED_SIGNATURE_ALGORITHMS)) {
241
-            throw new Exception('Unsupported signature algorithm '.var_export($this->signAlg, true));
241
+            throw new Exception('Unsupported signature algorithm ' . var_export($this->signAlg, true));
242 242
         }
243 243
 
244 244
         $this->sslCAFile = $config->getString('ssl.cafile', null);
@@ -304,24 +304,24 @@  discard block
 block discarded – undo
304 304
         assert('is_int($expires)');
305 305
         assert('is_null($tag) || is_string($tag)');
306 306
 
307
-        $cacheFile = $this->cacheDirectory.'/'.$id;
307
+        $cacheFile = $this->cacheDirectory . '/' . $id;
308 308
         try {
309 309
             System::writeFile($cacheFile, $data);
310 310
         } catch (\Exception $e) {
311
-            Logger::warning($this->logLoc.'Unable to write to cache file '.var_export($cacheFile, true));
311
+            Logger::warning($this->logLoc . 'Unable to write to cache file ' . var_export($cacheFile, true));
312 312
             return;
313 313
         }
314 314
 
315
-        $expireInfo = (string)$expires;
315
+        $expireInfo = (string) $expires;
316 316
         if ($tag !== null) {
317
-            $expireInfo .= ':'.$tag;
317
+            $expireInfo .= ':' . $tag;
318 318
         }
319 319
 
320
-        $expireFile = $cacheFile.'.expire';
320
+        $expireFile = $cacheFile . '.expire';
321 321
         try {
322 322
             System::writeFile($expireFile, $expireInfo);
323 323
         } catch (\Exception $e) {
324
-            Logger::warning($this->logLoc.'Unable to write expiration info to '.var_export($expireFile, true));
324
+            Logger::warning($this->logLoc . 'Unable to write expiration info to ' . var_export($expireFile, true));
325 325
         }
326 326
     }
327 327
 
@@ -338,12 +338,12 @@  discard block
 block discarded – undo
338 338
         assert('is_string($id)');
339 339
         assert('is_null($tag) || is_string($tag)');
340 340
 
341
-        $cacheFile = $this->cacheDirectory.'/'.$id;
341
+        $cacheFile = $this->cacheDirectory . '/' . $id;
342 342
         if (!file_exists($cacheFile)) {
343 343
             return false;
344 344
         }
345 345
 
346
-        $expireFile = $cacheFile.'.expire';
346
+        $expireFile = $cacheFile . '.expire';
347 347
         if (!file_exists($expireFile)) {
348 348
             return false;
349 349
         }
@@ -389,7 +389,7 @@  discard block
 block discarded – undo
389 389
             return null;
390 390
         }
391 391
 
392
-        $cacheFile = $this->cacheDirectory.'/'.$id;
392
+        $cacheFile = $this->cacheDirectory . '/' . $id;
393 393
         return @file_get_contents($cacheFile);
394 394
     }
395 395
 
@@ -404,7 +404,7 @@  discard block
 block discarded – undo
404 404
     {
405 405
         assert('is_string($id)');
406 406
 
407
-        $cacheFile = $this->cacheDirectory.'/'.$id;
407
+        $cacheFile = $this->cacheDirectory . '/' . $id;
408 408
         if (!file_exists($cacheFile)) {
409 409
             return null;
410 410
         }
@@ -616,7 +616,7 @@  discard block
 block discarded – undo
616 616
         }
617 617
         $this->excluded = $entities;
618 618
         sort($this->excluded);
619
-        $this->cacheId = sha1($this->cacheId.serialize($this->excluded));
619
+        $this->cacheId = sha1($this->cacheId . serialize($this->excluded));
620 620
     }
621 621
 
622 622
 
@@ -675,7 +675,7 @@  discard block
 block discarded – undo
675 675
         $options = ['saml2', 'shib13', 'saml20-aa', 'shib13-aa'];
676 676
         $this->roles['SAML2_XML_md_AttributeAuthorityDescriptor'] = (array_intersect($set, $options) !== []);
677 677
 
678
-        $this->cacheId = sha1($this->cacheId.serialize($this->protocols).serialize($this->roles));
678
+        $this->cacheId = sha1($this->cacheId . serialize($this->protocols) . serialize($this->roles));
679 679
     }
680 680
 
681 681
 
@@ -698,7 +698,7 @@  discard block
 block discarded – undo
698 698
         $xml = $xml->ownerDocument->saveXML($xml);
699 699
 
700 700
         if ($this->cacheGenerated !== null) {
701
-            Logger::debug($this->logLoc.'Saving generated metadata to cache.');
701
+            Logger::debug($this->logLoc . 'Saving generated metadata to cache.');
702 702
             $this->addCacheItem($this->cacheId, $xml, time() + $this->cacheGenerated, $this->cacheTag);
703 703
         }
704 704
 
@@ -716,7 +716,7 @@  discard block
 block discarded – undo
716 716
         if ($this->cacheGenerated !== null) {
717 717
             $xml = $this->getCacheItem($this->cacheId, $this->cacheTag);
718 718
             if ($xml !== null) {
719
-                Logger::debug($this->logLoc.'Loaded generated metadata from cache.');
719
+                Logger::debug($this->logLoc . 'Loaded generated metadata from cache.');
720 720
                 return $xml;
721 721
             }
722 722
         }
Please login to merge, or discard this patch.
lib/EntitySource.php 2 patches
Indentation   +233 added lines, -233 removed lines patch added patch discarded remove patch
@@ -19,237 +19,237 @@
 block discarded – undo
19 19
  */
20 20
 class EntitySource
21 21
 {
22
-    /**
23
-     * Our log "location".
24
-     *
25
-     * @var string
26
-     */
27
-    protected $logLoc;
28
-
29
-    /**
30
-     * The aggregator we belong to.
31
-     *
32
-     * @var sspmod_aggregator2_Aggregator
33
-     */
34
-    protected $aggregator;
35
-
36
-    /**
37
-     * The URL we should fetch it from.
38
-     *
39
-     * @var string
40
-     */
41
-    protected $url;
42
-
43
-    /**
44
-     * The SSL CA file that should be used to validate the connection.
45
-     *
46
-     * @var string|null
47
-     */
48
-    protected $sslCAFile;
49
-
50
-    /**
51
-     * The certificate we should use to validate downloaded metadata.
52
-     *
53
-     * @var string|null
54
-     */
55
-    protected $certificate;
56
-
57
-    /**
58
-     * The parsed metadata.
59
-     *
60
-     * @var \SAML2\XML\md\EntitiesDescriptor|\SAML2\XML\md\EntityDescriptor|null
61
-     */
62
-    protected $metadata;
63
-
64
-    /**
65
-     * The cache ID.
66
-     *
67
-     * @var string
68
-     */
69
-    protected $cacheId;
70
-
71
-    /**
72
-     * The cache tag.
73
-     *
74
-     * @var string
75
-     */
76
-    protected $cacheTag;
77
-
78
-    /**
79
-     * Whether we have attempted to update the cache already.
80
-     *
81
-     * @var bool
82
-     */
83
-    protected $updateAttempted;
84
-
85
-
86
-    /**
87
-     * Initialize this EntitySource.
88
-     *
89
-     * @param \SimpleSAML\Configuration $config  The configuration.
90
-     */
91
-    public function __construct(Aggregator $aggregator, Configuration $config)
92
-    {
93
-        $this->logLoc = 'aggregator2:'.$aggregator->getId().': ';
94
-        $this->aggregator = $aggregator;
95
-
96
-        $this->url = $config->getString('url');
97
-        $this->sslCAFile = $config->getString('ssl.cafile', null);
98
-        if ($this->sslCAFile === null) {
99
-            $this->sslCAFile = $aggregator->getCAFile();
100
-        }
101
-
102
-        $this->certificate = $config->getString('cert', null);
103
-
104
-        $this->cacheId = sha1($this->url);
105
-        $this->cacheTag = sha1(serialize($config));
106
-    }
107
-
108
-
109
-    /**
110
-     * Retrieve and parse the metadata.
111
-     *
112
-     * @return \SAML2\XML\md\EntitiesDescriptor|\SAML2\XML\md\EntityDescriptor|null
113
-     * The downloaded metadata or NULL if we were unable to download or parse it.
114
-     */
115
-    private function downloadMetadata()
116
-    {
117
-        Logger::debug($this->logLoc.'Downloading metadata from '.var_export($this->url, true));
118
-
119
-        $context = ['ssl' => []];
120
-        if ($this->sslCAFile !== null) {
121
-            $context['ssl']['cafile'] = Config::getCertPath($this->sslCAFile);
122
-            SimpleSAML\Logger::debug($this->logLoc.'Validating https connection against CA certificate(s) found in '.
123
-                var_export($context['ssl']['cafile'], true));
124
-            $context['ssl']['verify_peer'] = true;
125
-            $context['ssl']['CN_match'] = parse_url($this->url, PHP_URL_HOST);
126
-        }
127
-
128
-        $data = HTTP::fetch($this->url, $context);
129
-        if ($data === false || $data === null) {
130
-            Logger::error($this->logLoc.'Unable to load metadata from '.var_export($this->url, true));
131
-            return null;
132
-        }
133
-
134
-        $doc = new DOMDocument();
135
-        $res = $doc->loadXML($data);
136
-        if (!$res) {
137
-            Logger::error($this->logLoc.'Error parsing XML from '.var_export($this->url, true));
138
-            return null;
139
-        }
140
-
141
-        $root = Utils::xpQuery($doc->firstChild, '/saml_metadata:EntityDescriptor|/saml_metadata:EntitiesDescriptor');
142
-        if (count($root) === 0) {
143
-            Logger::error($this->logLoc.'No <EntityDescriptor> or <EntitiesDescriptor> in metadata from '.
144
-                var_export($this->url, true));
145
-            return null;
146
-        }
147
-
148
-        if (count($root) > 1) {
149
-            Logger::error($this->logLoc.'More than one <EntityDescriptor> or <EntitiesDescriptor> in metadata from '.
150
-                var_export($this->url, true));
151
-            return null;
152
-        }
153
-
154
-        $root = $root[0];
155
-        try {
156
-            if ($root->localName === 'EntityDescriptor') {
157
-                $md = new EntityDescriptor($root);
158
-            } else {
159
-                $md = new EntitiesDescriptor($root);
160
-            }
161
-        } catch (\Exception $e) {
162
-            Logger::error($this->logLoc.'Unable to parse metadata from '.
163
-                var_export($this->url, true).': '.$e->getMessage());
164
-            return null;
165
-        }
166
-
167
-        if ($this->certificate !== null) {
168
-            $file = Config::getCertPath($this->certificate);
169
-            $certData = file_get_contents($file);
170
-            if ($certData === false) {
171
-                throw new Exception('Error loading certificate from '.var_export($file, true));
172
-            }
173
-
174
-            // Extract the public key from the certificate for validation
175
-            $key = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, ['type'=>'public']);
176
-            $key->loadKey($file, true);
177
-
178
-            if (!$md->validate($key)) {
179
-                Logger::error($this->logLoc.'Error validating signature on metadata.');
180
-                return null;
181
-            }
182
-            Logger::debug($this->logLoc.'Validated signature on metadata from '.var_export($this->url, true));
183
-        }
184
-
185
-        return $md;
186
-    }
187
-
188
-
189
-    /**
190
-     * Attempt to update our cache file.
191
-     */
192
-    public function updateCache()
193
-    {
194
-        if ($this->updateAttempted) {
195
-            return;
196
-        }
197
-        $this->updateAttempted = true;
198
-
199
-        $this->metadata = $this->downloadMetadata();
200
-        if ($this->metadata === null) {
201
-            return;
202
-        }
203
-
204
-        $expires = time() + 24*60*60; // Default expires in one day
205
-
206
-        if ($this->metadata->validUntil !== null && $this->metadata->validUntil < $expires) {
207
-            $expires = $this->metadata->validUntil;
208
-        }
209
-
210
-        $metadataSerialized = serialize($this->metadata);
211
-
212
-        $this->aggregator->addCacheItem($this->cacheId, $metadataSerialized, $expires, $this->cacheTag);
213
-    }
214
-
215
-
216
-    /**
217
-     * Retrieve the metadata file.
218
-     *
219
-     * This function will check its cached copy, to see whether it can be used.
220
-     *
221
-     * @return \SAML2\XML\md\EntityDescriptor|\SAML2\XML\md\EntitiesDescriptor|null  The downloaded metadata.
222
-     */
223
-    public function getMetadata()
224
-    {
225
-        if ($this->metadata !== null) {
226
-            /* We have already downloaded the metdata. */
227
-            return $this->metadata;
228
-        }
229
-
230
-        if (!$this->aggregator->isCacheValid($this->cacheId, $this->cacheTag)) {
231
-            $this->updateCache();
232
-            if ($this->metadata !== null) {
233
-                return $this->metadata;
234
-            }
235
-            /* We were unable to update the cache - use cached metadata. */
236
-        }
237
-
238
-        $cacheFile = $this->aggregator->getCacheFile($this->cacheId);
239
-
240
-        if (!file_exists($cacheFile)) {
241
-            Logger::error($this->logLoc . 'No cached metadata available.');
242
-            return null;
243
-        }
244
-
245
-        Logger::debug($this->logLoc.'Using cached metadata from '.var_export($cacheFile, true));
246
-
247
-        $metadata = file_get_contents($cacheFile);
248
-        if ($metadata !== null) {
249
-            $this->metadata = unserialize($metadata);
250
-            return $this->metadata;
251
-        }
252
-
253
-        return null;
254
-    }
22
+	/**
23
+	 * Our log "location".
24
+	 *
25
+	 * @var string
26
+	 */
27
+	protected $logLoc;
28
+
29
+	/**
30
+	 * The aggregator we belong to.
31
+	 *
32
+	 * @var sspmod_aggregator2_Aggregator
33
+	 */
34
+	protected $aggregator;
35
+
36
+	/**
37
+	 * The URL we should fetch it from.
38
+	 *
39
+	 * @var string
40
+	 */
41
+	protected $url;
42
+
43
+	/**
44
+	 * The SSL CA file that should be used to validate the connection.
45
+	 *
46
+	 * @var string|null
47
+	 */
48
+	protected $sslCAFile;
49
+
50
+	/**
51
+	 * The certificate we should use to validate downloaded metadata.
52
+	 *
53
+	 * @var string|null
54
+	 */
55
+	protected $certificate;
56
+
57
+	/**
58
+	 * The parsed metadata.
59
+	 *
60
+	 * @var \SAML2\XML\md\EntitiesDescriptor|\SAML2\XML\md\EntityDescriptor|null
61
+	 */
62
+	protected $metadata;
63
+
64
+	/**
65
+	 * The cache ID.
66
+	 *
67
+	 * @var string
68
+	 */
69
+	protected $cacheId;
70
+
71
+	/**
72
+	 * The cache tag.
73
+	 *
74
+	 * @var string
75
+	 */
76
+	protected $cacheTag;
77
+
78
+	/**
79
+	 * Whether we have attempted to update the cache already.
80
+	 *
81
+	 * @var bool
82
+	 */
83
+	protected $updateAttempted;
84
+
85
+
86
+	/**
87
+	 * Initialize this EntitySource.
88
+	 *
89
+	 * @param \SimpleSAML\Configuration $config  The configuration.
90
+	 */
91
+	public function __construct(Aggregator $aggregator, Configuration $config)
92
+	{
93
+		$this->logLoc = 'aggregator2:'.$aggregator->getId().': ';
94
+		$this->aggregator = $aggregator;
95
+
96
+		$this->url = $config->getString('url');
97
+		$this->sslCAFile = $config->getString('ssl.cafile', null);
98
+		if ($this->sslCAFile === null) {
99
+			$this->sslCAFile = $aggregator->getCAFile();
100
+		}
101
+
102
+		$this->certificate = $config->getString('cert', null);
103
+
104
+		$this->cacheId = sha1($this->url);
105
+		$this->cacheTag = sha1(serialize($config));
106
+	}
107
+
108
+
109
+	/**
110
+	 * Retrieve and parse the metadata.
111
+	 *
112
+	 * @return \SAML2\XML\md\EntitiesDescriptor|\SAML2\XML\md\EntityDescriptor|null
113
+	 * The downloaded metadata or NULL if we were unable to download or parse it.
114
+	 */
115
+	private function downloadMetadata()
116
+	{
117
+		Logger::debug($this->logLoc.'Downloading metadata from '.var_export($this->url, true));
118
+
119
+		$context = ['ssl' => []];
120
+		if ($this->sslCAFile !== null) {
121
+			$context['ssl']['cafile'] = Config::getCertPath($this->sslCAFile);
122
+			SimpleSAML\Logger::debug($this->logLoc.'Validating https connection against CA certificate(s) found in '.
123
+				var_export($context['ssl']['cafile'], true));
124
+			$context['ssl']['verify_peer'] = true;
125
+			$context['ssl']['CN_match'] = parse_url($this->url, PHP_URL_HOST);
126
+		}
127
+
128
+		$data = HTTP::fetch($this->url, $context);
129
+		if ($data === false || $data === null) {
130
+			Logger::error($this->logLoc.'Unable to load metadata from '.var_export($this->url, true));
131
+			return null;
132
+		}
133
+
134
+		$doc = new DOMDocument();
135
+		$res = $doc->loadXML($data);
136
+		if (!$res) {
137
+			Logger::error($this->logLoc.'Error parsing XML from '.var_export($this->url, true));
138
+			return null;
139
+		}
140
+
141
+		$root = Utils::xpQuery($doc->firstChild, '/saml_metadata:EntityDescriptor|/saml_metadata:EntitiesDescriptor');
142
+		if (count($root) === 0) {
143
+			Logger::error($this->logLoc.'No <EntityDescriptor> or <EntitiesDescriptor> in metadata from '.
144
+				var_export($this->url, true));
145
+			return null;
146
+		}
147
+
148
+		if (count($root) > 1) {
149
+			Logger::error($this->logLoc.'More than one <EntityDescriptor> or <EntitiesDescriptor> in metadata from '.
150
+				var_export($this->url, true));
151
+			return null;
152
+		}
153
+
154
+		$root = $root[0];
155
+		try {
156
+			if ($root->localName === 'EntityDescriptor') {
157
+				$md = new EntityDescriptor($root);
158
+			} else {
159
+				$md = new EntitiesDescriptor($root);
160
+			}
161
+		} catch (\Exception $e) {
162
+			Logger::error($this->logLoc.'Unable to parse metadata from '.
163
+				var_export($this->url, true).': '.$e->getMessage());
164
+			return null;
165
+		}
166
+
167
+		if ($this->certificate !== null) {
168
+			$file = Config::getCertPath($this->certificate);
169
+			$certData = file_get_contents($file);
170
+			if ($certData === false) {
171
+				throw new Exception('Error loading certificate from '.var_export($file, true));
172
+			}
173
+
174
+			// Extract the public key from the certificate for validation
175
+			$key = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, ['type'=>'public']);
176
+			$key->loadKey($file, true);
177
+
178
+			if (!$md->validate($key)) {
179
+				Logger::error($this->logLoc.'Error validating signature on metadata.');
180
+				return null;
181
+			}
182
+			Logger::debug($this->logLoc.'Validated signature on metadata from '.var_export($this->url, true));
183
+		}
184
+
185
+		return $md;
186
+	}
187
+
188
+
189
+	/**
190
+	 * Attempt to update our cache file.
191
+	 */
192
+	public function updateCache()
193
+	{
194
+		if ($this->updateAttempted) {
195
+			return;
196
+		}
197
+		$this->updateAttempted = true;
198
+
199
+		$this->metadata = $this->downloadMetadata();
200
+		if ($this->metadata === null) {
201
+			return;
202
+		}
203
+
204
+		$expires = time() + 24*60*60; // Default expires in one day
205
+
206
+		if ($this->metadata->validUntil !== null && $this->metadata->validUntil < $expires) {
207
+			$expires = $this->metadata->validUntil;
208
+		}
209
+
210
+		$metadataSerialized = serialize($this->metadata);
211
+
212
+		$this->aggregator->addCacheItem($this->cacheId, $metadataSerialized, $expires, $this->cacheTag);
213
+	}
214
+
215
+
216
+	/**
217
+	 * Retrieve the metadata file.
218
+	 *
219
+	 * This function will check its cached copy, to see whether it can be used.
220
+	 *
221
+	 * @return \SAML2\XML\md\EntityDescriptor|\SAML2\XML\md\EntitiesDescriptor|null  The downloaded metadata.
222
+	 */
223
+	public function getMetadata()
224
+	{
225
+		if ($this->metadata !== null) {
226
+			/* We have already downloaded the metdata. */
227
+			return $this->metadata;
228
+		}
229
+
230
+		if (!$this->aggregator->isCacheValid($this->cacheId, $this->cacheTag)) {
231
+			$this->updateCache();
232
+			if ($this->metadata !== null) {
233
+				return $this->metadata;
234
+			}
235
+			/* We were unable to update the cache - use cached metadata. */
236
+		}
237
+
238
+		$cacheFile = $this->aggregator->getCacheFile($this->cacheId);
239
+
240
+		if (!file_exists($cacheFile)) {
241
+			Logger::error($this->logLoc . 'No cached metadata available.');
242
+			return null;
243
+		}
244
+
245
+		Logger::debug($this->logLoc.'Using cached metadata from '.var_export($cacheFile, true));
246
+
247
+		$metadata = file_get_contents($cacheFile);
248
+		if ($metadata !== null) {
249
+			$this->metadata = unserialize($metadata);
250
+			return $this->metadata;
251
+		}
252
+
253
+		return null;
254
+	}
255 255
 }
Please login to merge, or discard this patch.
Spacing   +13 added lines, -13 removed lines patch added patch discarded remove patch
@@ -90,7 +90,7 @@  discard block
 block discarded – undo
90 90
      */
91 91
     public function __construct(Aggregator $aggregator, Configuration $config)
92 92
     {
93
-        $this->logLoc = 'aggregator2:'.$aggregator->getId().': ';
93
+        $this->logLoc = 'aggregator2:' . $aggregator->getId() . ': ';
94 94
         $this->aggregator = $aggregator;
95 95
 
96 96
         $this->url = $config->getString('url');
@@ -114,12 +114,12 @@  discard block
 block discarded – undo
114 114
      */
115 115
     private function downloadMetadata()
116 116
     {
117
-        Logger::debug($this->logLoc.'Downloading metadata from '.var_export($this->url, true));
117
+        Logger::debug($this->logLoc . 'Downloading metadata from ' . var_export($this->url, true));
118 118
 
119 119
         $context = ['ssl' => []];
120 120
         if ($this->sslCAFile !== null) {
121 121
             $context['ssl']['cafile'] = Config::getCertPath($this->sslCAFile);
122
-            SimpleSAML\Logger::debug($this->logLoc.'Validating https connection against CA certificate(s) found in '.
122
+            SimpleSAML\Logger::debug($this->logLoc . 'Validating https connection against CA certificate(s) found in ' .
123 123
                 var_export($context['ssl']['cafile'], true));
124 124
             $context['ssl']['verify_peer'] = true;
125 125
             $context['ssl']['CN_match'] = parse_url($this->url, PHP_URL_HOST);
@@ -127,26 +127,26 @@  discard block
 block discarded – undo
127 127
 
128 128
         $data = HTTP::fetch($this->url, $context);
129 129
         if ($data === false || $data === null) {
130
-            Logger::error($this->logLoc.'Unable to load metadata from '.var_export($this->url, true));
130
+            Logger::error($this->logLoc . 'Unable to load metadata from ' . var_export($this->url, true));
131 131
             return null;
132 132
         }
133 133
 
134 134
         $doc = new DOMDocument();
135 135
         $res = $doc->loadXML($data);
136 136
         if (!$res) {
137
-            Logger::error($this->logLoc.'Error parsing XML from '.var_export($this->url, true));
137
+            Logger::error($this->logLoc . 'Error parsing XML from ' . var_export($this->url, true));
138 138
             return null;
139 139
         }
140 140
 
141 141
         $root = Utils::xpQuery($doc->firstChild, '/saml_metadata:EntityDescriptor|/saml_metadata:EntitiesDescriptor');
142 142
         if (count($root) === 0) {
143
-            Logger::error($this->logLoc.'No <EntityDescriptor> or <EntitiesDescriptor> in metadata from '.
143
+            Logger::error($this->logLoc . 'No <EntityDescriptor> or <EntitiesDescriptor> in metadata from ' .
144 144
                 var_export($this->url, true));
145 145
             return null;
146 146
         }
147 147
 
148 148
         if (count($root) > 1) {
149
-            Logger::error($this->logLoc.'More than one <EntityDescriptor> or <EntitiesDescriptor> in metadata from '.
149
+            Logger::error($this->logLoc . 'More than one <EntityDescriptor> or <EntitiesDescriptor> in metadata from ' .
150 150
                 var_export($this->url, true));
151 151
             return null;
152 152
         }
@@ -159,8 +159,8 @@  discard block
 block discarded – undo
159 159
                 $md = new EntitiesDescriptor($root);
160 160
             }
161 161
         } catch (\Exception $e) {
162
-            Logger::error($this->logLoc.'Unable to parse metadata from '.
163
-                var_export($this->url, true).': '.$e->getMessage());
162
+            Logger::error($this->logLoc . 'Unable to parse metadata from ' .
163
+                var_export($this->url, true) . ': ' . $e->getMessage());
164 164
             return null;
165 165
         }
166 166
 
@@ -168,7 +168,7 @@  discard block
 block discarded – undo
168 168
             $file = Config::getCertPath($this->certificate);
169 169
             $certData = file_get_contents($file);
170 170
             if ($certData === false) {
171
-                throw new Exception('Error loading certificate from '.var_export($file, true));
171
+                throw new Exception('Error loading certificate from ' . var_export($file, true));
172 172
             }
173 173
 
174 174
             // Extract the public key from the certificate for validation
@@ -176,10 +176,10 @@  discard block
 block discarded – undo
176 176
             $key->loadKey($file, true);
177 177
 
178 178
             if (!$md->validate($key)) {
179
-                Logger::error($this->logLoc.'Error validating signature on metadata.');
179
+                Logger::error($this->logLoc . 'Error validating signature on metadata.');
180 180
                 return null;
181 181
             }
182
-            Logger::debug($this->logLoc.'Validated signature on metadata from '.var_export($this->url, true));
182
+            Logger::debug($this->logLoc . 'Validated signature on metadata from ' . var_export($this->url, true));
183 183
         }
184 184
 
185 185
         return $md;
@@ -242,7 +242,7 @@  discard block
 block discarded – undo
242 242
             return null;
243 243
         }
244 244
 
245
-        Logger::debug($this->logLoc.'Using cached metadata from '.var_export($cacheFile, true));
245
+        Logger::debug($this->logLoc . 'Using cached metadata from ' . var_export($cacheFile, true));
246 246
 
247 247
         $metadata = file_get_contents($cacheFile);
248 248
         if ($metadata !== null) {
Please login to merge, or discard this patch.
templates/list.php 2 patches
Indentation   +20 added lines, -20 removed lines patch added patch discarded remove patch
@@ -6,29 +6,29 @@
 block discarded – undo
6 6
 
7 7
 <?php
8 8
 if (count($this->data['sources']) === 0) {
9
-    echo "    <p>".$this->t('{aggregator2:aggregator:no_aggregators}')."</p>\n";
9
+	echo "    <p>".$this->t('{aggregator2:aggregator:no_aggregators}')."</p>\n";
10 10
 } else {
11
-    echo "    <ul>";
11
+	echo "    <ul>";
12 12
 
13
-    foreach ($this->data['sources'] as $id => $source) {
14
-        $encId = urlencode($id);
15
-        $params = [
16
-            'id' => $encId,
17
-        ];
18
-        echo str_repeat(' ', 8)."<li>\n";
19
-        echo str_repeat(' ', 12).'<a href="';
20
-        echo SimpleSAML\Module::getModuleURL('aggregator2/get.php', $params).'">'.htmlspecialchars($id)."</a>\n";
21
-        echo str_repeat(' ', 12).'<a href="';
22
-        $params['mimetype'] = 'text/plain';
23
-        echo SimpleSAML\Module::getModuleURL('aggregator2/get.php', $params).'">['.
24
-            $this->t('{aggregator2:aggregator:text}')."]</a>\n";
25
-        echo str_repeat(' ', 12).'<a href="';
26
-        $params['mimetype'] = 'application/xml';
27
-        echo SimpleSAML\Module::getModuleURL('aggregator2/get.php', $params)."\">[XML]</a>\n";
28
-        echo str_repeat(' ', 8)."</li>\n";
29
-    }
13
+	foreach ($this->data['sources'] as $id => $source) {
14
+		$encId = urlencode($id);
15
+		$params = [
16
+			'id' => $encId,
17
+		];
18
+		echo str_repeat(' ', 8)."<li>\n";
19
+		echo str_repeat(' ', 12).'<a href="';
20
+		echo SimpleSAML\Module::getModuleURL('aggregator2/get.php', $params).'">'.htmlspecialchars($id)."</a>\n";
21
+		echo str_repeat(' ', 12).'<a href="';
22
+		$params['mimetype'] = 'text/plain';
23
+		echo SimpleSAML\Module::getModuleURL('aggregator2/get.php', $params).'">['.
24
+			$this->t('{aggregator2:aggregator:text}')."]</a>\n";
25
+		echo str_repeat(' ', 12).'<a href="';
26
+		$params['mimetype'] = 'application/xml';
27
+		echo SimpleSAML\Module::getModuleURL('aggregator2/get.php', $params)."\">[XML]</a>\n";
28
+		echo str_repeat(' ', 8)."</li>\n";
29
+	}
30 30
 
31
-    echo "    </ul>\n";
31
+	echo "    </ul>\n";
32 32
 }
33 33
 
34 34
 $this->includeAtTemplateBase('includes/footer.php');
Please login to merge, or discard this patch.
Spacing   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -6,7 +6,7 @@  discard block
 block discarded – undo
6 6
 
7 7
 <?php
8 8
 if (count($this->data['sources']) === 0) {
9
-    echo "    <p>".$this->t('{aggregator2:aggregator:no_aggregators}')."</p>\n";
9
+    echo "    <p>" . $this->t('{aggregator2:aggregator:no_aggregators}') . "</p>\n";
10 10
 } else {
11 11
     echo "    <ul>";
12 12
 
@@ -15,17 +15,17 @@  discard block
 block discarded – undo
15 15
         $params = [
16 16
             'id' => $encId,
17 17
         ];
18
-        echo str_repeat(' ', 8)."<li>\n";
19
-        echo str_repeat(' ', 12).'<a href="';
20
-        echo SimpleSAML\Module::getModuleURL('aggregator2/get.php', $params).'">'.htmlspecialchars($id)."</a>\n";
21
-        echo str_repeat(' ', 12).'<a href="';
18
+        echo str_repeat(' ', 8) . "<li>\n";
19
+        echo str_repeat(' ', 12) . '<a href="';
20
+        echo SimpleSAML\Module::getModuleURL('aggregator2/get.php', $params) . '">' . htmlspecialchars($id) . "</a>\n";
21
+        echo str_repeat(' ', 12) . '<a href="';
22 22
         $params['mimetype'] = 'text/plain';
23
-        echo SimpleSAML\Module::getModuleURL('aggregator2/get.php', $params).'">['.
24
-            $this->t('{aggregator2:aggregator:text}')."]</a>\n";
25
-        echo str_repeat(' ', 12).'<a href="';
23
+        echo SimpleSAML\Module::getModuleURL('aggregator2/get.php', $params) . '">[' .
24
+            $this->t('{aggregator2:aggregator:text}') . "]</a>\n";
25
+        echo str_repeat(' ', 12) . '<a href="';
26 26
         $params['mimetype'] = 'application/xml';
27
-        echo SimpleSAML\Module::getModuleURL('aggregator2/get.php', $params)."\">[XML]</a>\n";
28
-        echo str_repeat(' ', 8)."</li>\n";
27
+        echo SimpleSAML\Module::getModuleURL('aggregator2/get.php', $params) . "\">[XML]</a>\n";
28
+        echo str_repeat(' ', 8) . "</li>\n";
29 29
     }
30 30
 
31 31
     echo "    </ul>\n";
Please login to merge, or discard this patch.
config-templates/module_aggregator2.php 1 patch
Indentation   +38 added lines, -38 removed lines patch added patch discarded remove patch
@@ -2,35 +2,35 @@  discard block
 block discarded – undo
2 2
 
3 3
 // This is the configuration file for the aggregator2-module
4 4
 $config = [
5
-    /*
5
+	/*
6 6
      * 'example' will be one set of aggregated metadata.
7 7
      * The aggregated metadata can be retrieved from:
8 8
      *   https://.../simplesaml/module.php/aggregator2/get.php?id=example
9 9
      */
10
-    'example' => [
11
-        // 'sources' is an array with the places we want to fetch metadata from
12
-        'sources' => [
13
-            /* Metadata validated by the https-certificate of the server. */
14
-            [
15
-                /* The URL we should fetch the metadata from. */
16
-                'url' => 'https://sp.example.org/metadata.xml',
10
+	'example' => [
11
+		// 'sources' is an array with the places we want to fetch metadata from
12
+		'sources' => [
13
+			/* Metadata validated by the https-certificate of the server. */
14
+			[
15
+				/* The URL we should fetch the metadata from. */
16
+				'url' => 'https://sp.example.org/metadata.xml',
17 17
 
18
-                /*
18
+				/*
19 19
                  * To enable validation of the https-certificate, we must
20 20
                  * specify a file with valid CA certificates.
21 21
                  *
22 22
                  * This can be an absolute path, or a path relative to the
23 23
                  * cert-directory.
24 24
                  */
25
-                'ssl.cafile' => '/etc/ssl/certs/ca-certificates.crt',
26
-            ],
25
+				'ssl.cafile' => '/etc/ssl/certs/ca-certificates.crt',
26
+			],
27 27
 
28
-            /* Metadata validated by its signature. */
29
-            [
30
-                /* The URL we should fetch the metadata from. */
31
-                'url' => 'http://idp.example.org/metadata.xml',
28
+			/* Metadata validated by its signature. */
29
+			[
30
+				/* The URL we should fetch the metadata from. */
31
+				'url' => 'http://idp.example.org/metadata.xml',
32 32
 
33
-                /*
33
+				/*
34 34
                  * To verify the signature in the metadata, we must specify
35 35
                  * a certificate that should be used. Note: This cannot
36 36
                  * be a CA certificate.
@@ -38,17 +38,17 @@  discard block
 block discarded – undo
38 38
                  * This can be an absolute path, or a path relative to the
39 39
                  * cert-directory.
40 40
                  */
41
-                'cert' => 'idp.example.org.crt',
42
-            ],
41
+				'cert' => 'idp.example.org.crt',
42
+			],
43 43
 
44
-            /* Metadata from a file. */
45
-            [
46
-                'url' => '/var/simplesaml/somemetadata.xml',
47
-            ],
44
+			/* Metadata from a file. */
45
+			[
46
+				'url' => '/var/simplesaml/somemetadata.xml',
47
+			],
48 48
 
49
-        ],
49
+		],
50 50
 
51
-        /*
51
+		/*
52 52
          * Update this metadata during this cron tag.
53 53
          *
54 54
          * For this option to work, you must configure the cron-module,
@@ -57,9 +57,9 @@  discard block
 block discarded – undo
57 57
          * This option is optional. If cron is not configured, the metadata
58 58
          * caches will be updated when receiving requests for metadata.
59 59
          */
60
-        'cron.tag' => 'hourly',
60
+		'cron.tag' => 'hourly',
61 61
 
62
-        /*
62
+		/*
63 63
          * The directory we will store downloaded and generated metadata.
64 64
          * This directory must be writeable by the web-server.
65 65
          *
@@ -67,9 +67,9 @@  discard block
 block discarded – undo
67 67
          * aggregated metadata will result in the aggregator fetching and
68 68
          * parsing all metadata sources.
69 69
          */
70
-        'cache.directory' => '/var/cache/simplesaml-aggregator2',
70
+		'cache.directory' => '/var/cache/simplesaml-aggregator2',
71 71
 
72
-        /*
72
+		/*
73 73
          * This is the number of seconds we will cache the metadata file we generate.
74 74
          * This should be a longer time than the interval between each time the cron
75 75
          * job is executed.
@@ -77,34 +77,34 @@  discard block
 block discarded – undo
77 77
          * This option is optional. If unspecified, the metadata will be generated
78 78
          * on every request.
79 79
          */
80
-        'cache.generated' => 24*60*60,
80
+		'cache.generated' => 24*60*60,
81 81
 
82
-        /*
82
+		/*
83 83
          * The generated metadata will have a validUntil set to the time it is generated
84 84
          * plus this number of seconds.
85 85
          */
86
-        'valid.length' => 7*24*60*60,
86
+		'valid.length' => 7*24*60*60,
87 87
 
88
-        /*
88
+		/*
89 89
          * The private key we should use to sign the metadata, in pem-format.
90 90
          *
91 91
          * This is optional. If it is not specified, the metadata will not be signed.
92 92
          */
93
-        'sign.privatekey' => 'metadata.pem',
93
+		'sign.privatekey' => 'metadata.pem',
94 94
 
95
-        /*
95
+		/*
96 96
          * The password for the private key.
97 97
          *
98 98
          * Optional, the private key is assumed to be unencrypted if this option
99 99
          * isn't set.
100 100
          */
101
-        'sign.privatekey_pass' => 'secret',
101
+		'sign.privatekey_pass' => 'secret',
102 102
 
103
-        /*
103
+		/*
104 104
          * The certificate that corresponds to the private key.
105 105
          *
106 106
          * If specified, the certificate will be included in the signature in the metadata.
107 107
          */
108
-        'sign.certificate' => 'metadata.crt',
109
-    ],
108
+		'sign.certificate' => 'metadata.crt',
109
+	],
110 110
 ];
Please login to merge, or discard this patch.
tests/bootstrap.php 2 patches
Indentation   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -6,7 +6,7 @@
 block discarded – undo
6 6
 // Symlink module into ssp vendor lib so that templates and urls can resolve correctly
7 7
 $linkPath = $projectRoot.'/vendor/simplesamlphp/simplesamlphp/modules/aggregator2';
8 8
 if (file_exists($linkPath) === false) {
9
-    echo "Linking '$linkPath' to '$projectRoot'\n";
10
-    symlink($projectRoot, $linkPath);
9
+	echo "Linking '$linkPath' to '$projectRoot'\n";
10
+	symlink($projectRoot, $linkPath);
11 11
 }
12 12
 
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -1,10 +1,10 @@
 block discarded – undo
1 1
 <?php
2 2
 
3 3
 $projectRoot = dirname(__DIR__);
4
-require_once($projectRoot.'/vendor/autoload.php');
4
+require_once($projectRoot . '/vendor/autoload.php');
5 5
 
6 6
 // Symlink module into ssp vendor lib so that templates and urls can resolve correctly
7
-$linkPath = $projectRoot.'/vendor/simplesamlphp/simplesamlphp/modules/aggregator2';
7
+$linkPath = $projectRoot . '/vendor/simplesamlphp/simplesamlphp/modules/aggregator2';
8 8
 if (file_exists($linkPath) === false) {
9 9
     echo "Linking '$linkPath' to '$projectRoot'\n";
10 10
     symlink($projectRoot, $linkPath);
Please login to merge, or discard this patch.
hooks/hook_cron.php 1 patch
Indentation   +20 added lines, -20 removed lines patch added patch discarded remove patch
@@ -7,28 +7,28 @@
 block discarded – undo
7 7
  */
8 8
 function aggregator2_hook_cron(&$croninfo)
9 9
 {
10
-    assert('is_array($croninfo)');
11
-    assert('array_key_exists("summary", $croninfo)');
12
-    assert('array_key_exists("tag", $croninfo)');
10
+	assert('is_array($croninfo)');
11
+	assert('array_key_exists("summary", $croninfo)');
12
+	assert('array_key_exists("tag", $croninfo)');
13 13
 
14
-    $cronTag = $croninfo['tag'];
14
+	$cronTag = $croninfo['tag'];
15 15
 
16
-    $config = \SimpleSAML\Configuration::getConfig('module_aggregator2.php');
17
-    $config = $config->toArray();
16
+	$config = \SimpleSAML\Configuration::getConfig('module_aggregator2.php');
17
+	$config = $config->toArray();
18 18
 
19
-    foreach ($config as $id => $c) {
20
-        if (!isset($c['cron.tag'])) {
21
-            continue;
22
-        }
23
-        if ($c['cron.tag'] !== $cronTag) {
24
-            continue;
25
-        }
19
+	foreach ($config as $id => $c) {
20
+		if (!isset($c['cron.tag'])) {
21
+			continue;
22
+		}
23
+		if ($c['cron.tag'] !== $cronTag) {
24
+			continue;
25
+		}
26 26
 
27
-        try {
28
-            $a = \SimpleSAML\Module\aggregator2\Aggregator::getAggregator($id);
29
-            $a->updateCache();
30
-        } catch (\Exception $e) {
31
-            $croninfo['summary'][] = 'Error during aggregator2 cacheupdate: ' . $e->getMessage();
32
-        }
33
-    }
27
+		try {
28
+			$a = \SimpleSAML\Module\aggregator2\Aggregator::getAggregator($id);
29
+			$a->updateCache();
30
+		} catch (\Exception $e) {
31
+			$croninfo['summary'][] = 'Error during aggregator2 cacheupdate: ' . $e->getMessage();
32
+		}
33
+	}
34 34
 }
Please login to merge, or discard this patch.
hooks/hook_frontpage.php 1 patch
Indentation   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -7,11 +7,11 @@
 block discarded – undo
7 7
  */
8 8
 function aggregator2_hook_frontpage(&$links)
9 9
 {
10
-    assert('is_array($links)');
11
-    assert('array_key_exists("links", $links)');
10
+	assert('is_array($links)');
11
+	assert('array_key_exists("links", $links)');
12 12
 
13
-    $links['federation'][] = [
14
-        'href' => \SimpleSAML\Module::getModuleURL('aggregator2/'),
15
-        'text' => '{aggregator2:aggregator:frontpage_link}',
16
-    ];
13
+	$links['federation'][] = [
14
+		'href' => \SimpleSAML\Module::getModuleURL('aggregator2/'),
15
+		'text' => '{aggregator2:aggregator:frontpage_link}',
16
+	];
17 17
 }
Please login to merge, or discard this patch.