Skip to content
Snippets Groups Projects
Configuration.php 47.1 KiB
Newer Older
/**
 * Configuration of SimpleSAMLphp
 * @author Andreas Aakre Solberg, UNINETT AS. <andreas.solberg@uninett.no>
 * @package SimpleSAMLphp
class SimpleSAML_Configuration
{

    /**
     * A default value which means that the given option is required.
     */
    const REQUIRED_OPTION = '___REQUIRED_OPTION___';


    /**
     * Associative array with mappings from instance-names to configuration objects.
     */
    private static $instance = array();


    /**
     * Configuration directories.
     *
     * This associative array contains the mappings from configuration sets to
     * configuration directories.
     */
    private static $configDirs = array();


    /**
     * Cache of loaded configuration files.
     *
     * The index in the array is the full path to the file.
     */
    private static $loadedConfigs = array();


    /**
     * The configuration array.
     */
    private $configuration;


    /**
     * The location which will be given when an error occurs.
     */
    private $location;


    /**
     * The file this configuration was loaded from.
     */
    private $filename = null;


    /**
     * Temporary property that tells if the deprecated getBaseURL() method has been called or not.
     *
     * @var bool
     */
    private $deprecated_base_url_used = false;


    /**
     * Initializes a configuration from the given array.
     *
     * @param array $config The configuration array.
     * @param string $location The location which will be given when an error occurs.
     */
    public function __construct($config, $location)
    {
        assert('is_array($config)');
        assert('is_string($location)');

        $this->configuration = $config;
        $this->location = $location;
    }


    /**
     * Load the given configuration file.
     *
     * @param string $filename The full path of the configuration file.
     * @param bool $required Whether the file is required.
     * @return SimpleSAML_Configuration The configuration file. An exception will be thrown if the
     *                                   configuration file is missing.
     *
     * @throws Exception If the configuration file is invalid or missing.
     */
    private static function loadFromFile($filename, $required)
    {
        assert('is_string($filename)');
        assert('is_bool($required)');

        if (array_key_exists($filename, self::$loadedConfigs)) {
            return self::$loadedConfigs[$filename];
        }

        if (file_exists($filename)) {
            $config = 'UNINITIALIZED';

            // the file initializes a variable named '$config'
            if (interface_exists('Throwable')) {
                try {
                    require($filename);
                } catch (ParseError $e) {
                    self::$loadedConfigs[$filename] = self::loadFromArray(array(), '[ARRAY]', 'simplesaml');
                    throw new SimpleSAML\Error\ConfigurationError($e->getMessage(), $filename, array());
                }
            } else {
                require($filename);
            }

            // check that $config exists
            if (!isset($config)) {
                throw new \SimpleSAML\Error\ConfigurationError(
                    '$config is not defined in the configuration file.',
                    $filename
                );
            }

            // check that $config is initialized to an array
            if (!is_array($config)) {
                throw new \SimpleSAML\Error\ConfigurationError(
                    '$config is not an array.',
                    $filename
                );
            }

            // check that $config is not empty
            if (empty($config)) {
                throw new \SimpleSAML\Error\ConfigurationError(
                    '$config is empty.',
                    $filename
                );
            }
        } elseif ($required) {
            // file does not exist, but is required
            throw new \SimpleSAML\Error\ConfigurationError('Missing configuration file', $filename);
            // file does not exist, but is optional, so return an empty configuration object without saving it
            $cfg = new SimpleSAML_Configuration(array(), $filename);
            $cfg->filename = $filename;
            return $cfg;
        }

        $cfg = new SimpleSAML_Configuration($config, $filename);
        $cfg->filename = $filename;

        self::$loadedConfigs[$filename] = $cfg;

        if ($spurious_output) {
            SimpleSAML\Logger::warning(
                "The configuration file '$filename' generates output. Please review your configuration."
            );
        }

        return $cfg;
    }


    /**
     * Set the directory for configuration files for the given configuration set.
     *
     * @param string $path The directory which contains the configuration files.
     * @param string $configSet The configuration set. Defaults to 'simplesaml'.
     */
    public static function setConfigDir($path, $configSet = 'simplesaml')
    {
        assert('is_string($path)');
        assert('is_string($configSet)');

        self::$configDirs[$configSet] = $path;
    }


    /**
     * Load a configuration file from a configuration set.
     *
     * @param string $filename The name of the configuration file.
     * @param string $configSet The configuration set. Optional, defaults to 'simplesaml'.
     *
     * @return SimpleSAML_Configuration The SimpleSAML_Configuration object.
     * @throws Exception If the configuration set is not initialized.
     */
    public static function getConfig($filename = 'config.php', $configSet = 'simplesaml')
    {
        assert('is_string($filename)');
        assert('is_string($configSet)');

        if (!array_key_exists($configSet, self::$configDirs)) {
            if ($configSet !== 'simplesaml') {
                throw new Exception('Configuration set \''.$configSet.'\' not initialized.');
            } else {
                self::$configDirs['simplesaml'] = SimpleSAML\Utils\Config::getConfigDir();
            }
        }

        $dir = self::$configDirs[$configSet];
        $filePath = $dir.'/'.$filename;
        return self::loadFromFile($filePath, true);
    }


    /**
     * Load a configuration file from a configuration set.
     *
     * This function will return a configuration object even if the file does not exist.
     *
     * @param string $filename The name of the configuration file.
     * @param string $configSet The configuration set. Optional, defaults to 'simplesaml'.
     *
     * @return SimpleSAML_Configuration A configuration object.
     * @throws Exception If the configuration set is not initialized.
     */
    public static function getOptionalConfig($filename = 'config.php', $configSet = 'simplesaml')
    {
        assert('is_string($filename)');
        assert('is_string($configSet)');

        if (!array_key_exists($configSet, self::$configDirs)) {
            if ($configSet !== 'simplesaml') {
                throw new Exception('Configuration set \''.$configSet.'\' not initialized.');
            } else {
                self::$configDirs['simplesaml'] = SimpleSAML\Utils\Config::getConfigDir();
            }
        }

        $dir = self::$configDirs[$configSet];
        $filePath = $dir.'/'.$filename;
        return self::loadFromFile($filePath, false);
    }


    /**
     * Loads a configuration from the given array.
     *
     * @param array  $config The configuration array.
     * @param string $location The location which will be given when an error occurs. Optional.
     * @param string|null $instance The name of this instance. If specified, the configuration will be loaded and an
     * instance with that name will be kept for it to be retrieved later with getInstance($instance). If null, the
     * configuration will not be kept for later use. Defaults to null.
     * @return SimpleSAML_Configuration The configuration object.
    public static function loadFromArray($config, $location = '[ARRAY]', $instance = null)
    {
        assert('is_array($config)');
        assert('is_string($location)');

        $c = new SimpleSAML_Configuration($config, $location);
        if ($instance !== null) {
            self::$instance[$instance] = $c;
        }
        return $c;
    }


    /**
     * Get a configuration file by its instance name.
     *
     * This function retrieves a configuration file by its instance name. The instance
     * name is initialized by the init function, or by copyFromBase function.
     *
     * If no configuration file with the given instance name is found, an exception will
     * be thrown.
     *
     * @param string $instancename The instance name of the configuration file. Deprecated.
     * @return SimpleSAML_Configuration The configuration object.
     *
     * @throws Exception If the configuration with $instancename name is not initialized.
     */
    public static function getInstance($instancename = 'simplesaml')
    {
        assert('is_string($instancename)');

        // check if the instance exists already
        if (array_key_exists($instancename, self::$instance)) {
            return self::$instance[$instancename];
        }

        if ($instancename === 'simplesaml') {
            try {
                return self::getConfig();
            } catch (SimpleSAML\Error\ConfigurationError $e) {
                throw \SimpleSAML\Error\CriticalConfigurationError::fromException($e);
            }

        throw new \SimpleSAML\Error\CriticalConfigurationError(
            'Configuration with name '.$instancename.' is not initialized.'
        );
    }


    /**
     * Initialize a instance name with the given configuration file.
     *
     * @param string $path
     * @param string $instancename
     * @param string $configfilename
     *
     * @see setConfigDir()
     * @deprecated This function is superseeded by the setConfigDir function.
     */
    public static function init($path, $instancename = 'simplesaml', $configfilename = 'config.php')
    {
        assert('is_string($path)');
        assert('is_string($instancename)');
        assert('is_string($configfilename)');

        if ($instancename === 'simplesaml') {
            // for backwards compatibility
            self::setConfigDir($path, 'simplesaml');
        }

        // check if we already have loaded the given config - return the existing instance if we have
        if (array_key_exists($instancename, self::$instance)) {
            return self::$instance[$instancename];
        }

        self::$instance[$instancename] = self::loadFromFile($path.'/'.$configfilename, true);
        return self::$instance[$instancename];
    }


    /**
     * Load a configuration file which is located in the same directory as this configuration file.
     *
     * @param string $instancename
     * @param string $filename
     *
     * @see getConfig()
     * @deprecated This function is superseeded by the getConfig() function.
     */
    public function copyFromBase($instancename, $filename)
    {
        assert('is_string($instancename)');
        assert('is_string($filename)');
        assert('$this->filename !== NULL');

        // check if we already have loaded the given config - return the existing instance if we have
        if (array_key_exists($instancename, self::$instance)) {
            return self::$instance[$instancename];
        }

        $dir = dirname($this->filename);

        self::$instance[$instancename] = self::loadFromFile($dir.'/'.$filename, true);
        return self::$instance[$instancename];
    }


    /**
     * Retrieve the current version of SimpleSAMLphp.
     *
     * @return string
     */
    public function getVersion()
    {
    }


    /**
     * Retrieve a configuration option set in config.php.
     *
     * @param string $name Name of the configuration option.
     * @param mixed  $default Default value of the configuration option. This parameter will default to null if not
     *                        specified. This can be set to SimpleSAML_Configuration::REQUIRED_OPTION, which will
     *                        cause an exception to be thrown if the option isn't found.
     *
     * @return mixed The configuration option with name $name, or $default if the option was not found.
     *
     * @throws Exception If the required option cannot be retrieved.
     */
    public function getValue($name, $default = null)
    {
        // return the default value if the option is unset
        if (!array_key_exists($name, $this->configuration)) {
            if ($default === self::REQUIRED_OPTION) {
                throw new Exception(
                    $this->location.': Could not retrieve the required option '.
                    var_export($name, true)
                );
            }
            return $default;
        }

        return $this->configuration[$name];
    }


    /**
Jaime Pérez's avatar
Jaime Pérez committed
     * Check whether a key in the configuration exists or not.
     *
     * @param string $name The key in the configuration to look for.
     *
     * @return boolean If the value is set in this configuration.
     */
    public function hasValue($name)
    {
        return array_key_exists($name, $this->configuration);
    }


    /**
     * Check whether any key of the set given exists in the configuration.
     *
     * @param array $names An array of options to look for.
     *
     * @return boolean If any of the keys in $names exist in the configuration
     */
    public function hasValueOneOf($names)
    {
        foreach ($names as $name) {
            if ($this->hasValue($name)) {
                return true;
            }
        }
        return false;
    }


    /**
     * Retrieve the absolute path of the SimpleSAMLphp installation, relative to the root of the website.
     *
     * For example: simplesaml/
     *
     * The path will always end with a '/' and never have a leading slash.
     *
     * @return string The absolute path relative to the root of the website.
     *
     * @throws SimpleSAML\Error\CriticalConfigurationError If the format of 'baseurlpath' is incorrect.
     *
     * @deprecated This method will be removed in SimpleSAMLphp 2.0. Please use getBasePath() instead.
     */
    public function getBaseURL()
    {
        if (!$this->deprecated_base_url_used) {
            $this->deprecated_base_url_used = true;
            SimpleSAML\Logger::warning(
                "SimpleSAML_Configuration::getBaseURL() is deprecated, please use getBasePath() instead."
            );
        }
        if (preg_match('/^\*(.*)$/D', $this->getString('baseurlpath', 'simplesaml/'), $matches)) {
            // deprecated behaviour, will be removed in the future
            return \SimpleSAML\Utils\HTTP::getFirstPathElement(false).$matches[1];
        }
        return ltrim($this->getBasePath(), '/');
    }


    /**
     * Retrieve the absolute path pointing to the SimpleSAMLphp installation.
     *
     * The path is guaranteed to start and end with a slash ('/'). E.g.: /simplesaml/
     *
     * @return string The absolute path where SimpleSAMLphp can be reached in the web server.
     *
     * @throws SimpleSAML\Error\CriticalConfigurationError If the format of 'baseurlpath' is incorrect.
     */
    public function getBasePath()
    {
        $baseURL = $this->getString('baseurlpath', 'simplesaml/');
        if (preg_match('#^https?://[^/]*(?:/(.+/?)?)?$#', $baseURL, $matches)) {
            // we have a full url, we need to strip the path
        } elseif ($baseURL === '' || $baseURL === '/') {
            return '/';
        } elseif (preg_match('#^/?((?:[^/\s]+/?)+)#', $baseURL, $matches)) {
            // local path only
            /*
             * Invalid 'baseurlpath'. We cannot recover from this, so throw a critical exception and try to be graceful
             * with the configuration. Use a guessed base path instead of the one provided.
             */
            $c = $this->toArray();
            $c['baseurlpath'] = SimpleSAML\Utils\HTTP::guessBasePath();
            throw new SimpleSAML\Error\CriticalConfigurationError(
                'Incorrect format for option \'baseurlpath\'. Value is: "'.
                $this->getString('baseurlpath', 'simplesaml/').'". Valid format is in the form'.
                ' [(http|https)://(hostname|fqdn)[:port]]/[path/to/simplesaml/].',
                $this->filename,
                $c
     * This function resolves a path which may be relative to the SimpleSAMLphp base directory.
     *
     * The path will never end with a '/'.
     *
     * @param string|null $path The path we should resolve. This option may be null.
     * @return string|null $path if $path is an absolute path, or $path prepended with the base directory of this
     * SimpleSAMLphp installation. We will return NULL if $path is null.
     */
    public function resolvePath($path)
    {
        if ($path === null) {
            return null;
        }

        assert('is_string($path)');

        /* Prepend path with basedir if it doesn't start with a slash or a Windows drive letter (e.g. "C:\"). We assume
         * getBaseDir ends with a slash.
         */
        if ($path[0] !== '/' &&
            !(preg_match('@^[a-z]:[\\\\/]@i', $path, $matches) && is_dir($matches[0]))
        ) {
            $path = $this->getBaseDir().$path;
        }

        // remove trailing slashes
        $path = rtrim($path, '/');

        return $path;
    }


    /**
     * Retrieve a path configuration option set in config.php.
     *
     * The function will always return an absolute path unless the option is not set. It will then return the default
     * value.
     * It checks if the value starts with a slash, and prefixes it with the value from getBaseDir if it doesn't.
     * @param string $name Name of the configuration option.
     * @param string|null $default Default value of the configuration option. This parameter will default to null if
     * not specified.
     *
     * @return string|null The path configuration option with name $name, or $default if the option was not found.
     */
    public function getPathValue($name, $default = null)
    {
        // return the default value if the option is unset
        if (!array_key_exists($name, $this->configuration)) {
            $path = $default;
        } else {
            $path = $this->configuration[$name];
        }

        if ($path === null) {
            return null;
        }

        return $this->resolvePath($path).'/';
    }


    /**
     * Retrieve the base directory for this SimpleSAMLphp installation.
     *
     * This function first checks the 'basedir' configuration option. If this option is undefined or null, then we
     * fall back to looking at the current filename.
     * @return string The absolute path to the base directory for this SimpleSAMLphp installation. This path will
     * always end with a slash.
     */
    public function getBaseDir()
    {
        // check if a directory is configured in the configuration file
        $dir = $this->getString('basedir', null);
        if ($dir !== null) {
            // add trailing slash if it is missing
            if (substr($dir, -1) !== DIRECTORY_SEPARATOR) {
                $dir .= DIRECTORY_SEPARATOR;
        // the directory wasn't set in the configuration file, path is <base directory>/lib/SimpleSAML/Configuration.php
        $dir = __FILE__;
        assert('basename($dir) === "Configuration.php"');

        $dir = dirname($dir);
        assert('basename($dir) === "SimpleSAML"');

        $dir = dirname($dir);
        assert('basename($dir) === "lib"');

        $dir = dirname($dir);

        // Add trailing directory separator
        $dir .= DIRECTORY_SEPARATOR;

        return $dir;
    }


    /**
     * This function retrieves a boolean configuration option.
     *
     * An exception will be thrown if this option isn't a boolean, or if this option isn't found, and no default value
     * is given.
     *
     * @param string $name The name of the option.
     * @param mixed  $default A default value which will be returned if the option isn't found. The option will be
     *                  required if this parameter isn't given. The default value can be any value, including
     *
     * @return boolean|mixed The option with the given name, or $default if the option isn't found and $default is
     *     specified.
     *
     * @throws Exception If the option is not boolean.
     */
    public function getBoolean($name, $default = self::REQUIRED_OPTION)
    {
        assert('is_string($name)');

        $ret = $this->getValue($name, $default);

        if ($ret === $default) {
            // the option wasn't found, or it matches the default value. In any case, return this value
            return $ret;
        }

        if (!is_bool($ret)) {
            throw new Exception(
                $this->location.': The option '.var_export($name, true).
                ' is not a valid boolean value.'
            );
        }

        return $ret;
    }


    /**
     * This function retrieves a string configuration option.
     *
     * An exception will be thrown if this option isn't a string, or if this option isn't found, and no default value
     * is given.
     *
     * @param string $name The name of the option.
     * @param mixed  $default A default value which will be returned if the option isn't found. The option will be
     *                  required if this parameter isn't given. The default value can be any value, including
     *
     * @return string|mixed The option with the given name, or $default if the option isn't found and $default is
     *     specified.
     *
     * @throws Exception If the option is not a string.
     */
    public function getString($name, $default = self::REQUIRED_OPTION)
    {
        assert('is_string($name)');

        $ret = $this->getValue($name, $default);

        if ($ret === $default) {
            // the option wasn't found, or it matches the default value. In any case, return this value
            return $ret;
        }

        if (!is_string($ret)) {
            throw new Exception(
                $this->location.': The option '.var_export($name, true).
                ' is not a valid string value.'
            );
        }

        return $ret;
    }


    /**
     * This function retrieves an integer configuration option.
     *
     * An exception will be thrown if this option isn't an integer, or if this option isn't found, and no default value
     * is given.
     *
     * @param string $name The name of the option.
     * @param mixed  $default A default value which will be returned if the option isn't found. The option will be
     *                  required if this parameter isn't given. The default value can be any value, including
     *
     * @return int|mixed The option with the given name, or $default if the option isn't found and $default is
     * specified.
     *
     * @throws Exception If the option is not an integer.
     */
    public function getInteger($name, $default = self::REQUIRED_OPTION)
    {
        assert('is_string($name)');

        $ret = $this->getValue($name, $default);

        if ($ret === $default) {
            // the option wasn't found, or it matches the default value. In any case, return this value
            return $ret;
        }

        if (!is_int($ret)) {
            throw new Exception(
                $this->location.': The option '.var_export($name, true).
                ' is not a valid integer value.'
            );
        }

        return $ret;
    }


    /**
     * This function retrieves an integer configuration option where the value must be in the specified range.
     *
     * An exception will be thrown if:
     * - the option isn't an integer
     * - the option isn't found, and no default value is given
     * - the value is outside of the allowed range
     *
     * @param string $name The name of the option.
     * @param int    $minimum The smallest value which is allowed.
     * @param int    $maximum The largest value which is allowed.
     * @param mixed  $default A default value which will be returned if the option isn't found. The option will be
     *                  required if this parameter isn't given. The default value can be any value, including
     *
     * @return int|mixed The option with the given name, or $default if the option isn't found and $default is
     *     specified.
     *
     * @throws Exception If the option is not in the range specified.
     */
    public function getIntegerRange($name, $minimum, $maximum, $default = self::REQUIRED_OPTION)
    {
        assert('is_string($name)');
        assert('is_int($minimum)');
        assert('is_int($maximum)');

        $ret = $this->getInteger($name, $default);

        if ($ret === $default) {
            // the option wasn't found, or it matches the default value. In any case, return this value
            return $ret;
        }

        if ($ret < $minimum || $ret > $maximum) {
            throw new Exception(
                $this->location.': Value of option '.var_export($name, true).
                ' is out of range. Value is '.$ret.', allowed range is ['
                .$minimum.' - '.$maximum.']'
            );
        }

        return $ret;
    }


    /**
     * Retrieve a configuration option with one of the given values.
     *
     * This will check that the configuration option matches one of the given values. The match will use
     * strict comparison. An exception will be thrown if it does not match.
     *
     * The option can be mandatory or optional. If no default value is given, it will be considered to be
     * mandatory, and an exception will be thrown if it isn't provided. If a default value is given, it
     * is considered to be optional, and the default value is returned. The default value is automatically
     * included in the list of allowed values.
     *
     * @param string $name The name of the option.
     * @param array  $allowedValues The values the option is allowed to take, as an array.
     * @param mixed  $default The default value which will be returned if the option isn't found. If this parameter
     *                  isn't given, the option will be considered to be mandatory. The default value can be
     *                  any value, including null.
Jaime Pérez's avatar
Jaime Pérez committed
     * @return mixed The option with the given name, or $default if the option isn't found and $default is given.
     *
     * @throws Exception If the option does not have any of the allowed values.
     */
    public function getValueValidate($name, $allowedValues, $default = self::REQUIRED_OPTION)
    {
        assert('is_string($name)');
        assert('is_array($allowedValues)');

        $ret = $this->getValue($name, $default);
        if ($ret === $default) {
            // the option wasn't found, or it matches the default value. In any case, return this value
            return $ret;
        }

        if (!in_array($ret, $allowedValues, true)) {
            $strValues = array();
            foreach ($allowedValues as $av) {
                $strValues[] = var_export($av, true);
            }
            $strValues = implode(', ', $strValues);

            throw new Exception(
                $this->location.': Invalid value given for the option '.
                var_export($name, true).'. It should have one of the following values: '.
                $strValues.'; but it had the following value: '.var_export($ret, true)
            );
        }

        return $ret;
    }


    /**
     * This function retrieves an array configuration option.
     *
     * An exception will be thrown if this option isn't an array, or if this option isn't found, and no
     * default value is given.
     *
     * @param string $name The name of the option.
     * @param mixed  $default A default value which will be returned if the option isn't found. The option will be
     *                       required if this parameter isn't given. The default value can be any value, including
     * @return array|mixed The option with the given name, or $default if the option isn't found and $default is
     * specified.
     *
     * @throws Exception If the option is not an array.
     */
    public function getArray($name, $default = self::REQUIRED_OPTION)
    {
        assert('is_string($name)');

        $ret = $this->getValue($name, $default);

        if ($ret === $default) {
            // the option wasn't found, or it matches the default value. In any case, return this value
            return $ret;
        }

        if (!is_array($ret)) {
            throw new Exception($this->location.': The option '.var_export($name, true).' is not an array.');
        }

        return $ret;
    }


    /**
     * This function retrieves an array configuration option.
     *
     * If the configuration option isn't an array, it will be converted to an array.
     *
     * @param string $name The name of the option.
     * @param mixed  $default A default value which will be returned if the option isn't found. The option will be
     *                       required if this parameter isn't given. The default value can be any value, including
     *
     * @return array The option with the given name, or $default if the option isn't found and $default is specified.
     */
    public function getArrayize($name, $default = self::REQUIRED_OPTION)
    {
        assert('is_string($name)');

        $ret = $this->getValue($name, $default);

        if ($ret === $default) {
            // the option wasn't found, or it matches the default value. In any case, return this value
            return $ret;
        }

        if (!is_array($ret)) {
            $ret = array($ret);
        }

        return $ret;
    }


    /**
     * This function retrieves a configuration option with a string or an array of strings.
     *
     * If the configuration option is a string, it will be converted to an array with a single string
     *
     * @param string $name The name of the option.
     * @param mixed  $default A default value which will be returned if the option isn't found. The option will be
     *                       required if this parameter isn't given. The default value can be any value, including
     *
     * @return array The option with the given name, or $default if the option isn't found and $default is specified.
     *
     * @throws Exception If the option is not a string or an array of strings.
     */
    public function getArrayizeString($name, $default = self::REQUIRED_OPTION)
    {
        assert('is_string($name)');

        $ret = $this->getArrayize($name, $default);

        if ($ret === $default) {
            // the option wasn't found, or it matches the default value. In any case, return this value
            return $ret;
        }

        foreach ($ret as $value) {
            if (!is_string($value)) {
                throw new Exception(
                    $this->location.': The option '.var_export($name, true).
                    ' must be a string or an array of strings.'
                );
            }
        }

        return $ret;
    }


    /**
     * Retrieve an array as a SimpleSAML_Configuration object.
     *
     * This function will load the value of an option into a SimpleSAML_Configuration object. The option must contain
     * an array.
     * An exception will be thrown if this option isn't an array, or if this option isn't found, and no default value
     * is given.
     *
     * @param string $name The name of the option.
     * @param mixed  $default A default value which will be returned if the option isn't found. The option will be
     *                        required if this parameter isn't given. The default value can be any value, including
     *
     * @return mixed The option with the given name, or $default if the option isn't found and $default is specified.
     *
     * @throws Exception If the option is not an array.
     */
    public function getConfigItem($name, $default = self::REQUIRED_OPTION)
    {
        assert('is_string($name)');

        $ret = $this->getValue($name, $default);

        if ($ret === $default) {
            // the option wasn't found, or it matches the default value. In any case, return this value
            return $ret;
        }

        if (!is_array($ret)) {
            throw new Exception(
                $this->location.': The option '.var_export($name, true).
                ' is not an array.'
            );
        }

        return self::loadFromArray($ret, $this->location.'['.var_export($name, true).']');
    }


    /**
     * Retrieve an array of arrays as an array of SimpleSAML_Configuration objects.
     *
     * This function will retrieve an option containing an array of arrays, and create an array of
     * SimpleSAML_Configuration objects from that array. The indexes in the new array will be the same as the original
     * indexes, but the values will be SimpleSAML_Configuration objects.
     * An exception will be thrown if this option isn't an array of arrays, or if this option isn't found, and no
     * default value is given.
     *
     * @param string $name The name of the option.
     * @param mixed  $default A default value which will be returned if the option isn't found. The option will be
     *                        required if this parameter isn't given. The default value can be any value, including