Newer
Older
*
* @throws Exception If the value of this element is not an array.
*/
public function getConfigList($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.'
);
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
}
$out = 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.');
}
$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)
{
assert('is_string($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 \SAML2\Constants::BINDING_HTTP_REDIRECT;
case 'saml20-sp-remote:AssertionConsumerService':
return \SAML2\Constants::BINDING_HTTP_POST;
case 'saml20-idp-remote:ArtifactResolutionService':
return \SAML2\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)
{
assert('is_string($endpointType)');
$loc = $this->location.'['.var_export($endpointType, true).']:';
if (!array_key_exists($endpointType, $this->configuration)) {
// no endpoints of the given type
return array();
}
$eps = $this->configuration[$endpointType];
if (is_string($eps)) {
$eps = array($eps);
} elseif (!is_array($eps)) {
throw new Exception($loc.': Expected array or string.');
}
foreach ($eps as $i => &$ep) {
$iloc = $loc.'['.var_export($i, true).']';
if (is_string($ep)) {
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
$ep = array(
'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.
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
*/
public function getEndpointPrioritizedByBinding($endpointType, array $bindings, $default = self::REQUIRED_OPTION)
{
assert('is_string($endpointType)');
$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 array|null The default endpoint, or null if no acceptable endpoints are used.
*
* @throws Exception If no supported endpoint is found.
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
*/
public function getDefaultEndpoint($endpointType, array $bindings = null, $default = self::REQUIRED_OPTION)
{
assert('is_string($endpointType)');
$endpoints = $this->getEndpoints($endpointType);
$defaultEndpoint = \SimpleSAML\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 array Associative array with language => string pairs.
*
* @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)
{
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
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
return $ret;
}
$loc = $this->location.'['.var_export($name, true).']';
if (is_string($ret)) {
$ret = array('en' => $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));
}
if (!is_string($v)) {
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|null Public key data, or null 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')) {
$ret = array();
foreach ($this->getArray($prefix.'keys') as $key) {
if ($use !== null && isset($key[$use]) && !$key[$use]) {
continue;
}
if (isset($key['X509Certificate'])) {
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
$key['X509Certificate'] = preg_replace('/\s+/', '', $key['X509Certificate']);
}
$ret[] = $key;
}
if (!empty($ret)) {
return $ret;
}
} elseif ($this->hasValue($prefix.'certData')) {
$certData = $this->getString($prefix.'certData');
$certData = preg_replace('/\s+/', '', $certData);
return array(
array(
'encryption' => true,
'signing' => true,
'type' => 'X509Certificate',
'X509Certificate' => $certData,
),
);
} elseif ($this->hasValue($prefix.'certificate')) {
$file = $this->getString($prefix.'certificate');
$file = \SimpleSAML\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)
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
$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]);
return array(
array(
'encryption' => true,
'signing' => true,
'type' => 'X509Certificate',
'X509Certificate' => $certData,
),
);
}
if ($required) {
throw new SimpleSAML_Error_Exception($this->location.': Missing certificate in metadata.');
} else {
return null;
}
}
/**
* 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 = array();
self::$instance = array();
self::$loadedConfigs = array();
}