summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortailor <cygnus@janrain.com>2006-08-15 23:00:10 +0000
committertailor <cygnus@janrain.com>2006-08-15 23:00:10 +0000
commitb8fd5e36ac459ffd880a25f8c545e1f5afb6ee73 (patch)
treee09ce76efd9ba9ee6635ed2a6de567769263efda
parentff8400c8b23d4e5228ec5a044cc13e1879a6fc24 (diff)
downloadphp-openid-b8fd5e36ac459ffd880a25f8c545e1f5afb6ee73.zip
php-openid-b8fd5e36ac459ffd880a25f8c545e1f5afb6ee73.tar.gz
php-openid-b8fd5e36ac459ffd880a25f8c545e1f5afb6ee73.tar.bz2
[project @ XRI resolution support]
-rw-r--r--Auth/OpenID/Consumer.php15
-rw-r--r--Auth/OpenID/Discover.php20
-rw-r--r--Auth/OpenID/URINorm.php47
-rw-r--r--Services/Yadis/Misc.php53
-rw-r--r--Services/Yadis/XRI.php173
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