Index: modules/openid/openid.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/openid/openid.module,v
retrieving revision 1.44
diff -u -9 -p -r1.44 openid.module
--- modules/openid/openid.module	17 Mar 2009 15:26:29 -0000	1.44
+++ modules/openid/openid.module	18 Mar 2009 19:28:08 -0000
@@ -119,19 +119,19 @@ function _openid_user_login_form_alter(&
     '#description' => l(t('What is OpenID?'), 'http://openid.net/', array('external' => TRUE)),
   );
   $form['openid.return_to'] = array('#type' => 'hidden', '#value' => url('openid/authenticate', array('absolute' => TRUE, 'query' => drupal_get_destination())));
 }
 
 /**
  * Implementation of hook_form_alter(). Adds OpenID login to the login forms.
  */
 function openid_form_user_register_alter(&$form, &$form_state) {
-  if (isset($_SESSION['openid'])) {
+  if (isset($_SESSION['openid']['values'])) {
     // We were unable to auto-register a new user. Prefill the registration
     // form with the values we have.
     $form['name']['#default_value'] = $_SESSION['openid']['values']['name'];
     $form['mail']['#default_value'] = $_SESSION['openid']['values']['mail'];
     // If user_email_verification is off, hide the password field and just fill
     // with random password to avoid confusion.
     if (!variable_get('user_email_verification', TRUE)) {
       $form['pass']['#type'] = 'hidden';
       $form['pass']['#value'] = user_password();
Index: modules/openid/openid.test
===================================================================
RCS file: modules/openid/openid.test
diff -N modules/openid/openid.test
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/openid/openid.test	18 Mar 2009 19:28:08 -0000
@@ -0,0 +1,171 @@
+<?php
+// $Id: openid.test,v 1.29 2009/02/22 17:55:30 foo Exp $
+
+/**
+ * Check OpenID discovery and login using OpenID.
+ */
+class OpenIDFunctionalTest extends DrupalWebTestCase {
+  protected $user;
+
+  function getInfo() {
+    return array(
+      'name' => t('OpenID discovery and login'),
+      'description' => t('Test registration and login using OpenID.'),
+      'group' => t('OpenID')
+    );
+  }
+
+  function setUp() {
+    parent::setUp('openid', 'openid_test');
+
+    $this->user = $this->drupalCreateUser(array());
+  }
+
+  /**
+   * Test discovery via Yadis and HTML.
+   */
+  function testYadisDiscovery() {
+    $this->drupalLogin($this->user);
+
+    // Note that all of the following refer to the same endpoint, so only the
+    // first will trigger an associate request in openid_association().
+    $this->addIdentity(url('openid-test/yadis/x-xrds-location', array('absolute' => TRUE)), 2);
+    $this->addIdentity(url('openid-test/yadis/http-equiv', array('absolute' => TRUE)), 2);
+    $this->addIdentity(url('openid-test/yadis/html/openid1', array('absolute' => TRUE)), 1);
+    $this->addIdentity(url('openid-test/yadis/html/openid2', array('absolute' => TRUE)), 2);
+  }
+
+  /**
+   * Test login using OpenID.
+   */
+  function testLogin() {
+    $this->drupalLogin($this->user);
+
+    $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE));
+    $this->addIdentity($identity);
+
+    $this->drupalLogout();
+
+    $edit = array('openid_identifier' => $identity);
+    $this->drupalPost(NULL, $edit, t('Log in'));
+    $this->assertRaw('<script type="text/javascript">document.getElementById("openid-redirect-form").submit();</script>', t('JavaScript form submission found.'));
+    $this->drupalPost(NULL, array(), t('Send'));
+
+    $this->assertText(t('My account'), t('User was logged in.'));
+  }
+
+  /**
+   * Test unregistering an identity.
+   */
+  function testDeleteIdentity() {
+    $this->drupalLogin($this->user);
+
+    $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE));
+    $this->addIdentity($identity);
+    $this->assertText($identity, t('Identity appears in list.'));
+
+    $this->clickLink(t('Delete'));
+    $this->drupalPost(NULL, array(), t('Confirm'));
+
+    $this->assertText(t('OpenID deleted.'), t('Identity deleted'));
+    $this->assertNoText($identity, t('Identity no longer appears in list.'));
+  }
+
+  /**
+   * Register OpenID identity.
+   */
+  function addIdentity($identity, $version = 2) {
+    $this->drupalGet('user/' . $this->user->uid . '/openid');
+    $edit = array('openid_identifier' => $identity);
+    $this->drupalPost(NULL, $edit, t('Add an OpenID'));
+
+    // OpenID 1 used a HTTP redirect, OpenID 2 uses a HTML form that is submitted automatically using JavaScript.
+    if ($version == 2) {
+      // Manually submit form because SimpleTest is not able to execute JavaScript.
+      $this->assertRaw('<script type="text/javascript">document.getElementById("openid-redirect-form").submit();</script>', t('JavaScript form submission found.'));
+      $this->drupalPost(NULL, array(), t('Send'));
+    }
+
+    $this->assertRaw(t('Successfully added %identity', array('%identity' => $identity)), t('Identity %identity was added.', array('%identity' => $identity)));
+  }
+
+  /**
+   * Test account registration using OpenID with email verification disabled.
+   */
+  function testCreateAccountWithoutEmailVerification() {
+    variable_set('user_email_verification', FALSE);
+
+    $this->drupalGet('');
+    $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE));
+    $edit = array('openid_identifier' => $identity);
+    $this->drupalPost(NULL, $edit, t('Log in'));
+    $this->assertRaw('<script type="text/javascript">document.getElementById("openid-redirect-form").submit();</script>', t('JavaScript form submission found.'));
+    $this->drupalPost(NULL, array(), t('Send'));
+    $this->assertText(t('My account'), t('User was logged in.'));
+
+    $user = user_load_by_name('johndoe');
+    $this->assertTrue($user, t('User was found.'));
+    $this->assertEqual($user->mail, 'johndoe@example.com', t('User was registered with right email address.'));
+    $this->drupalGet(user_pass_reset_url($user));
+  }
+}
+
+/**
+ * Test internal helper functions.
+ */
+class OpenIDUnitTest extends DrupalWebTestCase {
+  function getInfo() {
+    return array(
+      'name' => t('OpenID helper functions'),
+      'description' => t('Test OpenID helper functions.'),
+      'group' => t('OpenID')
+    );
+  }
+
+  function setUp() {
+    parent::setUp('openid');
+    module_load_include('inc', 'openid');
+  }
+
+  /**
+   * Test _openid_dh_XXX_to_XXX() functions.
+   */
+  function testConversion() {
+    $this->assertEqual(_openid_dh_long_to_base64('12345678901234567890123456789012345678901234567890'), 'CHJ/Y2mq+DyhUCZ0evjH8ZbOPwrS', t('_openid_dh_long_to_base64() returned expected result.'));
+    $this->assertEqual(_openid_dh_base64_to_long('BsH/g8Nrpn2dtBSdu/sr1y8hxwyx'), '09876543210987654321098765432109876543210987654321', t('_openid_dh_base64_to_long() returned expected result.'));
+
+    $this->assertEqual(_openid_dh_long_to_binary('12345678901234567890123456789012345678901234567890'), "\x08r\x7fci\xaa\xf8<\xa1P&tz\xf8\xc7\xf1\x96\xce?\x0a\xd2", t('_openid_dh_long_to_binary() returned expected result.'));
+    $this->assertEqual(_openid_dh_binary_to_long("\x06\xc1\xff\x83\xc3k\xa6}\x9d\xb4\x14\x9d\xbb\xfb+\xd7/!\xc7\x0c\xb1"), '09876543210987654321098765432109876543210987654321', t('_openid_dh_binary_to_long() returned expected result.'));
+  }
+
+  /**
+   * Test _openid_dh_xorsecret().
+   */
+  function testOpenidDhXorsecret() {
+    $this->assertEqual(_openid_dh_xorsecret('123456790123456790123456790', "abc123ABC\x00\xFF"), "\xa4'\x06\xbe\xf1.\x00y\xff\xc2\xc1", t('_openid_dh_xorsecret() returned expected result.'));
+  }
+
+  /**
+   * Test _openid_get_bytes().
+   */
+  function testOpenidGetBytes() {
+    $this->assertEqual(strlen(_openid_get_bytes(20)), 20, t('_openid_get_bytes() returned expected result.'));
+  }
+
+  /**
+   * Test _openid_signature().
+   */
+  function testOpenidSignature() {
+    $response = array(
+      'openid.foo' => 'abc1',
+      'openid.bar' => 'abc2',
+      'openid.baz' => 'abc3',
+      'foobar.foo' => 'abc4',
+    );
+
+    $association = new stdClass;
+    $association->mac_key = "1234567890abcdefghij\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9";
+    $this->assertEqual(_openid_signature($association, $response, array('foo', 'bar')), 'QnKZQzSFstT+GNiJDFOptdcZjrc=', t('Expected signature calculated.'));
+  }
+}
+
Index: modules/openid/openid_test.info
===================================================================
RCS file: modules/openid/openid_test.info
diff -N modules/openid/openid_test.info
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/openid/openid_test.info	18 Mar 2009 19:28:08 -0000
@@ -0,0 +1,10 @@
+; $Id: openid_test.info,v 1.6 2008/10/11 02:32:53 foo Exp $
+name = OpenID dummy provider
+description = "OpenID provider used for testing."
+package = Testing
+version = VERSION
+core = 7.x
+files[] = openid_test.install
+files[] = openid_test.module
+dependencies[] = openid
+hidden = TRUE
Index: modules/openid/openid_test.install
===================================================================
RCS file: modules/openid/openid_test.install
diff -N modules/openid/openid_test.install
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/openid/openid_test.install	18 Mar 2009 19:28:08 -0000
@@ -0,0 +1,12 @@
+<?php
+
+// $Id: openid_test.install,v 1.4 2008/12/23 07:48:24 foo Exp $
+
+/**
+ * Implementation of hook_install().
+ */
+function openid_test_install() {
+  module_load_include('inc', 'openid');
+  // base64-encode mac_key, because variables cannot contain non-UTF-8 data.
+  variable_set('openid_test_mac_key', base64_encode(_openid_get_bytes(20)));
+}
Index: modules/openid/openid_test.module
===================================================================
RCS file: modules/openid/openid_test.module
diff -N modules/openid/openid_test.module
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/openid/openid_test.module	18 Mar 2009 19:28:08 -0000
@@ -0,0 +1,181 @@
+<?php
+// $Id: openid_test.module,v 1.41 2009/03/01 17:19:08 foo Exp $
+
+/**
+ * @file
+ * Dummy OpenID Provider used with SimpleTest.
+ */
+
+/**
+ * Implementation of hook_menu().
+ */
+function openid_test_menu() {
+  $items['openid-test/yadis/xrds'] = array(
+    'title' => 'XRDS service document',
+    'page callback' => 'openid_test_yadis_xrds',
+    'access callback' => TRUE,
+    'type' => MENU_CALLBACK,
+  );
+  $items['openid-test/yadis/x-xrds-location'] = array(
+    'title' => 'Yadis discovery using X-XRDS-Location header',
+    'page callback' => 'openid_test_yadis_xrds_location',
+    'access callback' => TRUE,
+    'type' => MENU_CALLBACK,
+  );
+  $items['openid-test/yadis/http-equiv'] = array(
+    'title' => 'Yadis discovery using <meta http-equiv="X-XRDS-Location" ...>',
+    'page callback' => 'openid_test_yadis_http_equiv',
+    'access callback' => TRUE,
+    'type' => MENU_CALLBACK,
+  );
+  $items['openid-test/yadis/html/openid1'] = array(
+    'title' => 'Yadis discovery using <link rel="openid.server" ...>',
+    'page callback' => 'openid_test_yadis_html_openid1',
+    'access callback' => TRUE,
+    'type' => MENU_CALLBACK,
+  );
+  $items['openid-test/yadis/html/openid2'] = array(
+    'title' => 'Yadis discovery using <link rel="openid2.provider" ...>',
+    'page callback' => 'openid_test_yadis_html_openid2',
+    'access callback' => TRUE,
+    'type' => MENU_CALLBACK,
+  );
+  $items['openid-test/endpoint'] = array(
+    'title' => 'OpenID Provider Endpoint',
+    'page callback' => 'openid_test_endpoint',
+    'access callback' => TRUE,
+    'type' => MENU_CALLBACK,
+  );
+  return $items;
+}
+
+/**
+ * Menu callback; XRDS document that references the OP Endpoint URL.
+ */
+function openid_test_yadis_xrds() {
+  if ($_SERVER['HTTP_ACCEPT'] == 'application/xrds+xml') {
+    drupal_set_header('Content-Type: application/xrds+xml');
+    print '<?xml version="1.0" encoding="UTF-8"?>
+      <xrds:XRDS xmlns:xrds="xri://$xrds" xmlns="xri://$xrd*($v*2.0)">
+        <XRD>
+          <Service>
+            <Type>http://specs.openid.net/auth/2.0/signon</Type>
+            <URI>'  . url('openid-test/endpoint', array('absolute' => TRUE)) . '</URI>
+          </Service>
+        <XRD>
+      </xrds:XRDS>';
+  }
+  else {
+    return 'Lorem ipsum';
+  }
+}
+
+/**
+ * Menu callback; regular HTML page with an X-XRDS-Location HTTP header.
+ */
+function openid_test_yadis_xrds_location() {
+  drupal_set_header('X-XRDS-Location: ' . url('openid-test/yadis/xrds', array('absolute' => TRUE)));
+  return 'Lorem ipsum';
+}
+
+/**
+ * Menu callback; regular HTML page with <meta> element.
+ */
+function openid_test_yadis_http_equiv() {
+  drupal_set_html_head('<meta http-equiv="X-XRDS-Location" content="' . url('openid-test/yadis/xrds', array('absolute' => TRUE)) . '" />');
+  return 'Lorem ipsum';
+}
+
+/**
+ * Menu callback; regular HTML page with OpenID 1.0 <link> element.
+ */
+function openid_test_yadis_html_openid1() {
+  drupal_set_html_head('<link rel="openid.server" href="' . url('openid-test/endpoint', array('absolute' => TRUE)) . '" />');
+  return 'Lorem ipsum';
+}
+
+/**
+ * Menu callback; regular HTML page with OpenID 2.0 <link> element.
+ */
+function openid_test_yadis_html_openid2() {
+  drupal_set_html_head('<link rel="openid2.provider" href="' . url('openid-test/endpoint', array('absolute' => TRUE)) . '" />');
+  return 'Lorem ipsum';
+}
+
+/**
+ * Menu callback; OpenID endpoint.
+ */
+function openid_test_endpoint() {
+  switch ($_REQUEST['openid_mode']) {
+    case 'associate';
+      _openid_test_endpoint_associate();
+      break;
+    case 'checkid_setup';
+      _openid_test_endpoint_authenticate();
+      break;
+  }
+}
+
+/**
+ * OpenID endpoint; handle associate request.
+ */
+function _openid_test_endpoint_associate() {
+  module_load_include('inc', 'openid');
+
+  $mod = OPENID_DH_DEFAULT_MOD;
+  $gen = OPENID_DH_DEFAULT_GEN;
+  $r = _openid_dh_rand($mod);
+  $private = bcadd($r, 1);
+
+  $public = bcpowmod($gen, $private, $mod);
+
+  $cpub = _openid_dh_base64_to_long($_REQUEST['openid_dh_consumer_public']);
+  $shared = bcpowmod($cpub, $private, $mod);
+
+  $response = array(
+    'ns' => 'http://specs.openid.net/auth/2.0',
+    'assoc_handle' => 'openid-test',
+    'session_type' => $_REQUEST['openid_session_type'],
+    'assoc_type' => $_REQUEST['openid_assoc_type'],
+    'expires_in' => '3600',
+    'dh_server_public' => _openid_dh_long_to_base64($public),
+    'enc_mac_key' => base64_encode(_openid_dh_xorsecret($shared, base64_decode(variable_get('mac_key')))),
+  );
+
+  drupal_set_header('Content-Type: text/plain');
+  print _openid_create_message($response);
+}
+
+/**
+ * OpenID endpoint; handle authenticate request.
+ */
+function _openid_test_endpoint_authenticate() {
+  global $base_url;
+
+  module_load_include('inc', 'openid');
+
+  $nonce = _openid_nonce();
+
+  $response = array(
+    'openid.ns' => 'http://specs.openid.net/auth/2.0',
+    'openid.mode' => 'id_res',
+    'openid.op_endpoint' => $base_url . url('openid/provider'),
+    'openid.claimed_id' => $_REQUEST['openid_claimed_id'],
+    'openid.identity' => $_REQUEST['openid_identity'],
+    'openid.return_to' => $_REQUEST['openid_return_to'],
+    'openid.response_nonce' => $nonce,
+    'openid.assoc_handle' => 'openid-test',
+    'openid.sreg.email' => 'johndoe@example.com',
+    'openid.sreg.nickname' => 'johndoe',
+    'openid.signed' => 'op_endpoint,claimed_id,identity,return_to,response_nonce,assoc_handle',
+  );
+  
+  $association = new stdClass;
+  $association->mac_key = variable_get('mac_key');
+  $keys_to_sign = explode(',', $response['openid.signed']);
+  $response['openid.sig'] = _openid_signature($association, $response, $keys_to_sign);
+
+  drupal_set_header('Content-Type: text/plain');
+  header('Location: ' . url($_REQUEST['openid_return_to'], array('query' => http_build_query($response, '', '&'), 'external' => TRUE)));
+}
+
