| 42 | aurelien | 1 | <?php
 | 
        
           |  |  | 2 |   | 
        
           |  |  | 3 | /**
 | 
        
           |  |  | 4 |  * The OpenID and Yadis discovery implementation for OpenID 1.2.
 | 
        
           |  |  | 5 |  */
 | 
        
           |  |  | 6 |   | 
        
           |  |  | 7 | require_once "Auth/OpenID.php";
 | 
        
           |  |  | 8 | require_once "Auth/OpenID/Parse.php";
 | 
        
           |  |  | 9 | require_once "Services/Yadis/XRIRes.php";
 | 
        
           |  |  | 10 | require_once "Services/Yadis/Yadis.php";
 | 
        
           |  |  | 11 |   | 
        
           |  |  | 12 | define('_OPENID_1_0_NS', 'http://openid.net/xmlns/1.0');
 | 
        
           |  |  | 13 | define('_OPENID_1_2_TYPE', 'http://openid.net/signon/1.2');
 | 
        
           |  |  | 14 | define('_OPENID_1_1_TYPE', 'http://openid.net/signon/1.1');
 | 
        
           |  |  | 15 | define('_OPENID_1_0_TYPE', 'http://openid.net/signon/1.0');
 | 
        
           |  |  | 16 |   | 
        
           |  |  | 17 | /**
 | 
        
           |  |  | 18 |  * Object representing an OpenID service endpoint.
 | 
        
           |  |  | 19 |  */
 | 
        
           |  |  | 20 | class Auth_OpenID_ServiceEndpoint {
 | 
        
           |  |  | 21 |     function Auth_OpenID_ServiceEndpoint()
 | 
        
           |  |  | 22 |     {
 | 
        
           |  |  | 23 |         $this->identity_url = null;
 | 
        
           |  |  | 24 |         $this->server_url = null;
 | 
        
           |  |  | 25 |         $this->type_uris = array();
 | 
        
           |  |  | 26 |         $this->delegate = null;
 | 
        
           |  |  | 27 |         $this->canonicalID = null;
 | 
        
           |  |  | 28 |         $this->used_yadis = false; // whether this came from an XRDS
 | 
        
           |  |  | 29 |     }
 | 
        
           |  |  | 30 |   | 
        
           |  |  | 31 |     function usesExtension($extension_uri)
 | 
        
           |  |  | 32 |     {
 | 
        
           |  |  | 33 |         return in_array($extension_uri, $this->type_uris);
 | 
        
           |  |  | 34 |     }
 | 
        
           |  |  | 35 |   | 
        
           |  |  | 36 |     function parseService($yadis_url, $uri, $type_uris, $service_element)
 | 
        
           |  |  | 37 |     {
 | 
        
           |  |  | 38 |         // Set the state of this object based on the contents of the
 | 
        
           |  |  | 39 |         // service element.
 | 
        
           |  |  | 40 |         $this->type_uris = $type_uris;
 | 
        
           |  |  | 41 |         $this->identity_url = $yadis_url;
 | 
        
           |  |  | 42 |         $this->server_url = $uri;
 | 
        
           |  |  | 43 |         $this->delegate = Auth_OpenID_ServiceEndpoint::findDelegate(
 | 
        
           |  |  | 44 |                                                          $service_element);
 | 
        
           |  |  | 45 |         $this->used_yadis = true;
 | 
        
           |  |  | 46 |     }
 | 
        
           |  |  | 47 |   | 
        
           |  |  | 48 |     function findDelegate($service)
 | 
        
           |  |  | 49 |     {
 | 
        
           |  |  | 50 |         // Extract a openid:Delegate value from a Yadis Service
 | 
        
           |  |  | 51 |         // element.  If no delegate is found, returns null.
 | 
        
           |  |  | 52 |   | 
        
           |  |  | 53 |         // Try to register new namespace.
 | 
        
           |  |  | 54 |         $service->parser->registerNamespace('openid',
 | 
        
           |  |  | 55 |                                             'http://openid.net/xmlns/1.0');
 | 
        
           |  |  | 56 |   | 
        
           |  |  | 57 |         // XXX: should this die if there is more than one delegate
 | 
        
           |  |  | 58 |         // element?
 | 
        
           |  |  | 59 |         $delegates = $service->getElements("openid:Delegate");
 | 
        
           |  |  | 60 |   | 
        
           |  |  | 61 |         if ($delegates) {
 | 
        
           |  |  | 62 |             return $service->parser->content($delegates[0]);
 | 
        
           |  |  | 63 |         } else {
 | 
        
           |  |  | 64 |             return null;
 | 
        
           |  |  | 65 |         }
 | 
        
           |  |  | 66 |     }
 | 
        
           |  |  | 67 |   | 
        
           |  |  | 68 |     function getServerID()
 | 
        
           |  |  | 69 |     {
 | 
        
           |  |  | 70 |         // Return the identifier that should be sent as the
 | 
        
           |  |  | 71 |         // openid.identity_url parameter to the server.
 | 
        
           |  |  | 72 |         if ($this->delegate === null) {
 | 
        
           |  |  | 73 |             if ($this->canonicalID) {
 | 
        
           |  |  | 74 |                 return $this->canonicalID;
 | 
        
           |  |  | 75 |             } else {
 | 
        
           |  |  | 76 |                 return $this->identity_url;
 | 
        
           |  |  | 77 |             }
 | 
        
           |  |  | 78 |         } else {
 | 
        
           |  |  | 79 |             return $this->delegate;
 | 
        
           |  |  | 80 |         }
 | 
        
           |  |  | 81 |     }
 | 
        
           |  |  | 82 |   | 
        
           |  |  | 83 |     function fromHTML($uri, $html)
 | 
        
           |  |  | 84 |     {
 | 
        
           |  |  | 85 |         // Parse the given document as HTML looking for an OpenID <link
 | 
        
           |  |  | 86 |         // rel=...>
 | 
        
           |  |  | 87 |         $urls = Auth_OpenID_legacy_discover($html);
 | 
        
           |  |  | 88 |         if ($urls === false) {
 | 
        
           |  |  | 89 |             return null;
 | 
        
           |  |  | 90 |         }
 | 
        
           |  |  | 91 |   | 
        
           |  |  | 92 |         list($delegate_url, $server_url) = $urls;
 | 
        
           |  |  | 93 |   | 
        
           |  |  | 94 |         $service = new Auth_OpenID_ServiceEndpoint();
 | 
        
           |  |  | 95 |         $service->identity_url = $uri;
 | 
        
           |  |  | 96 |         $service->delegate = $delegate_url;
 | 
        
           |  |  | 97 |         $service->server_url = $server_url;
 | 
        
           |  |  | 98 |         $service->type_uris = array(_OPENID_1_0_TYPE);
 | 
        
           |  |  | 99 |         return $service;
 | 
        
           |  |  | 100 |     }
 | 
        
           |  |  | 101 | }
 | 
        
           |  |  | 102 |   | 
        
           |  |  | 103 | function filter_MatchesAnyOpenIDType(&$service)
 | 
        
           |  |  | 104 | {
 | 
        
           |  |  | 105 |     $uris = $service->getTypes();
 | 
        
           |  |  | 106 |   | 
        
           |  |  | 107 |     foreach ($uris as $uri) {
 | 
        
           |  |  | 108 |         if (in_array($uri,
 | 
        
           |  |  | 109 |                      array(_OPENID_1_0_TYPE,
 | 
        
           |  |  | 110 |                            _OPENID_1_1_TYPE,
 | 
        
           |  |  | 111 |                            _OPENID_1_2_TYPE))) {
 | 
        
           |  |  | 112 |             return true;
 | 
        
           |  |  | 113 |         }
 | 
        
           |  |  | 114 |     }
 | 
        
           |  |  | 115 |   | 
        
           |  |  | 116 |     return false;
 | 
        
           |  |  | 117 | }
 | 
        
           |  |  | 118 |   | 
        
           |  |  | 119 | function Auth_OpenID_makeOpenIDEndpoints($uri, $endpoints)
 | 
        
           |  |  | 120 | {
 | 
        
           |  |  | 121 |     $s = array();
 | 
        
           |  |  | 122 |   | 
        
           |  |  | 123 |     if (!$endpoints) {
 | 
        
           |  |  | 124 |         return $s;
 | 
        
           |  |  | 125 |     }
 | 
        
           |  |  | 126 |   | 
        
           |  |  | 127 |     foreach ($endpoints as $service) {
 | 
        
           |  |  | 128 |         $type_uris = $service->getTypes();
 | 
        
           |  |  | 129 |         $uris = $service->getURIs();
 | 
        
           |  |  | 130 |   | 
        
           |  |  | 131 |         // If any Type URIs match and there is an endpoint URI
 | 
        
           |  |  | 132 |         // specified, then this is an OpenID endpoint
 | 
        
           |  |  | 133 |         if ($type_uris &&
 | 
        
           |  |  | 134 |             $uris) {
 | 
        
           |  |  | 135 |   | 
        
           |  |  | 136 |             foreach ($uris as $service_uri) {
 | 
        
           |  |  | 137 |                 $openid_endpoint = new Auth_OpenID_ServiceEndpoint();
 | 
        
           |  |  | 138 |                 $openid_endpoint->parseService($uri,
 | 
        
           |  |  | 139 |                                                $service_uri,
 | 
        
           |  |  | 140 |                                                $type_uris,
 | 
        
           |  |  | 141 |                                                $service);
 | 
        
           |  |  | 142 |   | 
        
           |  |  | 143 |                 $s[] = $openid_endpoint;
 | 
        
           |  |  | 144 |             }
 | 
        
           |  |  | 145 |         }
 | 
        
           |  |  | 146 |     }
 | 
        
           |  |  | 147 |   | 
        
           |  |  | 148 |     return $s;
 | 
        
           |  |  | 149 | }
 | 
        
           |  |  | 150 |   | 
        
           |  |  | 151 | function Auth_OpenID_discoverWithYadis($uri, &$fetcher)
 | 
        
           |  |  | 152 | {
 | 
        
           |  |  | 153 |     // Discover OpenID services for a URI. Tries Yadis and falls back
 | 
        
           |  |  | 154 |     // on old-style <link rel='...'> discovery if Yadis fails.
 | 
        
           |  |  | 155 |   | 
        
           |  |  | 156 |     // Might raise a yadis.discover.DiscoveryFailure if no document
 | 
        
           |  |  | 157 |     // came back for that URI at all.  I don't think falling back to
 | 
        
           |  |  | 158 |     // OpenID 1.0 discovery on the same URL will help, so don't bother
 | 
        
           |  |  | 159 |     // to catch it.
 | 
        
           |  |  | 160 |     $openid_services = array();
 | 
        
           |  |  | 161 |   | 
        
           |  |  | 162 |     $http_response = null;
 | 
        
           |  |  | 163 |     $response = Services_Yadis_Yadis::discover($uri, $http_response,
 | 
        
           |  |  | 164 |                                                 $fetcher);
 | 
        
           |  |  | 165 |   | 
        
           |  |  | 166 |     if ($response) {
 | 
        
           |  |  | 167 |         $identity_url = $response->uri;
 | 
        
           |  |  | 168 |         $openid_services =
 | 
        
           |  |  | 169 |             $response->xrds->services(array('filter_MatchesAnyOpenIDType'));
 | 
        
           |  |  | 170 |     }
 | 
        
           |  |  | 171 |   | 
        
           |  |  | 172 |     if (!$openid_services) {
 | 
        
           |  |  | 173 |         return @Auth_OpenID_discoverWithoutYadis($uri,
 | 
        
           |  |  | 174 |                                                  $fetcher);
 | 
        
           |  |  | 175 |     }
 | 
        
           |  |  | 176 |   | 
        
           |  |  | 177 |     if (!$openid_services) {
 | 
        
           |  |  | 178 |         $body = $response->body;
 | 
        
           |  |  | 179 |   | 
        
           |  |  | 180 |         // Try to parse the response as HTML to get OpenID 1.0/1.1
 | 
        
           |  |  | 181 |         // <link rel="...">
 | 
        
           |  |  | 182 |         $service = Auth_OpenID_ServiceEndpoint::fromHTML($identity_url,
 | 
        
           |  |  | 183 |                                                          $body);
 | 
        
           |  |  | 184 |   | 
        
           |  |  | 185 |         if ($service !== null) {
 | 
        
           |  |  | 186 |             $openid_services = array($service);
 | 
        
           |  |  | 187 |         }
 | 
        
           |  |  | 188 |     } else {
 | 
        
           |  |  | 189 |         $openid_services = Auth_OpenID_makeOpenIDEndpoints($response->uri,
 | 
        
           |  |  | 190 |                                                            $openid_services);
 | 
        
           |  |  | 191 |     }
 | 
        
           |  |  | 192 |   | 
        
           |  |  | 193 |     return array($identity_url, $openid_services, $http_response);
 | 
        
           |  |  | 194 | }
 | 
        
           |  |  | 195 |   | 
        
           |  |  | 196 | function _Auth_OpenID_discoverServiceList($uri, &$fetcher)
 | 
        
           |  |  | 197 | {
 | 
        
           |  |  | 198 |     list($url, $services, $resp) = Auth_OpenID_discoverWithYadis($uri,
 | 
        
           |  |  | 199 |                                                                  $fetcher);
 | 
        
           |  |  | 200 |   | 
        
           |  |  | 201 |     return $services;
 | 
        
           |  |  | 202 | }
 | 
        
           |  |  | 203 |   | 
        
           |  |  | 204 | function _Auth_OpenID_discoverXRIServiceList($uri, &$fetcher)
 | 
        
           |  |  | 205 | {
 | 
        
           |  |  | 206 |     list($url, $services, $resp) = _Auth_OpenID_discoverXRI($uri,
 | 
        
           |  |  | 207 |                                                             $fetcher);
 | 
        
           |  |  | 208 |     return $services;
 | 
        
           |  |  | 209 | }
 | 
        
           |  |  | 210 |   | 
        
           |  |  | 211 | function Auth_OpenID_discoverWithoutYadis($uri, &$fetcher)
 | 
        
           |  |  | 212 | {
 | 
        
           |  |  | 213 |     $http_resp = @$fetcher->get($uri);
 | 
        
           |  |  | 214 |   | 
        
           |  |  | 215 |     if ($http_resp->status != 200) {
 | 
        
           |  |  | 216 |         return array(null, array(), $http_resp);
 | 
        
           |  |  | 217 |     }
 | 
        
           |  |  | 218 |   | 
        
           |  |  | 219 |     $identity_url = $http_resp->final_url;
 | 
        
           |  |  | 220 |   | 
        
           |  |  | 221 |     // Try to parse the response as HTML to get OpenID 1.0/1.1 <link
 | 
        
           |  |  | 222 |     // rel="...">
 | 
        
           |  |  | 223 |     $endpoint =& new Auth_OpenID_ServiceEndpoint();
 | 
        
           |  |  | 224 |     $service = $endpoint->fromHTML($identity_url, $http_resp->body);
 | 
        
           |  |  | 225 |     if ($service === null) {
 | 
        
           |  |  | 226 |         $openid_services = array();
 | 
        
           |  |  | 227 |     } else {
 | 
        
           |  |  | 228 |         $openid_services = array($service);
 | 
        
           |  |  | 229 |     }
 | 
        
           |  |  | 230 |   | 
        
           |  |  | 231 |     return array($identity_url, $openid_services, $http_resp);
 | 
        
           |  |  | 232 | }
 | 
        
           |  |  | 233 |   | 
        
           |  |  | 234 | function _Auth_OpenID_discoverXRI($iname, &$fetcher)
 | 
        
           |  |  | 235 | {
 | 
        
           |  |  | 236 |     $services = new Services_Yadis_ProxyResolver($fetcher);
 | 
        
           |  |  | 237 |     list($canonicalID, $service_list) = $services->query($iname,
 | 
        
           |  |  | 238 |                                                   array(_OPENID_1_0_TYPE,
 | 
        
           |  |  | 239 |                                                         _OPENID_1_1_TYPE,
 | 
        
           |  |  | 240 |                                                         _OPENID_1_2_TYPE),
 | 
        
           |  |  | 241 |                                      array('filter_MatchesAnyOpenIDType'));
 | 
        
           |  |  | 242 |   | 
        
           |  |  | 243 |     $endpoints = Auth_OpenID_makeOpenIDEndpoints($iname, $service_list);
 | 
        
           |  |  | 244 |   | 
        
           |  |  | 245 |     for ($i = 0; $i < count($endpoints); $i++) {
 | 
        
           |  |  | 246 |         $endpoints[$i]->canonicalID = $canonicalID;
 | 
        
           |  |  | 247 |     }
 | 
        
           |  |  | 248 |   | 
        
           |  |  | 249 |     // FIXME: returned xri should probably be in some normal form
 | 
        
           |  |  | 250 |     return array($iname, $endpoints, null);
 | 
        
           |  |  | 251 | }
 | 
        
           |  |  | 252 |   | 
        
           |  |  | 253 | function Auth_OpenID_discover($uri, &$fetcher)
 | 
        
           |  |  | 254 | {
 | 
        
           |  |  | 255 |     return @Auth_OpenID_discoverWithYadis($uri, $fetcher);
 | 
        
           |  |  | 256 | }
 | 
        
           |  |  | 257 |   | 
        
           |  |  | 258 | ?>
 |