From 315c419322526294d9f53ab44bdbcc4bdef02e7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Hojtsy?= <gabor@hojtsy.hu> Date: Wed, 30 Jan 2008 22:11:22 +0000 Subject: [PATCH] #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(-) diff --git a/modules/openid/openid.css b/modules/openid/openid.css index 5437350ff217..5a05d63806b5 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 9ff4af5a2950..e20cf980668f 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('|<link\s+rel=["\'](.*)'. $rel .'(.*)["\'](.*)/?>|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('|<meta\s+http-equiv=["\']'. $equiv .'["\'](.*)/?>|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 9a7b9252e23e..bd2948dc9623 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 eb281d26dcc3..d77ee73b2d2e 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 <a href="@login">log in</a> 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 1dcfe04b7b85..981a6d11ba6b 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); } } -- GitLab