Viewing file: Discover.php (18.13 KB) -rwxrwxr-x Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
<?php
/** * The OpenID and Yadis discovery implementation for OpenID 1.2. */
require_once "Auth/OpenID.php"; require_once "Auth/OpenID/Parse.php"; require_once "Auth/OpenID/Message.php"; require_once "Auth/Yadis/XRIRes.php"; require_once "Auth/Yadis/Yadis.php";
// XML namespace value define('Auth_OpenID_XMLNS_1_0', 'http://openid.net/xmlns/1.0');
// Yadis service types define('Auth_OpenID_TYPE_1_2', 'http://openid.net/signon/1.2'); define('Auth_OpenID_TYPE_1_1', 'http://openid.net/signon/1.1'); define('Auth_OpenID_TYPE_1_0', 'http://openid.net/signon/1.0'); define('Auth_OpenID_TYPE_2_0_IDP', 'http://specs.openid.net/auth/2.0/server'); define('Auth_OpenID_TYPE_2_0', 'http://specs.openid.net/auth/2.0/signon'); define('Auth_OpenID_RP_RETURN_TO_URL_TYPE', 'http://specs.openid.net/auth/2.0/return_to');
function Auth_OpenID_getOpenIDTypeURIs() { return array(Auth_OpenID_TYPE_2_0_IDP, Auth_OpenID_TYPE_2_0, Auth_OpenID_TYPE_1_2, Auth_OpenID_TYPE_1_1, Auth_OpenID_TYPE_1_0); }
function Auth_OpenID_getOpenIDConsumerTypeURIs() { return array(Auth_OpenID_RP_RETURN_TO_URL_TYPE); }
/* * Provides a user-readable interpretation of a type uri. * Useful for error messages. */ function Auth_OpenID_getOpenIDTypeName($type_uri) { switch ($type_uri) { case Auth_OpenID_TYPE_2_0_IDP: return 'OpenID 2.0 IDP'; case Auth_OpenID_TYPE_2_0: return 'OpenID 2.0'; case Auth_OpenID_TYPE_1_2: return 'OpenID 1.2'; case Auth_OpenID_TYPE_1_1: return 'OpenID 1.1'; case Auth_OpenID_TYPE_1_0: return 'OpenID 1.0'; case Auth_OpenID_RP_RETURN_TO_URL_TYPE: return 'OpenID relying party'; } }
/** * Object representing an OpenID service endpoint. */ class Auth_OpenID_ServiceEndpoint { function Auth_OpenID_ServiceEndpoint() { $this->claimed_id = null; $this->server_url = null; $this->type_uris = array(); $this->local_id = null; $this->canonicalID = null; $this->used_yadis = false; // whether this came from an XRDS $this->display_identifier = null; }
function getDisplayIdentifier() { if ($this->display_identifier) { return $this->display_identifier; } if (! $this->claimed_id) { return $this->claimed_id; } $parsed = parse_url($this->claimed_id); $scheme = $parsed['scheme']; $host = $parsed['host']; $path = $parsed['path']; if (array_key_exists('query', $parsed)) { $query = $parsed['query']; $no_frag = "$scheme://$host$path?$query"; } else { $no_frag = "$scheme://$host$path"; } return $no_frag; }
function usesExtension($extension_uri) { return in_array($extension_uri, $this->type_uris); }
function preferredNamespace() { if (in_array(Auth_OpenID_TYPE_2_0_IDP, $this->type_uris) || in_array(Auth_OpenID_TYPE_2_0, $this->type_uris)) { return Auth_OpenID_OPENID2_NS; } else { return Auth_OpenID_OPENID1_NS; } }
/* * Query this endpoint to see if it has any of the given type * URIs. This is useful for implementing other endpoint classes * that e.g. need to check for the presence of multiple versions * of a single protocol. * * @param $type_uris The URIs that you wish to check * * @return all types that are in both in type_uris and * $this->type_uris */ function matchTypes($type_uris) { $result = array(); foreach ($type_uris as $test_uri) { if ($this->supportsType($test_uri)) { $result[] = $test_uri; } }
return $result; }
function supportsType($type_uri) { // Does this endpoint support this type? return ((in_array($type_uri, $this->type_uris)) || (($type_uri == Auth_OpenID_TYPE_2_0) && $this->isOPIdentifier())); }
function compatibilityMode() { return $this->preferredNamespace() != Auth_OpenID_OPENID2_NS; }
function isOPIdentifier() { return in_array(Auth_OpenID_TYPE_2_0_IDP, $this->type_uris); }
static function fromOPEndpointURL($op_endpoint_url) { // Construct an OP-Identifier OpenIDServiceEndpoint object for // a given OP Endpoint URL $obj = new Auth_OpenID_ServiceEndpoint(); $obj->server_url = $op_endpoint_url; $obj->type_uris = array(Auth_OpenID_TYPE_2_0_IDP); return $obj; }
function parseService($yadis_url, $uri, $type_uris, $service_element) { // Set the state of this object based on the contents of the // service element. Return true if successful, false if not // (if findOPLocalIdentifier returns false). $this->type_uris = $type_uris; $this->server_url = $uri; $this->used_yadis = true;
if (!$this->isOPIdentifier()) { $this->claimed_id = $yadis_url; $this->local_id = Auth_OpenID_findOPLocalIdentifier( $service_element, $this->type_uris); if ($this->local_id === false) { return false; } }
return true; }
function getLocalID() { // Return the identifier that should be sent as the // openid.identity_url parameter to the server. if ($this->local_id === null && $this->canonicalID === null) { return $this->claimed_id; } else { if ($this->local_id) { return $this->local_id; } else { return $this->canonicalID; } } }
/* * Parse the given document as XRDS looking for OpenID consumer services. * * @return array of Auth_OpenID_ServiceEndpoint or null if the * document cannot be parsed. */ function consumerFromXRDS($uri, $xrds_text) { $xrds =& Auth_Yadis_XRDS::parseXRDS($xrds_text);
if ($xrds) { $yadis_services = $xrds->services(array('filter_MatchesAnyOpenIDConsumerType')); return Auth_OpenID_makeOpenIDEndpoints($uri, $yadis_services); }
return null; }
/* * Parse the given document as XRDS looking for OpenID services. * * @return array of Auth_OpenID_ServiceEndpoint or null if the * document cannot be parsed. */ static function fromXRDS($uri, $xrds_text) { $xrds = Auth_Yadis_XRDS::parseXRDS($xrds_text);
if ($xrds) { $yadis_services = $xrds->services(array('filter_MatchesAnyOpenIDType')); return Auth_OpenID_makeOpenIDEndpoints($uri, $yadis_services); }
return null; }
/* * Create endpoints from a DiscoveryResult. * * @param discoveryResult Auth_Yadis_DiscoveryResult * @return array of Auth_OpenID_ServiceEndpoint or null if * endpoints cannot be created. */ static function fromDiscoveryResult($discoveryResult) { if ($discoveryResult->isXRDS()) { return Auth_OpenID_ServiceEndpoint::fromXRDS( $discoveryResult->normalized_uri, $discoveryResult->response_text); } else { return Auth_OpenID_ServiceEndpoint::fromHTML( $discoveryResult->normalized_uri, $discoveryResult->response_text); } }
static function fromHTML($uri, $html) { $discovery_types = array( array(Auth_OpenID_TYPE_2_0, 'openid2.provider', 'openid2.local_id'), array(Auth_OpenID_TYPE_1_1, 'openid.server', 'openid.delegate') );
$services = array();
foreach ($discovery_types as $triple) { list($type_uri, $server_rel, $delegate_rel) = $triple;
$urls = Auth_OpenID_legacy_discover($html, $server_rel, $delegate_rel);
if ($urls === false) { continue; }
list($delegate_url, $server_url) = $urls;
$service = new Auth_OpenID_ServiceEndpoint(); $service->claimed_id = $uri; $service->local_id = $delegate_url; $service->server_url = $server_url; $service->type_uris = array($type_uri);
$services[] = $service; }
return $services; }
function copy() { $x = new Auth_OpenID_ServiceEndpoint();
$x->claimed_id = $this->claimed_id; $x->server_url = $this->server_url; $x->type_uris = $this->type_uris; $x->local_id = $this->local_id; $x->canonicalID = $this->canonicalID; $x->used_yadis = $this->used_yadis;
return $x; } }
function Auth_OpenID_findOPLocalIdentifier($service, $type_uris) { // Extract a openid:Delegate value from a Yadis Service element. // If no delegate is found, returns null. Returns false on // discovery failure (when multiple delegate/localID tags have // different values).
$service->parser->registerNamespace('openid', Auth_OpenID_XMLNS_1_0);
$service->parser->registerNamespace('xrd', Auth_Yadis_XMLNS_XRD_2_0);
$parser = $service->parser;
$permitted_tags = array();
if (in_array(Auth_OpenID_TYPE_1_1, $type_uris) || in_array(Auth_OpenID_TYPE_1_0, $type_uris)) { $permitted_tags[] = 'openid:Delegate'; }
if (in_array(Auth_OpenID_TYPE_2_0, $type_uris)) { $permitted_tags[] = 'xrd:LocalID'; }
$local_id = null;
foreach ($permitted_tags as $tag_name) { $tags = $service->getElements($tag_name);
foreach ($tags as $tag) { $content = $parser->content($tag);
if ($local_id === null) { $local_id = $content; } else if ($local_id != $content) { return false; } } }
return $local_id; }
function filter_MatchesAnyOpenIDType($service) { $uris = $service->getTypes();
foreach ($uris as $uri) { if (in_array($uri, Auth_OpenID_getOpenIDTypeURIs())) { return true; } }
return false; }
function filter_MatchesAnyOpenIDConsumerType(&$service) { $uris = $service->getTypes();
foreach ($uris as $uri) { if (in_array($uri, Auth_OpenID_getOpenIDConsumerTypeURIs())) { return true; } }
return false; }
function Auth_OpenID_bestMatchingService($service, $preferred_types) { // Return the index of the first matching type, or something // higher if no type matches. // // This provides an ordering in which service elements that // contain a type that comes earlier in the preferred types list // come before service elements that come later. If a service // element has more than one type, the most preferred one wins.
foreach ($preferred_types as $index => $typ) { if (in_array($typ, $service->type_uris)) { return $index; } }
return count($preferred_types); }
function Auth_OpenID_arrangeByType($service_list, $preferred_types) { // Rearrange service_list in a new list so services are ordered by // types listed in preferred_types. Return the new list.
// Build a list with the service elements in tuples whose // comparison will prefer the one with the best matching service $prio_services = array(); foreach ($service_list as $index => $service) { $prio_services[] = array(Auth_OpenID_bestMatchingService($service, $preferred_types), $index, $service); }
sort($prio_services);
// Now that the services are sorted by priority, remove the sort // keys from the list. foreach ($prio_services as $index => $s) { $prio_services[$index] = $prio_services[$index][2]; }
return $prio_services; }
// Extract OP Identifier services. If none found, return the rest, // sorted with most preferred first according to // OpenIDServiceEndpoint.openid_type_uris. // // openid_services is a list of OpenIDServiceEndpoint objects. // // Returns a list of OpenIDServiceEndpoint objects.""" function Auth_OpenID_getOPOrUserServices($openid_services) { $op_services = Auth_OpenID_arrangeByType($openid_services, array(Auth_OpenID_TYPE_2_0_IDP));
$openid_services = Auth_OpenID_arrangeByType($openid_services, Auth_OpenID_getOpenIDTypeURIs());
if ($op_services) { return $op_services; } else { return $openid_services; } }
function Auth_OpenID_makeOpenIDEndpoints($uri, $yadis_services) { $s = array();
if (!$yadis_services) { return $s; }
foreach ($yadis_services as $service) { $type_uris = $service->getTypes(); $uris = $service->getURIs();
// If any Type URIs match and there is an endpoint URI // specified, then this is an OpenID endpoint if ($type_uris && $uris) { foreach ($uris as $service_uri) { $openid_endpoint = new Auth_OpenID_ServiceEndpoint(); if ($openid_endpoint->parseService($uri, $service_uri, $type_uris, $service)) { $s[] = $openid_endpoint; } } } }
return $s; }
function Auth_OpenID_discoverWithYadis($uri, $fetcher, $endpoint_filter='Auth_OpenID_getOPOrUserServices', $discover_function=null) { // Discover OpenID services for a URI. Tries Yadis and falls back // on old-style <link rel='...'> discovery if Yadis fails.
// Might raise a yadis.discover.DiscoveryFailure if no document // came back for that URI at all. I don't think falling back to // OpenID 1.0 discovery on the same URL will help, so don't bother // to catch it. if ($discover_function === null) { $discover_function = array('Auth_Yadis_Yadis', 'discover'); }
$openid_services = array();
$response = call_user_func_array($discover_function, array($uri, $fetcher));
$yadis_url = $response->normalized_uri; $yadis_services = array();
if ($response->isFailure() && !$response->isXRDS()) { return array($uri, array()); }
$openid_services = Auth_OpenID_ServiceEndpoint::fromXRDS( $yadis_url, $response->response_text);
if (!$openid_services) { if ($response->isXRDS()) { return Auth_OpenID_discoverWithoutYadis($uri, $fetcher); }
// Try to parse the response as HTML to get OpenID 1.0/1.1 // <link rel="..."> $openid_services = Auth_OpenID_ServiceEndpoint::fromHTML( $yadis_url, $response->response_text); }
$openid_services = call_user_func_array($endpoint_filter, array($openid_services));
return array($yadis_url, $openid_services); }
function Auth_OpenID_discoverURI($uri, $fetcher) { $uri = Auth_OpenID::normalizeUrl($uri); return Auth_OpenID_discoverWithYadis($uri, $fetcher); }
function Auth_OpenID_discoverWithoutYadis($uri, $fetcher) { $http_resp = @$fetcher->get($uri);
if ($http_resp->status != 200 and $http_resp->status != 206) { return array($uri, array()); }
$identity_url = $http_resp->final_url;
// Try to parse the response as HTML to get OpenID 1.0/1.1 <link // rel="..."> $openid_services = Auth_OpenID_ServiceEndpoint::fromHTML( $identity_url, $http_resp->body);
return array($identity_url, $openid_services); }
function Auth_OpenID_discoverXRI($iname, $fetcher) { $resolver = new Auth_Yadis_ProxyResolver($fetcher); list($canonicalID, $yadis_services) = $resolver->query($iname, Auth_OpenID_getOpenIDTypeURIs(), array('filter_MatchesAnyOpenIDType'));
$openid_services = Auth_OpenID_makeOpenIDEndpoints($iname, $yadis_services);
$openid_services = Auth_OpenID_getOPOrUserServices($openid_services);
for ($i = 0; $i < count($openid_services); $i++) { $openid_services[$i]->canonicalID = $canonicalID; $openid_services[$i]->claimed_id = $canonicalID; $openid_services[$i]->display_identifier = $iname; }
// FIXME: returned xri should probably be in some normal form return array($iname, $openid_services); }
function Auth_OpenID_discover($uri, $fetcher) { // If the fetcher (i.e., PHP) doesn't support SSL, we can't do // discovery on an HTTPS URL. if ($fetcher->isHTTPS($uri) && !$fetcher->supportsSSL()) { return array($uri, array()); }
if (Auth_Yadis_identifierScheme($uri) == 'XRI') { $result = Auth_OpenID_discoverXRI($uri, $fetcher); } else { $result = Auth_OpenID_discoverURI($uri, $fetcher); }
// If the fetcher doesn't support SSL, we can't interact with // HTTPS server URLs; remove those endpoints from the list. if (!$fetcher->supportsSSL()) { $http_endpoints = array(); list($new_uri, $endpoints) = $result;
foreach ($endpoints as $e) { if (!$fetcher->isHTTPS($e->server_url)) { $http_endpoints[] = $e; } }
$result = array($new_uri, $http_endpoints); }
return $result; }
|