Revision: 1894
Author: andreassolberg
Date: Fri Oct 23 03:47:27 2009
Log: Improvements to the aggregator module. Added documentation, and
re-written more OO-oriented.
http://code.google.com/p/simplesamlphp/source/detail?r=1894
Added:
/trunk/modules/aggregator/config-templates/module_aggregator.php
/trunk/modules/aggregator/docs
/trunk/modules/aggregator/docs/aggregator.txt
/trunk/modules/aggregator/lib
/trunk/modules/aggregator/lib/Aggregator.php
Deleted:
/trunk/modules/aggregator/config-templates/aggregator.php
Modified:
/trunk/modules/aggregator/www/index.php
=======================================
--- /dev/null
+++ /trunk/modules/aggregator/config-templates/module_aggregator.php Fri
Oct 23 03:47:27 2009
@@ -0,0 +1,45 @@
+<?php
+
+/* Configuration for the aggregator module. */
+$config = array(
+
+ /* List of aggregators. */
+ 'aggregators' => array(
+ 'example' => array(
+ 'source' => array(
+ array('type' => 'flatfile'), /* Metadata from
metadata-directory. */
+ array('type' => 'xml', 'url' =>
'https://idp.example.org/Metadata'),
+ array('type' => 'xml', 'file' =>
'static-metadata.xml'),
+ ),
+ ),
+ 'example2' => array(
+ 'source' => array(
+ array('type' => 'xml', 'url' =>
'https://idp.example.org/Metadata2'),
+ ),
+ 'set' => 'saml2',
+ 'sign.privatekey' => 'server2.key',
+ 'sign.certificate' => 'server2.crt',
+ )
+ ),
+
+
+ 'maxDuration' => 60*60*24*5, // Maximum 5 days duration on ValidUntil.
+
+ // If base64 encoded for entity is already cached in the entity, should
we
+ // reconstruct the XML or re-use.
+ 'reconstruct' => FALSE,
+
+ /* Whether metadata should be signed. */
+ 'sign.enable' => FALSE,
+
+ /* Private key which should be used when signing the metadata. */
+ 'sign.privatekey' => 'server.key',
+
+ /* Password to decrypt private key, or NULL if the private key is
unencrypted. */
+ 'sign.privatekey_pass' => NULL,
+
+ /* Certificate which should be included in the signature. Should
correspond to the private key. */
+ 'sign.certificate' => 'server.crt',
+
+);
+
=======================================
--- /dev/null
+++ /trunk/modules/aggregator/docs/aggregator.txt Fri Oct 23 03:47:27 2009
@@ -0,0 +1,90 @@
+aggregator Module
+=================
+
+<!--
+ This file is written in Markdown syntax.
+ For more information about how to use the Markdown syntax, read here:
+ http://daringfireball.net/projects/markdown/syntax
+-->
+
+ * Version: `$Id$`
+ * Author: Andreas Åkre Solberg <[email protected]>, UNINETT AS
+ * Package: simpleSAMLphp
+
+This module, aggregates a set of metadata of SAML entities to SAML 2.0
documents with an `EntitiesDescriptor` with multiple entities inside.
+
+Multiple aggregates can be configured.
+
+
+
+The configuration file: module_aggregate.php
+--------------------------------------------
+
+The configuration file includes an option `aggregators`, which includes a
indexed list of different aggregator configurations that all can be
accessed independently. The structure is as follows:
+
+ 'aggregators' => array(
+ 'aggr1' => array(
+ 'sources' => [...]
+ [...local params...]
+ ),
+ 'aggr2' => ...
+ )
+ [...global params...]
+
+All of the global parameters can be overriden for each aggregator. Here is
a list of the available (global) paramters:
+
+`set`
+: By default all SAML types are available, including:
`array('saml20-idp-remote', 'saml20-sp-remote', 'shib13-idp-remote',
'shib13-sp-remote')`.
This list can be reduced by specifying one of the following values:
+
+ * `saml20-idp-remote`
+ * `saml20-sp-remote`
+ * `shib13-idp-remote`
+ * `shib13-sp-remote`
+ * `saml2`
+ * `shib13`
+
+`foo`
+: sldkfjdslkjf
+
+`reconstruct`
+: Whether simpleSAMLphp should regenerate the metadata XML (TRUE) or
pass-through the input metadata XML (FALSE).
+
+`maxDuration`
+: Max validity of metadata (duration) in seconds.
+
+`sign.enable`
+: Enable signing of metadata document
+
+`sign.privatekey`
+: Private key to use when signing
+
+`sign.privatekey_pass`
+: Optionally a passphrase to the private key
+
+`sign.certificate`
+: Certificate to embed, corresponding to the private key.
+
+
+Accessing the aggregate
+-----------------------
+
+On the SimpleSAMLphp frontpage on the federation tab, there is a link to
the aggregator named *Metadata aggregator*.
+
+When accessing the aggregator endpoint without specifying an aggregate ID,
a list of available aggregators will be presented, with different options
for mime-type presenting the result.
+
+The endpoint supports the following query parameter:
+
+`id`
+: The ID of the aggregator (From configuration file)
+
+`set`
+: Subset the available types of SAML entities. Similar to the `set`
parameter described over in the configuration file description.
+
+`exclude`
+: Specify a `tag` that will be excluded from the metadata set. Useful for
leaving out your own federation metadata.
+
+`mimetype`
+: Select Mime-Type that will be used. Default is
`application/samlmetadata+xml`.
+
+
+
=======================================
--- /dev/null
+++ /trunk/modules/aggregator/lib/Aggregator.php Fri Oct 23 03:47:27 2009
@@ -0,0 +1,247 @@
+<?php
+
+/**
+ * Aggregates metadata for multiple sources into one signed file
+ *
+ * @author Andreas Åkre Solberg <[email protected]>
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+
+class sspmod_aggregator_Aggregator {
+
+ // Configuration for the whole aggregator module
+ private $gConfig;
+
+ // Configuration for the specific aggregate
+ private $aConfig;
+
+ private $sets;
+
+ private $excludeTags = array();
+
+ private $id;
+
+ /**
+ * Constructor for the Aggregator.
+ *
+ */
+ public function __construct($gConfig, $aConfig, $id) {
+ $this->gConfig = $gConfig;
+ $this->aConfig = $aConfig;
+ $this->id = $id;
+
+ $this->sets =
array('saml20-idp-remote', 'saml20-sp-remote', 'shib13-idp-remote',
'shib13-sp-remote');
+
+ if ($this->aConfig->hasValue('set')) {
+ $this->limitSets($this->aConfig->getString('set'));
+ }
+ }
+
+
+
+ public function limitSets($set) {
+
+
+ if (is_array($set)) {
+ $this->sets = array_intersect($this->sets, $set);
+ return;
+ }
+
+ switch($set) {
+ case 'saml2' :
+ $this->sets = array_intersect($this->sets,
array('saml20-idp-remote', 'saml20-sp-remote')); break;
+ case 'shib13' :
+ $this->sets = array_intersect($this->sets,
array('shib13-idp-remote', 'shib13-sp-remote')); break;
+ case 'idp' :
+ $this->sets = array_intersect($this->sets,
array('saml20-idp-remote', 'shib13-idp-remote')); break;
+ case 'sp' :
+ $this->sets = array_intersect($this->sets,
array('saml20-sp-remote', 'shib13-sp-remote')); break;
+
+ default:
+ $this->sets = array_intersect($this->sets,
array($set));
+ }
+ }
+
+ /**
+ * Add tag to excelude when collecting source metadata.
+ *
+ * $exclude May be string or array identifying a tag to exclude.
+ */
+ public function exclude($exclude) {
+ $this->excludeTags = array_merge($this->excludeTags,
SimpleSAML_Utilities::arrayize($exclude));
+ }
+
+ /**
+ * Returns a list of entities with metadata
+ */
+ public function getSources() {
+
+ $sourcesDef = $this->aConfig->getArray('sources');
+
+ try {
+ $sources =
SimpleSAML_Metadata_MetaDataStorageSource::parseSources($sourcesDef);
+ } catch (Exception $e) {
+ throw new Exception('Invalid aggregator source
configuration for
aggregator ' .
+ var_export($id, TRUE) . ': ' .
$e->getMessage());
+ }
+
+
+ #echo $exclude; exit;
+ /* Find list of all available entities. */
+ $entities = array();
+ #echo '<pre>'; print_r($this->sets); exit;
+
+ foreach ($sources as $source) {
+ foreach ($this->sets as $set) {
+
+ foreach ($source->getMetadataSet($set) as
$entityId => $metadata) {
+
+ if (isset($metadata['tags']) &&
+
count(array_intersect($this->excludeTags, $metadata['tags'])) > 0) {
+
+
SimpleSAML_Logger::debug('Excluding entity ID [' . $entityId . ']
becuase it is tagged with one of [' .
+
var_export($this->excludeTags, TRUE) . ']');
+ continue;
+ } else {
+ #echo('<pre>');
print_r($metadata); exit;
+ }
+ if (!array_key_exists($entityId,
$entities))
+ $entities[$entityId] = array();
+
+ if (array_key_exists($set,
$entities[$entityId])) {
+ /* Entity already has metadata
for the given set. */
+ continue;
+ }
+
+ $entities[$entityId][$set] = $metadata;
+ }
+ }
+ }
+ return $entities;
+
+ }
+
+ public function getMaxDuration() {
+ if ($this->aConfig->hasValue('maxDuration'))
+ return $this->aConfig->getInteger('maxDuration');
+ if ($this->gConfig->hasValue('maxDuration'))
+ return $this->gConfig->getInteger('maxDuration');
+ return NULL;
+ }
+
+
+
+ public function getReconstruct() {
+ if ($this->aConfig->hasValue('reconstruct'))
+ return $this->aConfig->getBoolean('reconstruct');
+ if ($this->gConfig->hasValue('reconstruct'))
+ return $this->gConfig->getBoolean('reconstruct');
+ return FALSE;
+ }
+
+ public function shouldSign() {
+ if ($this->aConfig->hasValue('sign.enable'))
+ return $this->aConfig->getBoolean('sign.enable');
+ if ($this->gConfig->hasValue('sign.enable'))
+ return $this->gConfig->getBoolean('sign.enable');
+ return FALSE;
+ }
+
+
+ public function getSigningInfo() {
+ if ($this->aConfig->hasValue('sign.privatekey')) {
+ return array(
+ 'privatekey' =>
$this->aConfig->getString('sign.privatekey'),
+ 'privatekey_pass' =>
$this->aConfig->getString('sign.privatekey_pass',
NULL),
+ 'certificate' =>
$this->aConfig->getString('sign.certificate'),
+ 'id' => 'ID'
+ );
+ }
+
+ return array(
+ 'privatekey' =>
$this->gConfig->getString('sign.privatekey'),
+ 'privatekey_pass' =>
$this->gConfig->getString('sign.privatekey_pass',
NULL),
+ 'certificate' =>
$this->gConfig->getString('sign.certificate'),
+ 'id' => 'ID'
+ );
+ }
+
+
+
+ public function getMetadataDocument() {
+
+ // Get metadata entries
+ $entities = $this->getSources();
+
+
+ // Generate XML Document
+ $xml = new DOMDocument();
+ $entitiesDescriptor =
$xml->createElementNS('urn:oasis:names:tc:SAML:2.0:metadata',
'EntitiesDescriptor');
+ $entitiesDescriptor->setAttribute('Name', $this->id);
+ $xml->appendChild($entitiesDescriptor);
+
+
+ $maxDuration = $this->getMaxDuration();
+ $reconstruct = $this->getReconstruct();
+
+
+ /* Build EntityDescriptor elements for them. */
+ foreach ($entities as $entity => $sets) {
+
+ $entityDescriptor = NULL;
+ foreach ($sets as $set => $metadata) {
+ if (!array_key_exists('entityDescriptor',
$metadata)) {
+ /* One of the sets doesn't contain an
EntityDescriptor element. */
+ $entityDescriptor = FALSE;
+ break;
+ }
+
+ if ($entityDescriptor == NULL) {
+ /* First EntityDescriptor elements. */
+ $entityDescriptor =
$metadata['entityDescriptor'];
+ continue;
+ }
+
+ assert('is_string($entityDescriptor)');
+ if ($entityDescriptor !==
$metadata['entityDescriptor']) {
+ /* Entity contains multiple different
EntityDescriptor elements. */
+ $entityDescriptor = FALSE;
+ break;
+ }
+ }
+
+ if (is_string($entityDescriptor) && !$reconstruct) {
+ /* All metadata sets for the entity contain the
same entity
descriptor. Use that one. */
+ $tmp = new DOMDocument();
+ $tmp->loadXML(base64_decode($entityDescriptor));
+ $entityDescriptor = $tmp->documentElement;
+ } else {
+
+ $tmp = new
SimpleSAML_Metadata_SAMLBuilder($entity, $maxDuration,
$maxDuration);
+
+ $orgmeta = NULL;
+ foreach ($sets as $set => $metadata) {
+ $tmp->addMetadata($set, $metadata);
+ $orgmeta = $metadata;
+ }
+ $tmp->addOrganizationInfo($orgmeta);
+ $entityDescriptor = $tmp->getEntityDescriptor();
+ }
+
+
$entitiesDescriptor->appendChild($xml->importNode($entityDescriptor,
TRUE));
+ }
+
+
+ /* Sign the metadata if enabled. */
+ if ($this->shouldSign()) {
+ $signer = new
SimpleSAML_XML_Signer($this->getSigningInfo());
+ $signer->sign($entitiesDescriptor, $entitiesDescriptor,
$entitiesDescriptor->firstChild);
+ }
+
+
+ return $xml;
+ }
+
+
+}
=======================================
--- /trunk/modules/aggregator/config-templates/aggregator.php Tue Jun 16
04:50:53 2009
+++ /dev/null
@@ -1,37 +0,0 @@
-<?php
-
-/* Configuration for the aggregator module. */
-$config = array(
-
- /* List of aggregators. */
- 'aggregators' => array(
- 'example' => array(
- array('type' => 'flatfile'), /* Metadata from
metadata-directory. */
- array('type' => 'xml', 'url' =>
'https://idp.example.org/Metadata'),
- array('type' => 'xml', 'file' => 'static-metadata.xml'),
- ),
- ),
-
-
- 'maxCache' => 60*60*24, // 24 hour cache time
- 'maxDuration' => 60*60*24*5, // Maximum 5 days duration on ValidUntil.
-
- // If base64 encoded for entity is already cached in the entity, should
we
- // reconstruct the XML or re-use.
- 'reconstruct' => TRUE,
-
- /* Whether metadata should be signed. */
- 'sign.enable' => FALSE,
-
- /* Private key which should be used when signing the metadata. */
- 'sign.privatekey' => 'server.key',
-
- /* Password to decrypt private key, or NULL if the private key is
unencrypted. */
- 'sign.privatekey_pass' => NULL,
-
- /* Certificate which should be included in the signature. Should
correspond to the private key. */
- 'sign.certificate' => 'server.crt',
-
-);
-
-?>
=======================================
--- /trunk/modules/aggregator/www/index.php Tue Jun 16 05:14:31 2009
+++ /trunk/modules/aggregator/www/index.php Fri Oct 23 03:47:27 2009
@@ -1,159 +1,36 @@
<?php
-$globalConfig = SimpleSAML_Configuration::getInstance();
-$aggregatorConfig = SimpleSAML_Configuration::getConfig('aggregator.php');
+$config = SimpleSAML_Configuration::getInstance();
+$gConfig = SimpleSAML_Configuration::getConfig('module_aggregator.php');
-$reconstruct = $aggregatorConfig->getBoolean('reconstruct', FALSE);
-$aggregators = $aggregatorConfig->getArray('aggregators');
-
-$metadataSets =
array('saml20-idp-remote', 'saml20-sp-remote', 'shib13-idp-remote',
'shib13-sp-remote');
-if ($aggregatorConfig->hasValue('default-set')) {
- $metadataSets = $aggregatorConfig->getArray('default-set');
-}
-if (isset($_REQUEST['set'])) {
- switch($_REQUEST['set']) {
- case 'saml2' :
- $metadataSets = array('saml20-idp-remote',
'saml20-sp-remote'); break;
- case 'shib13' :
- $metadataSets = array('shib13-idp-remote',
'shib13-sp-remote'); break;
- case 'idp' :
- $metadataSets = array('saml20-idp-remote',
'shib13-idp-remote'); break;
- case 'sp' :
- $metadataSets = array('saml20-sp-remote',
'shib13-sp-remote'); break;
-
- default:
- $metadataSets = array($_REQUEST['set']);
- }
-}
-
-// print_r($metadataSets); exit;
-
+// Get list of aggregators
+$aggregators = $gConfig->getConfigItem('aggregators');
+
+// If aggregator ID is not provided, show the list of available aggregates
if (!array_key_exists('id', $_GET)) {
- $t = new SimpleSAML_XHTML_Template($globalConfig,
'aggregator:list.php');
- $t->data['sources'] = array_keys($aggregators);
+ $t = new SimpleSAML_XHTML_Template($config, 'aggregator:list.php');
+ $t->data['sources'] = $aggregators->getOptions();
$t->show();
exit;
}
-
$id = $_GET['id'];
-if (!array_key_exists($id, $aggregators)) {
+if (!in_array($id, $aggregators->getOptions()))
throw new SimpleSAML_Error_NotFound('No aggregator with id ' .
var_export($id, TRUE) . ' found.');
-}
-
-
-/* Parse metadata sources. */
-$sources = $aggregators[$id];
-if (!is_array($sources)) {
- throw new Exception('Invalid aggregator source configuration for
aggregator ' .
- var_export($id, TRUE) . ': Aggregator wasn\'t an array.');
-};
-
-try {
- $sources =
SimpleSAML_Metadata_MetaDataStorageSource::parseSources($sources);
-} catch (Exception $e) {
- throw new Exception('Invalid aggregator source configuration for
aggregator ' .
- var_export($id, TRUE) . ': ' . $e->getMessage());
-}
-
-$exclude = NULL;
-if (array_key_exists('exclude', $_REQUEST)) $exclude =
$_REQUEST['exclude'];
-
-#echo $exclude; exit;
-/* Find list of all available entities. */
-$entities = array();
-foreach ($sources as $source) {
- foreach ($metadataSets as $set) {
- foreach ($source->getMetadataSet($set) as $entityId =>
$metadata) {
- if (isset($exclude) &&
- array_key_exists('tags', $metadata) &&
- in_array($exclude, $metadata['tags'])) {
- SimpleSAML_Logger::debug('Excluding entity ID
[' . $entityId . ']
becuase it is tagged with [' . $exclude . ']');
- continue;
- } else {
- #echo('<pre>'); print_r($metadata); exit;
- }
- if (!array_key_exists($entityId, $entities))
- $entities[$entityId] = array();
-
- if (array_key_exists($set, $entities[$entityId])) {
- /* Entity already has metadata for the given
set. */
- continue;
- }
-
- $entities[$entityId][$set] = $metadata;
- }
- }
-}
-
-$xml = new DOMDocument();
-$entitiesDescriptor =
$xml->createElementNS('urn:oasis:names:tc:SAML:2.0:metadata',
'EntitiesDescriptor');
-$entitiesDescriptor->setAttribute('Name', $id);
-$xml->appendChild($entitiesDescriptor);
-
-
-
-/* Build EntityDescriptor elements for them. */
-foreach ($entities as $entity => $sets) {
-
- $entityDescriptor = NULL;
- foreach ($sets as $set => $metadata) {
- if (!array_key_exists('entityDescriptor', $metadata)) {
- /* One of the sets doesn't contain an EntityDescriptor
element. */
- $entityDescriptor = FALSE;
- break;
- }
-
- if ($entityDescriptor == NULL) {
- /* First EntityDescriptor elements. */
- $entityDescriptor = $metadata['entityDescriptor'];
- continue;
- }
-
- assert('is_string($entityDescriptor)');
- if ($entityDescriptor !== $metadata['entityDescriptor']) {
- /* Entity contains multiple different EntityDescriptor
elements. */
- $entityDescriptor = FALSE;
- break;
- }
- }
-
- if (is_string($entityDescriptor) && !$reconstruct) {
- /* All metadata sets for the entity contain the same entity
descriptor.
Use that one. */
- $tmp = new DOMDocument();
- $tmp->loadXML(base64_decode($entityDescriptor));
- $entityDescriptor = $tmp->documentElement;
- } else {
- $tmp = new SimpleSAML_Metadata_SAMLBuilder($entity,
- $aggregatorConfig->getValue('maxCache', NULL),
$aggregatorConfig->getValue('maxDuration', NULL));
-
- $orgmeta = NULL;
- foreach ($sets as $set => $metadata) {
- $tmp->addMetadata($set, $metadata);
- $orgmeta = $metadata;
- }
- $tmp->addOrganizationInfo($orgmeta);
- $entityDescriptor = $tmp->getEntityDescriptor();
- }
-
- $entitiesDescriptor->appendChild($xml->importNode($entityDescriptor,
TRUE));
-}
-
-
-/* Sign the metadata if enabled. */
-if ($aggregatorConfig->getBoolean('sign.enable', FALSE)) {
- $privateKey = $aggregatorConfig->getString('sign.privatekey');
- $privateKeyPass = $aggregatorConfig->getString('sign.privatekey_pass',
NULL);
- $certificate = $aggregatorConfig->getString('sign.certificate');
-
- $signer = new SimpleSAML_XML_Signer(array(
- 'privatekey' => $privateKey,
- 'privatekey_pass' => $privateKeyPass,
- 'certificate' => $certificate,
- 'id' => 'ID',
- ));
- $signer->sign($entitiesDescriptor, $entitiesDescriptor,
$entitiesDescriptor->firstChild);
-}
+
+$aConfig = $aggregators->getConfigItem($id);
+
+
+$aggregator = new sspmod_aggregator_Aggregator($gConfig, $aConfig, $id);
+
+if (isset($_REQUEST['set']))
+ $aggregator->limitSets($_REQUEST['set']);
+
+if (isset($_REQUEST['exclude']))
+ $aggregator->exclude($_REQUEST['exclude']);
+
+
+$xml = $aggregator->getMetadataDocument();
/* Show the metadata. */
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"simpleSAMLphp commits" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/simplesamlphp-commits?hl=en
-~----------~----~----~----~------~----~------~--~---