Index: CHANGELOG.txt
===================================================================
RCS file: /cvs/drupal/drupal/CHANGELOG.txt,v
retrieving revision 1.253.2.42
diff -u -9 -p -r1.253.2.42 CHANGELOG.txt
--- CHANGELOG.txt	11 Aug 2010 21:10:41 -0000	1.253.2.42
+++ CHANGELOG.txt	23 Nov 2010 23:09:07 -0000
@@ -1,13 +1,15 @@
 // $Id: CHANGELOG.txt,v 1.253.2.42 2010/08/11 21:10:41 goba Exp $
 
 Drupal 6.20-dev, xxxx-xx-xx (development release)
 ----------------------
+- OpenID i-name identities are now resolved to their CanonicalID, so users with
+  such OpenID identities may need to re-add their identity to their account.
 
 Drupal 6.19, 2010-08-11
 ----------------------
 - Fixed a variety of small bugs, improved code documentation.
 
 Drupal 6.18, 2010-08-11
 ----------------------
 - Fixed security issues (OpenID authentication bypass, File download access
   bypass, Comment unpublishing bypass, Actions cross site scripting),
Index: modules/openid/openid.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/openid/openid.module,v
retrieving revision 1.19.2.11
diff -u -9 -p -r1.19.2.11 openid.module
--- modules/openid/openid.module	11 Aug 2010 20:35:48 -0000	1.19.2.11
+++ modules/openid/openid.module	23 Nov 2010 23:09:07 -0000
@@ -177,26 +177,28 @@ function openid_begin($claimed_id, $retu
   $_SESSION['openid']['user_login_values'] = $form_values;
 
   $op_endpoint = $services[0]['uri'];
   // If bcmath is present, then create an association
   $assoc_handle = '';
   if (function_exists('bcadd')) {
     $assoc_handle = openid_association($op_endpoint);
   }
 
-  // Now that there is an association created, move on
-  // to request authentication from the IdP
-  // First check for LocalID. If not found, check for Delegate. Fall
-  // back to $claimed_id if neither is found.
+  // Now that there is an association created, move on to request authentication
+  // from the IdP. Use Claimed ID and/or OP-Local Identifier from service
+  // description, if available.
+  if (_openid_is_xri($claimed_id)) {
+    $claimed_id = $services[0]['canonicalid'];
+  }
   if (!empty($services[0]['localid'])) {
     $identity = $services[0]['localid'];
   }
-  else if (!empty($services[0]['delegate'])) {
+  elseif (!empty($services[0]['delegate'])) {
     $identity = $services[0]['delegate'];
   }
   else {
     $identity = $claimed_id;
   }
 
   if (isset($services[0]['types']) && is_array($services[0]['types']) && in_array(OPENID_NS_2_0 .'/server', $services[0]['types'])) {
     $claimed_id = $identity = 'http://specs.openid.net/auth/2.0/identifier_select';
   }
@@ -234,21 +236,30 @@ function openid_complete($response = arr
     $claimed_id = $_SESSION['openid']['claimed_id'];
     unset($_SESSION['openid']['service']);
     unset($_SESSION['openid']['claimed_id']);
     if (isset($response['openid.mode'])) {
       if ($response['openid.mode'] == 'cancel') {
         $response['status'] = 'cancel';
       }
       else {
         if (openid_verify_assertion($service, $response)) {
+          // OpenID Authentication, section 7.3.2.3 and Appendix A.5:
+          // The CanonicalID specified in the XRDS document must be used as the
+          // account key. We rely on the XRI proxy resolver to verify that the
+          // provider is authorized to respond on behalf of the specified
+          // identifer (required per Extensible Resource Identifier (XRI)
+          // Resolution Version 2.0, section 14.3).
+          if (!empty($service['claimed_id'])) {
+            $response['openid.claimed_id'] = $service['claimed_id'];
+          }
           // If the returned claimed_id is different from the session claimed_id,
           // then we need to do discovery and make sure the op_endpoint matches.
-          if ($service['version'] == 2 && $response['openid.claimed_id'] != $claimed_id) {
+          elseif ($service['version'] == 2 && $response['openid.claimed_id'] != $claimed_id) {
             $disco = openid_discovery($response['openid.claimed_id']);
             if ($disco[0]['uri'] != $service['uri']) {
               return $response;
             }
           }
           else {
             $response['openid.claimed_id'] = $claimed_id;
           }
           // Verify that openid.return_to matches the current URL (see OpenID
@@ -294,19 +305,21 @@ function openid_complete($response = arr
  */
 function openid_discovery($claimed_id) {
   module_load_include('inc', 'openid');
   module_load_include('inc', 'openid', 'xrds');
 
   $services = array();
 
   $xrds_url = $claimed_id;
   if (_openid_is_xri($claimed_id)) {
-    $xrds_url = 'http://xri.net/'. $claimed_id;
+    // Resolve XRI using a proxy resolver (Extensible Resource Identifier (XRI)
+    // Resolution Version 2.0, section 11.2).
+    $xrds_url = variable_get('xri_proxy_resolver', 'http://xri.net/') . rawurlencode($claimed_id) .'?_xrd_r=application/xrds+xml';
   }
   $url = @parse_url($xrds_url);
   if ($url['scheme'] == 'http' || $url['scheme'] == 'https') {
     // For regular URLs, try Yadis resolution first, then HTML-based discovery
     $headers = array('Accept' => 'application/xrds+xml');
     $result = drupal_http_request($xrds_url, $headers);
 
     if (!isset($result->error)) {
       if (isset($result->headers['Content-Type']) && preg_match("/application\/xrds\+xml/", $result->headers['Content-Type'])) {
Index: modules/openid/xrds.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/openid/Attic/xrds.inc,v
retrieving revision 1.2
diff -u -9 -p -r1.2 xrds.inc
--- modules/openid/xrds.inc	15 Oct 2007 09:40:42 -0000	1.2
+++ modules/openid/xrds.inc	23 Nov 2010 23:09:07 -0000
@@ -1,16 +1,15 @@
 <?php
 // $Id: xrds.inc,v 1.2 2007/10/15 09:40:42 goba Exp $
 
 // Global variables to track parsing state
 $xrds_open_elements = array();
 $xrds_services = array();
-$xrds_current_service = array();
 
 /**
  * Main entry point for parsing XRDS documents
  */
 function xrds_parse($xml) {
   global $xrds_services;
 
   $parser = xml_parser_create_ns();
   xml_set_element_handler($parser, '_xrds_element_start', '_xrds_element_end');
@@ -20,48 +19,65 @@ function xrds_parse($xml) {
   xml_parser_free($parser);
 
   return $xrds_services;
 }
 
 /**
  * Parser callback functions
  */
 function _xrds_element_start(&$parser, $name, $attribs) {
-  global $xrds_open_elements;
+  global $xrds_open_elements, $xrds_current_xrd;
 
   $xrds_open_elements[] = _xrds_strip_namespace($name);
+  $path = strtoupper(implode('/', $xrds_open_elements));
+  switch ($path) {
+    case 'XRDS/XRD':
+      $xrds_current_xrd = array();
+      break;
+    case 'XRDS/XRD/SERVICE':
+      $xrds_current_service = array();
+      break;
+    case 'XRDS/XRD/STATUS':
+      $xrds_current_xrd['status'] = $attribs['CID'];
+      break;
+  }
 }
 
 function _xrds_element_end(&$parser, $name) {
-  global $xrds_open_elements, $xrds_services, $xrds_current_service;
+  global $xrds_open_elements, $xrds_services, $xrds_current_xrd, $xrds_current_service;
 
-  $name = _xrds_strip_namespace($name);
-  if ($name == 'SERVICE') {
+  $path = strtoupper(implode('/', $xrds_open_elements));
+  if ($path == 'XRDS/XRD/SERVICE') {
+    if (!empty($xrds_current_xrd['status']) && $xrds_current_xrd['status'] == 'verified') {
+      $xrds_current_service['canonicalid'] = $xrds_current_xrd['canonicalid'];
+    }
     if (in_array(OPENID_NS_2_0 .'/signon', $xrds_current_service['types']) ||
         in_array(OPENID_NS_2_0 .'/server', $xrds_current_service['types'])) {
       $xrds_current_service['version'] = 2;
     }
     elseif (in_array(OPENID_NS_1_1, $xrds_current_service['types']) ||
             in_array(OPENID_NS_1_0, $xrds_current_service['types'])) {
       $xrds_current_service['version'] = 1;
     }
     if (!empty($xrds_current_service['version'])) {
       $xrds_services[] = $xrds_current_service;
     }
-    $xrds_current_service = array();
   }
   array_pop($xrds_open_elements);
 }
 
 function _xrds_cdata(&$parser, $data) {
-  global $xrds_open_elements, $xrds_services, $xrds_current_service;
+  global $xrds_open_elements, $xrds_services, $xrds_current_xrd, $xrds_current_service;
   $path = strtoupper(implode('/', $xrds_open_elements));
   switch ($path) {
+    case 'XRDS/XRD/CANONICALID':
+      $xrds_current_xrd['canonicalid'] = $data;
+      break;
     case 'XRDS/XRD/SERVICE/TYPE':
       $xrds_current_service['types'][] = $data;
       break;
     case 'XRDS/XRD/SERVICE/URI':
       $xrds_current_service['uri'] = $data;
       break;
     case 'XRDS/XRD/SERVICE/DELEGATE':
       $xrds_current_service['delegate'] = $data;
       break;
@@ -73,10 +89,10 @@ function _xrds_cdata(&$parser, $data) {
 
 function _xrds_strip_namespace($name) {
   // Strip namespacing.
   $pos = strrpos($name, ':');
   if ($pos !== FALSE) {
     $name = substr($name, $pos + 1, strlen($name));
   }
 
   return $name;
-}
\ No newline at end of file
+}
