Newer
Older
* @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.
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
*/
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_Const::BINDING_HTTP_REDIRECT;
case 'saml20-sp-remote:AssertionConsumerService':
return SAML2_Const::BINDING_HTTP_POST;
case 'saml20-idp-remote:ArtifactResolutionService':
return SAML2_Const::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)) {
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
$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.
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
*/
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.
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
*/
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
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
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'])) {
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
$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)
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
$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;
}
}