From 315c419322526294d9f53ab44bdbcc4bdef02e7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Hojtsy?= Date: Wed, 30 Jan 2008 22:11:22 +0000 Subject: #216022 reported by johnnysxip, patch by walkah: (SA-2008-016) OpenID - Incorrect claimed_id returned for OpenID 2.0 and other minor OpenID 2.0 compliance fixes --- modules/openid/openid.css | 8 ++--- modules/openid/openid.inc | 51 +++++++++++++++++++--------- modules/openid/openid.js | 14 ++++---- modules/openid/openid.module | 75 +++++++++++++++++++++++------------------ modules/openid/openid.pages.inc | 17 +++++----- 5 files changed, 98 insertions(+), 67 deletions(-) (limited to 'modules') diff --git a/modules/openid/openid.css b/modules/openid/openid.css index 5437350ff..5a05d6380 100644 --- a/modules/openid/openid.css +++ b/modules/openid/openid.css @@ -1,18 +1,18 @@ /* $Id$ */ -#edit-openid-url { +#edit-openid-identifier { background-image: url("login-bg.png"); background-position: 0% 50%; background-repeat: no-repeat; padding-left: 20px; } -div#edit-openid-url-wrapper { +div#edit-openid-identifier-wrapper { display: block; } -html.js #user-login-form div#edit-openid-url-wrapper, -html.js #user-login div#edit-openid-url-wrapper { +html.js #user-login-form div#edit-openid-identifier-wrapper, +html.js #user-login div#edit-openid-identifier-wrapper { display: none; } diff --git a/modules/openid/openid.inc b/modules/openid/openid.inc index 9ff4af5a2..e20cf9806 100644 --- a/modules/openid/openid.inc +++ b/modules/openid/openid.inc @@ -193,7 +193,7 @@ function _openid_link_href($rel, $html) { $rel = preg_quote($rel); preg_match('||iUs', $html, $matches); if (isset($matches[3])) { - preg_match('|href=["\']([^"]+)["\']|iU', $matches[0], $href); + preg_match('|href=["\']([^"]+)["\']|iU', $matches[3], $href); return trim($href[1]); } return FALSE; @@ -206,7 +206,9 @@ function _openid_meta_httpequiv($equiv, $html) { preg_match('||iUs', $html, $matches); if (isset($matches[1])) { preg_match('|content=["\']([^"]+)["\']|iUs', $matches[1], $content); - return $content[1]; + if (isset($content[1])) { + return $content[1]; + } } return FALSE; } @@ -382,23 +384,40 @@ function _openid_get_bytes($num_bytes) { return $bytes; } -/** - * Fix PHP's habit of replacing '.' by '_' in posted data. - */ -function _openid_fix_post(&$post) { - $extensions = module_invoke_all('openid', 'extension'); - foreach ($post as $key => $value) { - if (strpos($key, 'openid_') === 0) { - $fixed_key = str_replace('openid_', 'openid.', $key); - $fixed_key = str_replace('openid.ns_', 'openid.ns.', $fixed_key); - $fixed_key = str_replace('openid.sreg_', 'openid.sreg.', $fixed_key); - foreach ($extensions as $ext) { - $fixed_key = str_replace('openid.'. $ext .'_', 'openid.'. $ext .'.', $fixed_key); +function _openid_response($str = NULL) { + $data = array(); + + if (isset($_SERVER['REQUEST_METHOD'])) { + $data = _openid_get_params($_SERVER['QUERY_STRING']); + + if ($_SERVER['REQUEST_METHOD'] == 'POST') { + $str = file_get_contents('php://input'); + + $post = array(); + if ($str !== false) { + $post = _openid_get_params($str); } - unset($post[$key]); - $post[$fixed_key] = $value; + + $data = array_merge($data, $post); + } + } + + return $data; +} + +function _openid_get_params($str) { + $chunks = explode("&", $str); + + $data = array(); + foreach ($chunks as $chunk) { + $parts = explode("=", $chunk, 2); + + if (count($parts) == 2) { + list($k, $v) = $parts; + $data[$k] = urldecode($v); } } + return $data; } /** diff --git a/modules/openid/openid.js b/modules/openid/openid.js index 9a7b9252e..bd2948dc9 100644 --- a/modules/openid/openid.js +++ b/modules/openid/openid.js @@ -2,11 +2,11 @@ Drupal.behaviors.openid = function (context) { var $loginElements = $("#edit-name-wrapper, #edit-pass-wrapper, li.openid-link"); - var $openidElements = $("#edit-openid-url-wrapper, li.user-link"); + var $openidElements = $("#edit-openid-identifier-wrapper, li.user-link"); // This behavior attaches by ID, so is only valid once on a page. - if (!$("#edit-openid-url.openid-processed").size() && $("#edit-openid-url").val()) { - $("#edit-openid-url").addClass('openid-processed'); + if (!$("#edit-openid-identifier.openid-processed").size() && $("#edit-openid-identifier").val()) { + $("#edit-openid-identifier").addClass('openid-processed'); $loginElements.hide(); // Use .css("display", "block") instead of .show() to be Konqueror friendly. $openidElements.css("display", "block"); @@ -19,8 +19,8 @@ Drupal.behaviors.openid = function (context) { // Remove possible error message. $("#edit-name, #edit-pass").removeClass("error"); $("div.messages.error").hide(); - // Set focus on OpenID URL field. - $("#edit-openid-url")[0].focus(); + // Set focus on OpenID Identifier field. + $("#edit-openid-identifier")[0].focus(); return false; }); $("li.user-link:not(.openid-processed)", context) @@ -28,8 +28,8 @@ Drupal.behaviors.openid = function (context) { .click(function() { $openidElements.hide(); $loginElements.css("display", "block"); - // Clear OpenID URL field and remove possible error message. - $("#edit-openid-url").val('').removeClass("error"); + // Clear OpenID Identifier field and remove possible error message. + $("#edit-openid-identifier").val('').removeClass("error"); $("div.messages.error").css("display", "block"); // Set focus on username field. $("#edit-name")[0].focus(); diff --git a/modules/openid/openid.module b/modules/openid/openid.module index eb281d26d..d77ee73b2 100644 --- a/modules/openid/openid.module +++ b/modules/openid/openid.module @@ -62,7 +62,7 @@ function openid_help($path, $arg) { * Implementation of hook_user(). */ function openid_user($op, &$edit, &$account, $category = NULL) { - if ($op == 'insert' && isset($_SESSION['openid'])) { + if ($op == 'insert' && isset($_SESSION['openid']['values'])) { // The user has registered after trying to login via OpenID. if (variable_get('user_email_verification', TRUE)) { drupal_set_message(t('Once you have verified your email address, you may log in via OpenID.')); @@ -78,7 +78,7 @@ function openid_form_alter(&$form, $form_state, $form_id) { if ($form_id == 'user_login_block' || $form_id == 'user_login') { drupal_add_css(drupal_get_path('module', 'openid') .'/openid.css', 'module'); drupal_add_js(drupal_get_path('module', 'openid') .'/openid.js'); - if (!empty($form_state['post']['openid_url'])) { + if (!empty($form_state['post']['openid_identifier'])) { $form['name']['#required'] = FALSE; $form['pass']['#required'] = FALSE; unset($form['#submit']); @@ -102,7 +102,7 @@ function openid_form_alter(&$form, $form_state, $form_id) { $form['links']['#weight'] = 2; - $form['openid_url'] = array( + $form['openid_identifier'] = array( '#type' => 'textfield', '#title' => t('Log in using OpenID'), '#size' => ($form_id == 'user_login') ? 58 : 13, @@ -115,15 +115,15 @@ function openid_form_alter(&$form, $form_state, $form_id) { elseif ($form_id == 'user_register' && isset($_SESSION['openid'])) { // We were unable to auto-register a new user. Prefill the registration // form with the values we have. - $form['name']['#default_value'] = $_SESSION['openid']['name']; - $form['mail']['#default_value'] = $_SESSION['openid']['mail']; + $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(); } - $form['auth_openid'] = array('#type' => 'hidden', '#value' => $_SESSION['openid']['auth_openid']); + $form['auth_openid'] = array('#type' => 'hidden', '#value' => $_SESSION['openid']['values']['auth_openid']); } return $form; } @@ -137,7 +137,7 @@ function openid_login_validate($form, &$form_state) { $return_to = url('', array('absolute' => TRUE)); } - openid_begin($form_state['values']['openid_url'], $return_to, $form_state['values']); + openid_begin($form_state['values']['openid_identifier'], $return_to, $form_state['values']); } /** @@ -157,19 +157,19 @@ function openid_begin($claimed_id, $return_to = '', $form_values = array()) { $services = openid_discovery($claimed_id); if (count($services) == 0) { - form_set_error('openid_url', t('Sorry, that is not a valid OpenID. Please ensure you have spelled your ID correctly.')); + form_set_error('openid_identifier', t('Sorry, that is not a valid OpenID. Please ensure you have spelled your ID correctly.')); return; } - $op_endpoint = $services[0]['uri']; - // Store the discovered endpoint in the session (so we don't have to rediscover). - $_SESSION['openid_op_endpoint'] = $op_endpoint; - // Store the claimed_id in the session (for handling delegation). - $_SESSION['openid_claimed_id'] = $claimed_id; + // Store discovered information in the users' session so we don't have to rediscover. + $_SESSION['openid']['service'] = $services[0]; + // Store the claimed id + $_SESSION['openid']['claimed_id'] = $claimed_id; // Store the login form values so we can pass them to // user_exteral_login later. - $_SESSION['openid_user_login_values'] = $form_values; + $_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')) { @@ -191,8 +191,8 @@ function openid_begin($claimed_id, $return_to = '', $form_values = array()) { } if (isset($services[0]['types']) && is_array($services[0]['types']) && in_array(OPENID_NS_2_0 .'/server', $services[0]['types'])) { - $identity = 'http://openid.net/identifier_select/2.0'; - } + $identity = 'http://specs.openid.net/auth/2.0/identifier_select'; + } $authn_request = openid_authentication_request($claimed_id, $identity, $return_to, $assoc_handle, $services[0]['version']); if ($services[0]['version'] == 2) { @@ -207,29 +207,42 @@ function openid_begin($claimed_id, $return_to = '', $form_values = array()) { * Completes OpenID authentication by validating returned data from the OpenID * Provider. * - * @param $response Array of returned from the OpenID provider (typically $_REQUEST). + * @param $response Array of returned values from the OpenID Provider. * * @return $response Response values for further processing with * $response['status'] set to one of 'success', 'failed' or 'cancel'. */ -function openid_complete($response) { +function openid_complete($response = array()) { module_load_include('inc', 'openid'); + if (count($response) == 0) { + $response = _openid_response(); + } + // Default to failed response $response['status'] = 'failed'; - if (isset($_SESSION['openid_op_endpoint']) && isset($_SESSION['openid_claimed_id'])) { - _openid_fix_post($response); - $op_endpoint = $_SESSION['openid_op_endpoint']; - $claimed_id = $_SESSION['openid_claimed_id']; - unset($_SESSION['openid_op_endpoint']); - unset($_SESSION['openid_claimed_id']); + if (isset($_SESSION['openid']['service']['uri']) && isset($_SESSION['openid']['claimed_id'])) { + $service = $_SESSION['openid']['service']; + $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($op_endpoint, $response)) { - $response['openid.identity'] = $claimed_id; + if (openid_verify_assertion($service['uri'], $response)) { + // 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) { + $disco = openid_discovery($response['openid.claimed_id']); + if ($disco[0]['uri'] != $service['uri']) { + return $response; + } + } + else { + $response['openid.claimed_id'] = $claimed_id; + } $response['status'] = 'success'; } } @@ -371,12 +384,12 @@ function openid_association($op_endpoint) { function openid_authentication($response) { module_load_include('inc', 'openid'); - $identity = $response['openid.identity']; + $identity = $response['openid.claimed_id']; $account = user_external_load($identity); if (isset($account->uid)) { if (!variable_get('user_email_verification', TRUE) || $account->login) { - user_external_login($account, $_SESSION['openid_user_login_values']); + user_external_login($account, $_SESSION['openid']['user_login_values']); } else { drupal_set_message(t('You must validate your email address for this account before logging in via OpenID')); @@ -398,7 +411,7 @@ function openid_authentication($response) { // We were unable to register a valid new user, redirect to standard // user/register and prefill with the values we received. drupal_set_message(t('OpenID registration failed for the reasons listed. You may register now, or if you already have an account you can log in now and add your OpenID under "My Account"', array('@login' => url('user/login'))), 'error'); - $_SESSION['openid'] = $form_state['values']; + $_SESSION['openid']['values'] = $form_state['values']; // We'll want to redirect back to the same place. $destination = drupal_get_destination(); unset($_REQUEST['destination']); @@ -443,8 +456,6 @@ function openid_association_request($public) { function openid_authentication_request($claimed_id, $identity, $return_to = '', $assoc_handle = '', $version = 2) { module_load_include('inc', 'openid'); - $realm = ($return_to) ? $return_to : url('', array('absolute' => TRUE)); - $ns = ($version == 2) ? OPENID_NS_2_0 : OPENID_NS_1_0; $request = array( 'openid.ns' => $ns, @@ -456,7 +467,7 @@ function openid_authentication_request($claimed_id, $identity, $return_to = '', ); if ($version == 2) { - $request['openid.realm'] = $realm; + $request['openid.realm'] = url('', array('absolute' => TRUE)); } else { $request['openid.trust_root'] = $realm; diff --git a/modules/openid/openid.pages.inc b/modules/openid/openid.pages.inc index 1dcfe04b7..981a6d11b 100644 --- a/modules/openid/openid.pages.inc +++ b/modules/openid/openid.pages.inc @@ -10,7 +10,7 @@ * Menu callback; Process an OpenID authentication. */ function openid_authentication_page() { - $result = openid_complete($_REQUEST); + $result = openid_complete(); switch ($result['status']) { case 'success': return openid_authentication($result); @@ -32,10 +32,11 @@ function openid_user_identities($account) { drupal_add_css(drupal_get_path('module', 'openid') .'/openid.css', 'module'); // Check to see if we got a response - $result = openid_complete($_REQUEST); + $result = openid_complete(); if ($result['status'] == 'success') { - db_query("INSERT INTO {authmap} (uid, authname, module) VALUES (%d, '%s','openid')", $account->uid, $result['openid.identity']); - drupal_set_message(t('Successfully added %identity', array('%identity' => $result['openid.identity']))); + $identity = $result['openid.claimed_id']; + db_query("INSERT INTO {authmap} (uid, authname, module) VALUES (%d, '%s','openid')", $account->uid, $identity); + drupal_set_message(t('Successfully added %identity', array('%identity' => $identity))); } $header = array(t('OpenID'), t('Operations')); @@ -58,7 +59,7 @@ function openid_user_identities($account) { * @see openid_user_add_validate() */ function openid_user_add() { - $form['openid_url'] = array( + $form['openid_identifier'] = array( '#type' => 'textfield', '#title' => t('OpenID'), ); @@ -68,13 +69,13 @@ function openid_user_add() { function openid_user_add_validate($form, &$form_state) { // Check for existing entries. - $claimed_id = _openid_normalize($form_state['values']['openid_url']); + $claimed_id = _openid_normalize($form_state['values']['openid_identifier']); if (db_result(db_query("SELECT authname FROM {authmap} WHERE authname='%s'", $claimed_id))) { - form_set_error('openid_url', t('That OpenID is already in use on this site.')); + form_set_error('openid_identifier', t('That OpenID is already in use on this site.')); } else { $return_to = url('user/'. arg(1) .'/openid', array('absolute' => TRUE)); - openid_begin($form_state['values']['openid_url'], $return_to); + openid_begin($form_state['values']['openid_identifier'], $return_to); } } -- cgit v1.2.3