1: <?php
  2: 
  3:   4:   5: 
  6: 
  7: require_once "Auth/OpenID.php";
  8: require_once "Auth/OpenID/Parse.php";
  9: require_once "Auth/OpenID/Message.php";
 10: require_once "Auth/Yadis/XRIRes.php";
 11: require_once "Auth/Yadis/Yadis.php";
 12: 
 13: 
 14: define('Auth_OpenID_XMLNS_1_0', 'http://openid.net/xmlns/1.0');
 15: 
 16: 
 17: define('Auth_OpenID_TYPE_1_2', 'http://openid.net/signon/1.2');
 18: define('Auth_OpenID_TYPE_1_1', 'http://openid.net/signon/1.1');
 19: define('Auth_OpenID_TYPE_1_0', 'http://openid.net/signon/1.0');
 20: define('Auth_OpenID_TYPE_2_0_IDP', 'http://specs.openid.net/auth/2.0/server');
 21: define('Auth_OpenID_TYPE_2_0', 'http://specs.openid.net/auth/2.0/signon');
 22: define('Auth_OpenID_RP_RETURN_TO_URL_TYPE',
 23:        'http://specs.openid.net/auth/2.0/return_to');
 24: 
 25: function Auth_OpenID_getOpenIDTypeURIs()
 26: {
 27:     return array(Auth_OpenID_TYPE_2_0_IDP,
 28:                  Auth_OpenID_TYPE_2_0,
 29:                  Auth_OpenID_TYPE_1_2,
 30:                  Auth_OpenID_TYPE_1_1,
 31:                  Auth_OpenID_TYPE_1_0);
 32: }
 33: 
 34: function Auth_OpenID_getOpenIDConsumerTypeURIs()
 35: {
 36:     return array(Auth_OpenID_RP_RETURN_TO_URL_TYPE);
 37: }
 38: 
 39: 
 40:  41:  42:  43: 
 44: function Auth_OpenID_getOpenIDTypeName($type_uri) {
 45:     switch ($type_uri) {
 46:     case Auth_OpenID_TYPE_2_0_IDP:
 47:       return 'OpenID 2.0 IDP';
 48:     case Auth_OpenID_TYPE_2_0:
 49:       return 'OpenID 2.0';
 50:     case Auth_OpenID_TYPE_1_2:
 51:       return 'OpenID 1.2';
 52:     case Auth_OpenID_TYPE_1_1:
 53:       return 'OpenID 1.1';
 54:     case Auth_OpenID_TYPE_1_0:
 55:       return 'OpenID 1.0';
 56:     case Auth_OpenID_RP_RETURN_TO_URL_TYPE:
 57:       return 'OpenID relying party';
 58:     }
 59: }
 60: 
 61:  62:  63: 
 64: class Auth_OpenID_ServiceEndpoint {
 65:     function Auth_OpenID_ServiceEndpoint()
 66:     {
 67:         $this->claimed_id = null;
 68:         $this->server_url = null;
 69:         $this->type_uris = array();
 70:         $this->local_id = null;
 71:         $this->canonicalID = null;
 72:         $this->used_yadis = false; 
 73:         $this->display_identifier = null;
 74:     }
 75: 
 76:     function getDisplayIdentifier()
 77:     {
 78:         if ($this->display_identifier) {
 79:             return $this->display_identifier;
 80:         }
 81:         if (! $this->claimed_id) {
 82:           return $this->claimed_id;
 83:         }
 84:         $parsed = parse_url($this->claimed_id);
 85:         $scheme = $parsed['scheme'];
 86:         $host = $parsed['host'];
 87:         $path = $parsed['path'];
 88:         if (array_key_exists('query', $parsed)) {
 89:             $query = $parsed['query'];
 90:             $no_frag = "$scheme://$host$path?$query";
 91:         } else {
 92:             $no_frag = "$scheme://$host$path";
 93:         }
 94:         return $no_frag;
 95:     }
 96: 
 97:     function usesExtension($extension_uri)
 98:     {
 99:         return in_array($extension_uri, $this->type_uris);
100:     }
101: 
102:     function preferredNamespace()
103:     {
104:         if (in_array(Auth_OpenID_TYPE_2_0_IDP, $this->type_uris) ||
105:             in_array(Auth_OpenID_TYPE_2_0, $this->type_uris)) {
106:             return Auth_OpenID_OPENID2_NS;
107:         } else {
108:             return Auth_OpenID_OPENID1_NS;
109:         }
110:     }
111: 
112:     113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 
123:     function matchTypes($type_uris)
124:     {
125:         $result = array();
126:         foreach ($type_uris as $test_uri) {
127:             if ($this->supportsType($test_uri)) {
128:                 $result[] = $test_uri;
129:             }
130:         }
131: 
132:         return $result;
133:     }
134: 
135:     function supportsType($type_uri)
136:     {
137:         
138:         return ((in_array($type_uri, $this->type_uris)) ||
139:                 (($type_uri == Auth_OpenID_TYPE_2_0) &&
140:                  $this->isOPIdentifier()));
141:     }
142: 
143:     function compatibilityMode()
144:     {
145:         return $this->preferredNamespace() != Auth_OpenID_OPENID2_NS;
146:     }
147: 
148:     function isOPIdentifier()
149:     {
150:         return in_array(Auth_OpenID_TYPE_2_0_IDP, $this->type_uris);
151:     }
152: 
153:     static function fromOPEndpointURL($op_endpoint_url)
154:     {
155:         
156:         
157:         $obj = new Auth_OpenID_ServiceEndpoint();
158:         $obj->server_url = $op_endpoint_url;
159:         $obj->type_uris = array(Auth_OpenID_TYPE_2_0_IDP);
160:         return $obj;
161:     }
162: 
163:     function parseService($yadis_url, $uri, $type_uris, $service_element)
164:     {
165:         
166:         
167:         
168:         $this->type_uris = $type_uris;
169:         $this->server_url = $uri;
170:         $this->used_yadis = true;
171: 
172:         if (!$this->isOPIdentifier()) {
173:             $this->claimed_id = $yadis_url;
174:             $this->local_id = Auth_OpenID_findOPLocalIdentifier(
175:                                                     $service_element,
176:                                                     $this->type_uris);
177:             if ($this->local_id === false) {
178:                 return false;
179:             }
180:         }
181: 
182:         return true;
183:     }
184: 
185:     function getLocalID()
186:     {
187:         
188:         
189:         if ($this->local_id === null && $this->canonicalID === null) {
190:             return $this->claimed_id;
191:         } else {
192:             if ($this->local_id) {
193:                 return $this->local_id;
194:             } else {
195:                 return $this->canonicalID;
196:             }
197:         }
198:     }
199: 
200:     201: 202: 203: 204: 205: 
206:     function consumerFromXRDS($uri, $xrds_text)
207:     {
208:         $xrds =& Auth_Yadis_XRDS::parseXRDS($xrds_text);
209: 
210:         if ($xrds) {
211:             $yadis_services =
212:               $xrds->services(array('filter_MatchesAnyOpenIDConsumerType'));
213:             return Auth_OpenID_makeOpenIDEndpoints($uri, $yadis_services);
214:         }
215: 
216:         return null;
217:     }
218: 
219:     220: 221: 222: 223: 224: 
225:     static function fromXRDS($uri, $xrds_text)
226:     {
227:         $xrds = Auth_Yadis_XRDS::parseXRDS($xrds_text);
228: 
229:         if ($xrds) {
230:             $yadis_services =
231:               $xrds->services(array('filter_MatchesAnyOpenIDType'));
232:             return Auth_OpenID_makeOpenIDEndpoints($uri, $yadis_services);
233:         }
234: 
235:         return null;
236:     }
237: 
238:     239: 240: 241: 242: 243: 244: 
245:     static function fromDiscoveryResult($discoveryResult)
246:     {
247:         if ($discoveryResult->isXRDS()) {
248:             return Auth_OpenID_ServiceEndpoint::fromXRDS(
249:                                      $discoveryResult->normalized_uri,
250:                                      $discoveryResult->response_text);
251:         } else {
252:             return Auth_OpenID_ServiceEndpoint::fromHTML(
253:                                      $discoveryResult->normalized_uri,
254:                                      $discoveryResult->response_text);
255:         }
256:     }
257: 
258:     static function fromHTML($uri, $html)
259:     {
260:         $discovery_types = array(
261:                                  array(Auth_OpenID_TYPE_2_0,
262:                                        'openid2.provider', 'openid2.local_id'),
263:                                  array(Auth_OpenID_TYPE_1_1,
264:                                        'openid.server', 'openid.delegate')
265:                                  );
266: 
267:         $services = array();
268: 
269:         foreach ($discovery_types as $triple) {
270:             list($type_uri, $server_rel, $delegate_rel) = $triple;
271: 
272:             $urls = Auth_OpenID_legacy_discover($html, $server_rel,
273:                                                 $delegate_rel);
274: 
275:             if ($urls === false) {
276:                 continue;
277:             }
278: 
279:             list($delegate_url, $server_url) = $urls;
280: 
281:             $service = new Auth_OpenID_ServiceEndpoint();
282:             $service->claimed_id = $uri;
283:             $service->local_id = $delegate_url;
284:             $service->server_url = $server_url;
285:             $service->type_uris = array($type_uri);
286: 
287:             $services[] = $service;
288:         }
289: 
290:         return $services;
291:     }
292: 
293:     function copy()
294:     {
295:         $x = new Auth_OpenID_ServiceEndpoint();
296: 
297:         $x->claimed_id = $this->claimed_id;
298:         $x->server_url = $this->server_url;
299:         $x->type_uris = $this->type_uris;
300:         $x->local_id = $this->local_id;
301:         $x->canonicalID = $this->canonicalID;
302:         $x->used_yadis = $this->used_yadis;
303: 
304:         return $x;
305:     }
306: }
307: 
308: function Auth_OpenID_findOPLocalIdentifier($service, $type_uris)
309: {
310:     
311:     
312:     
313:     
314: 
315:     $service->parser->registerNamespace('openid',
316:                                         Auth_OpenID_XMLNS_1_0);
317: 
318:     $service->parser->registerNamespace('xrd',
319:                                         Auth_Yadis_XMLNS_XRD_2_0);
320: 
321:     $parser = $service->parser;
322: 
323:     $permitted_tags = array();
324: 
325:     if (in_array(Auth_OpenID_TYPE_1_1, $type_uris) ||
326:         in_array(Auth_OpenID_TYPE_1_0, $type_uris)) {
327:         $permitted_tags[] = 'openid:Delegate';
328:     }
329: 
330:     if (in_array(Auth_OpenID_TYPE_2_0, $type_uris)) {
331:         $permitted_tags[] = 'xrd:LocalID';
332:     }
333: 
334:     $local_id = null;
335: 
336:     foreach ($permitted_tags as $tag_name) {
337:         $tags = $service->getElements($tag_name);
338: 
339:         foreach ($tags as $tag) {
340:             $content = $parser->content($tag);
341: 
342:             if ($local_id === null) {
343:                 $local_id = $content;
344:             } else if ($local_id != $content) {
345:                 return false;
346:             }
347:         }
348:     }
349: 
350:     return $local_id;
351: }
352: 
353: function filter_MatchesAnyOpenIDType($service)
354: {
355:     $uris = $service->getTypes();
356: 
357:     foreach ($uris as $uri) {
358:         if (in_array($uri, Auth_OpenID_getOpenIDTypeURIs())) {
359:             return true;
360:         }
361:     }
362: 
363:     return false;
364: }
365: 
366: function filter_MatchesAnyOpenIDConsumerType(&$service)
367: {
368:     $uris = $service->getTypes();
369: 
370:     foreach ($uris as $uri) {
371:         if (in_array($uri, Auth_OpenID_getOpenIDConsumerTypeURIs())) {
372:             return true;
373:         }
374:     }
375: 
376:     return false;
377: }
378: 
379: function Auth_OpenID_bestMatchingService($service, $preferred_types)
380: {
381:     
382:     
383:     
384:     
385:     
386:     
387:     
388: 
389:     foreach ($preferred_types as $index => $typ) {
390:         if (in_array($typ, $service->type_uris)) {
391:             return $index;
392:         }
393:     }
394: 
395:     return count($preferred_types);
396: }
397: 
398: function Auth_OpenID_arrangeByType($service_list, $preferred_types)
399: {
400:     
401:     
402: 
403:     
404:     
405:     $prio_services = array();
406:     foreach ($service_list as $index => $service) {
407:         $prio_services[] = array(Auth_OpenID_bestMatchingService($service,
408:                                                         $preferred_types),
409:                                  $index, $service);
410:     }
411: 
412:     sort($prio_services);
413: 
414:     
415:     
416:     foreach ($prio_services as $index => $s) {
417:         $prio_services[$index] = $prio_services[$index][2];
418:     }
419: 
420:     return $prio_services;
421: }
422: 
423: 
424: 
425: 
426: 
427: 
428: 
429: 
430: function Auth_OpenID_getOPOrUserServices($openid_services)
431: {
432:     $op_services = Auth_OpenID_arrangeByType($openid_services,
433:                                      array(Auth_OpenID_TYPE_2_0_IDP));
434: 
435:     $openid_services = Auth_OpenID_arrangeByType($openid_services,
436:                                      Auth_OpenID_getOpenIDTypeURIs());
437: 
438:     if ($op_services) {
439:         return $op_services;
440:     } else {
441:         return $openid_services;
442:     }
443: }
444: 
445: function Auth_OpenID_makeOpenIDEndpoints($uri, $yadis_services)
446: {
447:     $s = array();
448: 
449:     if (!$yadis_services) {
450:         return $s;
451:     }
452: 
453:     foreach ($yadis_services as $service) {
454:         $type_uris = $service->getTypes();
455:         $uris = $service->getURIs();
456: 
457:         
458:         
459:         if ($type_uris &&
460:             $uris) {
461:             foreach ($uris as $service_uri) {
462:                 $openid_endpoint = new Auth_OpenID_ServiceEndpoint();
463:                 if ($openid_endpoint->parseService($uri,
464:                                                    $service_uri,
465:                                                    $type_uris,
466:                                                    $service)) {
467:                     $s[] = $openid_endpoint;
468:                 }
469:             }
470:         }
471:     }
472: 
473:     return $s;
474: }
475: 
476: function Auth_OpenID_discoverWithYadis($uri, $fetcher,
477:               $endpoint_filter='Auth_OpenID_getOPOrUserServices',
478:               $discover_function=null)
479: {
480:     
481:     
482: 
483:     
484:     
485:     
486:     
487:     if ($discover_function === null) {
488:         $discover_function = array('Auth_Yadis_Yadis', 'discover');
489:     }
490: 
491:     $openid_services = array();
492: 
493:     $response = call_user_func_array($discover_function,
494:                                      array($uri, $fetcher));
495: 
496:     $yadis_url = $response->normalized_uri;
497:     $yadis_services = array();
498: 
499:     if ($response->isFailure() && !$response->isXRDS()) {
500:         return array($uri, array());
501:     }
502: 
503:     $openid_services = Auth_OpenID_ServiceEndpoint::fromXRDS(
504:                                          $yadis_url,
505:                                          $response->response_text);
506: 
507:     if (!$openid_services) {
508:         if ($response->isXRDS()) {
509:             return Auth_OpenID_discoverWithoutYadis($uri,
510:                                                     $fetcher);
511:         }
512: 
513:         
514:         
515:         $openid_services = Auth_OpenID_ServiceEndpoint::fromHTML(
516:                                         $yadis_url,
517:                                         $response->response_text);
518:     }
519: 
520:     $openid_services = call_user_func_array($endpoint_filter,
521:                                             array($openid_services));
522: 
523:     return array($yadis_url, $openid_services);
524: }
525: 
526: function Auth_OpenID_discoverURI($uri, $fetcher)
527: {
528:     $uri = Auth_OpenID::normalizeUrl($uri);
529:     return Auth_OpenID_discoverWithYadis($uri, $fetcher);
530: }
531: 
532: function Auth_OpenID_discoverWithoutYadis($uri, $fetcher)
533: {
534:     $http_resp = @$fetcher->get($uri);
535: 
536:     if ($http_resp->status != 200 and $http_resp->status != 206) {
537:         return array($uri, array());
538:     }
539: 
540:     $identity_url = $http_resp->final_url;
541: 
542:     
543:     
544:     $openid_services = Auth_OpenID_ServiceEndpoint::fromHTML(
545:                                            $identity_url,
546:                                            $http_resp->body);
547: 
548:     return array($identity_url, $openid_services);
549: }
550: 
551: function Auth_OpenID_discoverXRI($iname, $fetcher)
552: {
553:     $resolver = new Auth_Yadis_ProxyResolver($fetcher);
554:     list($canonicalID, $yadis_services) =
555:         $resolver->query($iname,
556:                          Auth_OpenID_getOpenIDTypeURIs(),
557:                          array('filter_MatchesAnyOpenIDType'));
558: 
559:     $openid_services = Auth_OpenID_makeOpenIDEndpoints($iname,
560:                                                        $yadis_services);
561: 
562:     $openid_services = Auth_OpenID_getOPOrUserServices($openid_services);
563: 
564:     for ($i = 0; $i < count($openid_services); $i++) {
565:         $openid_services[$i]->canonicalID = $canonicalID;
566:         $openid_services[$i]->claimed_id = $canonicalID;
567:         $openid_services[$i]->display_identifier = $iname;
568:     }
569: 
570:      return array($iname, $openid_services);
571: }
572: 
573: function Auth_OpenID_discover($uri, $fetcher)
574: {
575:     
576:     
577:     if ($fetcher->isHTTPS($uri) && !$fetcher->supportsSSL()) {
578:         return array($uri, array());
579:     }
580: 
581:     if (Auth_Yadis_identifierScheme($uri) == 'XRI') {
582:         $result = Auth_OpenID_discoverXRI($uri, $fetcher);
583:     } else {
584:         $result = Auth_OpenID_discoverURI($uri, $fetcher);
585:     }
586: 
587:     
588:     
589:     if (!$fetcher->supportsSSL()) {
590:         $http_endpoints = array();
591:         list($new_uri, $endpoints) = $result;
592: 
593:         foreach ($endpoints as $e) {
594:             if (!$fetcher->isHTTPS($e->server_url)) {
595:                 $http_endpoints[] = $e;
596:             }
597:         }
598: 
599:         $result = array($new_uri, $http_endpoints);
600:     }
601: 
602:     return $result;
603: }
604: 
605: 
606: