diff --git a/modules/openid/openid.api.php b/modules/openid/openid.api.php index 11faa71..5e3d15d 100644 --- a/modules/openid/openid.api.php +++ b/modules/openid/openid.api.php @@ -49,8 +49,13 @@ function hook_openid_response($response, $account) { * Allow modules to declare OpenID discovery methods. * * The discovery function callbacks will be called in turn with an unique - * parameter, the claimed identifier. They have to return an array of services, - * in the same form returned by openid_discover(). + * parameter, the claimed identifier. They have to return an associative array + * with array of services and claimed identifier in the same form as returned by + * openid_discover(). The resulting array must contain following keys: + * - 'services' (required) an array of discovered services (including OpenID + * version, endpoint URI, etc). + * - 'claimed_id' (optional) new claimed identifer, found by following HTTP + * redirects during the services discovery. * * The first discovery method that succeed (return at least one services) will * stop the discovery process. @@ -58,6 +63,7 @@ function hook_openid_response($response, $account) { * @return * An associative array which keys are the name of the discovery methods and * values are function callbacks. + * * @see hook_openid_discovery_method_info_alter() */ function hook_openid_discovery_method_info() { diff --git a/modules/openid/openid.inc b/modules/openid/openid.inc index 6945f34..c05e422 100644 --- a/modules/openid/openid.inc +++ b/modules/openid/openid.inc @@ -89,7 +89,7 @@ function openid_redirect_http($url, $message) { */ function openid_redirect($url, $message) { global $language; - + $output = '' . "\n"; $output .= '' . "\n"; $output .= "\n"; @@ -793,3 +793,77 @@ function _openid_math_powmod($x, $y, $z) { return bcpowmod($x, $y, $z); } } + +/** + * Provides transition for accounts with possibly invalid OpenID identifiers in authmap. + * + * This function provides a safe and less obtrusive procedure for users who + * cannot login with their OpenID identifiers. OpenID identifiers in the + * authmap could be incomplete due to invalid OpenID implementation in previous + * versions of Drupal (e.g. fragment part of the identifier could be missing). + * For more information read http://drupal.org/node/1120290. + * + * @param string $identity + * The user's claimed OpenID identifier. + * + * @return + * A fully-loaded user object if the user is found or FALSE if not found. + */ +function _openid_invalid_openid_transition($identity, $response) { + $account = FALSE; + $fallback_account = NULL; + $fallback_identity = $identity; + + // Step 1: Try to strip the fragment if it is present. + if (strpos($fallback_identity, '#') !== FALSE) { + $fallback_identity = preg_replace('/#.*/', '', $fallback_identity); + $fallback_account = user_external_load($fallback_identity); + } + + // Step 2: Try to replace https with http. OpenID providers often redirects + // from http to https, but Drupal didn't follow these redirects. + if (!$fallback_account && strpos($fallback_identity, 'https://') !== FALSE) { + $fallback_identity = str_replace('https://', 'http://', $fallback_identity); + $fallback_account = user_external_load($fallback_identity); + } + + // Step 3: Try to use original identifier. + if (!$fallback_account && isset($_SESSION['openid']['user_login_values']['openid_identifier'])) { + $fallback_identity = openid_normalize($_SESSION['openid']['user_login_values']['openid_identifier']); + $fallback_account = user_external_load($fallback_identity); + } + + if ($fallback_account) { + // 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 == $fallback_account->mail || $email == $fallback_account->init)) { + $query = db_insert('authmap') + ->fields(array( + 'authname' => $identity, + 'uid' => $fallback_account->uid, + 'module' => 'openid', + )) + ->execute(); + drupal_set_message(t('New OpenID identifier %identity was added as a replacement for invalid identifier %invalid_identity. To finish the invalid OpenID transition process, please go to your OpenID identities page and remove the old identifier %invalid_identity.', array('%invalid_identity' => $fallback_identity, '%identity' => $identity, '@openid_url' => 'user/' . $fallback_account->uid . '/openid'))); + // Set the account to the found one. + $account =& $fallback_account; + } + else { + drupal_set_message(t('There is already an existing account associated with the OpenID identifier that you have provided. However, due to the bug in the previous version of the authentication system, we can\'t be sure that this account belongs to you. If you are new on this site, please continue registering the new user account. If you already have a registered account on this site associated with the provided OpenID identifier, please try to reset the password or contact the site administrator.', array('@url_password' => 'user/password')), 'warning'); + } + } + + return $account; +} diff --git a/modules/openid/openid.module b/modules/openid/openid.module index 7673de8..e993490 100644 --- a/modules/openid/openid.module +++ b/modules/openid/openid.module @@ -256,16 +256,25 @@ function openid_login_validate($form, &$form_state) { function openid_begin($claimed_id, $return_to = '', $form_values = array()) { module_load_include('inc', 'openid'); + $service = NULL; $claimed_id = openid_normalize($claimed_id); + $discovery = openid_discovery($claimed_id); - $services = openid_discovery($claimed_id); - $service = _openid_select_service($services); + if (!empty($discovery['services'])) { + $service = _openid_select_service($discovery['services']); + } - if (!$service) { + // Quit if the discovery result was empty or if we can't select any service. + if (!$discovery || !$service) { form_set_error('openid_identifier', t('Sorry, that is not a valid OpenID. Ensure you have spelled your ID correctly.')); return; } + // Set claimed id from discovery. + if (!empty($discovery['claimed_id'])) { + $claimed_id = $discovery['claimed_id']; + } + // Store discovered information in the users' session so we don't have to rediscover. $_SESSION['openid']['service'] = $service; // Store the claimed id @@ -341,18 +350,23 @@ function openid_complete($response = array()) { $response['openid.claimed_id'] = $service['claimed_id']; } elseif ($service['version'] == 2) { - $response['openid.claimed_id'] = openid_normalize($response['openid.claimed_id']); + // Returned claimed id could have unique fragment hash to allow + // identifier recycling so we need to preserve it in response. + $response_claimed_id = openid_normalize($response['openid.claimed_id']); + // OpenID Authentication, section 11.2: // If the returned Claimed Identifier is different from the one sent // to the OpenID Provider, we need to do discovery on the returned // identififer to make sure that the provider is authorized to // respond on behalf of this. - if ($response['openid.claimed_id'] != $claimed_id) { - $services = openid_discovery($response['openid.claimed_id']); - $uris = array(); - foreach ($services as $discovered_service) { - if (in_array('http://specs.openid.net/auth/2.0/server', $discovered_service['types']) || in_array('http://specs.openid.net/auth/2.0/signon', $discovered_service['types'])) { - $uris[] = $discovered_service['uri']; + if ($response_claimed_id != $claimed_id) { + $discovery = openid_discovery($response['openid.claimed_id']); + if ($discovery && !empty($discovery['services'])) { + $uris = array(); + foreach ($discovery['services'] as $discovered_service) { + if (in_array('http://specs.openid.net/auth/2.0/server', $discovered_service['types']) || in_array('http://specs.openid.net/auth/2.0/signon', $discovered_service['types'])) { + $uris[] = $discovered_service['uri']; + } } } if (!in_array($service['uri'], $uris)) { @@ -374,10 +388,21 @@ function openid_complete($response = array()) { /** * Perform discovery on a claimed ID to determine the OpenID provider endpoint. * - * @param $claimed_id The OpenID URL to perform discovery on. + * Discovery methods are provided by the hook_openid_discovery_method_info and + * could be further altered using the hook_openid_discovery_method_info_alter. * - * @return Array of services discovered (including OpenID version, endpoint - * URI, etc). + * @param $claimed_id + * The OpenID URL to perform discovery on. + * + * @return + * The resulting discovery array from the first successful discovery method, + * which must contain following keys: + * - 'services' (required) an array of discovered services (including OpenID + * version, endpoint URI, etc). + * - 'claimed_id' (optional) new claimed identifer, found by following HTTP + * redirects during the services discovery. + * If all the discovery method fails or if no appropriate discovery method is + * found, FALSE is returned. */ function openid_discovery($claimed_id) { module_load_include('inc', 'openid'); @@ -385,15 +410,15 @@ function openid_discovery($claimed_id) { $methods = module_invoke_all('openid_discovery_method_info'); drupal_alter('openid_discovery_method_info', $methods); - // Execute each method in turn. + // Execute each method in turn and return first successful discovery. foreach ($methods as $method) { - $discovered_services = $method($claimed_id); - if (!empty($discovered_services)) { - return $discovered_services; + $discovery = $method($claimed_id); + if (!empty($discovery)) { + return $discovery; } } - return array(); + return FALSE; } /** @@ -417,24 +442,33 @@ function openid_openid_discovery_method_info() { * * @see http://openid.net/specs/openid-authentication-2_0.html#discovery * @see hook_openid_discovery_method_info() + * @see openid_discovery() + * + * @return + * An array of discovered services and claimed identifier or NULL. See + * openid_discovery() for more specific information. */ function _openid_xri_discovery($claimed_id) { if (_openid_is_xri($claimed_id)) { // Resolve XRI using a proxy resolver (Extensible Resource Identifier (XRI) // Resolution Version 2.0, section 11.2 and 14.3). $xrds_url = variable_get('xri_proxy_resolver', 'http://xri.net/') . rawurlencode($claimed_id) . '?_xrd_r=application/xrds+xml'; - $services = _openid_xrds_discovery($xrds_url); - foreach ($services as $i => &$service) { - $status = $service['xrd']->children(OPENID_NS_XRD)->Status; - if ($status && $status->attributes()->cid == 'verified') { - $service['claimed_id'] = openid_normalize((string)$service['xrd']->children(OPENID_NS_XRD)->CanonicalID); + $discovery = _openid_xrds_discovery($xrds_url); + if (!empty($discovery['services']) && is_array($discovery['services'])) { + foreach ($discovery['services'] as $i => &$service) { + $status = $service['xrd']->children(OPENID_NS_XRD)->Status; + if ($status && $status->attributes()->cid == 'verified') { + $service['claimed_id'] = openid_normalize((string)$service['xrd']->children(OPENID_NS_XRD)->CanonicalID); + } + else { + // Ignore service if the Canonical ID could not be verified. + unset($discovery['services'][$i]); + } } - else { - // Ignore service if CanonicalID could not be verified. - unset($services[$i]); + if (!empty($discovery['services'])) { + return $discovery; } } - return $services; } } @@ -443,6 +477,11 @@ function _openid_xri_discovery($claimed_id) { * * @see http://openid.net/specs/openid-authentication-2_0.html#discovery * @see hook_openid_discovery_method_info() + * @see openid_discovery() + * + * @return + * An array of discovered services and claimed identifier or NULL. See + * openid_discovery() for more specific information. */ function _openid_xrds_discovery($claimed_id) { $services = array(); @@ -454,7 +493,18 @@ function _openid_xrds_discovery($claimed_id) { $headers = array('Accept' => 'application/xrds+xml'); $result = drupal_http_request($xrds_url, array('headers' => $headers)); - if (!isset($result->error)) { + // Check for HTTP error and make sure, that we reach the target. If the + // maximum allowed redirects are exhausted, final destination URL isn't + // reached, but drupal_http_request() doesn't return any error. + // @todo Remove the check for 200 HTTP result code after the following issue + // will be fixed: http://drupal.org/node/1096890. + if (!isset($result->error) && $result->code == 200) { + + // Replace the user-entered claimed_id if we received a redirect. + if (!empty($result->redirect_url)) { + $claimed_id = openid_normalize($result->redirect_url); + } + if (isset($result->headers['content-type']) && preg_match("/application\/xrds\+xml/", $result->headers['content-type'])) { // Parse XML document to find URL $services = _openid_xrds_parse($result->data); @@ -500,7 +550,13 @@ function _openid_xrds_discovery($claimed_id) { } } } - return $services; + + if (!empty($services)) { + return array( + 'services' => $services, + 'claimed_id' => $claimed_id, + ); + } } /** @@ -589,8 +645,15 @@ function openid_association($op_endpoint) { */ function openid_authentication($response) { $identity = $response['openid.claimed_id']; - $account = user_external_load($identity); + + // Tries to load user account if user_external_load fails due to possibly + // incompletely stored OpenID identifier in the authmap. + if (!isset($account->uid) && variable_get('openid_less_obtrusive_transition', FALSE)) { + module_load_include('inc', 'openid'); + $account = _openid_invalid_openid_transition($identity, $response); + } + if (isset($account->uid)) { if (!variable_get('user_email_verification', TRUE) || $account->login) { // Check if user is blocked. @@ -634,7 +697,7 @@ function openid_authentication($response) { drupal_set_message(t('Account registration using the information provided by your OpenID provider failed due to the reasons listed below. Complete the registration by filling out the form below. If you already have an account, you can log in now and add your OpenID under "My account".', array('@login' => url('user/login'))), 'warning'); // Append form validation errors below the above warning. foreach ($messages['error'] as $message) { - drupal_set_message( $message, 'error'); + drupal_set_message($message, 'error'); } } diff --git a/modules/openid/openid.test b/modules/openid/openid.test index 202a835..02366d1 100644 --- a/modules/openid/openid.test +++ b/modules/openid/openid.test @@ -89,12 +89,12 @@ class OpenIDFunctionalTestCase extends OpenIDWebTestCase { // Identifier is the URL of an XRDS document containing an OP Identifier // Element. The Relying Party sends the special value // "http://specs.openid.net/auth/2.0/identifier_select" as Claimed - // Identifier. The OpenID Provider responds with the actual identifier. - $identity = url('openid-test/yadis/xrds/dummy-user', array('absolute' => TRUE)); - // Tell openid_test.module to respond with this identifier. The URL scheme - // is stripped in order to test that the returned identifier is normalized in - // openid_complete(). - variable_set('openid_test_response', array('openid.claimed_id' => preg_replace('@^https?://@', '', $identity))); + // Identifier. The OpenID Provider responds with the actual identifier + // including fragment. + $identity = url('openid-test/yadis/xrds/dummy-user', array('absolute' => TRUE, 'fragment' => $this->randomName())); + // Tell openid_test.module to respond with this identifier. We test if + // openid_complete() process it right. + variable_set('openid_test_response', array('openid.claimed_id' => $identity)); $this->addIdentity(url('openid-test/yadis/xrds/server', array('absolute' => TRUE)), 2, 'http://specs.openid.net/auth/2.0/identifier_select', $identity); variable_set('openid_test_response', array()); @@ -124,6 +124,28 @@ class OpenIDFunctionalTestCase extends OpenIDWebTestCase { // OpenID Authentication 2.0, section 7.3.3: $this->addIdentity(url('openid-test/html/openid2', array('absolute' => TRUE)), 2, 'http://example.com/html-openid2'); + + // OpenID Authentication 2.0, section 7.2.4: + // URL Identifiers MUST then be further normalized by both (1) following + // redirects when retrieving their content and finally (2) applying the + // rules in Section 6 of RFC3986 to the final destination URL. This final + // URL MUST be noted by the Relying Party as the Claimed Identifier and be + // used when requesting authentication. + + // Single redirect. + $identity = $expected_claimed_id = url('openid-test/redirected/yadis/xrds/1', array('absolute' => TRUE)); + $this->addRedirectedIdentity($identity, 2, 'http://example.com/xrds', $expected_claimed_id, 0); + + // Exact 3 redirects (default value for the 'max_redirects' option in + // drupal_http_request()). + $identity = $expected_claimed_id = url('openid-test/redirected/yadis/xrds/2', array('absolute' => TRUE)); + $this->addRedirectedIdentity($identity, 2, 'http://example.com/xrds', $expected_claimed_id, 2); + + // Fails because there are more than 3 redirects (default value for the + // 'max_redirects' option in drupal_http_request()). + $identity = url('openid-test/redirected/yadis/xrds/3', array('absolute' => TRUE)); + $expected_claimed_id = FALSE; + $this->addRedirectedIdentity($identity, 2, 'http://example.com/xrds', $expected_claimed_id, 3); } /** @@ -280,6 +302,41 @@ class OpenIDFunctionalTestCase extends OpenIDWebTestCase { } /** + * Add OpenID identity, changed by the following redirects, to user's profile. + * + * According to OpenID Authentication 2.0, section 7.2.4, URL Identifiers MUST + * be further normalized by following redirects when retrieving their content + * and this final URL MUST be noted by the Relying Party as the Claimed + * Identifier and be used when requesting authentication. + * + * @param $identity + * The User-supplied Identifier. + * @param $version + * The protocol version used by the service. + * @param $local_id + * The expected OP-Local Identifier found during discovery. + * @param $claimed_id + * The expected Claimed Identifier returned by the OpenID Provider, or FALSE + * if the discovery is expected to fail. + * @param $redirects + * The number of redirects. + */ + function addRedirectedIdentity($identity, $version = 2, $local_id = 'http://example.com/xrds', $claimed_id = NULL, $redirects = 0) { + // Set the final destination URL which is the same as the Claimed + // Identifier, we insert the same identifier also to the provider response, + // but provider could futher change the Claimed ID actually (e.g. it could + // add unique fragment). + variable_set('openid_test_redirect_url', $identity); + variable_set('openid_test_response', array('openid.claimed_id' => $identity)); + + $this->addIdentity(url('openid-test/redirect/' . $redirects, array('absolute' => TRUE)), $version, $local_id, $claimed_id); + + // Clean up. + variable_del('openid_test_redirect_url'); + variable_del('openid_test_response'); + } + + /** * Tests that openid.signed is verified. */ function testSignatureValidation() { @@ -479,6 +536,115 @@ 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 their identifiers were stripped.', + 'group' => 'OpenID', + ); + } + + function setUp() { + parent::setUp('openid', 'openid_test'); + variable_set('user_register', USER_REGISTER_VISITORS); + variable_set('openid_less_obtrusive_transition', TRUE); + } + + /** + * 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('There is already an existing account associated with the OpenID identifier that you have provided.'), 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('New OpenID identifier %identity was added as a replacement for invalid identifier %invalid_identity.', array('%invalid_identity' => $identity_stripped, '%identity' => $identity)), t('Message that OpenID identifier was added automatically was displayed.')); + + variable_set('openid_test_response', array()); + } +} + +/** * Test internal helper functions. */ class OpenIDUnitTest extends DrupalWebTestCase { diff --git a/modules/openid/tests/openid_test.module b/modules/openid/tests/openid_test.module index bad1184..a3a0126 100644 --- a/modules/openid/tests/openid_test.module +++ b/modules/openid/tests/openid_test.module @@ -60,6 +60,25 @@ function openid_test_menu() { 'access callback' => TRUE, 'type' => MENU_CALLBACK, ); + $items['openid-test/redirect'] = array( + 'title' => 'OpenID Redirect', + 'page callback' => 'openid_test_redirect', + 'access callback' => TRUE, + 'type' => MENU_CALLBACK, + ); + $items['openid-test/redirect'] = array( + 'title' => 'OpenID Provider Redirection Point', + 'page callback' => 'openid_test_redirect', + 'access callback' => TRUE, + 'type' => MENU_CALLBACK, + ); + $items['openid-test/redirected/%/%'] = array( + 'title' => 'OpenID Provider Final URL', + 'page callback' => 'openid_test_redirected_method', + 'page arguments' => array(2, 3), + 'access callback' => TRUE, + 'type' => MENU_CALLBACK, + ); return $items; } @@ -213,6 +232,28 @@ function openid_test_endpoint() { } /** + * Menu callback; redirect during Normalization/Discovery. + */ +function openid_test_redirect($count = 0) { + if ($count == 0) { + $url = variable_get('openid_test_redirect_url', ''); + } + else { + $url = url('openid-test/redirect/' . --$count, array('absolute' => TRUE)); + } + $http_response_code = variable_get('openid_test_redirect_http_reponse_code', 301); + header('Location: ' . $url, TRUE, $http_response_code); + exit(); +} + +/** + * Menu callback; respond with appropriate callback. + */ +function openid_test_redirected_method($method1, $method2) { + return call_user_func('openid_test_' . $method1 . '_' . $method2); +} + +/** * OpenID endpoint; handle "associate" requests (see OpenID Authentication 2.0, * section 8). * diff --git a/sites/default/default.settings.php b/sites/default/default.settings.php index 0472f02..0795eea 100644 --- a/sites/default/default.settings.php +++ b/sites/default/default.settings.php @@ -442,3 +442,28 @@ ini_set('session.cookie_lifetime', 2000000); * Remove the leading hash signs to disable. */ # $conf['allow_authorize_operations'] = FALSE; + +/** + * Automatic invalid Openid transition: + * + * A less obtrusive but also less secure (and optional) method of invalid OpenID + * identifier transition. Due to the bug in the OpenID module, wrong identifiers + * were saved to the authmap table (affects only particular OpenID providers). + * After the bug was fixed in Drupal 7.8 some the stored OpenID identifiers + * could be different from the current resulting identifiers. Affected users + * aren't able to login to the site with the OpenID credentials which worked + * before the Drupal core upgrade. + * + * If enabled, Drupal will try to find matching account from the user database + * using the alternative OpenID identifier matching when OpenID login failed. + * Matched user account must have same e-mail address as the OpenID account! + * If disabled or when e-mail address doesn't match user must login to the site + * using other method, e.g. using ordinary user login. After login, user could + * fix the account by himself by deleting the obsolete OpenID account and adding + * the new one, the right OpenID identifier will be stored this time. If user + * doesn't know his credentials, he can use password reset for the one-time + * temporary login. For more information, see http://drupal.org/node/1120290. + * + * Remove the leading hash sign to enable. + */ +# $conf['openid_less_obtrusive_transition'] = TRUE;