Commit eee3f965 authored by Francis Devine's avatar Francis Devine Committed by Robert Lyon

Bug 1722435: Add support for refreshing SAML metadata regularly

We utilise the simplesamlphp metarefresh plugin, and hook it into the
mahara cron for the auth plugin.

This adds a new field to each instance configuration form that allows
the user to specify a url that metadata should be fetched from.

This information is fed into the metarefresh plugin's config and a cron
hook is run every hour that triggers the plugin.

The simplesamlphp configuration is updated to read both the metarefresh
target location and the normal xml config file location, with the
metarefresh config files taking precedence.

NB: because of the way that the auth/saml plugin stores the idp entity
ids you are still required to present an XML file at least once, with
the metadata refresh config only taking over once it's fetched in the
next run.

This gives a smooth upgrade path for all existing mahara instances,
where they should continue to operate as normal, and then an
administrator can add the metadata refresh url at their leisure and have
it take precedence as soon as the metadata is available


Change-Id: Ib5733f7526a1c19d3150b45d90c9b675d4dd7ad2
parent c9280d5a
* @package mahara
* @subpackage auth-saml
* @author Francis Devine <>
* @author Catalyst IT Ltd
* @license GNU GPL version 3 or later
* @copyright For copyright information on Mahara, please see the README file distributed with this software.
* @copyright (C) 2011 INSA de Lyon France
* This will manually trigger the metarefresh hook outside of the cron context
* useful for debugging any issues that you might find
define('INTERNAL', 1);
define('ADMIN', 1);
define('INSTALLER', 1);
define('CLI', 1);
require(dirname(dirname(dirname(dirname(__FILE__)))) . '/init.php');
require(get_config('libroot') . 'cli.php');
require(get_config('docroot') . 'auth/saml/lib.php');
$cli = get_cli();
$options = array();
$settings = new stdClass();
$settings->options = $options;
try {
// we catch any unexpected errors (inner hook also has a try catch since it runs in cron)
catch (Exception $e) {
cli::cli_exit($e->getMessage(), true);
cli::cli_exit('---------- ended at ' . date('r', time()) . ' ----------', true);
* @package mahara
* @subpackage auth-saml
* @author Francis Devine <>
* @license GNU GPL version 3 or later
* @copyright For copyright information on Mahara, please see the README file distributed with this software.
$finalsources = array();
$sources = Metarefresh::get_metadata_urls();
//Pull through each idp's fetch url
foreach($sources as $identityid => $src) {
$finalsources[] = array('src' => $src);
$config = array(
'conditionalGET' => TRUE,
//We only have one set of automatic idps, theoretically someone could add more sets if they have unique requirements
//around templating and so forth
'sets' => array(
'remote-idp' => array(
'cron' => array('hourly'),
'sources' => $finalsources,
'expireAfter' => 60*60*24*4, // Maximum 4 days cache time.
'outputDir' => Metarefresh::get_metadata_path(),
'outputFormat' => 'flatfile',
......@@ -20,11 +20,17 @@ $path = realpath('../lib');
set_include_path($path . PATH_SEPARATOR . get_include_path());
// calculate the log process name
$LOG_PROCESS = explode('.', $_SERVER['HTTP_HOST']);
$LOG_PROCESS = explode('.', get_config('wwwroot'));
$LOG_PROCESS = 'ssphp-' . array_shift($LOG_PROCESS);
$metadata_files = glob(AuthSaml::get_metadata_path() . '*.xml');
$metadata_sources = array();
//This must be first so we always prefer the meta refresh metadata files
//over the xml files wherever we can
$metadata_sources[] = array('type' => 'flatfile', 'directory' => Metarefresh::get_metadata_path());
//Now load any xml files from the xml style metadata
foreach ($metadata_files as $file) {
$metadata_sources[]= array('type' => 'xml', 'file' => $file);
......@@ -112,7 +118,7 @@ $config = array (
* A possible way to generate a random salt is by running the following command from a unix shell:
* tr -c -d '0123456789abcdefghijklmnopqrstuvwxyz' </dev/urandom | dd bs=32 count=1 2>/dev/null;echo
'secretsalt' => get_config('installation_key') . $_SERVER['HTTP_HOST'],
'secretsalt' => get_config('installation_key') . get_config('wwwroot'),
* Some information about the technical persons running this installation.
......@@ -19,6 +19,7 @@ $idp = param_variable('idp', null);
$data = new StdClass();
if (file_exists(AuthSaml::prepare_metadata_path($idp))) {
$rawxml = file_get_contents(AuthSaml::prepare_metadata_path($idp));
$data->metarefresh_metadata_url = Metarefresh::get_metadata_url($idp);
$data->metadata = $rawxml;
$data->error = false;
......@@ -54,6 +54,7 @@ $string['idpentityupdatedduplicates'] = array(
0 => "Updated the Identity Provider metadata for this and 1 other SAML instance.",
1 => "Updated the Identity Provider metadata for this and %s other SAML instances."
$string['metarefresh_metadata_url'] = 'Metadata URL to auto refresh from';
$string['idpprovider'] = 'Provider';
$string['institutionattribute'] = 'Institution attribute (contains "%s")';
$string['institutionidp'] = 'Institution Identity Provider SAML metadata';
<!-- @license GNU GPL version 3 or later -->
<!-- @copyright For copyright information on Mahara, please see the README file distributed with this software. -->
<h3>Metadata Refresh URL</h3>
<p>If a valid URL is provided in this field the SAML plugin will automatically download the latest metadata and store it locally, this removes the need to manually update the metadata when it changes on your Identity Provider. Note that the data fetched from this URL will take precedence over the XML metadata and replace it</p>
This diff is collapsed.
......@@ -11,8 +11,8 @@
defined('INTERNAL') || die();
$config = new StdClass;
$config->version = 2018021600;
$config->release = '1.2.4';
$config->version = 2018030800;
$config->release = '1.3.0';
$config->name = 'saml';
$config->requires_config = 1;
$config->requires_parent = 0;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment