From 6586b7646585d34b878bda18155a37e5eec729cb Mon Sep 17 00:00:00 2001 From: Dries Buytaert Date: Sat, 5 Sep 2009 13:05:31 +0000 Subject: =?UTF-8?q?-=20Patch=20by=20#1577=20by=20chx,=20boombatower,=20B?= =?UTF-8?q?=C3=A8r=20Kessels,=20kkaefer:=20made=20SSL=20support=20a=20bit?= =?UTF-8?q?=20easier=20by=20providing=20two=20cookies=20and=20...=20hook?= =?UTF-8?q?=5Fgoto=5Falter.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/simpletest/drupal_web_test_case.php | 20 +++--- modules/simpletest/tests/common.test | 37 +++++++++++ modules/simpletest/tests/common_test.module | 64 +++++++++++++++++++ modules/simpletest/tests/https.php | 25 ++++++++ modules/simpletest/tests/session.test | 92 ++++++++++++++++++++++++++++ modules/simpletest/tests/session_test.module | 17 +++++ modules/system/system.api.php | 24 +++++++- modules/system/system.install | 10 +++ 8 files changed, 280 insertions(+), 9 deletions(-) create mode 100644 modules/simpletest/tests/https.php (limited to 'modules') diff --git a/modules/simpletest/drupal_web_test_case.php b/modules/simpletest/drupal_web_test_case.php index 41abb195c..f9789fe2f 100644 --- a/modules/simpletest/drupal_web_test_case.php +++ b/modules/simpletest/drupal_web_test_case.php @@ -1310,13 +1310,19 @@ class DrupalWebTestCase extends DrupalTestCase { call_user_func_array(array(&$this, 'error'), unserialize(urldecode($matches[1]))); } - // Save the session cookie, if set. - if (preg_match('/^Set-Cookie: ' . preg_quote($this->session_name) . '=([a-z90-9]+)/', $header, $matches)) { - if ($matches[1] != 'deleted') { - $this->session_id = $matches[1]; - } - else { - $this->session_id = NULL; + // Save cookies. + if (preg_match('/^Set-Cookie: ([^=]+)=(.+)/', $header, $matches)) { + $name = $matches[1]; + $parts = array_map('trim', explode(';', $matches[2])); + $value = array_shift($parts); + $this->cookies[$name] = array('value' => $value, 'secure' => in_array('secure', $parts)); + if ($name == $this->session_name) { + if ($value != 'deleted') { + $this->session_id = $value; + } + else { + $this->session_id = NULL; + } } } diff --git a/modules/simpletest/tests/common.test b/modules/simpletest/tests/common.test index ad565b1ab..dc6b0c7c8 100644 --- a/modules/simpletest/tests/common.test +++ b/modules/simpletest/tests/common.test @@ -600,6 +600,43 @@ class DrupalSetContentTestCase extends DrupalWebTestCase { } } +/** + * Testing drupal_goto and hook_drupal_goto_alter(). + */ +class DrupalGotoTest extends DrupalWebTestCase { + public static function getInfo() { + return array( + 'name' => 'Drupal goto', + 'description' => 'Performs tests on the drupal_goto function and hook_drupal_goto_alter', + 'group' => 'System' + ); + } + + function setUp() { + parent::setUp('common_test'); + } + + /** + * Test setting and retrieving content for theme regions. + */ + function testDrupalGoto() { + $this->drupalGet('common-test/drupal_goto/redirect'); + + $this->assertNoText(t("Drupal goto failed to stop program"), t("Drupal goto stopped program.")); + $this->assertText('drupal_goto', t("Drupal goto redirect failed.")); + } + + /** + * Test setting and retrieving content for theme regions. + */ + function testDrupalGotoAlter() { + $this->drupalGet('common-test/drupal_goto/redirect_fail'); + + $this->assertNoText(t("Drupal goto failed to stop program"), t("Drupal goto stopped program.")); + $this->assertNoText('drupal_goto_fail', t("Drupal goto redirect failed.")); + } +} + /** * Tests for the JavaScript system. */ diff --git a/modules/simpletest/tests/common_test.module b/modules/simpletest/tests/common_test.module index c1a8b7917..e94f72811 100644 --- a/modules/simpletest/tests/common_test.module +++ b/modules/simpletest/tests/common_test.module @@ -6,6 +6,70 @@ * Helper module for the Common tests. */ +/** + * Implement hook_menu(). + */ +function common_test_menu() { + $items = array(); + $items['common-test/drupal_goto'] = array( + 'title' => 'Drupal Goto', + 'page callback' => 'common_test_drupal_goto_land', + 'access arguments' => array('access content'), + 'type' => MENU_CALLBACK, + ); + $items['common-test/drupal_goto/fail'] = array( + 'title' => 'Drupal Goto', + 'page callback' => 'common_test_drupal_goto_land_fail', + 'access arguments' => array('access content'), + 'type' => MENU_CALLBACK, + ); + $items['common-test/drupal_goto/redirect'] = array( + 'title' => 'Drupal Goto', + 'page callback' => 'common_test_drupal_goto_redirect', + 'access arguments' => array('access content'), + 'type' => MENU_CALLBACK, + ); + $items['common-test/drupal_goto/redirect_fail'] = array( + 'title' => 'Drupal Goto Failure', + 'page callback' => 'drupal_goto', + 'page arguments' => array('common-test/drupal_goto/fail'), + 'access arguments' => array('access content'), + 'type' => MENU_CALLBACK, + ); + return $items; +} + +/** + * Check that drupal_goto() exits once called. + */ +function common_test_drupal_goto_redirect() { + drupal_goto('common-test/drupal_goto'); + print t("Drupal goto failed to stop program"); +} + +/** + * Landing page for drupal_goto(). + */ +function common_test_drupal_goto_land() { + print "drupal_goto"; +} + +/** + * Fail landing page for drupal_goto(). + */ +function common_test_drupal_goto_land_fail() { + print "drupal_goto_fail"; +} + +/** + * Implement hook_drupal_goto_alter(). + */ +function common_test_drupal_goto_alter(&$args) { + if ($args['path'] == 'common-test/drupal_goto/fail') { + $args['path'] = 'common-test/drupal_goto/redirect'; + } +} + /** * Implement hook_theme(). */ diff --git a/modules/simpletest/tests/https.php b/modules/simpletest/tests/https.php new file mode 100644 index 000000000..bc473875d --- /dev/null +++ b/modules/simpletest/tests/https.php @@ -0,0 +1,25 @@ + $value) { + $_SERVER[$key] = str_replace('modules/simpletest/tests/https.php', 'index.php', $value); + $_SERVER[$key] = str_replace('http://', 'https://', $_SERVER[$key]); +} + +require_once 'index.php'; diff --git a/modules/simpletest/tests/session.test b/modules/simpletest/tests/session.test index 6a2b4d32d..72648656c 100644 --- a/modules/simpletest/tests/session.test +++ b/modules/simpletest/tests/session.test @@ -250,3 +250,95 @@ class SessionTestCase extends DrupalWebTestCase { } } } + +/** + * Ensure that when running under https two session cookies are generated. + */ +class SessionHttpsTestCase extends DrupalWebTestCase { + + public static function getInfo() { + return array( + 'name' => 'Session https handling', + 'description' => 'Ensure that when running under https two session cookies are generated.', + 'group' => 'Session' + ); + } + + public function setUp() { + parent::setUp('session_test'); + } + + protected function testHttpsSession() { + global $is_https; + + if ($is_https) { + // The functionality does not make sense when running on https. + return; + } + + $insecure_session_name = session_name(); + $secure_session_name = "S$insecure_session_name"; + + // Enable secure pages. + variable_set('https', TRUE); + + $user = $this->drupalCreateUser(array('access administration pages')); + + $this->curlClose(); + $this->drupalGet('session-test/set/1'); + // Check secure cookie on insecure page. + $this->assertFalse(isset($this->cookies[$secure_session_name]), 'The secure cookie is not sent on insecure pages.'); + // Check insecure cookie on insecure page. + $this->assertFalse($this->cookies[$insecure_session_name]['secure'], 'The insecure cookie does not have the secure attribute'); + + // Check that password request form action is not secure. + $this->drupalGet('user/password'); + $form = $this->xpath('//form[@id="user-pass"]'); + $this->assertNotEqual(substr($form[0]['action'], 0, 6), 'https:', 'Password request form action is not secure'); + $form[0]['action'] = $this->httpsUrl('user'); + + // Check that user login form action is secure. + $this->drupalGet('user'); + $form = &$this->xpath('//form[@id="user-login"]'); + $this->assertEqual(substr($form[0]['action'], 0, 6), 'https:', 'Login form action is secure'); + $form[0]['action'] = $this->httpsUrl('user'); + + $edit = array( + 'name' => $user->name, + 'pass' => $user->pass_raw, + ); + $this->drupalPost(NULL, $edit, t('Log in')); + // Check secure cookie on secure page. + $this->assertTrue($this->cookies[$secure_session_name]['secure'], 'The secure cookie has the secure attribute'); + // Check insecure cookie on secure page. + $this->assertFalse($this->cookies[$insecure_session_name]['secure'], 'The insecure cookie does not have the secure attribute'); + $args = array( + ':sid' => $this->cookies[$insecure_session_name]['value'], + ':ssid' => $this->cookies[$secure_session_name]['value'], + ); + $this->assertTrue(db_query('SELECT sid FROM {sessions} WHERE sid = :sid AND ssid = :ssid', $args)->fetchField(), 'Session has both SIDs'); + $cookies = array( + $insecure_session_name . '=' . $args[':sid'], + $secure_session_name . '=' . $args[':ssid'], + ); + + foreach ($cookies as $cookie_key => $cookie) { + foreach (array('admin', $this->httpsUrl('admin')) as $url_key => $url) { + $this->curlClose(); + + $this->drupalGet($url, array(), array('Cookie: ' . $cookie)); + if ($cookie_key == $url_key) { + $this->assertText(t('Administer')); + } + else { + $this->assertNoText(t('Administer')); + } + } + } + } + + protected function httpsUrl($url) { + global $base_url; + return $base_url . '/modules/simpletest/tests/https.php?q=' . $url; + } +} diff --git a/modules/simpletest/tests/session_test.module b/modules/simpletest/tests/session_test.module index 48a655001..303c3c89a 100644 --- a/modules/simpletest/tests/session_test.module +++ b/modules/simpletest/tests/session_test.module @@ -143,3 +143,20 @@ function session_test_user_login($edit = array(), $user = NULL) { } } +/** + * Implement hook_form_FORM_ID_alter(). + */ +function session_test_form_user_login_alter(&$form) { + $form['#https'] = TRUE; +} + +/** + * Implement hook_drupal_goto_alter(). + * + * Force the redirection to go to a non-secure page after being on a secure + * page through https.php. + */ +function session_test_drupal_goto_alter(&$args) { + global $base_insecure_url; + $args['path'] = $base_insecure_url . '/' . $args['path']; +} diff --git a/modules/system/system.api.php b/modules/system/system.api.php index a4ca25049..4f2ec074b 100644 --- a/modules/system/system.api.php +++ b/modules/system/system.api.php @@ -731,7 +731,7 @@ function hook_system_info_alter(&$info, $file) { * Permissions are checked using user_access(). * * For a detailed usage example, see page_example.module. - * + * * @return * An array of which permission names are the keys and their corresponding * values are descriptions of each permission. @@ -2189,7 +2189,27 @@ function hook_profile_tasks() { 'myprofile_final_site_setup' => array( ), ); - return $tasks; + return $tasks; +} + +/** + * Change the page the user is sent to by drupal_goto(). + * + * @param $args + * The array keys are the same as drupal_goto() arguments and the array can + * be changed. + * + * $args = array( + * 'path' => &$path, + * 'query' => &$query, + * 'fragment' => &$fragment, + * 'http_response_code' => &$http_response_code, + * ); + * + */ +function hook_drupal_goto_alter(array $args) { + // A good addition to misery module. + $args['http_response_code'] = 500; } /** diff --git a/modules/system/system.install b/modules/system/system.install index f22a6f2b5..4757d9b75 100644 --- a/modules/system/system.install +++ b/modules/system/system.install @@ -1316,6 +1316,13 @@ function system_schema() { 'not null' => TRUE, 'default' => '', ), + 'ssid' => array( + 'description' => "Unique key: Secure session ID. The value is generated by PHP's Session API.", + 'type' => 'varchar', + 'length' => 64, + 'not null' => FALSE, + 'default' => NULL, + ), 'hostname' => array( 'description' => 'The IP address that last used this session ID (sid).', 'type' => 'varchar', @@ -1347,6 +1354,9 @@ function system_schema() { 'timestamp' => array('timestamp'), 'uid' => array('uid'), ), + 'unique keys' => array( + 'ssid' => array('ssid'), + ), 'foreign keys' => array( 'uid' => array('users' => 'uid'), ), -- cgit v1.2.3