Index: modules/openid/openid.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/openid/openid.inc,v
retrieving revision 1.21
diff -u -9 -p -r1.21 openid.inc
--- modules/openid/openid.inc	13 Oct 2009 21:16:43 -0000	1.21
+++ modules/openid/openid.inc	23 Nov 2009 22:36:00 -0000
@@ -138,18 +138,21 @@ function _openid_normalize_xri($xri) {
 }
 
 function _openid_normalize_url($url) {
   $normalized_url = $url;
 
   if (stristr($url, '://') === FALSE) {
     $normalized_url = 'http://' . $url;
   }
 
+  // Strip the fragment and fragment delimiter if present.
+  $normalized_url = strtok($normalized_url, '#');
+
   if (substr_count($normalized_url, '/') < 3) {
     $normalized_url .= '/';
   }
 
   return $normalized_url;
 }
 
 /**
  * Create a serialized message packet as per spec: $key:$value\n .
Index: modules/openid/openid.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/openid/openid.test,v
retrieving revision 1.7
diff -u -9 -p -r1.7 openid.test
--- modules/openid/openid.test	16 Nov 2009 05:08:47 -0000	1.7
+++ modules/openid/openid.test	23 Nov 2009 22:36:00 -0000
@@ -329,31 +329,51 @@ class OpenIDUnitTest extends DrupalWebTe
 
   /**
    * Test _openid_is_xri().
    */
   function testOpenidXRITest() {
     // Test that the XRI test is according to OpenID Authentication 2.0,
     // section 7.2. If the user-supplied string starts with xri:// it should be
     // stripped and the resulting string should be treated as an XRI when it
     // starts with "=", "@", "+", "$", "!" or "(".
-    $this->assertTrue(_openid_is_xri('xri://=foo'), t('_openid_is_xri returned expected result for an xri identifier with xri scheme.'));
-    $this->assertTrue(_openid_is_xri('xri://@foo'), t('_openid_is_xri returned expected result for an xri identifier with xri scheme.'));
-    $this->assertTrue(_openid_is_xri('xri://+foo'), t('_openid_is_xri returned expected result for an xri identifier with xri scheme.'));
-    $this->assertTrue(_openid_is_xri('xri://$foo'), t('_openid_is_xri returned expected result for an xri identifier with xri scheme.'));
-    $this->assertTrue(_openid_is_xri('xri://!foo'), t('_openid_is_xri returned expected result for an xri identifier with xri scheme..'));
-    $this->assertTrue(_openid_is_xri('xri://(foo'), t('_openid_is_xri returned expected result for an xri identifier with xri scheme..'));
-
-    $this->assertTrue(_openid_is_xri('=foo'), t('_openid_is_xri returned expected result for an xri identifier.'));
-    $this->assertTrue(_openid_is_xri('@foo'), t('_openid_is_xri returned expected result for an xri identifier.'));
-    $this->assertTrue(_openid_is_xri('+foo'), t('_openid_is_xri returned expected result for an xri identifier.'));
-    $this->assertTrue(_openid_is_xri('$foo'), t('_openid_is_xri returned expected result for an xri identifier.'));
-    $this->assertTrue(_openid_is_xri('!foo'), t('_openid_is_xri returned expected result for an xri identifier.'));
-    $this->assertTrue(_openid_is_xri('(foo'), t('_openid_is_xri returned expected result for an xri identifier.'));
-
-    $this->assertFalse(_openid_is_xri('foo'), t('_openid_is_xri returned expected result for an http URL.'));
-    $this->assertFalse(_openid_is_xri('xri://foo'), t('_openid_is_xri returned expected result for an http URL.'));
-    $this->assertFalse(_openid_is_xri('http://foo/'), t('_openid_is_xri returned expected result for an http URL.'));
-    $this->assertFalse(_openid_is_xri('http://example.com/'), t('_openid_is_xri returned expected result for an http URL.'));
-    $this->assertFalse(_openid_is_xri('user@example.com/'), t('_openid_is_xri returned expected result for an http URL.'));
-    $this->assertFalse(_openid_is_xri('http://user@example.com/'), t('_openid_is_xri returned expected result for an http URL.'));
+    $this->assertTrue(_openid_is_xri('xri://=foo'), t('_openid_is_xri() returned expected result for an xri identifier with xri scheme.'));
+    $this->assertTrue(_openid_is_xri('xri://@foo'), t('_openid_is_xri() returned expected result for an xri identifier with xri scheme.'));
+    $this->assertTrue(_openid_is_xri('xri://+foo'), t('_openid_is_xri() returned expected result for an xri identifier with xri scheme.'));
+    $this->assertTrue(_openid_is_xri('xri://$foo'), t('_openid_is_xri() returned expected result for an xri identifier with xri scheme.'));
+    $this->assertTrue(_openid_is_xri('xri://!foo'), t('_openid_is_xri() returned expected result for an xri identifier with xri scheme..'));
+    $this->assertTrue(_openid_is_xri('xri://(foo'), t('_openid_is_xri() returned expected result for an xri identifier with xri scheme..'));
+
+    $this->assertTrue(_openid_is_xri('=foo'), t('_openid_is_xri() returned expected result for an xri identifier.'));
+    $this->assertTrue(_openid_is_xri('@foo'), t('_openid_is_xri() returned expected result for an xri identifier.'));
+    $this->assertTrue(_openid_is_xri('+foo'), t('_openid_is_xri() returned expected result for an xri identifier.'));
+    $this->assertTrue(_openid_is_xri('$foo'), t('_openid_is_xri() returned expected result for an xri identifier.'));
+    $this->assertTrue(_openid_is_xri('!foo'), t('_openid_is_xri() returned expected result for an xri identifier.'));
+    $this->assertTrue(_openid_is_xri('(foo'), t('_openid_is_xri() returned expected result for an xri identifier.'));
+
+    $this->assertFalse(_openid_is_xri('foo'), t('_openid_is_xri() returned expected result for an http URL.'));
+    $this->assertFalse(_openid_is_xri('xri://foo'), t('_openid_is_xri() returned expected result for an http URL.'));
+    $this->assertFalse(_openid_is_xri('http://foo/'), t('_openid_is_xri() returned expected result for an http URL.'));
+    $this->assertFalse(_openid_is_xri('http://example.com/'), t('_openid_is_xri() returned expected result for an http URL.'));
+    $this->assertFalse(_openid_is_xri('user@example.com/'), t('_openid_is_xri() returned expected result for an http URL.'));
+    $this->assertFalse(_openid_is_xri('http://user@example.com/'), t('_openid_is_xri() returned expected result for an http URL.'));
   }
+
+  /**
+   * Test _openid_normalize().
+   */
+  function testOpenidNormalize() {
+    // Test that the normalization is according to OpenID Authentication 2.0,
+    // section 7.2 and 11.5.2.
+
+    $this->assertEqual(_openid_normalize('$foo'), '$foo', t('_openid_normalize() correctly normalized an XRI.'));
+    $this->assertEqual(_openid_normalize('xri://$foo'), '$foo', t('_openid_normalize() correctly normalized an XRI with an xri:// scheme.'));
+
+    $this->assertEqual(_openid_normalize('example.com/'), 'http://example.com/', t('_openid_normalize() correctly normalized a URL with a missing scheme.'));
+    $this->assertEqual(_openid_normalize('example.com'), 'http://example.com/', t('_openid_normalize() correctly normalized a URL with a missing scheme and empty path.'));
+    $this->assertEqual(_openid_normalize('http://example.com'), 'http://example.com/', t('_openid_normalize() correctly normalized a URL with an empty path.'));
+
+    $this->assertEqual(_openid_normalize('http://example.com/path'), 'http://example.com/path', t('_openid_normalize() correctly normalized a URL with a path.'));
+
+    $this->assertEqual(_openid_normalize('http://example.com/path#fragment'), 'http://example.com/path', t('_openid_normalize() correctly normalized a URL with a fragment.'));
+  }
+
 }
