Discover.php

Go to the documentation of this file.
00001 <?php
00002 
00007 require_once "Auth/OpenID.php";
00008 require_once "Auth/OpenID/Parse.php";
00009 require_once "Auth/OpenID/Message.php";
00010 require_once "Auth/Yadis/XRIRes.php";
00011 require_once "Auth/Yadis/Yadis.php";
00012 
00013 // XML namespace value
00014 define('Auth_OpenID_XMLNS_1_0', 'http://openid.net/xmlns/1.0');
00015 
00016 // Yadis service types
00017 define('Auth_OpenID_TYPE_1_2', 'http://openid.net/signon/1.2');
00018 define('Auth_OpenID_TYPE_1_1', 'http://openid.net/signon/1.1');
00019 define('Auth_OpenID_TYPE_1_0', 'http://openid.net/signon/1.0');
00020 define('Auth_OpenID_TYPE_2_0_IDP', 'http://specs.openid.net/auth/2.0/server');
00021 define('Auth_OpenID_TYPE_2_0', 'http://specs.openid.net/auth/2.0/signon');
00022 define('Auth_OpenID_RP_RETURN_TO_URL_TYPE',
00023        'http://specs.openid.net/auth/2.0/return_to');
00024 
00025 function Auth_OpenID_getOpenIDTypeURIs()
00026 {
00027     return array(Auth_OpenID_TYPE_2_0_IDP,
00028                  Auth_OpenID_TYPE_2_0,
00029                  Auth_OpenID_TYPE_1_2,
00030                  Auth_OpenID_TYPE_1_1,
00031                  Auth_OpenID_TYPE_1_0,
00032                  Auth_OpenID_RP_RETURN_TO_URL_TYPE);
00033 }
00034 
00038 class Auth_OpenID_ServiceEndpoint {
00039     function Auth_OpenID_ServiceEndpoint()
00040     {
00041         $this->claimed_id = null;
00042         $this->server_url = null;
00043         $this->type_uris = array();
00044         $this->local_id = null;
00045         $this->canonicalID = null;
00046         $this->used_yadis = false; // whether this came from an XRDS
00047         $this->display_identifier = null;
00048     }
00049 
00050     function getDisplayIdentifier()
00051     {
00052         if ($this->display_identifier) {
00053             return $this->display_identifier;
00054         }
00055         if (! $this->claimed_id) {
00056           return $this->claimed_id;
00057         }
00058         $parsed = parse_url($this->claimed_id);
00059         $scheme = $parsed['scheme'];
00060         $host = $parsed['host'];
00061         $path = $parsed['path'];
00062         if (array_key_exists('query', $parsed)) {
00063             $query = $parsed['query'];
00064             $no_frag = "$scheme://$host$path?$query";
00065         } else {
00066             $no_frag = "$scheme://$host$path";
00067         }
00068         return $no_frag;
00069     }
00070 
00071     function usesExtension($extension_uri)
00072     {
00073         return in_array($extension_uri, $this->type_uris);
00074     }
00075 
00076     function preferredNamespace()
00077     {
00078         if (in_array(Auth_OpenID_TYPE_2_0_IDP, $this->type_uris) ||
00079             in_array(Auth_OpenID_TYPE_2_0, $this->type_uris)) {
00080             return Auth_OpenID_OPENID2_NS;
00081         } else {
00082             return Auth_OpenID_OPENID1_NS;
00083         }
00084     }
00085 
00086     /*
00087      * Query this endpoint to see if it has any of the given type
00088      * URIs. This is useful for implementing other endpoint classes
00089      * that e.g. need to check for the presence of multiple versions
00090      * of a single protocol.
00091      *
00092      * @param $type_uris The URIs that you wish to check
00093      *
00094      * @return all types that are in both in type_uris and
00095      * $this->type_uris
00096      */
00097     function matchTypes($type_uris)
00098     {
00099         $result = array();
00100         foreach ($type_uris as $test_uri) {
00101             if ($this->supportsType($test_uri)) {
00102                 $result[] = $test_uri;
00103             }
00104         }
00105 
00106         return $result;
00107     }
00108 
00109     function supportsType($type_uri)
00110     {
00111         // Does this endpoint support this type?
00112         return ((in_array($type_uri, $this->type_uris)) ||
00113                 (($type_uri == Auth_OpenID_TYPE_2_0) &&
00114                  $this->isOPIdentifier()));
00115     }
00116 
00117     function compatibilityMode()
00118     {
00119         return $this->preferredNamespace() != Auth_OpenID_OPENID2_NS;
00120     }
00121 
00122     function isOPIdentifier()
00123     {
00124         return in_array(Auth_OpenID_TYPE_2_0_IDP, $this->type_uris);
00125     }
00126 
00127     function fromOPEndpointURL($op_endpoint_url)
00128     {
00129         // Construct an OP-Identifier OpenIDServiceEndpoint object for
00130         // a given OP Endpoint URL
00131         $obj = new Auth_OpenID_ServiceEndpoint();
00132         $obj->server_url = $op_endpoint_url;
00133         $obj->type_uris = array(Auth_OpenID_TYPE_2_0_IDP);
00134         return $obj;
00135     }
00136 
00137     function parseService($yadis_url, $uri, $type_uris, $service_element)
00138     {
00139         // Set the state of this object based on the contents of the
00140         // service element.  Return true if successful, false if not
00141         // (if findOPLocalIdentifier returns false).
00142         $this->type_uris = $type_uris;
00143         $this->server_url = $uri;
00144         $this->used_yadis = true;
00145 
00146         if (!$this->isOPIdentifier()) {
00147             $this->claimed_id = $yadis_url;
00148             $this->local_id = Auth_OpenID_findOPLocalIdentifier(
00149                                                     $service_element,
00150                                                     $this->type_uris);
00151             if ($this->local_id === false) {
00152                 return false;
00153             }
00154         }
00155 
00156         return true;
00157     }
00158 
00159     function getLocalID()
00160     {
00161         // Return the identifier that should be sent as the
00162         // openid.identity_url parameter to the server.
00163         if ($this->local_id === null && $this->canonicalID === null) {
00164             return $this->claimed_id;
00165         } else {
00166             if ($this->local_id) {
00167                 return $this->local_id;
00168             } else {
00169                 return $this->canonicalID;
00170             }
00171         }
00172     }
00173 
00174     /*
00175      * Parse the given document as XRDS looking for OpenID services.
00176      *
00177      * @return array of Auth_OpenID_ServiceEndpoint or null if the
00178      * document cannot be parsed.
00179      */
00180     function fromXRDS($uri, $xrds_text)
00181     {
00182         $xrds =& Auth_Yadis_XRDS::parseXRDS($xrds_text);
00183 
00184         if ($xrds) {
00185             $yadis_services =
00186               $xrds->services(array('filter_MatchesAnyOpenIDType'));
00187             return Auth_OpenID_makeOpenIDEndpoints($uri, $yadis_services);
00188         }
00189 
00190         return null;
00191     }
00192 
00193     /*
00194      * Create endpoints from a DiscoveryResult.
00195      *
00196      * @param discoveryResult Auth_Yadis_DiscoveryResult
00197      * @return array of Auth_OpenID_ServiceEndpoint or null if
00198      * endpoints cannot be created.
00199      */
00200     function fromDiscoveryResult($discoveryResult)
00201     {
00202         if ($discoveryResult->isXRDS()) {
00203             return Auth_OpenID_ServiceEndpoint::fromXRDS(
00204                                      $discoveryResult->normalized_uri,
00205                                      $discoveryResult->response_text);
00206         } else {
00207             return Auth_OpenID_ServiceEndpoint::fromHTML(
00208                                      $discoveryResult->normalized_uri,
00209                                      $discoveryResult->response_text);
00210         }
00211     }
00212 
00213     function fromHTML($uri, $html)
00214     {
00215         $discovery_types = array(
00216                                  array(Auth_OpenID_TYPE_2_0,
00217                                        'openid2.provider', 'openid2.local_id'),
00218                                  array(Auth_OpenID_TYPE_1_1,
00219                                        'openid.server', 'openid.delegate')
00220                                  );
00221 
00222         $services = array();
00223 
00224         foreach ($discovery_types as $triple) {
00225             list($type_uri, $server_rel, $delegate_rel) = $triple;
00226 
00227             $urls = Auth_OpenID_legacy_discover($html, $server_rel,
00228                                                 $delegate_rel);
00229 
00230             if ($urls === false) {
00231                 continue;
00232             }
00233 
00234             list($delegate_url, $server_url) = $urls;
00235 
00236             $service = new Auth_OpenID_ServiceEndpoint();
00237             $service->claimed_id = $uri;
00238             $service->local_id = $delegate_url;
00239             $service->server_url = $server_url;
00240             $service->type_uris = array($type_uri);
00241 
00242             $services[] = $service;
00243         }
00244 
00245         return $services;
00246     }
00247 
00248     function copy()
00249     {
00250         $x = new Auth_OpenID_ServiceEndpoint();
00251 
00252         $x->claimed_id = $this->claimed_id;
00253         $x->server_url = $this->server_url;
00254         $x->type_uris = $this->type_uris;
00255         $x->local_id = $this->local_id;
00256         $x->canonicalID = $this->canonicalID;
00257         $x->used_yadis = $this->used_yadis;
00258 
00259         return $x;
00260     }
00261 }
00262 
00263 function Auth_OpenID_findOPLocalIdentifier($service, $type_uris)
00264 {
00265     // Extract a openid:Delegate value from a Yadis Service element.
00266     // If no delegate is found, returns null.  Returns false on
00267     // discovery failure (when multiple delegate/localID tags have
00268     // different values).
00269 
00270     $service->parser->registerNamespace('openid',
00271                                         Auth_OpenID_XMLNS_1_0);
00272 
00273     $service->parser->registerNamespace('xrd',
00274                                         Auth_Yadis_XMLNS_XRD_2_0);
00275 
00276     $parser =& $service->parser;
00277 
00278     $permitted_tags = array();
00279 
00280     if (in_array(Auth_OpenID_TYPE_1_1, $type_uris) ||
00281         in_array(Auth_OpenID_TYPE_1_0, $type_uris)) {
00282         $permitted_tags[] = 'openid:Delegate';
00283     }
00284 
00285     if (in_array(Auth_OpenID_TYPE_2_0, $type_uris)) {
00286         $permitted_tags[] = 'xrd:LocalID';
00287     }
00288 
00289     $local_id = null;
00290 
00291     foreach ($permitted_tags as $tag_name) {
00292         $tags = $service->getElements($tag_name);
00293 
00294         foreach ($tags as $tag) {
00295             $content = $parser->content($tag);
00296 
00297             if ($local_id === null) {
00298                 $local_id = $content;
00299             } else if ($local_id != $content) {
00300                 return false;
00301             }
00302         }
00303     }
00304 
00305     return $local_id;
00306 }
00307 
00308 function filter_MatchesAnyOpenIDType(&$service)
00309 {
00310     $uris = $service->getTypes();
00311 
00312     foreach ($uris as $uri) {
00313         if (in_array($uri, Auth_OpenID_getOpenIDTypeURIs())) {
00314             return true;
00315         }
00316     }
00317 
00318     return false;
00319 }
00320 
00321 function Auth_OpenID_bestMatchingService($service, $preferred_types)
00322 {
00323     // Return the index of the first matching type, or something
00324     // higher if no type matches.
00325     //
00326     // This provides an ordering in which service elements that
00327     // contain a type that comes earlier in the preferred types list
00328     // come before service elements that come later. If a service
00329     // element has more than one type, the most preferred one wins.
00330 
00331     foreach ($preferred_types as $index => $typ) {
00332         if (in_array($typ, $service->type_uris)) {
00333             return $index;
00334         }
00335     }
00336 
00337     return count($preferred_types);
00338 }
00339 
00340 function Auth_OpenID_arrangeByType($service_list, $preferred_types)
00341 {
00342     // Rearrange service_list in a new list so services are ordered by
00343     // types listed in preferred_types.  Return the new list.
00344 
00345     // Build a list with the service elements in tuples whose
00346     // comparison will prefer the one with the best matching service
00347     $prio_services = array();
00348     foreach ($service_list as $index => $service) {
00349         $prio_services[] = array(Auth_OpenID_bestMatchingService($service,
00350                                                         $preferred_types),
00351                                  $index, $service);
00352     }
00353 
00354     sort($prio_services);
00355 
00356     // Now that the services are sorted by priority, remove the sort
00357     // keys from the list.
00358     foreach ($prio_services as $index => $s) {
00359         $prio_services[$index] = $prio_services[$index][2];
00360     }
00361 
00362     return $prio_services;
00363 }
00364 
00365 // Extract OP Identifier services.  If none found, return the rest,
00366 // sorted with most preferred first according to
00367 // OpenIDServiceEndpoint.openid_type_uris.
00368 //
00369 // openid_services is a list of OpenIDServiceEndpoint objects.
00370 //
00371 // Returns a list of OpenIDServiceEndpoint objects."""
00372 function Auth_OpenID_getOPOrUserServices($openid_services)
00373 {
00374     $op_services = Auth_OpenID_arrangeByType($openid_services,
00375                                      array(Auth_OpenID_TYPE_2_0_IDP));
00376 
00377     $openid_services = Auth_OpenID_arrangeByType($openid_services,
00378                                      Auth_OpenID_getOpenIDTypeURIs());
00379 
00380     if ($op_services) {
00381         return $op_services;
00382     } else {
00383         return $openid_services;
00384     }
00385 }
00386 
00387 function Auth_OpenID_makeOpenIDEndpoints($uri, $yadis_services)
00388 {
00389     $s = array();
00390 
00391     if (!$yadis_services) {
00392         return $s;
00393     }
00394 
00395     foreach ($yadis_services as $service) {
00396         $type_uris = $service->getTypes();
00397         $uris = $service->getURIs();
00398 
00399         // If any Type URIs match and there is an endpoint URI
00400         // specified, then this is an OpenID endpoint
00401         if ($type_uris &&
00402             $uris) {
00403             foreach ($uris as $service_uri) {
00404                 $openid_endpoint = new Auth_OpenID_ServiceEndpoint();
00405                 if ($openid_endpoint->parseService($uri,
00406                                                    $service_uri,
00407                                                    $type_uris,
00408                                                    $service)) {
00409                     $s[] = $openid_endpoint;
00410                 }
00411             }
00412         }
00413     }
00414 
00415     return $s;
00416 }
00417 
00418 function Auth_OpenID_discoverWithYadis($uri, &$fetcher,
00419               $endpoint_filter='Auth_OpenID_getOPOrUserServices',
00420               $discover_function=null)
00421 {
00422     // Discover OpenID services for a URI. Tries Yadis and falls back
00423     // on old-style <link rel='...'> discovery if Yadis fails.
00424 
00425     // Might raise a yadis.discover.DiscoveryFailure if no document
00426     // came back for that URI at all.  I don't think falling back to
00427     // OpenID 1.0 discovery on the same URL will help, so don't bother
00428     // to catch it.
00429     if ($discover_function === null) {
00430         $discover_function = array('Auth_Yadis_Yadis', 'discover');
00431     }
00432 
00433     $openid_services = array();
00434 
00435     $response = call_user_func_array($discover_function,
00436                                      array($uri, &$fetcher));
00437 
00438     $yadis_url = $response->normalized_uri;
00439     $yadis_services = array();
00440 
00441     if ($response->isFailure()) {
00442         return array($uri, array());
00443     }
00444 
00445     $openid_services = Auth_OpenID_ServiceEndpoint::fromXRDS(
00446                                          $yadis_url,
00447                                          $response->response_text);
00448 
00449     if (!$openid_services) {
00450         if ($response->isXRDS()) {
00451             return Auth_OpenID_discoverWithoutYadis($uri,
00452                                                     $fetcher);
00453         }
00454 
00455         // Try to parse the response as HTML to get OpenID 1.0/1.1
00456         // <link rel="...">
00457         $openid_services = Auth_OpenID_ServiceEndpoint::fromHTML(
00458                                         $yadis_url,
00459                                         $response->response_text);
00460     }
00461 
00462     $openid_services = call_user_func_array($endpoint_filter,
00463                                             array(&$openid_services));
00464 
00465     return array($yadis_url, $openid_services);
00466 }
00467 
00468 function Auth_OpenID_discoverURI($uri, &$fetcher)
00469 {
00470     $uri = Auth_OpenID::normalizeUrl($uri);
00471     return Auth_OpenID_discoverWithYadis($uri, $fetcher);
00472 }
00473 
00474 function Auth_OpenID_discoverWithoutYadis($uri, &$fetcher)
00475 {
00476     $http_resp = @$fetcher->get($uri);
00477 
00478     if ($http_resp->status != 200 and $http_resp->status != 206) {
00479         return array($uri, array());
00480     }
00481 
00482     $identity_url = $http_resp->final_url;
00483 
00484     // Try to parse the response as HTML to get OpenID 1.0/1.1 <link
00485     // rel="...">
00486     $openid_services = Auth_OpenID_ServiceEndpoint::fromHTML(
00487                                            $identity_url,
00488                                            $http_resp->body);
00489 
00490     return array($identity_url, $openid_services);
00491 }
00492 
00493 function Auth_OpenID_discoverXRI($iname, &$fetcher)
00494 {
00495     $resolver = new Auth_Yadis_ProxyResolver($fetcher);
00496     list($canonicalID, $yadis_services) =
00497         $resolver->query($iname,
00498                          Auth_OpenID_getOpenIDTypeURIs(),
00499                          array('filter_MatchesAnyOpenIDType'));
00500 
00501     $openid_services = Auth_OpenID_makeOpenIDEndpoints($iname,
00502                                                        $yadis_services);
00503 
00504     $openid_services = Auth_OpenID_getOPOrUserServices($openid_services);
00505 
00506     for ($i = 0; $i < count($openid_services); $i++) {
00507         $openid_services[$i]->canonicalID = $canonicalID;
00508         $openid_services[$i]->claimed_id = $canonicalID;
00509         $openid_services[$i]->display_identifier = $iname;
00510     }
00511 
00512     // FIXME: returned xri should probably be in some normal form
00513     return array($iname, $openid_services);
00514 }
00515 
00516 function Auth_OpenID_discover($uri, &$fetcher)
00517 {
00518     // If the fetcher (i.e., PHP) doesn't support SSL, we can't do
00519     // discovery on an HTTPS URL.
00520     if ($fetcher->isHTTPS($uri) && !$fetcher->supportsSSL()) {
00521         return array($uri, array());
00522     }
00523 
00524     if (Auth_Yadis_identifierScheme($uri) == 'XRI') {
00525         $result = Auth_OpenID_discoverXRI($uri, $fetcher);
00526     } else {
00527         $result = Auth_OpenID_discoverURI($uri, $fetcher);
00528     }
00529 
00530     // If the fetcher doesn't support SSL, we can't interact with
00531     // HTTPS server URLs; remove those endpoints from the list.
00532     if (!$fetcher->supportsSSL()) {
00533         $http_endpoints = array();
00534         list($new_uri, $endpoints) = $result;
00535 
00536         foreach ($endpoints as $e) {
00537             if (!$fetcher->isHTTPS($e->server_url)) {
00538                 $http_endpoints[] = $e;
00539             }
00540         }
00541 
00542         $result = array($new_uri, $http_endpoints);
00543     }
00544 
00545     return $result;
00546 }
00547 
00548 ?>

Generated on Thu Feb 19 15:02:21 2009 for OXID eShop CE by  doxygen 1.5.5