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: