summaryrefslogtreecommitdiff
path: root/modules/simpletest
diff options
context:
space:
mode:
authorDavid Rothstein <drothstein@gmail.com>2015-03-18 15:20:37 -0400
committerDavid Rothstein <drothstein@gmail.com>2015-03-18 15:20:37 -0400
commitb44056d2f8e8c71d35c85ec5c2fb8f7c8a02d8a8 (patch)
tree466ec33c9527f1eaffd1b37031af6047d606cd60 /modules/simpletest
parent81586d9e9d04dcee487c50de426c04221899b6d0 (diff)
downloadbrdo-b44056d2f8e8c71d35c85ec5c2fb8f7c8a02d8a8.tar.gz
brdo-b44056d2f8e8c71d35c85ec5c2fb8f7c8a02d8a8.tar.bz2
Drupal 7.35
Diffstat (limited to 'modules/simpletest')
-rw-r--r--modules/simpletest/tests/bootstrap.test82
-rw-r--r--modules/simpletest/tests/common.test20
-rw-r--r--modules/simpletest/tests/system_test.module38
3 files changed, 140 insertions, 0 deletions
diff --git a/modules/simpletest/tests/bootstrap.test b/modules/simpletest/tests/bootstrap.test
index f723c6301..14523f28c 100644
--- a/modules/simpletest/tests/bootstrap.test
+++ b/modules/simpletest/tests/bootstrap.test
@@ -546,3 +546,85 @@ class BootstrapOverrideServerVariablesTestCase extends DrupalUnitTestCase {
}
}
}
+
+/**
+ * Tests for $_GET['destination'] and $_REQUEST['destination'] validation.
+ */
+class BootstrapDestinationTestCase extends DrupalWebTestCase {
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'URL destination validation',
+ 'description' => 'Test that $_GET[\'destination\'] and $_REQUEST[\'destination\'] cannot contain external URLs.',
+ 'group' => 'Bootstrap',
+ );
+ }
+
+ function setUp() {
+ parent::setUp('system_test');
+ }
+
+ /**
+ * Tests that $_GET/$_REQUEST['destination'] only contain internal URLs.
+ *
+ * @see _drupal_bootstrap_variables()
+ * @see system_test_get_destination()
+ * @see system_test_request_destination()
+ */
+ public function testDestination() {
+ $test_cases = array(
+ array(
+ 'input' => 'node',
+ 'output' => 'node',
+ 'message' => "Standard internal example node path is present in the 'destination' parameter.",
+ ),
+ array(
+ 'input' => '/example.com',
+ 'output' => '/example.com',
+ 'message' => 'Internal path with one leading slash is allowed.',
+ ),
+ array(
+ 'input' => '//example.com/test',
+ 'output' => '',
+ 'message' => 'External URL without scheme is not allowed.',
+ ),
+ array(
+ 'input' => 'example:test',
+ 'output' => 'example:test',
+ 'message' => 'Internal URL using a colon is allowed.',
+ ),
+ array(
+ 'input' => 'http://example.com',
+ 'output' => '',
+ 'message' => 'External URL is not allowed.',
+ ),
+ array(
+ 'input' => 'javascript:alert(0)',
+ 'output' => 'javascript:alert(0)',
+ 'message' => 'Javascript URL is allowed because it is treated as an internal URL.',
+ ),
+ );
+ foreach ($test_cases as $test_case) {
+ // Test $_GET['destination'].
+ $this->drupalGet('system-test/get-destination', array('query' => array('destination' => $test_case['input'])));
+ $this->assertIdentical($test_case['output'], $this->drupalGetContent(), $test_case['message']);
+ // Test $_REQUEST['destination']. There's no form to submit to, so
+ // drupalPost() won't work here; this just tests a direct $_POST request
+ // instead.
+ $curl_parameters = array(
+ CURLOPT_URL => $this->getAbsoluteUrl('system-test/request-destination'),
+ CURLOPT_POST => TRUE,
+ CURLOPT_POSTFIELDS => 'destination=' . urlencode($test_case['input']),
+ CURLOPT_HTTPHEADER => array(),
+ );
+ $post_output = $this->curlExec($curl_parameters);
+ $this->assertIdentical($test_case['output'], $post_output, $test_case['message']);
+ }
+
+ // Make sure that 404 pages do not populate $_GET['destination'] with
+ // external URLs.
+ variable_set('site_404', 'system-test/get-destination');
+ $this->drupalGet('http://example.com', array('external' => FALSE));
+ $this->assertIdentical('', $this->drupalGetContent(), 'External URL is not allowed on 404 pages.');
+ }
+}
diff --git a/modules/simpletest/tests/common.test b/modules/simpletest/tests/common.test
index eebfdbe49..b8ad0cca5 100644
--- a/modules/simpletest/tests/common.test
+++ b/modules/simpletest/tests/common.test
@@ -209,7 +209,16 @@ class CommonURLUnitTest extends DrupalWebTestCase {
// Test that drupal can recognize an absolute URL. Used to prevent attack vectors.
$this->assertTrue(url_is_external($url), 'Correctly identified an external URL.');
+ // External URL without an explicit protocol.
+ $url = '//drupal.org/foo/bar?foo=bar&bar=baz&baz#foo';
+ $this->assertTrue(url_is_external($url), 'Correctly identified an external URL without a protocol part.');
+
+ // Internal URL starting with a slash.
+ $url = '/drupal.org';
+ $this->assertFalse(url_is_external($url), 'Correctly identified an internal URL with a leading slash.');
+
// Test the parsing of absolute URLs.
+ $url = 'http://drupal.org/foo/bar?foo=bar&bar=baz&baz#foo';
$result = array(
'path' => 'http://drupal.org/foo/bar',
'query' => array('foo' => 'bar', 'bar' => 'baz', 'baz' => ''),
@@ -349,6 +358,17 @@ class CommonURLUnitTest extends DrupalWebTestCase {
$query = array($this->randomName(5) => $this->randomName(5));
$result = url($url, array('query' => $query));
$this->assertEqual($url . '&' . http_build_query($query, '', '&'), $result, 'External URL query string can be extended with a custom query string in $options.');
+
+ // Verify that an internal URL does not result in an external URL without
+ // protocol part.
+ $url = '/drupal.org';
+ $result = url($url);
+ $this->assertTrue(strpos($result, '//') === FALSE, 'Internal URL does not turn into an external URL.');
+
+ // Verify that an external URL without protocol part is recognized as such.
+ $url = '//drupal.org';
+ $result = url($url);
+ $this->assertEqual($url, $result, 'External URL without protocol is not altered.');
}
}
diff --git a/modules/simpletest/tests/system_test.module b/modules/simpletest/tests/system_test.module
index 2eda351e9..c0eed034f 100644
--- a/modules/simpletest/tests/system_test.module
+++ b/modules/simpletest/tests/system_test.module
@@ -106,6 +106,20 @@ function system_test_menu() {
'type' => MENU_CALLBACK,
);
+ $items['system-test/get-destination'] = array(
+ 'title' => 'Test $_GET[\'destination\']',
+ 'page callback' => 'system_test_get_destination',
+ 'access callback' => TRUE,
+ 'type' => MENU_CALLBACK,
+ );
+
+ $items['system-test/request-destination'] = array(
+ 'title' => 'Test $_REQUEST[\'destination\']',
+ 'page callback' => 'system_test_request_destination',
+ 'access callback' => TRUE,
+ 'type' => MENU_CALLBACK,
+ );
+
return $items;
}
@@ -420,3 +434,27 @@ function system_test_authorize_init_page($page_title) {
system_authorized_init('system_test_authorize_run', drupal_get_path('module', 'system_test') . '/system_test.module', array(), $page_title);
drupal_goto($authorize_url);
}
+
+/**
+ * Page callback to print out $_GET['destination'] for testing.
+ */
+function system_test_get_destination() {
+ if (isset($_GET['destination'])) {
+ print $_GET['destination'];
+ }
+ // No need to render the whole page, we are just interested in this bit of
+ // information.
+ exit;
+}
+
+/**
+ * Page callback to print out $_REQUEST['destination'] for testing.
+ */
+function system_test_request_destination() {
+ if (isset($_REQUEST['destination'])) {
+ print $_REQUEST['destination'];
+ }
+ // No need to render the whole page, we are just interested in this bit of
+ // information.
+ exit;
+}