diff options
author | tailor <cygnus@janrain.com> | 2006-08-15 23:00:10 +0000 |
---|---|---|
committer | tailor <cygnus@janrain.com> | 2006-08-15 23:00:10 +0000 |
commit | b8fd5e36ac459ffd880a25f8c545e1f5afb6ee73 (patch) | |
tree | e09ce76efd9ba9ee6635ed2a6de567769263efda | |
parent | ff8400c8b23d4e5228ec5a044cc13e1879a6fc24 (diff) | |
download | php-openid-b8fd5e36ac459ffd880a25f8c545e1f5afb6ee73.zip php-openid-b8fd5e36ac459ffd880a25f8c545e1f5afb6ee73.tar.gz php-openid-b8fd5e36ac459ffd880a25f8c545e1f5afb6ee73.tar.bz2 |
[project @ XRI resolution support]
-rw-r--r-- | Auth/OpenID/Consumer.php | 15 | ||||
-rw-r--r-- | Auth/OpenID/Discover.php | 20 | ||||
-rw-r--r-- | Auth/OpenID/URINorm.php | 47 | ||||
-rw-r--r-- | Services/Yadis/Misc.php | 53 | ||||
-rw-r--r-- | Services/Yadis/XRI.php | 173 |
5 files changed, 262 insertions, 46 deletions
diff --git a/Auth/OpenID/Consumer.php b/Auth/OpenID/Consumer.php index 88f8889..3566b7b 100644 --- a/Auth/OpenID/Consumer.php +++ b/Auth/OpenID/Consumer.php @@ -172,6 +172,7 @@ require_once "Auth/OpenID/DiffieHellman.php"; require_once "Auth/OpenID/KVForm.php"; require_once "Auth/OpenID/Discover.php"; require_once "Services/Yadis/Manager.php"; +require_once "Services/Yadis/XRI.php"; /** * This is the status code returned when the complete method returns @@ -295,7 +296,15 @@ class Auth_OpenID_Consumer { */ function begin($user_url) { - $openid_url = Auth_OpenID::normalizeUrl($user_url); + $discoverMethod = '_Auth_OpenID_discoverServiceList'; + $openid_url = $user_url; + + if (Services_Yadis_identifierScheme($user_url) == 'XRI') { + $discoverMethod = '_Auth_OpenID_discoverXRIServiceList'; + } else { + $openid_url = Auth_OpenID::normalizeUrl($user_url); + } + $disco = new Services_Yadis_Discovery($this->session, $openid_url, $this->session_key_prefix); @@ -310,8 +319,7 @@ class Auth_OpenID_Consumer { serialize($m)); } - $endpoint = $disco->getNextService( - '_Auth_OpenID_discoverServiceList', + $endpoint = $disco->getNextService($discoverMethod, $this->consumer->fetcher); // Reset the 'stale' attribute of the manager. @@ -998,6 +1006,7 @@ class Auth_OpenID_AuthRequest { } $redir_args = array_merge($redir_args, $this->extra_args); + return Auth_OpenID::appendArgs($this->endpoint->server_url, $redir_args); } diff --git a/Auth/OpenID/Discover.php b/Auth/OpenID/Discover.php index 51e8013..67be2a3 100644 --- a/Auth/OpenID/Discover.php +++ b/Auth/OpenID/Discover.php @@ -88,6 +88,7 @@ class Auth_OpenID_ServiceEndpoint { } list($delegate_url, $server_url) = $urls; + $service = new Auth_OpenID_ServiceEndpoint(); $service->identity_url = $uri; $service->delegate = $delegate_url; @@ -194,6 +195,13 @@ function _Auth_OpenID_discoverServiceList($uri, &$fetcher) return $services; } +function _Auth_OpenID_discoverXRIServiceList($uri, &$fetcher) +{ + list($url, $services, $resp) = _Auth_OpenID_discoverXRI($uri, + $fetcher); + return $services; +} + function Auth_OpenID_discoverWithoutYadis($uri, &$fetcher) { $http_resp = @$fetcher->get($uri); @@ -217,6 +225,18 @@ function Auth_OpenID_discoverWithoutYadis($uri, &$fetcher) return array($identity_url, $openid_services, $http_resp); } +function _Auth_OpenID_discoverXRI($iname, &$fetcher) +{ + $services = new Services_Yadis_ProxyResolver($fetcher); + $service_list = $services->query($iname, array(_OPENID_1_0_TYPE, + _OPENID_1_1_TYPE, + _OPENID_1_2_TYPE), + array('filter_MatchesAnyOpenIDType')); + $endpoints = Auth_OpenID_makeOpenIDEndpoints($iname, $service_list); + // FIXME: returned xri should probably be in some normal form + return array($iname, $endpoints, null); +} + function Auth_OpenID_discover($uri, &$fetcher) { return @Auth_OpenID_discoverWithYadis($uri, $fetcher); diff --git a/Auth/OpenID/URINorm.php b/Auth/OpenID/URINorm.php index 5d3d91c..8e6de4d 100644 --- a/Auth/OpenID/URINorm.php +++ b/Auth/OpenID/URINorm.php @@ -9,37 +9,13 @@ * @license http://www.gnu.org/copyleft/lesser.html LGPL */ +require_once 'Services/Yadis/Misc.php'; + // from appendix B of rfc 3986 (http://www.ietf.org/rfc/rfc3986.txt) $__uri_pattern = '&^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?&'; $__authority_pattern = '/^([^@]*@)?([^:]*)(:.*)?/'; $__pct_encoded_pattern = '/%([0-9A-Fa-f]{2})/'; -$__UCSCHAR = array( - array(0xA0, 0xD7FF), - array(0xF900, 0xFDCF), - array(0xFDF0, 0xFFEF), - array(0x10000, 0x1FFFD), - array(0x20000, 0x2FFFD), - array(0x30000, 0x3FFFD), - array(0x40000, 0x4FFFD), - array(0x50000, 0x5FFFD), - array(0x60000, 0x6FFFD), - array(0x70000, 0x7FFFD), - array(0x80000, 0x8FFFD), - array(0x90000, 0x9FFFD), - array(0xA0000, 0xAFFFD), - array(0xB0000, 0xBFFFD), - array(0xC0000, 0xCFFFD), - array(0xD0000, 0xDFFFD), - array(0xE1000, 0xEFFFD) - ); - -$__IPRIVATE = array( - array(0xE000, 0xF8FF), - array(0xF0000, 0xFFFFD), - array(0x100000, 0x10FFFD) - ); - $_unreserved = array(); for ($i = 0; $i < 256; $i++) { $_unreserved[$i] = false; @@ -65,26 +41,11 @@ $_unreserved[ord('~')] = true; $parts = array(); foreach (array_merge($__UCSCHAR, $__IPRIVATE) as $pair) { list($m, $n) = $pair; - $parts[] = sprintf("%s-%s", $m, $n); + $parts[] = sprintf("%s-%s", chr($m), chr($n)); } $_escapeme_re = sprintf('[%s]', implode('', $parts)); -function _startswith($s, $stuff) -{ - return strpos($s, $stuff) === 0; -} - -function _pct_escape_unicode($char_match) -{ - $c = $char_match[0]; - $result = ""; - for ($i = 0; $i < strlen($c); $i++) { - $result .= "%".sprintf("%X", ord($c[$i])); - } - return $result; -} - function _pct_encoded_replace_unreserved($mo) { global $_unreserved; @@ -247,4 +208,4 @@ function Auth_OpenID_urinorm($uri) return $scheme . '://' . $authority . $path . $query . $fragment; } -?>
\ No newline at end of file +?> diff --git a/Services/Yadis/Misc.php b/Services/Yadis/Misc.php new file mode 100644 index 0000000..9d0a20b --- /dev/null +++ b/Services/Yadis/Misc.php @@ -0,0 +1,53 @@ +<?php + +/** + * Miscellaneous utility values and functions for OpenID and Yadis. + * + * @package OpenID + * @author JanRain, Inc. <openid@janrain.com> + * @copyright 2005 Janrain, Inc. + * @license http://www.gnu.org/copyleft/lesser.html LGPL + */ + +$__UCSCHAR = array( + array(0xA0, 0xD7FF), + array(0xF900, 0xFDCF), + array(0xFDF0, 0xFFEF), + array(0x10000, 0x1FFFD), + array(0x20000, 0x2FFFD), + array(0x30000, 0x3FFFD), + array(0x40000, 0x4FFFD), + array(0x50000, 0x5FFFD), + array(0x60000, 0x6FFFD), + array(0x70000, 0x7FFFD), + array(0x80000, 0x8FFFD), + array(0x90000, 0x9FFFD), + array(0xA0000, 0xAFFFD), + array(0xB0000, 0xBFFFD), + array(0xC0000, 0xCFFFD), + array(0xD0000, 0xDFFFD), + array(0xE1000, 0xEFFFD) + ); + +$__IPRIVATE = array( + array(0xE000, 0xF8FF), + array(0xF0000, 0xFFFFD), + array(0x100000, 0x10FFFD) + ); + +function _pct_escape_unicode($char_match) +{ + $c = $char_match[0]; + $result = ""; + for ($i = 0; $i < strlen($c); $i++) { + $result .= "%".sprintf("%X", ord($c[$i])); + } + return $result; +} + +function _startswith($s, $stuff) +{ + return strpos($s, $stuff) === 0; +} + +?>
\ No newline at end of file diff --git a/Services/Yadis/XRI.php b/Services/Yadis/XRI.php new file mode 100644 index 0000000..6a8a519 --- /dev/null +++ b/Services/Yadis/XRI.php @@ -0,0 +1,173 @@ +<?php + +/** + * Routines for XRI resolution. + * + * @package Yadis + * @author JanRain, Inc. <openid@janrain.com> + * @copyright 2005 Janrain, Inc. + * @license http://www.gnu.org/copyleft/lesser.html LGPL + */ + +require_once 'Services/Yadis/Misc.php'; +require_once 'Services/Yadis/Yadis.php'; +require_once 'Services/Yadis/XRDS.php'; + +$DEFAULT_PROXY = 'http://proxy.xri.net/'; +$XRI_AUTHORITIES = array('!', '=', '@', '+', '$', '('); + +$parts = array(); +foreach (array_merge($__UCSCHAR, $__IPRIVATE) as $pair) { + list($m, $n) = $pair; + $parts[] = sprintf("%s-%s", chr($m), chr($n)); +} + +$_escapeme_re = sprintf('/[%s]/', implode('', $parts)); +$_xref_re = '/\((.*?)\)/'; + +function Services_Yadis_identifierScheme($identifier) +{ + global $XRI_AUTHORITIES; + + if (_startswith($identifier, 'xri://') || + (in_array($identifier[0], $XRI_AUTHORITIES))) { + return "XRI"; + } else { + return "URI"; + } +} + +function Services_Yadis_toIRINormal($xri) +{ + if (!_startswith($xr, 'xri://')) { + $xri = 'xri://' . $xri; + } + + return Services_Yadis_escapeForIRI($xri); +} + +function _escape_xref($xref_match) +{ + $xref = $xref_match[0]; + $xref = str_replace('/', '%2F', $xref); + $xref = str_replace('?', '%3F', $xref); + $xref = str_replace('#', '%23', $xref); + return $xref; +} + +function Services_Yadis_escapeForIRI($xri) +{ + global $_xref_re, $_escapeme_re; + + $xri = str_replace('%', '%25', $xri); + $xri = preg_replace($_xref_re, $_escape_xref, $xri); + return $xri; +} + +function Services_Yadis_toURINormal($xri) +{ + return Services_Yadis_iriToURI(Services_Yadis_toIRINormal($xri)); +} + +function Services_Yadis_iriToURI($iri) +{ + if (1) { + return $iri; + } else { + global $_escapeme_re; + // According to RFC 3987, section 3.1, "Mapping of IRIs to URIs" + return preg_replace_callback($_escapeme_re, + '_pct_escape_unicode', $iri); + } +} + +class Services_Yadis_ProxyResolver { + function Services_Yadis_ProxyResolver(&$fetcher, $proxy_url = null) + { + global $DEFAULT_PROXY; + + $this->fetcher =& $fetcher; + $this->proxy_url = $proxy_url; + if (!$this->proxy_url) { + $this->proxy_url = $DEFAULT_PROXY; + } + } + + function queryURL($xri, $service_type) + { + // trim off the xri:// prefix + $qxri = substr(Services_Yadis_toURINormal($xri), 6); + $hxri = $this->proxy_url . $qxri; + $args = array( + '_xrd_r' => 'application/xrds+xml', + '_xrd_t' => $service_type + ); + $query = Services_Yadis_XRIAppendArgs($hxri, $args); + return $query; + } + + function query($xri, $service_types, $filters = array()) + { + $services = array(); + foreach ($service_types as $service_type) { + $url = $this->queryURL($xri, $service_type); + $response = $this->fetcher->get($url); + if ($response->status != 200) { + continue; + } + $xrds = Services_Yadis_XRDS::parseXRDS($response->body); + if (!$xrds) { + continue; + } + $some_services = $xrds->services($filters); + $services = array_merge($services, $some_services); + // TODO: + // * If we do get hits for multiple service_types, we're + // almost certainly going to have duplicated service + // entries and broken priority ordering. + } + return $services; + } +} + +function Services_Yadis_XRIAppendArgs($url, $args) +{ + // Append some arguments to an HTTP query. Yes, this is just like + // OpenID's appendArgs, but with special seasoning for XRI + // queries. + + if (count($args) == 0) { + return $url; + } + + // Non-empty array; if it is an array of arrays, use multisort; + // otherwise use sort. + if (array_key_exists(0, $args) && + is_array($args[0])) { + // Do nothing here. + } else { + $keys = array_keys($args); + sort($keys); + $new_args = array(); + foreach ($keys as $key) { + $new_args[] = array($key, $args[$key]); + } + $args = $new_args; + } + + // According to XRI Resolution section "QXRI query parameters": + // + // "If the original QXRI had a null query component (only a + // leading question mark), or a query component consisting of + // only question marks, one additional leading question mark MUST + // be added when adding any XRI resolution parameters." + if (strpos(rtrim($url, '?'), '?') !== false) { + $sep = '&'; + } else { + $sep = '?'; + } + + return $url . $sep . Auth_OpenID::httpBuildQuery($args); +} + +?>
\ No newline at end of file |