diff --git a/lib/SimpleSAML/Metadata/MetaDataStorageHandlerDynamicXML.php b/lib/SimpleSAML/Metadata/MetaDataStorageHandlerDynamicXML.php new file mode 100644 index 0000000000000000000000000000000000000000..9962614a4b121c56b3e2eb8cd71a60371a941aed --- /dev/null +++ b/lib/SimpleSAML/Metadata/MetaDataStorageHandlerDynamicXML.php @@ -0,0 +1,222 @@ +<?php + +require_once((isset($SIMPLESAML_INCPREFIX)?$SIMPLESAML_INCPREFIX:'') . 'SimpleSAML/Configuration.php'); +require_once((isset($SIMPLESAML_INCPREFIX)?$SIMPLESAML_INCPREFIX:'') . 'SimpleSAML/Metadata/MetaDataStorageSource.php'); +require_once((isset($SIMPLESAML_INCPREFIX)?$SIMPLESAML_INCPREFIX:'') . 'SimpleSAML/Metadata/SAMLParser.php'); +require_once((isset($SIMPLESAML_INCPREFIX)?$SIMPLESAML_INCPREFIX:'') . 'SimpleSAML/Logger.php'); + +/** + * This class implements the dynamic SAML profile, where the entityID equals an URL where metadata is located. + * The XML files should be in the SAML 2.0 metadata format. + * + * @author Andreas Ă…kre Solberg, UNINETT AS. + * @author Olav Morken, UNINETT AS. + * @package simpleSAMLphp + * @version $Id$ + */ +class SimpleSAML_Metadata_MetaDataStorageHandlerDynamicXML extends SimpleSAML_Metadata_MetaDataStorageSource { + + /** + * This variable contains an associative array with the parsed metadata. + */ + private $metadata; + private $config; + + /** + * This function initializes the XML metadata source. The configuration must contain one of + * the following options: + * - 'file': Path to a file with the metadata. This path is relative to the simpleSAMLphp + * base directory. + * - 'url': URL we should download the metadata from. This is only meant for testing. + * + * @param $config The configuration for this instance of the XML metadata source. + */ + protected function __construct($config) { + + $this->config = $config; + + /* Get the configuration. + $globalConfig = SimpleSAML_Configuration::getInstance(); + + if(array_key_exists('cache', $config)) { + $src = $globalConfig->resolvePath($config['file']); + } elseif(array_key_exists('url', $config)) { + $src = $config['url']; + } else { + throw new Exception('Missing either \'file\' or \'url\' in XML metadata source configuration.'); + } + + + $SP1x = array(); + $IdP1x = array(); + $SP20 = array(); + $IdP20 = array(); + + $entities = SimpleSAML_Metadata_SAMLParser::parseDescriptorsFile($src); + foreach($entities as $entityId => $entity) { + + $md = $entity->getMetadata1xSP(); + if($md !== NULL) { + $SP1x[$entityId] = $md; + } + + $md = $entity->getMetadata1xIdP(); + if($md !== NULL) { + $IdP1x[$entityId] = $md; + } + + $md = $entity->getMetadata20SP(); + if($md !== NULL) { + $SP20[$entityId] = $md; + } + + $md = $entity->getMetadata20IdP(); + if($md !== NULL) { + $IdP20[$entityId] = $md; + } + + } + + $this->metadata = array( + 'shib13-sp-remote' => $SP1x, + 'shib13-idp-remote' => $IdP1x, + 'saml20-sp-remote' => $SP20, + 'saml20-idp-remote' => $IdP20, + ); + */ + + } + + + /** + * This function returns an associative array with metadata for all entities in the given set. The + * key of the array is the entity id. + * + * @param $set The set we want to list metadata for. + * @return An associative array with all entities in the given set. + */ + public function getMetadataSet($set) { + /* + if(array_key_exists($set, $this->metadata)) { + return $this->metadata[$set]; + } + */ + + /* We don't have this metadata set. */ + return array(); + } + + + private function getCacheFilename($entityId) { + $cachekey = sha1($entityId); + $globalConfig = SimpleSAML_Configuration::getInstance(); + return $globalConfig->resolvePath($this->config['cachedir']) . '/' . $cachekey . '.cached.xml'; + } + + + private function getFromCache($entityId) { + $cachefilename = $this->getCacheFilename($entityId); + if (!file_exists($cachefilename)) return NULL; + if (!is_readable($cachefilename)) throw new Exception('Could not read cache file for entity [' . $cachefilename. ']'); + SimpleSAML_Logger::debug('MetaData - Handler.DynamicXML: Reading cache [' . $entityId . '] => [' . $cachefilename . ']' ); + return file_get_contents($cachefilename); + } + + private function writeToCache($entityId, $xmldata) { + $cachefilename = $this->getCacheFilename($entityId); + if (!is_writable(dirname($cachefilename))) throw new Exception('Could not write cache file for entity [' . $cachefilename. ']'); + SimpleSAML_Logger::debug('MetaData - Handler.DynamicXML: Writing cache [' . $entityId . '] => [' . $cachefilename . ']' ); + file_put_contents($cachefilename, $xmldata); + } + + + /** + * Overriding this function from the superclass SimpleSAML_Metadata_MetaDataStorageSource. + * + * This function retrieves metadata for the given entity id in the given set of metadata. + * It will return NULL if it is unable to locate the metadata. + * + * This class implements this function using the getMetadataSet-function. A subclass should + * override this function if it doesn't implement the getMetadataSet function, or if the + * implementation of getMetadataSet is slow. + * + * @param $index The entityId or metaindex we are looking up. + * @param $set The set we are looking for metadata in. + * @return An associative array with metadata for the given entity, or NULL if we are unable to + * locate the entity. + */ + public function getMetaData($index, $set) { + + + SimpleSAML_Logger::info('MetaData - Handler.DynamicXML: Loading metadata entity [' . $index . '] from [' . $set . ']' ); + + + /* Get the configuration. */ + $globalConfig = SimpleSAML_Configuration::getInstance(); + + if (!preg_match('@(https?://([-\w\.]+)+(:\d+)?(/([\w/_\.]*(\?\S+)?)?)?)@', $index)) { + SimpleSAML_Logger::info('MetaData - Handler.DynamicXML: EntityID/index [' . $index . '] does not look like an URL. Skipping.' ); + return NULL; + } + + $xmldata = NULL; + + /** + * Read from cache if cache is defined. + */ + if (!empty($this->config['cachedir'])) { + $xmldata = $this->getFromCache($index); + } + + if (empty($xmldata)) { + $xmldata = file_get_contents($index); + + if (!empty($this->config['cachedir'])) { + $this->writeToCache($index, $xmldata); + } + } + + + $entities = SimpleSAML_Metadata_SAMLParser::parseDescriptorsString($xmldata); + + + SimpleSAML_Logger::debug('MetaData - Handler.DynamicXML: Completed parsing of [' . $index . '] Found [' . count($entities). '] entries.' ); + + foreach($entities as $entityId => $entity) { + + SimpleSAML_Logger::debug('MetaData - Handler.DynamicXML: Looking for [' . $index . '] found [' . $entityId . '] entries.' ); + + switch($set) { + case 'saml20-idp-remote' : + $md = $entity->getMetadata20IdP(); + if ($md !== NULL) return $md; + break; + + case 'saml20-sp-remote' : + $md = $entity->getMetadata20SP(); + if ($md !== NULL) return $md; + break; + + case 'shib13-idp-remote' : + $md = $entity->getMetadata1xIdP(); + if ($md !== NULL) return $md; + break; + + case 'shib13-sp-remote' : + $md = $entity->getMetadata1xSP(); + if ($md !== NULL) return $md; + break; + + } + + + } + + return NULL; + + } + + +} + +?> \ No newline at end of file diff --git a/lib/SimpleSAML/Metadata/MetaDataStorageSource.php b/lib/SimpleSAML/Metadata/MetaDataStorageSource.php index ce96224158b058bc5292ffb18eb04a4208d8d7a0..6906c80e21eca0186ceebeae9187f4ece419d926 100644 --- a/lib/SimpleSAML/Metadata/MetaDataStorageSource.php +++ b/lib/SimpleSAML/Metadata/MetaDataStorageSource.php @@ -2,6 +2,7 @@ require_once((isset($SIMPLESAML_INCPREFIX)?$SIMPLESAML_INCPREFIX:'') . 'SimpleSAML/Metadata/MetaDataStorageHandlerFlatfile.php'); require_once((isset($SIMPLESAML_INCPREFIX)?$SIMPLESAML_INCPREFIX:'') . 'SimpleSAML/Metadata/MetaDataStorageHandlerXML.php'); +require_once((isset($SIMPLESAML_INCPREFIX)?$SIMPLESAML_INCPREFIX:'') . 'SimpleSAML/Metadata/MetaDataStorageHandlerDynamicXML.php'); /** * This abstract class defines an interface for metadata storage sources. @@ -41,6 +42,8 @@ abstract class SimpleSAML_Metadata_MetaDataStorageSource { return new SimpleSAML_Metadata_MetaDataStorageHandlerFlatFile($sourceConfig); case 'xml': return new SimpleSAML_Metadata_MetaDataStorageHandlerXML($sourceConfig); + case 'dynamicxml': + return new SimpleSAML_Metadata_MetaDataStorageHandlerDynamicXML($sourceConfig); default: throw new Exception('Invalid metadata source type: "' . $type . '".'); }