diff --git a/modules/openid/openid.module b/modules/openid/openid.module index 7673de8..59e942e 100644 --- a/modules/openid/openid.module +++ b/modules/openid/openid.module @@ -589,8 +589,43 @@ function openid_association($op_endpoint) { */ function openid_authentication($response) { $identity = $response['openid.claimed_id']; - $account = user_external_load($identity); + + // Transition for accounts which were registered with stripped fragment due + // to bug in openid_complete(). See http://drupal.org/node/1120290. + if (!isset($account->uid) && strpos($identity, '#') !== FALSE) { + $identity_stripped = preg_replace('/#[^?]*/', '', $identity); + $account_stripped = user_external_load($identity); + if (isset($account_stripped->uid)) { + // Try to extract e-mail address from Simple Registration (SREG) or + // Attribute Exchanges (AX) keys. + $email = ''; + $sreg_values = openid_extract_namespace($response, OPENID_NS_SREG, 'sreg'); + $ax_values = openid_extract_namespace($response, OPENID_NS_AX, 'ax'); + if (!empty($sreg_values['email']) && valid_email_address($sreg_values['email'])) { + $email = $sreg_values['email']; + } + elseif ($ax_mail_values = openid_extract_ax_values($ax_values, array('http://axschema.org/contact/email', 'http://schema.openid.net/contact/email'))) { + $email = current($ax_mail_values); + } + // If this e-mail address is the same as the e-mail address found in user + // account, login the user and update the claimed identifier. + if ($email && ($email == $account_stripped->mail) || ($email == $account_stripped->init)) { + $query = db_update('authmap') + ->fields(array('authname' => $identity)) + ->condition('uid', $account_stripped->uid) + ->condition('module', 'openid') + ->execute(); + drupal_set_message(t('Successfully updated %identity_stripped with %identity.', array('%identity_stripped' => $identity_stripped, '%identity' => $identity))); + // Set the account to the found one. + $account =& $account_stripped; + } + else { + drupal_set_message(t('We found that there has been already an account which matches your OpenID identifier. If you are new on this site, please continue with registering the new user account. If you already had registered account on this site attached to the OpenID which you have provided, please try to reset the password or contact the site administrator. We are very sorry for this inadvertency.', array('@url_password' => 'user/password'))); + } + } + } + if (isset($account->uid)) { if (!variable_get('user_email_verification', TRUE) || $account->login) { // Check if user is blocked. diff --git a/modules/openid/openid.test b/modules/openid/openid.test index 202a835..d1ee479 100644 --- a/modules/openid/openid.test +++ b/modules/openid/openid.test @@ -479,6 +479,114 @@ class OpenIDRegistrationTestCase extends OpenIDWebTestCase { } /** + * Test account registration using Simple Registration and Attribute Exchange. + */ +class OpenIDInvalidIdentifierTransitionTestCase extends OpenIDFunctionalTestCase { + public static function getInfo() { + return array( + 'name' => 'OpenID account update', + 'description' => 'Tries to correct openid identifiers attached to accounts if theirs identifiers were stripped.', + 'group' => 'OpenID' + ); + } + + function setUp() { + parent::setUp('openid', 'openid_test'); + variable_set('user_register', USER_REGISTER_VISITORS); + } + + /** + * Test OpenID transition with e-mail mismatch. + */ + function testStrippedFragmentAccountEmailMismatch() { + $this->drupalLogin($this->web_user); + + // Use a User-supplied Identity that is the URL of an XRDS document. + $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE, 'fragment' => $this->randomName())); + $identity_stripped = preg_replace('/#[^?]*/', '', $identity); + + $this->addIdentity($identity_stripped); + + $this->drupalLogout(); + + // Test logging in via the login block on the front page. + $this->submitLoginForm($identity); + $this->assertLink(t('Log out'), 0, t('User was logged in.')); + + $this->drupalLogout(); + + // Test logging in via the user/login page, provider will respond with full + // identifier (including fragment) but with different email, so we can't + // provide auto-update. + variable_set('openid_test_response', array( + 'openid.claimed_id' => $identity, + 'openid.sreg.nickname' => $this->web_user->name, + 'openid.sreg.email' => 'invalid-' . $this->web_user->mail)); + $edit = array('openid_identifier' => $identity_stripped); + $this->drupalPost('user/login', $edit, t('Log in')); + + // Check we are on the OpenID redirect form. + $this->assertTitle(t('OpenID redirect'), t('OpenID redirect page was displayed.')); + + // Submit form to the OpenID Provider Endpoint. + $this->drupalPost(NULL, array(), t('Send')); + + // Verify user was redirected away from user/login to an accessible page. + $this->assertResponse(200); + + // Verify the message. + $this->assertRaw(t('We found that there has been already an account which matches your OpenID identifier. If you are new on this site, please continue with registering the new user account. If you already had registered account on this site attached to the OpenID which you have provided, please try to reset the password or contact the site administrator. We are very sorry for this inadvertency.', array('@url_password' => 'user/password')), t('Message that OpenID identifier must be updated manually was displayed.')); + + variable_set('openid_test_response', array()); + } + + /** + * Test OpenID auto transition with e-mail. + */ + function testStrippedFragmentAccountAutoUpdateSreg() { + $this->drupalLogin($this->web_user); + + // Use a User-supplied Identity that is the URL of an XRDS document. + $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE, 'fragment' => $this->randomName())); + $identity_stripped = preg_replace('/#[^?]*/', '', $identity); + + $this->addIdentity($identity_stripped); + + $this->drupalLogout(); + + // Test logging in via the login block on the front page. + $this->submitLoginForm($identity); + $this->assertLink(t('Log out'), 0, t('User was logged in.')); + + $this->drupalLogout(); + + // Test logging in via the user/login page, provider will respond with full + // identifier (including fragment) but with different email, so we can't + // provide auto-update. + variable_set('openid_test_response', array( + 'openid.claimed_id' => $identity, + 'openid.sreg.nickname' => $this->web_user->name, + 'openid.sreg.email' => $this->web_user->mail)); + $edit = array('openid_identifier' => $identity_stripped); + $this->drupalPost('user/login', $edit, t('Log in')); + + // Check we are on the OpenID redirect form. + $this->assertTitle(t('OpenID redirect'), t('OpenID redirect page was displayed.')); + + // Submit form to the OpenID Provider Endpoint. + $this->drupalPost(NULL, array(), t('Send')); + + // Verify user was redirected away from user/login to an accessible page. + $this->assertResponse(200); + + // Verify the message. + $this->assertRaw(t('Successfully updated %identity_stripped with %identity.', array('%identity_stripped' => $identity_stripped, '%identity' => $identity)), t('Message that OpenID identifier was updated automatically was displayed.')); + + variable_set('openid_test_response', array()); + } +} + +/** * Test internal helper functions. */ class OpenIDUnitTest extends DrupalWebTestCase {