1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
|
<?php
/**
* This file defines a class for metadata handling.
*
* @author Andreas Åkre Solberg, UNINETT AS. <andreas.solberg@uninett.no>
* @package simpleSAMLphp
*/
class SimpleSAML_Metadata_MetaDataStorageHandler {
/**
* This static variable contains a reference to the current
* instance of the metadata handler. This variable will be NULL if
* we haven't instantiated a metadata handler yet.
*/
private static $metadataHandler = NULL;
/**
* This is a list of all the metadata sources we have in our metadata
* chain. When we need metadata, we will look through this chain from start to end.
*/
private $sources;
/**
* This function retrieves the current instance of the metadata handler.
* The metadata handler will be instantiated if this is the first call
* to this fuunction.
*
* @return The current metadata handler instance.
*/
public static function getMetadataHandler() {
if(self::$metadataHandler === NULL) {
self::$metadataHandler = new SimpleSAML_Metadata_MetaDataStorageHandler();
}
return self::$metadataHandler;
}
/**
* This constructor initializes this metadata storage handler. It will load and
* parse the configuration, and initialize the metadata source list.
*/
protected function __construct() {
$config = SimpleSAML_Configuration::getInstance();
$sourcesConfig = $config->getArray('metadata.sources', NULL);
/* For backwards compatibility, and to provide a default configuration. */
if($sourcesConfig === NULL) {
$type = $config->getString('metadata.handler', 'flatfile');
$sourcesConfig = array(array('type' => $type));
}
try {
$this->sources = SimpleSAML_Metadata_MetaDataStorageSource::parseSources($sourcesConfig);
} catch (Exception $e) {
throw new Exception('Invalid configuration of the \'metadata.sources\'' .
' configuration option: ' . $e->getMessage());
}
}
/**
* This function is used to generate some metadata elements automatically.
*
* @param $property The metadata property which should be autogenerated.
* @param $set The set we the property comes from.
* @return The autogenerated metadata property.
*/
public function getGenerated($property, $set) {
/* First we check if the user has overridden this property in the metadata. */
try {
$metadataSet = $this->getMetaDataCurrent($set);
if(array_key_exists($property, $metadataSet)) {
return $metadataSet[$property];
}
} catch(Exception $e) {
/* Probably metadata wasn't found. In any case we continue by generating the metadata. */
}
/* Get the configuration. */
$config = SimpleSAML_Configuration::getInstance();
assert($config instanceof SimpleSAML_Configuration);
$baseurl = \SimpleSAML\Utils\HTTP::getSelfURLHost() . '/' .
$config->getBaseURL();
if ($set == 'saml20-sp-hosted') {
switch ($property) {
case 'SingleLogoutServiceBinding' :
return SAML2_Const::BINDING_HTTP_REDIRECT;
}
} elseif($set == 'saml20-idp-hosted') {
switch ($property) {
case 'SingleSignOnService' :
return $baseurl . 'saml2/idp/SSOService.php';
case 'SingleSignOnServiceBinding' :
return SAML2_Const::BINDING_HTTP_REDIRECT;
case 'SingleLogoutService' :
return $baseurl . 'saml2/idp/SingleLogoutService.php';
case 'SingleLogoutServiceBinding' :
return SAML2_Const::BINDING_HTTP_REDIRECT;
}
} elseif($set == 'shib13-idp-hosted') {
switch ($property) {
case 'SingleSignOnService' :
return $baseurl . 'shib13/idp/SSOService.php';
}
}
throw new Exception('Could not generate metadata property ' . $property . ' for set ' . $set . '.');
}
/**
* This function lists all known metadata in the given set. It is returned as an associative array
* where the key is the entity id.
*
* @param $set The set we want to list metadata from.
* @return An associative array with the metadata from from the given set.
*/
public function getList($set = 'saml20-idp-remote') {
assert('is_string($set)');
$result = array();
foreach($this->sources as $source) {
$srcList = $source->getMetadataSet($set);
foreach($srcList AS $key => $le) {
if (array_key_exists('expire', $le)) {
if ($le['expire'] < time()) {
unset($srcList[$key]);
SimpleSAML_Logger::warning("Dropping metadata entity " .
var_export($key,true) . ", expired " .
SimpleSAML\Utils\Time::generateTimestamp($le['expire']) .
".");
}
}
}
/* $result is the last argument to array_merge because we want the content already
* in $result to have precedence.
*/
$result = array_merge($srcList, $result);
}
return $result;
}
/**
* This function retrieves metadata for the current entity based on the hostname/path the request
* was directed to. It will throw an exception if it is unable to locate the metadata.
*
* @param $set The set we want metadata from.
* @return An associative array with the metadata.
*/
public function getMetaDataCurrent($set) {
return $this->getMetaData(NULL, $set);
}
/**
* This function locates the current entity id based on the hostname/path combination the user accessed.
* It will throw an exception if it is unable to locate the entity id.
*
* @param $set The set we look for the entity id in.
* @param $type Do you want to return the metaindex or the entityID. [entityid|metaindex]
* @return The entity id which is associated with the current hostname/path combination.
*/
public function getMetaDataCurrentEntityID($set, $type = 'entityid') {
assert('is_string($set)');
/* First we look for the hostname/path combination. */
$currenthostwithpath = \SimpleSAML\Utils\HTTP::getSelfHostWithPath(); // sp.example.org/university
foreach($this->sources as $source) {
$index = $source->getEntityIdFromHostPath($currenthostwithpath, $set, $type);
if($index !== NULL) {
return $index;
}
}
/* Then we look for the hostname. */
$currenthost = \SimpleSAML\Utils\HTTP::getSelfHost(); // sp.example.org
if(strpos($currenthost, ":") !== FALSE) {
$currenthostdecomposed = explode(":", $currenthost);
$currenthost = $currenthostdecomposed[0];
}
foreach($this->sources as $source) {
$index = $source->getEntityIdFromHostPath($currenthost, $set, $type);
if($index !== NULL) {
return $index;
}
}
/* Then we look for the DEFAULT entry. */
foreach($this->sources as $source) {
$entityId = $source->getEntityIdFromHostPath('__DEFAULT__', $set, $type);
if($entityId !== NULL) {
return $entityId;
}
}
/* We were unable to find the hostname/path in any metadata source. */
throw new Exception('Could not find any default metadata entities in set [' . $set . '] for host [' . $currenthost . ' : ' . $currenthostwithpath . ']');
}
/**
* This method will call getPreferredEntityIdFromCIDRhint() on all of the
* sources.
*
* @param $set Which set of metadata we are looking it up in.
* @param $ip IP address
* @return The entity id of a entity which have a CIDR hint where the provided
* IP address match.
*/
public function getPreferredEntityIdFromCIDRhint($set, $ip) {
foreach($this->sources as $source) {
$entityId = $source->getPreferredEntityIdFromCIDRhint($set, $ip);
if($entityId !== NULL) {
return $entityId;
}
}
return NULL;
}
/**
* This function looks up the metadata for the given entity id in the given set. It will throw an
* exception if it is unable to locate the metadata.
*
* @param $index The entity id we are looking up. This parameter may be NULL, in which case we look up
* the current entity id based on the current hostname/path.
* @param $set The set of metadata we are looking up the entity id in.
*/
public function getMetaData($index, $set) {
assert('is_string($set)');
if($index === NULL) {
$index = $this->getMetaDataCurrentEntityID($set, 'metaindex');
}
assert('is_string($index)');
foreach($this->sources as $source) {
$metadata = $source->getMetaData($index, $set);
if($metadata !== NULL) {
if (array_key_exists('expire', $metadata)) {
if ($metadata['expire'] < time()) {
throw new Exception('Metadata for the entity [' . $index . '] expired ' .
(time() - $metadata['expire']) . ' seconds ago.'
);
}
}
$metadata['metadata-index'] = $index;
$metadata['metadata-set'] = $set;
assert('array_key_exists("entityid", $metadata)');
return $metadata;
}
}
throw new SimpleSAML_Error_MetadataNotFound($index);
}
/**
* Retrieve the metadata as a configuration object.
*
* This function will throw an exception if it is unable to locate the metadata.
*
* @param string $entityId The entity ID we are looking up.
* @param string $set The metadata set we are searching.
* @return SimpleSAML_Configuration The configuration object representing the metadata.
*/
public function getMetaDataConfig($entityId, $set) {
assert('is_string($entityId)');
assert('is_string($set)');
$metadata = $this->getMetaData($entityId, $set);
return SimpleSAML_Configuration::loadFromArray($metadata, $set . '/' . var_export($entityId, TRUE));
}
public function getMetaDataConfigForSha1($sha1, $set) {
assert('is_string($sha1)');
assert('is_string($set)');
$result = array();
foreach($this->sources as $source) {
$srcList = $source->getMetadataSet($set);
/* $result is the last argument to array_merge because we want the content already
* in $result to have precedence.
*/
$result = array_merge($srcList, $result);
}
foreach($result as $remote_provider ){
if(sha1($remote_provider['entityid'])==$sha1){
$remote_provider['metadata-set'] = $set;
return SimpleSAML_Configuration::loadFromArray($remote_provider, $set . '/' . var_export($remote_provider['entityid'], TRUE));
}
}
return null;
}
}
|