Newer
Older
// do not instantiate a new Configuration instance, but just return null
return null;
}
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.
*
* @return array The array of \SimpleSAML\Configuration objects.
* @throws \Exception If the value of this element is not an array.
*
* @deprecated Very specific function, will be removed in a future release; use getConfigItem or getArray instead
throw new \Exception(
$this->location.': The option '.var_export($name, true).
' is not an array.'
);
foreach ($ret as $index => $config) {
$newLoc = $this->location.'['.var_export($name, true).']['.
var_export($index, true).']';
if (!is_array($config)) {
throw new \Exception($newLoc.': The value of this element was expected to be an array.');
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
}
$out[$index] = self::loadFromArray($config, $newLoc);
}
return $out;
}
/**
* Retrieve list of options.
*
* This function returns the name of all options which are defined in this
* configuration file, as an array of strings.
*
* @return array Name of all options defined in this configuration file.
*/
public function getOptions()
{
return array_keys($this->configuration);
}
/**
* Convert this configuration object back to an array.
*
* @return array An associative array with all configuration options and values.
*/
public function toArray()
{
return $this->configuration;
}
/**
* Retrieve the default binding for the given endpoint type.
*
* This function combines the current metadata type (SAML 2 / SAML 1.1)
* with the endpoint type to determine which binding is the default.
*
* @param string $endpointType The endpoint type.
*
* @return string The default binding.
* @throws \Exception If the default binding is missing for this endpoint type.
*/
private function getDefaultBinding($endpointType)
{
$set = $this->getString('metadata-set');
switch ($set.':'.$endpointType) {
case 'saml20-idp-remote:SingleSignOnService':
case 'saml20-idp-remote:SingleLogoutService':
case 'saml20-sp-remote:SingleLogoutService':
return Constants::BINDING_HTTP_REDIRECT;
case 'saml20-sp-remote:AssertionConsumerService':
return Constants::BINDING_HTTP_POST;
case 'saml20-idp-remote:ArtifactResolutionService':
return Constants::BINDING_SOAP;
case 'shib13-idp-remote:SingleSignOnService':
return 'urn:mace:shibboleth:1.0:profiles:AuthnRequest';
case 'shib13-sp-remote:AssertionConsumerService':
return 'urn:oasis:names:tc:SAML:1.0:profiles:browser-post';
default:
throw new \Exception('Missing default binding for '.$endpointType.' in '.$set);
}
}
/**
* Helper function for dealing with metadata endpoints.
*
* @param string $endpointType The endpoint type.
*
* @return array Array of endpoints of the given type.
* @throws \Exception If any element of the configuration options for this endpoint type is incorrect.
*/
public function getEndpoints($endpointType)
{
$loc = $this->location.'['.var_export($endpointType, true).']:';
if (!array_key_exists($endpointType, $this->configuration)) {
// no endpoints of the given type
}
$eps = $this->configuration[$endpointType];
if (is_string($eps)) {
throw new \Exception($loc.': Expected array or string.');
}
foreach ($eps as $i => &$ep) {
$iloc = $loc.'['.var_export($i, true).']';
if (is_string($ep)) {
'Location' => $ep,
'Binding' => $this->getDefaultBinding($endpointType),
$responseLocation = $this->getString($endpointType.'Response', null);
if ($responseLocation !== null) {
$ep['ResponseLocation'] = $responseLocation;
}
} elseif (!is_array($ep)) {
throw new \Exception($iloc.': Expected a string or an array.');
}
if (!array_key_exists('Location', $ep)) {
throw new \Exception($iloc.': Missing Location.');
}
if (!is_string($ep['Location'])) {
throw new \Exception($iloc.': Location must be a string.');
}
if (!array_key_exists('Binding', $ep)) {
throw new \Exception($iloc.': Missing Binding.');
}
if (!is_string($ep['Binding'])) {
throw new \Exception($iloc.': Binding must be a string.');
}
if (array_key_exists('ResponseLocation', $ep)) {
if (!is_string($ep['ResponseLocation'])) {
throw new \Exception($iloc.': ResponseLocation must be a string.');
}
}
if (array_key_exists('index', $ep)) {
if (!is_int($ep['index'])) {
throw new \Exception($iloc.': index must be an integer.');
}
}
}
return $eps;
}
/**
* Find an endpoint of the given type, using a list of supported bindings as a way to prioritize.
*
* @param string $endpointType The endpoint type.
* @param array $bindings Sorted array of acceptable bindings.
* @param mixed $default The default value to return if no matching endpoint is found. If no default is provided,
* an exception will be thrown.
*
* @return array|null The default endpoint, or null if no acceptable endpoints are used.
*
* @throws \Exception If no supported endpoint is found.
*/
public function getEndpointPrioritizedByBinding($endpointType, array $bindings, $default = self::REQUIRED_OPTION)
{
$endpoints = $this->getEndpoints($endpointType);
foreach ($bindings as $binding) {
foreach ($endpoints as $ep) {
if ($ep['Binding'] === $binding) {
return $ep;
}
}
}
if ($default === self::REQUIRED_OPTION) {
$loc = $this->location.'['.var_export($endpointType, true).']:';
throw new \Exception($loc.'Could not find a supported '.$endpointType.' endpoint.');
}
return $default;
}
/**
* Find the default endpoint of the given type.
*
* @param string $endpointType The endpoint type.
* @param array $bindings Array with acceptable bindings. Can be null if any binding is allowed.
* @param mixed $default The default value to return if no matching endpoint is found. If no default is provided,
* an exception will be thrown.
*
* @return mixed The default endpoint, or the $default parameter if no acceptable endpoints are used.
* @throws \Exception If no supported endpoint is found and no $default parameter is specified.
*/
public function getDefaultEndpoint($endpointType, array $bindings = null, $default = self::REQUIRED_OPTION)
{
$endpoints = $this->getEndpoints($endpointType);
$defaultEndpoint = Utils\Config\Metadata::getDefaultEndpoint($endpoints, $bindings);
if ($defaultEndpoint !== null) {
return $defaultEndpoint;
}
if ($default === self::REQUIRED_OPTION) {
$loc = $this->location.'['.var_export($endpointType, true).']:';
throw new \Exception($loc.'Could not find a supported '.$endpointType.' endpoint.');
}
return $default;
}
/**
* Retrieve a string which may be localized into many languages.
*
* The default language returned is always 'en'.
*
* @param string $name The name of the option.
* @param mixed $default The default value. If no default is given, and the option isn't found, an exception will
* be thrown.
*
* @return mixed Associative array with language => string pairs, or the provided default value.
* @throws \Exception If the translation is not an array or a string, or its index or value are not strings.
*/
public function getLocalizedString($name, $default = self::REQUIRED_OPTION)
{
$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;
}
$loc = $this->location.'['.var_export($name, true).']';
if (is_string($ret)) {
}
if (!is_array($ret)) {
throw new \Exception($loc.': Must be an array or a string.');
}
foreach ($ret as $k => $v) {
if (!is_string($k)) {
throw new \Exception($loc.': Invalid language code: '.var_export($k, true));
throw new \Exception($loc.'['.var_export($v, true).']: Must be a string.');
}
}
return $ret;
}
/**
* Get public key from metadata.
*
* @param string|null $use The purpose this key can be used for. (encryption or signing).
* @param bool $required Whether the public key is required. If this is true, a
* missing key will cause an exception. Default is false.
* @param string $prefix The prefix which should be used when reading from the metadata
* array. Defaults to ''.
*
* @return array Public key data, or empty array if no public key or was found.
* @throws \Exception If the certificate or public key cannot be loaded from a file.
* @throws \SimpleSAML\Error\Exception If the file does not contain a valid PEM-encoded certificate, or there is no
* certificate in the metadata.
*/
public function getPublicKeys($use = null, $required = false, $prefix = '')
{
assert(is_bool($required));
assert(is_string($prefix));
if ($this->hasValue($prefix.'keys')) {
foreach ($this->getArray($prefix.'keys') as $key) {
if ($use !== null && isset($key[$use]) && !$key[$use]) {
continue;
}
if (isset($key['X509Certificate'])) {
$key['X509Certificate'] = preg_replace('/\s+/', '', $key['X509Certificate']);
}
$ret[] = $key;
}
} elseif ($this->hasValue($prefix.'certData')) {
$certData = $this->getString($prefix.'certData');
$certData = preg_replace('/\s+/', '', $certData);
'encryption' => true,
'signing' => true,
'type' => 'X509Certificate',
'X509Certificate' => $certData,
} elseif ($this->hasValue($prefix.'certificate')) {
$file = $this->getString($prefix.'certificate');
$file = Utils\Config::getCertPath($file);
$data = @file_get_contents($file);
if ($data === false) {
throw new \Exception($this->location.': Unable to load certificate/public key from file "'.$file.'".');
// extract certificate data (if this is a certificate)
$pattern = '/^-----BEGIN CERTIFICATE-----([^-]*)^-----END CERTIFICATE-----/m';
if (!preg_match($pattern, $data, $matches)) {
throw new \SimpleSAML\Error\Exception(
$this->location.': Could not find PEM encoded certificate in "'.$file.'".'
);
}
$certData = preg_replace('/\s+/', '', $matches[1]);
'encryption' => true,
'signing' => true,
'type' => 'X509Certificate',
'X509Certificate' => $certData,
} elseif ($required === true) {
throw new \SimpleSAML\Error\Exception($this->location.': Missing certificate in metadata.');
/**
* Clear any configuration information cached.
* Allows for configuration files to be changed and reloaded during a given request. Most useful
* when running phpunit tests and needing to alter config.php between test cases
*/
public static function clearInternalState()
{
self::$configDirs = [];
self::$instance = [];
self::$loadedConfigs = [];