Create module metarefreshsupann from existing metarefresh

This commit is contained in:
Benjamin Dauvergne 2015-01-06 15:17:55 +01:00
parent b61ef1fcaf
commit db940492bd
9 changed files with 998 additions and 0 deletions

View File

@ -0,0 +1,165 @@
#!/usr/bin/env php
<?php
/*
* This script can be used to generate metadata for simpleSAMLphp
* based on an XML metadata file.
*/
/* This is the base directory of the simpleSAMLphp installation. */
$baseDir = dirname(dirname(dirname(dirname(__FILE__))));
/* Add library autoloader. */
require_once($baseDir . '/lib/_autoload.php');
SimpleSAML_Session::useTransientSession(); /* No need to try to create a session here. */
if(!SimpleSAML_Module::isModuleEnabled('metarefresh')) {
echo("You need to enable the metarefresh module before this script can be used.\n");
echo("You can enable it by running the following command:\n");
echo(' echo >"' . $baseDir . '/modules/metarefresh/enable' . "\"\n");
exit(1);
}
/* Initialize the configuration. */
SimpleSAML_Configuration::setConfigDir($baseDir . '/config');
/* $outputDir contains the directory we will store the generated metadata in. */
$outputDir = $baseDir . '/metadata-generated';
/* $toStdOut is a boolean telling us wheter we will print the output to stdout instead
* of writing it to files in $outputDir.
*/
$toStdOut = FALSE;
/* $validateFingerprint contains the fingerprint of the certificate which should have been used
* to sign the EntityDescriptor in the metadata, or NULL if fingerprint validation shouldn't be
* done.
*/
$validateFingerprint = NULL;
/* This variable contains the files we will parse. */
$files = array();
/* Parse arguments. */
$progName = array_shift($argv);
foreach($argv as $a) {
if(strlen($a) === 0) {
continue;
}
if($a[0] !== '-') {
/* Not an option. Assume that it is a file we should parse. */
$files[] = $a;
continue;
}
if(strpos($a, '=') !== FALSE) {
$p = strpos($a, '=');
$v = substr($a, $p + 1);
$a = substr($a, 0, $p);
} else {
$v = NULL;
}
/* Map short options to long options. */
$shortOptMap = array(
'-h' => '--help',
'-o' => '--out-dir',
'-s' => '--stdout',
);
if(array_key_exists($a, $shortOptMap)) {
$a = $shortOptMap[$a];
}
switch($a) {
case '--validate-fingerprint':
if($v === NULL || strlen($v) === 0) {
echo('The --validate-fingerprint option requires an parameter.' . "\n");
echo('Please run `' . $progName . ' --help` for usage information.' . "\n");
exit(1);
}
$validateFingerprint = $v;
break;
case '--help':
printHelp();
exit(0);
case '--out-dir':
if($v === NULL || strlen($v) === 0) {
echo('The --out-dir option requires an parameter.' . "\n");
echo('Please run `' . $progName . ' --help` for usage information.' . "\n");
exit(1);
}
$outputDir = $baseDir . ($v[0] == '/' ? $v : '/' . $v);
break;
case '--stdout':
$toStdOut = TRUE;
break;
default:
echo('Unknown option: ' . $a . "\n");
echo('Please run `' . $progName . ' --help` for usage information.' . "\n");
exit(1);
}
}
if(count($files) === 0) {
echo($progName . ': Missing input files. Please run `' . $progName . ' --help` for usage information.' . "\n");
exit(1);
}
/* The metadata global variable will be filled with the metadata we extract. */
$metaloader = new sspmod_metarefresh_MetaLoader();
foreach($files as $f) {
$source = array('src' => $f);
if (isset($validateFingerprint)) $source['validateFingerprint'] = $validateFingerprint;
$metaloader->loadSource($source);
}
if($toStdOut) {
$metaloader->dumpMetadataStdOut();
} else {
$metaloader->writeMetadataFiles($outputDir);
}
exit(0);
/**
* This function prints the help output.
*/
function printHelp() {
global $progName;
/* '======================================================================' */
echo('Usage: ' . $progName . ' [options] [files]' . "\n");
echo("\n");
echo('This program parses a SAML metadata files and output pieces that can' . "\n");
echo('be added to the metadata files in metadata/.' . "\n");
echo("\n");
echo('Options:' . "\n");
echo(' --validate-fingerprint=<FINGERPRINT>' . "\n");
echo(' Check the signature of the metadata,' . "\n");
echo(' and check the fingerprint of the' . "\n");
echo(' certificate against <FINGERPRINT>.' . "\n");
echo(' -h, --help Print this help.' . "\n");
echo(' -o=<DIR>, --out-dir=<DIR> Write the output to this directory. The' . "\n");
echo(' default directory is metadata-generated/.' . "\n");
echo(' Path will be relative to the simpleSAMLphp' . "\n");
echo(' base directory.' . "\n");
echo(' -s, --stdout Write the output to stdout instead of' . "\n");
echo(' seperate files in the output directory.' . "\n");
echo("\n");
}

View File

@ -0,0 +1,65 @@
<?php
$config = array(
/*
* Global blacklist: entityIDs that should be excluded from ALL sets.
*/
#'blacklist' = array(
# 'http://my.own.uni/idp'
#),
/*
* Conditional GET requests
* Efficient downloading so polling can be done more frequently.
* Works for sources that send 'Last-Modified' or 'Etag' headers.
* Note that the 'data' directory needs to be writable for this to work.
*/
#'conditionalGET' => TRUE,
'sets' => array(
'kalmar' => array(
'cron' => array('hourly'),
'sources' => array(
array(
/*
* entityIDs that should be excluded from this src.
*/
#'blacklist' => array(
# 'http://some.other.uni/idp',
#),
/*
* Whitelist: only keep these EntityIDs.
*/
#'whitelist' => array(
# 'http://some.uni/idp',
# 'http://some.other.uni/idp',
#),
#'conditionalGET' => TRUE,
'src' => 'https://kalmar2.org/simplesaml/module.php/aggregator/?id=kalmarcentral&set=saml2&exclude=norway',
'validateFingerprint' => '59:1D:4B:46:70:46:3E:ED:A9:1F:CC:81:6D:C0:AF:2A:09:2A:A8:01',
'template' => array(
'tags' => array('kalmar'),
'authproc' => array(
51 => array('class' => 'core:AttributeMap', 'oid2name'),
),
),
),
),
'expireAfter' => 60*60*24*4, // Maximum 4 days cache time.
'outputDir' => 'metadata/metadata-kalmar-consuming/',
/*
* Which output format the metadata should be saved as.
* Can be 'flatfile' or 'serialize'. 'flatfile' is the default.
*/
'outputFormat' => 'flatfile',
),
),
);

View File

@ -0,0 +1,3 @@
This file indicates that the default state of this module
is disabled. To enable, create a file named enable in the
same directory as this file.

View File

@ -0,0 +1,98 @@
<?php
/**
* Hook to run a cron job.
*
* @param array &$croninfo Output
*/
function metarefresh_hook_cron(&$croninfo) {
assert('is_array($croninfo)');
assert('array_key_exists("summary", $croninfo)');
assert('array_key_exists("tag", $croninfo)');
SimpleSAML_Logger::info('cron [metarefresh]: Running cron in cron tag [' . $croninfo['tag'] . '] ');
try {
$config = SimpleSAML_Configuration::getInstance();
$mconfig = SimpleSAML_Configuration::getOptionalConfig('config-metarefresh.php');
$sets = $mconfig->getConfigList('sets', array());
$stateFile = $config->getPathValue('datadir', 'data/') . 'metarefresh-state.php';
foreach ($sets AS $setkey => $set) {
// Only process sets where cron matches the current cron tag.
$cronTags = $set->getArray('cron');
if (!in_array($croninfo['tag'], $cronTags)) continue;
SimpleSAML_Logger::info('cron [metarefresh]: Executing set [' . $setkey . ']');
$expireAfter = $set->getInteger('expireAfter', NULL);
if ($expireAfter !== NULL) {
$expire = time() + $expireAfter;
} else {
$expire = NULL;
}
$outputDir = $set->getString('outputDir');
$outputDir = $config->resolvePath($outputDir);
$outputFormat = $set->getValueValidate('outputFormat', array('flatfile', 'serialize'), 'flatfile');
$oldMetadataSrc = SimpleSAML_Metadata_MetaDataStorageSource::getSource(array(
'type' => $outputFormat,
'directory' => $outputDir,
));
$metaloader = new sspmod_metarefresh_MetaLoader($expire, $stateFile, $oldMetadataSrc);
# Get global blacklist, whitelist and caching info
$blacklist = $mconfig->getArray('blacklist', array());
$whitelist = $mconfig->getArray('whitelist', array());
$conditionalGET = $mconfig->getBoolean('conditionalGET', FALSE);
foreach($set->getArray('sources') AS $source) {
# Merge global and src specific blacklists
if(isset($source['blacklist'])) {
$source['blacklist'] = array_unique(array_merge($source['blacklist'], $blacklist));
} else {
$source['blacklist'] = $blacklist;
}
# Merge global and src specific whitelists
if(isset($source['whitelist'])) {
$source['whitelist'] = array_unique(array_merge($source['whitelist'], $whitelist));
} else {
$source['whitelist'] = $whitelist;
}
# Let src specific conditionalGET override global one
if(!isset($source['conditionalGET'])) {
$source['conditionalGET'] = $conditionalGET;
}
SimpleSAML_Logger::debug('cron [metarefresh]: In set [' . $setkey . '] loading source [' . $source['src'] . ']');
$metaloader->loadSource($source);
}
// Write state information back to disk
$metaloader->writeState();
switch ($outputFormat) {
case 'flatfile':
$metaloader->writeMetadataFiles($outputDir);
break;
case 'serialize':
$metaloader->writeMetadataSerialize($outputDir);
break;
}
if ($set->hasValue('arp')) {
$arpconfig = SimpleSAML_Configuration::loadFromArray($set->getValue('arp'));
$metaloader->writeARPfile($arpconfig);
}
}
} catch (Exception $e) {
$croninfo['summary'][] = 'Error during metarefresh: ' . $e->getMessage();
}
}
?>

View File

@ -0,0 +1,17 @@
<?php
/**
* Hook to add links to the frontpage.
*
* @param array &$links The links on the frontpage, split into sections.
*/
function metarefresh_hook_frontpage(&$links) {
assert('is_array($links)');
assert('array_key_exists("links", $links)');
$links['federation'][] = array(
'href' => SimpleSAML_Module::getModuleURL('metarefresh/fetch.php'),
'text' => array('en' => 'Metarefresh: fetch metadata'),
);
}
?>

View File

@ -0,0 +1,103 @@
<?php
/*
* @author Andreas Åkre Solberg <andreas.solberg@uninett.no>
* @package simpleSAMLphp
* @version $Id$
*/
class sspmod_metarefresh_ARP {
private $metadata;
private $attributes;
private $prefix;
private $suffix;
/**
* Constructor
*
* @param
*/
public function __construct($metadata, $attributemap, $prefix, $suffix) {
$this->metadata = $metadata;
$this->prefix = $prefix;
$this->suffix = $suffix;
if (isset($attributemap)) $this->loadAttributeMap($attributemap);
}
private function loadAttributeMap($attributemap) {
$config = SimpleSAML_Configuration::getInstance();
include($config->getPathValue('attributemap', 'attributemap/') . $attributemap . '.php');
$this->attributes = $attributemap;
# print_r($attributemap); exit;
}
private function surround($name) {
$ret = '';
if (!empty($this->prefix)) $ret .= $this->prefix;
$ret .= $name;
if (!empty($this->suffix)) $ret .= $this->suffix;
return $ret;
}
private function getAttributeID($name) {
if (empty($this->attributes)) {
return $this->surround($name);
}
if (array_key_exists($name, $this->attributes)) {
return $this->surround($this->attributes[$name]);
}
return $this->surround($name);
}
public function getXML() {
$xml = '<?xml version="1.0" encoding="UTF-8"?>
<AttributeFilterPolicyGroup id="urn:mace:funet.fi:haka:kalmar" xmlns="urn:mace:shibboleth:2.0:afp"
xmlns:basic="urn:mace:shibboleth:2.0:afp:mf:basic" xmlns:saml="urn:mace:shibboleth:2.0:afp:mf:saml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:mace:shibboleth:2.0:afp classpath:/schema/shibboleth-2.0-afp.xsd
urn:mace:shibboleth:2.0:afp:mf:basic classpath:/schema/shibboleth-2.0-afp-mf-basic.xsd
urn:mace:shibboleth:2.0:afp:mf:saml classpath:/schema/shibboleth-2.0-afp-mf-saml.xsd">
';
foreach($this->metadata AS $metadata) {
#$print_r($metadata); exit;
$xml .= $this->getEntryXML($metadata['metadata']);
}
$xml .= '</AttributeFilterPolicyGroup>';
return $xml;
}
private function getEntryXML($entry) {
$entityid = $entry['entityid'];
return ' <AttributeFilterPolicy id="' . $entityid . '">
<PolicyRequirementRule xsi:type="basic:AttributeRequesterString" value="' . $entityid . '" />
' . $this->getEntryXMLcontent($entry) . '
</AttributeFilterPolicy>
';
}
private function getEntryXMLcontent($entry) {
$ids = array();
if (!array_key_exists('attributes', $entry))
return '';
$ret = '';
foreach($entry['attributes'] AS $a) {
$ret .= ' <AttributeRule attributeID="' . $this->getAttributeID($a) . '">
<PermitValueRule xsi:type="basic:ANY" />
</AttributeRule>
';
}
return $ret;
}
}

View File

@ -0,0 +1,447 @@
<?php
/*
* @author Andreas Åkre Solberg <andreas.solberg@uninett.no>
* @package simpleSAMLphp
* @version $Id$
*/
class sspmod_metarefresh_MetaLoader {
private $expire;
private $metadata;
private $oldMetadataSrc;
private $stateFile;
private $changed;
private static $types = array('saml20-idp-remote', 'saml20-sp-remote',
'shib13-idp-remote', 'shib13-sp-remote', 'attributeauthority-remote');
/**
* Constructor
*
* @param array $sources Sources...
* @param
*/
public function __construct($expire = NULL, $stateFile = NULL, $oldMetadataSrc = NULL) {
$this->expire = $expire;
$this->metadata = array();
$this->oldMetadataSrc = $oldMetadataSrc;
$this->stateFile = $stateFile;
$this->changed = FALSE;
// Read file containing $state from disk
if(is_readable($stateFile)) {
require($stateFile);
}
$this->state = (isset($state)) ? $state : array();
}
/**
* This function processes a SAML metadata file.
*
* @param $source
*/
public function loadSource($source) {
if (preg_match('@^https?://@i', $source['src'])) {
// Build new HTTP context
$context = $this->createContext($source);
// GET!
try {
list($data, $responseHeaders) = SimpleSAML_Utilities::fetch($source['src'], $context, TRUE);
} catch(Exception $e) {
SimpleSAML_Logger::warning('metarefresh: ' . $e->getMessage());
}
// We have response headers, so the request succeeded
if(!isset($responseHeaders)) {
// No response headers, this means the request failed in some way, so re-use old data
SimpleSAML_Logger::debug('No response from ' . $source['src'] . ' - attempting to re-use cached metadata');
$this->addCachedMetadata($source);
return;
} elseif(preg_match('@^HTTP/1\.[01]\s304\s@', $responseHeaders[0])) {
// 304 response
SimpleSAML_Logger::debug('Received HTTP 304 (Not Modified) - attempting to re-use cached metadata');
$this->addCachedMetadata($source);
return;
} elseif(!preg_match('@^HTTP/1\.[01]\s200\s@', $responseHeaders[0])) {
// Other error.
SimpleSAML_Logger::debug('Error from ' . $source['src'] . ' - attempting to re-use cached metadata');
$this->addCachedMetadata($source);
return;
}
} else {
/* Local file. */
$data = file_get_contents($source['src']);
$responseHeaders = NULL;
}
/* Everything OK. Proceed. */
if (isset($source['conditionalGET']) && $source['conditionalGET']) {
// Stale or no metadata, so a fresh copy
SimpleSAML_Logger::debug('Downloaded fresh copy');
}
$entities = $this->loadXML($data, $source);
foreach($entities as $entity) {
if(isset($source['blacklist'])) {
if(!empty($source['blacklist']) && in_array($entity->getEntityID(), $source['blacklist'])) {
SimpleSAML_Logger::info('Skipping "' . $entity->getEntityID() . '" - blacklisted.' . "\n");
continue;
}
}
if(isset($source['whitelist'])) {
if(!empty($source['whitelist']) && !in_array($entity->getEntityID(), $source['whitelist'])) {
SimpleSAML_Logger::info('Skipping "' . $entity->getEntityID() . '" - not in the whitelist.' . "\n");
continue;
}
}
if(array_key_exists('validateFingerprint', $source) && $source['validateFingerprint'] !== NULL) {
if(!$entity->validateFingerprint($source['validateFingerprint'])) {
SimpleSAML_Logger::info('Skipping "' . $entity->getEntityId() . '" - could not verify signature.' . "\n");
continue;
}
}
$template = NULL;
if (array_key_exists('template', $source)) $template = $source['template'];
$this->addMetadata($source['src'], $entity->getMetadata1xSP(), 'shib13-sp-remote', $template);
$this->addMetadata($source['src'], $entity->getMetadata1xIdP(), 'shib13-idp-remote', $template);
$this->addMetadata($source['src'], $entity->getMetadata20SP(), 'saml20-sp-remote', $template);
$this->addMetadata($source['src'], $entity->getMetadata20IdP(), 'saml20-idp-remote', $template);
$attributeAuthorities = $entity->getAttributeAuthorities();
if (!empty($attributeAuthorities)) {
$this->addMetadata($source['src'], $attributeAuthorities[0], 'attributeauthority-remote', $template);
}
}
$this->saveState($source, $responseHeaders);
}
/**
* Create HTTP context, with any available caches taken into account
*/
private function createContext($source) {
$context = NULL;
$config = SimpleSAML_Configuration::getInstance();
$name = $config->getString('technicalcontact_name', NULL);
$mail = $config->getString('technicalcontact_email', NULL);
$rawheader = "User-Agent: SimpleSAMLphp metarefresh, run by $name <$mail>\r\n";
if (isset($source['conditionalGET']) && $source['conditionalGET']) {
if(array_key_exists($source['src'], $this->state)) {
$sourceState = $this->state[$source['src']];
if(isset($sourceState['last-modified'])) {
$rawheader .= 'If-Modified-Since: ' . $sourceState['last-modified'] . "\r\n";
}
if(isset($sourceState['etag'])) {
$rawheader .= 'If-None-Match: ' . $sourceState['etag'] . "\r\n";
}
}
}
return array('http' => array('header' => $rawheader));
}
private function addCachedMetadata($source) {
if(isset($this->oldMetadataSrc)) {
foreach(self::$types as $type) {
foreach($this->oldMetadataSrc->getMetadataSet($type) as $entity) {
if(array_key_exists('metarefresh:src', $entity)) {
if($entity['metarefresh:src'] == $source['src']) {
//SimpleSAML_Logger::debug('Re-using cached metadata for ' . $entity['entityid']);
$this->addMetadata($source['src'], $entity, $type);
}
}
}
}
}
}
/**
* Store caching state data for a source
*/
private function saveState($source, $responseHeaders) {
if (isset($source['conditionalGET']) && $source['conditionalGET']) {
// Headers section
$candidates = array('last-modified', 'etag');
foreach($candidates as $candidate) {
if(array_key_exists($candidate, $responseHeaders)) {
$this->state[$source['src']][$candidate] = $responseHeaders[$candidate];
}
}
if(!empty($this->state[$source['src']])) {
// Timestamp when this src was requested.
$this->state[$source['src']]['requested_at'] = $this->getTime();
$this->changed = TRUE;
}
}
}
/**
* Parse XML metadata and return entities
*/
private function loadXML($data, $source) {
$entities = array();
try {
$doc = new DOMDocument();
$res = $doc->loadXML($data);
if($res !== TRUE) {
throw new Exception('Failed to read XML from ' . $source['src']);
}
if($doc->documentElement === NULL) throw new Exception('Opened file is not an XML document: ' . $source['src']);
$entities = SimpleSAML_Metadata_SAMLParser::parseDescriptorsElement($doc->documentElement);
} catch(Exception $e) {
SimpleSAML_Logger::warning('metarefresh: Failed to retrieve metadata. ' . $e->getMessage());
}
return $entities;
}
/**
* This function writes the state array back to disk
*/
public function writeState() {
if($this->changed) {
SimpleSAML_Logger::debug('Writing: ' . $this->stateFile);
SimpleSAML_Utilities::writeFile(
$this->stateFile,
"<?php\n/* This file was generated by the metarefresh module at ".$this->getTime() . ".\n".
" Do not update it manually as it will get overwritten. */\n".
'$state = ' . var_export($this->state, TRUE) . ";\n?>\n",
0644
);
}
}
/**
* This function writes the metadata to stdout.
*/
public function dumpMetadataStdOut() {
foreach($this->metadata as $category => $elements) {
echo('/* The following data should be added to metadata/' . $category . '.php. */' . "\n");
foreach($elements as $m) {
$filename = $m['filename'];
$entityID = $m['metadata']['entityid'];
echo("\n");
echo('/* The following metadata was generated from ' . $filename . ' on ' . $this->getTime() . '. */' . "\n");
echo('$metadata[\'' . addslashes($entityID) . '\'] = ' . var_export($m['metadata'], TRUE) . ';' . "\n");
}
echo("\n");
echo('/* End of data which should be added to metadata/' . $category . '.php. */' . "\n");
echo("\n");
}
}
/**
* This function adds metadata from the specified file to the list of metadata.
* This function will return without making any changes if $metadata is NULL.
*
* @param $filename The filename the metadata comes from.
* @param $metadata The metadata.
* @param $type The metadata type.
*/
private function addMetadata($filename, $metadata, $type, $template = NULL) {
if($metadata === NULL) {
return;
}
if (isset($template)) {
// foreach($metadata AS $mkey => $mentry) {
// echo '<pre>'; print_r($metadata); exit;
// $metadata[$mkey] = array_merge($mentry, $template);
// }
$metadata = array_merge($metadata, $template);
}
$metadata['metarefresh:src'] = $filename;
if(!array_key_exists($type, $this->metadata)) {
$this->metadata[$type] = array();
}
// If expire is defined in constructor...
if (!empty($this->expire)) {
// If expire is already in metadata
if (array_key_exists('expire', $metadata)) {
// Override metadata expire with more restrictive global config-
if ($this->expire < $metadata['expire'])
$metadata['expire'] = $this->expire;
// If expire is not already in metadata use global config
} else {
$metadata['expire'] = $this->expire;
}
}
$this->metadata[$type][] = array('filename' => $filename, 'metadata' => $metadata);
}
/**
* This function writes the metadata to an ARP file
*/
function writeARPfile($config) {
assert('is_a($config, \'SimpleSAML_Configuration\')');
$arpfile = $config->getValue('arpfile');
$types = array('saml20-sp-remote');
$md = array();
foreach($this->metadata as $category => $elements) {
if (!in_array($category, $types)) continue;
$md = array_merge($md, $elements);
}
#$metadata, $attributemap, $prefix, $suffix
$arp = new sspmod_metarefresh_ARP($md,
$config->getValue('attributemap', ''),
$config->getValue('prefix', ''),
$config->getValue('suffix', '')
);
$arpxml = $arp->getXML();
SimpleSAML_Logger::info('Writing ARP file: ' . $arpfile . "\n");
file_put_contents($arpfile, $arpxml);
}
/**
* This function writes the metadata to to separate files in the output directory.
*/
function writeMetadataFiles($outputDir) {
while(strlen($outputDir) > 0 && $outputDir[strlen($outputDir) - 1] === '/') {
$outputDir = substr($outputDir, 0, strlen($outputDir) - 1);
}
if(!file_exists($outputDir)) {
SimpleSAML_Logger::info('Creating directory: ' . $outputDir . "\n");
$res = @mkdir($outputDir, 0777, TRUE);
if ($res === FALSE) {
throw new Exception('Error creating directory: ' . $outputDir);
}
}
foreach(self::$types as $type) {
$filename = $outputDir . '/' . $type . '.php';
if(array_key_exists($type, $this->metadata)) {
$elements = $this->metadata[$type];
SimpleSAML_Logger::debug('Writing: ' . $filename);
$content = '<?php' . "\n" . '/* This file was generated by the metarefresh module at '. $this->getTime() . "\n";
$content .= ' Do not update it manually as it will get overwritten' . "\n" . '*/' . "\n";
foreach($elements as $m) {
$entityID = $m['metadata']['entityid'];
$content .= "\n";
$content .= '$metadata[\'' . addslashes($entityID) . '\'] = ' . var_export($m['metadata'], TRUE) . ';' . "\n";
}
$content .= "\n" . '?>';
SimpleSAML_Utilities::writeFile($filename, $content, 0644);
} elseif(is_file($filename)) {
if(unlink($filename)) {
SimpleSAML_Logger::debug('Deleting stale metadata file: ' . $filename);
} else {
SimpleSAML_Logger::warning('Could not delete stale metadata file: ' . $filename);
}
}
}
}
/**
* Save metadata for loading with the 'serialize' metadata loader.
*
* @param string $outputDir The directory we should save the metadata to.
*/
public function writeMetadataSerialize($outputDir) {
assert('is_string($outputDir)');
$metaHandler = new SimpleSAML_Metadata_MetaDataStorageHandlerSerialize(array('directory' => $outputDir));
/* First we add all the metadata entries to the metadata handler. */
foreach ($this->metadata as $set => $elements) {
foreach ($elements as $m) {
$entityId = $m['metadata']['entityid'];
SimpleSAML_Logger::debug('metarefresh: Add metadata entry ' .
var_export($entityId, TRUE) . ' in set ' . var_export($set, TRUE) . '.');
$metaHandler->saveMetadata($entityId, $set, $m['metadata']);
}
}
/* Then we delete old entries which should no longer exist. */
$ct = time();
foreach ($metaHandler->getMetadataSets() as $set) {
foreach ($metaHandler->getMetadataSet($set) as $entityId => $metadata) {
if (!array_key_exists('expire', $metadata)) {
SimpleSAML_Logger::warning('metarefresh: Metadata entry without expire timestamp: ' . var_export($entityId, TRUE) .
' in set ' . var_export($set, TRUE) . '.');
continue;
}
if ($metadata['expire'] > $ct) {
continue;
}
SimpleSAML_Logger::debug('metarefresh: ' . $entityId . ' expired ' . date('l jS \of F Y h:i:s A', $metadata['expire']) );
SimpleSAML_Logger::debug('metarefresh: Delete expired metadata entry ' .
var_export($entityId, TRUE) . ' in set ' . var_export($set, TRUE) . '. (' . ($ct - $metadata['expire']) . ' sec)');
$metaHandler->deleteMetadata($entityId, $set);
}
}
}
private function getTime() {
/* The current date, as a string. */
date_default_timezone_set('UTC');
$when = date('Y-m-d\\TH:i:s\\Z');
return $when;
}
}
?>

View File

@ -0,0 +1,23 @@
<?php
$this->data['header'] = $this->t('{aggregator:aggregator:aggregator_header}');
$this->includeAtTemplateBase('includes/header.php');
echo('<h1>Metarefresh fetch</h1>');
if (!empty($this->data['logentries'])) {
echo '<pre style="border: 1px solid #aaa; padding: .5em; overflow: scroll">';
foreach($this->data['logentries'] AS $l) {
echo $l . "\n";
}
echo '</pre>';
} else {
echo 'No output from metarefresh.';
}
$this->includeAtTemplateBase('includes/footer.php');
?>

View File

@ -0,0 +1,77 @@
<?php
$config = SimpleSAML_Configuration::getInstance();
$mconfig = SimpleSAML_Configuration::getOptionalConfig('config-metarefresh.php');
SimpleSAML_Utilities::requireAdmin();
SimpleSAML_Logger::setCaptureLog(TRUE);
$sets = $mconfig->getConfigList('sets', array());
foreach ($sets AS $setkey => $set) {
SimpleSAML_Logger::info('[metarefresh]: Executing set [' . $setkey . ']');
try {
$expireAfter = $set->getInteger('expireAfter', NULL);
if ($expireAfter !== NULL) {
$expire = time() + $expireAfter;
} else {
$expire = NULL;
}
$metaloader = new sspmod_metarefresh_MetaLoader($expire);
# Get global black/whitelists
$blacklist = $mconfig->getArray('blacklist', array());
$whitelist = $mconfig->getArray('whitelist', array());
foreach($set->getArray('sources') AS $source) {
# Merge global and src specific blacklists
if(isset($source['blacklist'])) {
$source['blacklist'] = array_unique(array_merge($source['blacklist'], $blacklist));
} else {
$source['blacklist'] = $blacklist;
}
# Merge global and src specific whitelists
if(isset($source['whitelist'])) {
$source['whitelist'] = array_unique(array_merge($source['whitelist'], $whitelist));
} else {
$source['whitelist'] = $whitelist;
}
SimpleSAML_Logger::debug('[metarefresh]: In set [' . $setkey . '] loading source [' . $source['src'] . ']');
$metaloader->loadSource($source);
}
$outputDir = $set->getString('outputDir');
$outputDir = $config->resolvePath($outputDir);
$outputFormat = $set->getValueValidate('outputFormat', array('flatfile', 'serialize'), 'flatfile');
switch ($outputFormat) {
case 'flatfile':
$metaloader->writeMetadataFiles($outputDir);
break;
case 'serialize':
$metaloader->writeMetadataSerialize($outputDir);
break;
}
} catch (Exception $e) {
$e = SimpleSAML_Error_Exception::fromException($e);
$e->logWarning();
}
}
$logentries = SimpleSAML_Logger::getCapturedLog();
$t = new SimpleSAML_XHTML_Template($config, 'metarefresh:fetch.tpl.php');
$t->data['logentries'] = $logentries;
$t->show();