#144538 by Damien Tournoud: harden the logout link. From: damz --- menu.inc | 10 ++++++++++ menu/menu.test | 2 +- simpletest/drupal_web_test_case.php | 34 +++++++++++++++++++++++++++++++++- system/system.install | 4 ++-- user/user.module | 2 +- 5 files changed, 47 insertions(+), 5 deletions(-) diff --git includes/menu.inc includes/menu.inc index 6ea540b..8142d77 100644 --- includes/menu.inc +++ includes/menu.inc @@ -669,11 +669,21 @@ function _menu_link_map_translate(&$map, $to_arg_functions) { } } +/** + * Menu to arg function: convert %menu_tail by the tail used in the current page. + */ function menu_tail_to_arg($arg, $map, $index) { return implode('/', array_slice($map, $index)); } /** + * Menu to arg function: convert %token into a user specific token. + */ +function token_to_arg($arg, $map, $index) { + return drupal_get_token(); +} + +/** * This function is similar to _menu_translate() but does link-specific * preparation such as always calling to_arg functions * diff --git modules/menu/menu.test modules/menu/menu.test index c9197b4..fa3b964 100644 --- modules/menu/menu.test +++ modules/menu/menu.test @@ -417,7 +417,7 @@ class MenuTestCase extends DrupalWebTestCase { */ private function getStandardMenuLink() { // Retrieve menu link id of the Log out menu link, which will always be on the front page. - $mlid = db_query("SELECT mlid FROM {menu_links} WHERE module = 'system' AND router_path = 'user/logout'")->fetchField(); + $mlid = db_query("SELECT mlid FROM {menu_links} WHERE module = 'system' AND router_path = 'user/logout/%'")->fetchField(); $this->assertTrue($mlid > 0, 'Standard menu link id was found'); // Load menu link. // Use api function so that link is translated for rendering. diff --git modules/simpletest/drupal_web_test_case.php modules/simpletest/drupal_web_test_case.php index 3665426..bb104ca 100644 --- modules/simpletest/drupal_web_test_case.php +++ modules/simpletest/drupal_web_test_case.php @@ -592,6 +592,16 @@ class DrupalWebTestCase extends DrupalTestCase { protected $httpauth_credentials = NULL; /** + * The current session name, if available. + */ + protected $session_name = NULL; + + /** + * The current session ID, if available. + */ + protected $session_id = NULL; + + /** * Constructor for DrupalWebTestCase. */ function __construct($test_id = NULL) { @@ -913,12 +923,20 @@ class DrupalWebTestCase extends DrupalTestCase { } } + /** + * Generate a token for the currently logged in user. + */ + protected function drupalGetToken($value = '') { + $private_key = drupal_get_private_key(); + return md5($this->session_id . $value . $private_key); + } + /* * Logs a user out of the internal browser, then check the login page to confirm logout. */ protected function drupalLogout() { // Make a request to the logout page. - $this->drupalGet('user/logout'); + $this->drupalGet('user/logout/' . $this->drupalGetToken()); // Load the user page, the idea being if you were properly logged out you should be seeing a login screen. $this->drupalGet('user'); @@ -1169,6 +1187,7 @@ class DrupalWebTestCase extends DrupalTestCase { */ protected function curlHeaderCallback($curlHandler, $header) { $this->headers[] = $header; + // Errors are being sent via X-Drupal-Assertion-* headers, // generated by _drupal_log_error() in the exact form required // by DrupalWebTestCase::error(). @@ -1176,6 +1195,19 @@ class DrupalWebTestCase extends DrupalTestCase { // Call DrupalWebTestCase::error() with the parameters from the header. call_user_func_array(array(&$this, 'error'), unserialize(urldecode($matches[1]))); } + + // Save the session cookie, if set. + if (preg_match('/^Set-Cookie: (SESS[a-z0-9]+)=([a-z90-9]+)/', $header, $matches)) { + if ($matches[2] != 'deleted') { + $this->session_name = $matches[1]; + $this->session_id = $matches[2]; + } + else { + $this->session_name = NULL; + $this->session_id = NULL; + } + } + // This is required by cURL. return strlen($header); } diff --git modules/system/system.install modules/system/system.install index f0505aa..61fa728 100644 --- modules/system/system.install +++ modules/system/system.install @@ -3251,8 +3251,8 @@ function system_update_7014() { */ function system_update_7015() { $ret = array(); - $ret[] = update_sql("UPDATE {menu_links} SET link_path = 'user/logout' WHERE link_path = 'logout'"); - $ret[] = update_sql("UPDATE {menu_links} SET router_path = 'user/logout' WHERE router_path = 'logout'"); + $ret[] = update_sql("UPDATE {menu_links} SET link_path = 'user/logout/%' WHERE link_path = 'logout'"); + $ret[] = update_sql("UPDATE {menu_links} SET router_path = 'user/logout/%' WHERE router_path = 'logout'"); return $ret; } diff --git modules/user/user.module modules/user/user.module index ba3b19f..081fa3b 100644 --- modules/user/user.module +++ modules/user/user.module @@ -1321,7 +1321,7 @@ function user_menu() { 'type' => MENU_CALLBACK, ); - $items['user/logout'] = array( + $items['user/logout/%token'] = array( 'title' => 'Log out', 'access callback' => 'user_is_logged_in', 'page callback' => 'user_logout',