[BUGFIX] Fix T3editor after PSR-7 change
[Packages/TYPO3.CMS.git] / typo3 / sysext / openid / lib / php-openid / Auth / Yadis / Manager.php
1 <?php
2
3 /**
4 * Yadis service manager to be used during yadis-driven authentication
5 * attempts.
6 *
7 * @package OpenID
8 */
9
10 /**
11 * The base session class used by the Auth_Yadis_Manager. This
12 * class wraps the default PHP session machinery and should be
13 * subclassed if your application doesn't use PHP sessioning.
14 *
15 * @package OpenID
16 */
17 class Auth_Yadis_PHPSession {
18 /**
19 * Set a session key/value pair.
20 *
21 * @param string $name The name of the session key to add.
22 * @param string $value The value to add to the session.
23 */
24 function set($name, $value)
25 {
26 $_SESSION[$name] = $value;
27 }
28
29 /**
30 * Get a key's value from the session.
31 *
32 * @param string $name The name of the key to retrieve.
33 * @param string $default The optional value to return if the key
34 * is not found in the session.
35 * @return string $result The key's value in the session or
36 * $default if it isn't found.
37 */
38 function get($name, $default=null)
39 {
40 if (isset($_SESSION) && array_key_exists($name, $_SESSION)) {
41 return $_SESSION[$name];
42 } else {
43 return $default;
44 }
45 }
46
47 /**
48 * Remove a key/value pair from the session.
49 *
50 * @param string $name The name of the key to remove.
51 */
52 function del($name)
53 {
54 unset($_SESSION[$name]);
55 }
56
57 /**
58 * Return the contents of the session in array form.
59 */
60 function contents()
61 {
62 return $_SESSION;
63 }
64 }
65
66 /**
67 * A session helper class designed to translate between arrays and
68 * objects. Note that the class used must have a constructor that
69 * takes no parameters. This is not a general solution, but it works
70 * for dumb objects that just need to have attributes set. The idea
71 * is that you'll subclass this and override $this->check($data) ->
72 * bool to implement your own session data validation.
73 *
74 * @package OpenID
75 */
76 class Auth_Yadis_SessionLoader {
77 /**
78 * Override this.
79 *
80 * @access private
81 */
82 function check($data)
83 {
84 return true;
85 }
86
87 /**
88 * Given a session data value (an array), this creates an object
89 * (returned by $this->newObject()) whose attributes and values
90 * are those in $data. Returns null if $data lacks keys found in
91 * $this->requiredKeys(). Returns null if $this->check($data)
92 * evaluates to false. Returns null if $this->newObject()
93 * evaluates to false.
94 *
95 * @access private
96 */
97 function fromSession($data)
98 {
99 if (!$data) {
100 return null;
101 }
102
103 $required = $this->requiredKeys();
104
105 foreach ($required as $k) {
106 if (!array_key_exists($k, $data)) {
107 return null;
108 }
109 }
110
111 if (!$this->check($data)) {
112 return null;
113 }
114
115 $data = array_merge($data, $this->prepareForLoad($data));
116 $obj = $this->newObject($data);
117
118 if (!$obj) {
119 return null;
120 }
121
122 foreach ($required as $k) {
123 $obj->$k = $data[$k];
124 }
125
126 return $obj;
127 }
128
129 /**
130 * Prepares the data array by making any necessary changes.
131 * Returns an array whose keys and values will be used to update
132 * the original data array before calling $this->newObject($data).
133 *
134 * @access private
135 */
136 function prepareForLoad($data)
137 {
138 return array();
139 }
140
141 /**
142 * Returns a new instance of this loader's class, using the
143 * session data to construct it if necessary. The object need
144 * only be created; $this->fromSession() will take care of setting
145 * the object's attributes.
146 *
147 * @access private
148 */
149 function newObject($data)
150 {
151 return null;
152 }
153
154 /**
155 * Returns an array of keys and values built from the attributes
156 * of $obj. If $this->prepareForSave($obj) returns an array, its keys
157 * and values are used to update the $data array of attributes
158 * from $obj.
159 *
160 * @access private
161 */
162 function toSession($obj)
163 {
164 $data = array();
165 foreach ($obj as $k => $v) {
166 $data[$k] = $v;
167 }
168
169 $extra = $this->prepareForSave($obj);
170
171 if ($extra && is_array($extra)) {
172 foreach ($extra as $k => $v) {
173 $data[$k] = $v;
174 }
175 }
176
177 return $data;
178 }
179
180 /**
181 * Override this.
182 *
183 * @access private
184 */
185 function prepareForSave($obj)
186 {
187 return array();
188 }
189 }
190
191 /**
192 * A concrete loader implementation for Auth_OpenID_ServiceEndpoints.
193 *
194 * @package OpenID
195 */
196 class Auth_OpenID_ServiceEndpointLoader extends Auth_Yadis_SessionLoader {
197 function newObject($data)
198 {
199 return new Auth_OpenID_ServiceEndpoint();
200 }
201
202 function requiredKeys()
203 {
204 $obj = new Auth_OpenID_ServiceEndpoint();
205 $data = array();
206 foreach ($obj as $k => $v) {
207 $data[] = $k;
208 }
209 return $data;
210 }
211
212 function check($data)
213 {
214 return is_array($data['type_uris']);
215 }
216 }
217
218 /**
219 * A concrete loader implementation for Auth_Yadis_Managers.
220 *
221 * @package OpenID
222 */
223 class Auth_Yadis_ManagerLoader extends Auth_Yadis_SessionLoader {
224 function requiredKeys()
225 {
226 return array('starting_url',
227 'yadis_url',
228 'services',
229 'session_key',
230 '_current',
231 'stale');
232 }
233
234 function newObject($data)
235 {
236 return new Auth_Yadis_Manager($data['starting_url'],
237 $data['yadis_url'],
238 $data['services'],
239 $data['session_key']);
240 }
241
242 function check($data)
243 {
244 return is_array($data['services']);
245 }
246
247 function prepareForLoad($data)
248 {
249 $loader = new Auth_OpenID_ServiceEndpointLoader();
250 $services = array();
251 foreach ($data['services'] as $s) {
252 $services[] = $loader->fromSession($s);
253 }
254 return array('services' => $services);
255 }
256
257 function prepareForSave($obj)
258 {
259 $loader = new Auth_OpenID_ServiceEndpointLoader();
260 $services = array();
261 foreach ($obj->services as $s) {
262 $services[] = $loader->toSession($s);
263 }
264 return array('services' => $services);
265 }
266 }
267
268 /**
269 * The Yadis service manager which stores state in a session and
270 * iterates over <Service> elements in a Yadis XRDS document and lets
271 * a caller attempt to use each one. This is used by the Yadis
272 * library internally.
273 *
274 * @package OpenID
275 */
276 class Auth_Yadis_Manager {
277
278 /**
279 * Intialize a new yadis service manager.
280 *
281 * @access private
282 */
283 function Auth_Yadis_Manager($starting_url, $yadis_url,
284 $services, $session_key)
285 {
286 // The URL that was used to initiate the Yadis protocol
287 $this->starting_url = $starting_url;
288
289 // The URL after following redirects (the identifier)
290 $this->yadis_url = $yadis_url;
291
292 // List of service elements
293 $this->services = $services;
294
295 $this->session_key = $session_key;
296
297 // Reference to the current service object
298 $this->_current = null;
299
300 // Stale flag for cleanup if PHP lib has trouble.
301 $this->stale = false;
302 }
303
304 /**
305 * @access private
306 */
307 function length()
308 {
309 // How many untried services remain?
310 return count($this->services);
311 }
312
313 /**
314 * Return the next service
315 *
316 * $this->current() will continue to return that service until the
317 * next call to this method.
318 */
319 function nextService()
320 {
321
322 if ($this->services) {
323 $this->_current = array_shift($this->services);
324 } else {
325 $this->_current = null;
326 }
327
328 return $this->_current;
329 }
330
331 /**
332 * @access private
333 */
334 function current()
335 {
336 // Return the current service.
337 // Returns None if there are no services left.
338 return $this->_current;
339 }
340
341 /**
342 * @access private
343 */
344 function forURL($url)
345 {
346 return in_array($url, array($this->starting_url, $this->yadis_url));
347 }
348
349 /**
350 * @access private
351 */
352 function started()
353 {
354 // Has the first service been returned?
355 return $this->_current !== null;
356 }
357 }
358
359 /**
360 * State management for discovery.
361 *
362 * High-level usage pattern is to call .getNextService(discover) in
363 * order to find the next available service for this user for this
364 * session. Once a request completes, call .cleanup() to clean up the
365 * session state.
366 *
367 * @package OpenID
368 */
369 class Auth_Yadis_Discovery {
370
371 /**
372 * @access private
373 */
374 var $DEFAULT_SUFFIX = 'auth';
375
376 /**
377 * @access private
378 */
379 var $PREFIX = '_yadis_services_';
380
381 /**
382 * Initialize a discovery object.
383 *
384 * @param Auth_Yadis_PHPSession $session An object which
385 * implements the Auth_Yadis_PHPSession API.
386 * @param string $url The URL on which to attempt discovery.
387 * @param string $session_key_suffix The optional session key
388 * suffix override.
389 */
390 function Auth_Yadis_Discovery($session, $url,
391 $session_key_suffix = null)
392 {
393 /// Initialize a discovery object
394 $this->session = $session;
395 $this->url = $url;
396 if ($session_key_suffix === null) {
397 $session_key_suffix = $this->DEFAULT_SUFFIX;
398 }
399
400 $this->session_key_suffix = $session_key_suffix;
401 $this->session_key = $this->PREFIX . $this->session_key_suffix;
402 }
403
404 /**
405 * Return the next authentication service for the pair of
406 * user_input and session. This function handles fallback.
407 */
408 function getNextService($discover_cb, $fetcher)
409 {
410 $manager = $this->getManager();
411 if (!$manager || (!$manager->services)) {
412 $this->destroyManager();
413
414 list($yadis_url, $services) = call_user_func_array($discover_cb,
415 array(
416 $this->url,
417 $fetcher,
418 ));
419
420 $manager = $this->createManager($services, $yadis_url);
421 }
422
423 if ($manager) {
424 $loader = new Auth_Yadis_ManagerLoader();
425 $service = $manager->nextService();
426 $this->session->set($this->session_key,
427 serialize($loader->toSession($manager)));
428 } else {
429 $service = null;
430 }
431
432 return $service;
433 }
434
435 /**
436 * Clean up Yadis-related services in the session and return the
437 * most-recently-attempted service from the manager, if one
438 * exists.
439 *
440 * @param $force True if the manager should be deleted regardless
441 * of whether it's a manager for $this->url.
442 */
443 function cleanup($force=false)
444 {
445 $manager = $this->getManager($force);
446 if ($manager) {
447 $service = $manager->current();
448 $this->destroyManager($force);
449 } else {
450 $service = null;
451 }
452
453 return $service;
454 }
455
456 /**
457 * @access private
458 */
459 function getSessionKey()
460 {
461 // Get the session key for this starting URL and suffix
462 return $this->PREFIX . $this->session_key_suffix;
463 }
464
465 /**
466 * @access private
467 *
468 * @param $force True if the manager should be returned regardless
469 * of whether it's a manager for $this->url.
470 */
471 function getManager($force=false)
472 {
473 // Extract the YadisServiceManager for this object's URL and
474 // suffix from the session.
475
476 $manager_str = $this->session->get($this->getSessionKey());
477 $manager = null;
478
479 if ($manager_str !== null) {
480 $loader = new Auth_Yadis_ManagerLoader();
481 $manager = $loader->fromSession(unserialize($manager_str));
482 }
483
484 if ($manager && ($manager->forURL($this->url) || $force)) {
485 return $manager;
486 }
487 }
488
489 /**
490 * @access private
491 */
492 function createManager($services, $yadis_url = null)
493 {
494 $key = $this->getSessionKey();
495 if ($this->getManager()) {
496 return $this->getManager();
497 }
498
499 if ($services) {
500 $loader = new Auth_Yadis_ManagerLoader();
501 $manager = new Auth_Yadis_Manager($this->url, $yadis_url,
502 $services, $key);
503 $this->session->set($this->session_key,
504 serialize($loader->toSession($manager)));
505 return $manager;
506 }
507 }
508
509 /**
510 * @access private
511 *
512 * @param $force True if the manager should be deleted regardless
513 * of whether it's a manager for $this->url.
514 */
515 function destroyManager($force=false)
516 {
517 if ($this->getManager($force) !== null) {
518 $key = $this->getSessionKey();
519 $this->session->del($key);
520 }
521 }
522 }
523