diff --git a/core/includes/common.inc b/core/includes/common.inc index a70b66e..02b28d0 100644 --- a/core/includes/common.inc +++ b/core/includes/common.inc @@ -4768,7 +4768,15 @@ function drupal_get_private_key() { * An additional value to base the token on. */ function drupal_get_token($value = '') { - return drupal_hmac_base64($value, session_id() . drupal_get_private_key() . drupal_get_hash_salt()); + // For mixed HTTP(S) sessions, use a constant identifier so that tokens can be + // shared between protocols. + if (variable_get('https', FALSE) && $GLOBALS['is_https'] && isset($_COOKIE[substr(session_name(), 1)])) { + $session_id = $_COOKIE[substr(session_name(), 1)]; + } + else { + $session_id = session_id(); + } + return drupal_hmac_base64($value, $session_id . drupal_get_private_key() . drupal_get_hash_salt()); } /** diff --git a/core/includes/form.inc b/core/includes/form.inc index 002de6f..b140528 100644 --- a/core/includes/form.inc +++ b/core/includes/form.inc @@ -1149,6 +1149,11 @@ function drupal_validate_form($form_id, &$form, &$form_state) { } } + // Ensure the correct protocol when #https is set. + if (!empty($form['#https']) && !$GLOBALS['is_https']) { + form_set_error('', t('This form requires HTTPS. Contact the site administrator if the problem persists.')); + } + _form_validate($form, $form_state, $form_id); $validated_forms[$form_id] = TRUE; diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php index 001e521..e04535f 100644 --- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php +++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php @@ -3097,4 +3097,32 @@ protected function verboseEmail($count = 1) { $this->verbose(t('Email:') . '
' . print_r($mail, TRUE) . '
'); } } + + /** + * Builds a URL for submitting a mock HTTPS request to HTTP test environments. + * + * @param $url + * A Drupal path such as 'user'. + * + * @return + * An absolute URL. + */ + protected function httpsUrl($url) { + global $base_url; + return $base_url . '/core/modules/system/tests/https.php/' . $url; + } + + /** + * Builds a URL for submitting a mock HTTP request to HTTPS test environments. + * + * @param $url + * A Drupal path such as 'user'. + * + * @return + * An absolute URL. + */ + protected function httpUrl($url) { + global $base_url; + return $base_url . '/core/modules/system/tests/http.php/' . $url; + } } diff --git a/core/modules/system/lib/Drupal/system/Tests/Session/SessionHttpsTest.php b/core/modules/system/lib/Drupal/system/Tests/Session/SessionHttpsTest.php index 0ab45a9..11ddf05 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Session/SessionHttpsTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Session/SessionHttpsTest.php @@ -46,6 +46,7 @@ protected function testHttpsSession() { // Test HTTPS session handling by altering the form action to submit the // login form through https.php, which creates a mock HTTPS request. $this->drupalGet('user'); + $this->assertText(t('Log in'), 'Login page loaded for first session.'); $form = $this->xpath('//form[@id="user-login-form"]'); $form[0]['action'] = $this->httpsUrl('user'); $edit = array('name' => $user->name, 'pass' => $user->pass_raw); @@ -54,6 +55,7 @@ protected function testHttpsSession() { // Test a second concurrent session. $this->curlClose(); $this->drupalGet('user'); + $this->assertText(t('Log in'), 'Login page loaded for second session.'); $form = $this->xpath('//form[@id="user-login-form"]'); $form[0]['action'] = $this->httpsUrl('user'); $this->drupalPost(NULL, $edit, t('Log in')); @@ -89,6 +91,7 @@ protected function testHttpsSession() { // test environments. $this->curlClose(); $this->drupalGet('user'); + $this->assertText(t('Log in'), 'Login page loaded.'); $form = $this->xpath('//form[@id="user-login-form"]'); $form[0]['action'] = $this->httpUrl('user'); $edit = array('name' => $user->name, 'pass' => $user->pass_raw); @@ -137,7 +140,7 @@ protected function testHttpsSession() { // Check that user login form action is secure. $this->drupalGet('user'); $form = $this->xpath('//form[@id="user-login-form"]'); - $this->assertEqual(substr($form[0]['action'], 0, 6), 'https:', 'Login form action is secure'); + $this->assertNotEqual(substr($form[0]['action'], 0, 6), 'https:', 'Login form action is not secure'); $form[0]['action'] = $this->httpsUrl('user'); $edit = array( @@ -223,32 +226,4 @@ protected function assertSessionIds($sid, $ssid, $assertion_text) { ); return $this->assertTrue(db_query('SELECT timestamp FROM {sessions} WHERE sid = :sid AND ssid = :ssid', $args)->fetchField(), $assertion_text); } - - /** - * Builds a URL for submitting a mock HTTPS request to HTTP test environments. - * - * @param $url - * A Drupal path such as 'user'. - * - * @return - * An absolute URL. - */ - protected function httpsUrl($url) { - global $base_url; - return $base_url . '/core/modules/system/tests/https.php/' . $url; - } - - /** - * Builds a URL for submitting a mock HTTP request to HTTPS test environments. - * - * @param $url - * A Drupal path such as 'user'. - * - * @return - * An absolute URL. - */ - protected function httpUrl($url) { - global $base_url; - return $base_url . '/core/modules/system/tests/http.php/' . $url; - } } diff --git a/core/modules/system/tests/modules/form_test/form_test.module b/core/modules/system/tests/modules/form_test/form_test.module index 1801809..e60e368 100644 --- a/core/modules/system/tests/modules/form_test/form_test.module +++ b/core/modules/system/tests/modules/form_test/form_test.module @@ -219,6 +219,14 @@ function form_test_menu() { 'type' => MENU_CALLBACK, ); + $items['form-test/https-only'] = array( + 'title' => 'FAPI test for mixed-mode sessions', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('form_test_https_only'), + 'access callback' => TRUE, + 'type' => MENU_CALLBACK, + ); + $items['form-test/form-rebuild-preserve-values'] = array( 'title' => 'Form values preservation during rebuild test', 'page callback' => 'drupal_get_form', @@ -2318,6 +2326,32 @@ function form_test_html_id($form, &$form_state) { } /** + * Provides a page callback and form to test the form #https-attribute. + * + * @see \Drupal\system\Tests\Form\FormHttpsOnlyTest + */ +function form_test_https_only($form, &$form_state) { + $form['textfield'] = array( + '#type' => 'textfield', + '#title' => t('Textfield'), + ); + $form['submit'] = array( + '#type' => 'submit', + '#value' => t('Submit'), + ); + $form['#https'] = TRUE; + return $form; +} + +/** + * Submit handler for the #https-test form. + */ +function form_test_https_only_submit($form, &$form_state) { + drupal_set_message('The form has been successfully submitted.'); + $form_state['redirect'] = FALSE; +} + +/** * Builds a simple form to test form button classes. */ function form_test_button_class($form, &$form_state) { diff --git a/core/modules/system/tests/modules/session_test/session_test.module b/core/modules/system/tests/modules/session_test/session_test.module index 3b378ad..61341d1 100644 --- a/core/modules/system/tests/modules/session_test/session_test.module +++ b/core/modules/system/tests/modules/session_test/session_test.module @@ -165,7 +165,10 @@ function session_test_user_login($edit = array(), $user = NULL) { * Implements hook_form_FORM_ID_alter(). */ function session_test_form_user_login_form_alter(&$form) { - $form['#https'] = TRUE; + global $is_https; + if ($is_https) { + $form['#https'] = TRUE; + } } /**