diff --git a/core/core.services.yml b/core/core.services.yml index c73db7f..cad3229 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -249,6 +249,11 @@ services: tags: - { name: paramconverter } arguments: ['@plugin.manager.entity'] + reverse_proxy_subscriber: + class: Drupal\Core\EventSubscriber\ReverseProxySubscriber + tags: + - { name: event_subscriber } + arguments: ['@settings'] router_processor_subscriber: class: Drupal\Core\EventSubscriber\RouteProcessorSubscriber tags: @@ -350,7 +355,7 @@ services: class: Drupal\Core\Transliteration\PHPTransliteration flood: class: Drupal\Core\Flood\DatabaseBackend - arguments: ['@database'] + arguments: ['@request', '@database'] plugin.manager.condition: class: Drupal\Core\Condition\ConditionManager kernel_destruct_subscriber: diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index d42326b..4573770 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -559,9 +559,10 @@ function config_get_config_directory($type = CONFIG_ACTIVE_DIRECTORY) { * return the expected values. * * Most other parameters do not need to be passed in, but may be necessary in - * some cases; for example, if Drupal's ip_address() function needs to return - * anything but the standard localhost value ('127.0.0.1'), the command line - * script should pass in the desired value via the 'REMOTE_ADDR' key. + * some cases; for example, if Drupal::request()->getClientIP() + * needs to return anything but the standard localhost value ('127.0.0.1'), + * the command line script should pass in the desired value via the + * 'REMOTE_ADDR' key. * * @param $variables * (optional) An associative array of variables within $_SERVER that should @@ -572,7 +573,7 @@ function config_get_config_directory($type = CONFIG_ACTIVE_DIRECTORY) { * * @see conf_path() * @see request_uri() - * @see ip_address() + * @see \Symfony\Component\HttpFoundation\Request::getClientIP() */ function drupal_override_server_variables($variables = array()) { // Allow the provided URL to override any existing values in $_SERVER. @@ -1790,7 +1791,7 @@ function watchdog($type, $message, array $variables = NULL, $severity = WATCHDOG 'uid' => $user_uid, 'request_uri' => $base_root . request_uri(), 'referer' => isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '', - 'ip' => ip_address(), + 'ip' => Drupal::request()->getClientIP(), // Request time isn't accurate for long processes, use time() instead. 'timestamp' => time(), ); @@ -2054,7 +2055,7 @@ function drupal_hash_base64($data) { function drupal_anonymous_user() { $values = array( 'uid' => 0, - 'hostname' => ip_address(), + 'hostname' => Drupal::request()->getClientIP(), 'roles' => array( DRUPAL_ANONYMOUS_RID => DRUPAL_ANONYMOUS_RID, ), @@ -3115,52 +3116,6 @@ function arg($index = NULL, $path = NULL) { } /** - * Returns the IP address of the client machine. - * - * If Drupal is behind a reverse proxy, we use the X-Forwarded-For header - * instead of $_SERVER['REMOTE_ADDR'], which would be the IP address of - * the proxy server, and not the client's. The actual header name can be - * configured by the reverse_proxy_header variable. - * - * @return - * IP address of client machine, adjusted for reverse proxy and/or cluster - * environments. - */ -function ip_address() { - $ip_address = &drupal_static(__FUNCTION__); - - if (!isset($ip_address)) { - $ip_address = $_SERVER['REMOTE_ADDR']; - - if (settings()->get('reverse_proxy', 0)) { - $reverse_proxy_header = settings()->get('reverse_proxy_header', 'HTTP_X_FORWARDED_FOR'); - if (!empty($_SERVER[$reverse_proxy_header])) { - // If an array of known reverse proxy IPs is provided, then trust - // the XFF header if request really comes from one of them. - $reverse_proxy_addresses = settings()->get('reverse_proxy_addresses', array()); - - // Turn XFF header into an array. - $forwarded = explode(',', $_SERVER[$reverse_proxy_header]); - - // Trim the forwarded IPs; they may have been delimited by commas and spaces. - $forwarded = array_map('trim', $forwarded); - - // Tack direct client IP onto end of forwarded array. - $forwarded[] = $ip_address; - - // Eliminate all trusted IPs. - $untrusted = array_diff($forwarded, $reverse_proxy_addresses); - - // The right-most IP is the most specific we can trust. - $ip_address = array_pop($untrusted); - } - } - } - - return $ip_address; -} - -/** * Initializes and returns the class loader. * * The class loader is responsible for lazy-loading all PSR-0 compatible diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index 85dc45c..bbb54b8 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -331,6 +331,10 @@ function install_begin_request(&$install_state) { if ($install_state['settings_verified']) { $kernel = new DrupalKernel('install', FALSE, drupal_classloader(), FALSE); $kernel->boot(); + // Set the request in the kernel to the new created Request above + // so it is available to the rest of the installation process. + $kernel->getContainer() + ->set('request', $request); } else { // @todo Move into a proper Drupal\Core\DependencyInjection\InstallContainerBuilder. diff --git a/core/includes/session.inc b/core/includes/session.inc index 31e67a6..937b0f2 100644 --- a/core/includes/session.inc +++ b/core/includes/session.inc @@ -173,7 +173,7 @@ function _drupal_session_write($sid, $value) { // Either ssid or sid or both will be added from $key below. $fields = array( 'uid' => $user->uid, - 'hostname' => ip_address(), + 'hostname' => Drupal::request()->getClientIP(), 'session' => $value, 'timestamp' => REQUEST_TIME, ); diff --git a/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php index 884c99f..e600313 100644 --- a/core/lib/Drupal/Core/DrupalKernel.php +++ b/core/lib/Drupal/Core/DrupalKernel.php @@ -284,6 +284,11 @@ protected function getClassName() { */ protected function initializeContainer() { $persist = $this->getServicesToPersist(); + // If we are rebuilding the kernel and we are in a request scope, store + // request info so we can add them back after the rebuild. + if (isset($this->container) && $this->container->hasScope('request')) { + $request = $this->container->get('request'); + } $this->container = NULL; $class = $this->getClassName(); $cache_file = $class . '.php'; @@ -345,7 +350,11 @@ protected function initializeContainer() { $this->container->set('kernel', $this); // Set the class loader which was registered as a synthetic service. $this->container->set('class_loader', $this->classLoader); - + // If we have a request set it back to the new container. + if (isset($request)) { + $this->container->enterScope('request'); + $this->container->set('request', $request); + } \Drupal::setContainer($this->container); } diff --git a/core/lib/Drupal/Core/EventSubscriber/ReverseProxySubscriber.php b/core/lib/Drupal/Core/EventSubscriber/ReverseProxySubscriber.php new file mode 100644 index 0000000..cf0003d --- /dev/null +++ b/core/lib/Drupal/Core/EventSubscriber/ReverseProxySubscriber.php @@ -0,0 +1,63 @@ +settings = $settings; + } + + /** + * Passes reverse proxy settings to current request. + * + * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event + * The Event to process. + */ + public function onKernelRequestReverseProxyCheck(GetResponseEvent $event) { + $request = $event->getRequest(); + if ($this->settings->get('reverse_proxy', 0)) { + $reverse_proxy_header = $this->settings->get('reverse_proxy_header', 'HTTP_X_FORWARDED_FOR'); + $request::setTrustedHeaderName($request::HEADER_CLIENT_IP, $reverse_proxy_header); + $reverse_proxy_addresses = $this->settings->get('reverse_proxy_addresses', array()); + $request::setTrustedProxies($reverse_proxy_addresses); + } + } + + /** + * Registers the methods in this class that should be listeners. + * + * @return array + * An array of event listener definitions. + */ + static function getSubscribedEvents() { + $events[KernelEvents::REQUEST][] = array('onKernelRequestReverseProxyCheck', 10); + return $events; + } +} diff --git a/core/lib/Drupal/Core/Flood/DatabaseBackend.php b/core/lib/Drupal/Core/Flood/DatabaseBackend.php index a7b05f4..0bc30d1 100644 --- a/core/lib/Drupal/Core/Flood/DatabaseBackend.php +++ b/core/lib/Drupal/Core/Flood/DatabaseBackend.php @@ -7,6 +7,7 @@ namespace Drupal\Core\Flood; +use Symfony\Component\HttpFoundation\Request; use Drupal\Core\Database\Connection; /** @@ -22,14 +23,24 @@ class DatabaseBackend implements FloodInterface { protected $connection; /** + * A request object. + * + * @var \Symfony\Component\HttpFoundation\Request + */ + protected $request; + + /** * Construct the DatabaseBackend. * * @param \Drupal\Core\Database\Connection $connection * The database connection which will be used to store the flood event * information. + * @param \Symfony\Component\HttpFoundation\Request $request + * The HttpRequest object representing the current request. */ - public function __construct(Connection $connection) { + public function __construct(Connection $connection, Request $request) { $this->connection = $connection; + $this->request = $request; } /** @@ -37,7 +48,7 @@ public function __construct(Connection $connection) { */ public function register($name, $window = 3600, $identifier = NULL) { if (!isset($identifier)) { - $identifier = ip_address(); + $identifier = $this->request->getClientIp(); } $this->connection->insert('flood') ->fields(array( @@ -54,7 +65,7 @@ public function register($name, $window = 3600, $identifier = NULL) { */ public function clear($name, $identifier = NULL) { if (!isset($identifier)) { - $identifier = ip_address(); + $identifier = $this->request->getClientIp(); } $this->connection->delete('flood') ->condition('event', $name) @@ -67,7 +78,7 @@ public function clear($name, $identifier = NULL) { */ public function isAllowed($name, $threshold, $window = 3600, $identifier = NULL) { if (!isset($identifier)) { - $identifier = ip_address(); + $identifier = $this->request->getClientIp(); } $number = $this->connection->select('flood', 'f') ->condition('event', $name) diff --git a/core/lib/Drupal/Core/Flood/MemoryBackend.php b/core/lib/Drupal/Core/Flood/MemoryBackend.php index 63b19da..13ab55a 100644 --- a/core/lib/Drupal/Core/Flood/MemoryBackend.php +++ b/core/lib/Drupal/Core/Flood/MemoryBackend.php @@ -7,22 +7,41 @@ namespace Drupal\Core\Flood; +use Symfony\Component\HttpFoundation\Request; + /** * Defines the memory flood backend. This is used for testing. */ class MemoryBackend implements FloodInterface { /** + * A request object. + * + * @var \Symfony\Component\HttpFoundation\Request + */ + protected $request; + + /** * An array holding flood events, keyed by event name and identifier. */ protected $events = array(); /** + * Construct the MemoryBackend. + * + * @param \Symfony\Component\HttpFoundation\Request $request + * The HttpRequest object representing the current request. + */ + public function __construct(Request $request) { + $this->request = $request; + } + + /** * Implements Drupal\Core\Flood\FloodInterface::register(). */ public function register($name, $window = 3600, $identifier = NULL) { if (!isset($identifier)) { - $identifier = ip_address(); + $identifier = $this->request->getClientIP(); } // We can't use REQUEST_TIME here, because that would not guarantee // uniqueness. @@ -35,7 +54,7 @@ public function register($name, $window = 3600, $identifier = NULL) { */ public function clear($name, $identifier = NULL) { if (!isset($identifier)) { - $identifier = ip_address(); + $identifier = $this->request->getClientIP(); } unset($this->events[$name][$identifier]); } @@ -45,7 +64,7 @@ public function clear($name, $identifier = NULL) { */ public function isAllowed($name, $threshold, $window = 3600, $identifier = NULL) { if (!isset($identifier)) { - $identifier = ip_address(); + $identifier = $this->request->getClientIP(); } $limit = microtime(true) - $window; $number = count(array_filter($this->events[$name][$identifier], function ($timestamp) use ($limit) { diff --git a/core/modules/action/tests/action_loop_test/action_loop_test.module b/core/modules/action/tests/action_loop_test/action_loop_test.module index 8c3b98d..36f6d9b 100644 --- a/core/modules/action/tests/action_loop_test/action_loop_test.module +++ b/core/modules/action/tests/action_loop_test/action_loop_test.module @@ -69,7 +69,7 @@ function watchdog_skip_semaphore($type, $message, $variables = array(), $severit 'uid' => isset($user->uid) ? $user->uid : 0, 'request_uri' => $base_root . request_uri(), 'referer' => $_SERVER['HTTP_REFERER'], - 'ip' => ip_address(), + 'ip' => Drupal::request()->getClientIP(), 'timestamp' => REQUEST_TIME, ); diff --git a/core/modules/ban/ban.admin.inc b/core/modules/ban/ban.admin.inc index 0ea23fc..9f20a45 100644 --- a/core/modules/ban/ban.admin.inc +++ b/core/modules/ban/ban.admin.inc @@ -85,7 +85,7 @@ function ban_ip_form_validate($form, &$form_state) { if (db_query("SELECT * FROM {ban_ip} WHERE ip = :ip", array(':ip' => $ip))->fetchField()) { form_set_error('ip', t('This IP address is already banned.')); } - elseif ($ip == ip_address()) { + elseif ($ip == Drupal::request()->getClientIP()) { form_set_error('ip', t('You may not ban your own IP address.')); } elseif (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_RES_RANGE) == FALSE) { diff --git a/core/modules/ban/lib/Drupal/ban/EventSubscriber/BanSubscriber.php b/core/modules/ban/lib/Drupal/ban/EventSubscriber/BanSubscriber.php index 7dc141c..8d9f2ad 100644 --- a/core/modules/ban/lib/Drupal/ban/EventSubscriber/BanSubscriber.php +++ b/core/modules/ban/lib/Drupal/ban/EventSubscriber/BanSubscriber.php @@ -43,8 +43,7 @@ public function __construct(BanIpManager $manager) { * The Event to process. */ public function onKernelRequestBannedIpCheck(GetResponseEvent $event) { - // @todo convert this to Request::getClientIP(). - $ip = ip_address(); + $ip = $event->getRequest()->getClientIp(); if ($this->manager->isDenied($ip)) { $response = new Response('Sorry, ' . check_plain($ip) . ' has been banned.', 403); $event->setResponse($response); diff --git a/core/modules/ban/lib/Drupal/ban/Tests/IpAddressBlockingTest.php b/core/modules/ban/lib/Drupal/ban/Tests/IpAddressBlockingTest.php index 4b40572..8009de3 100644 --- a/core/modules/ban/lib/Drupal/ban/Tests/IpAddressBlockingTest.php +++ b/core/modules/ban/lib/Drupal/ban/Tests/IpAddressBlockingTest.php @@ -78,7 +78,7 @@ function testIPAddressValidation() { // manually. // TODO: On some systems this test fails due to a bug/inconsistency in cURL. // $edit = array(); - // $edit['ip'] = ip_address(); + // $edit['ip'] = \Drupal::request()->getClientIP(); // $this->drupalPost('admin/config/people/ban', $edit, t('Save')); // $this->assertText(t('You may not ban your own IP address.')); } diff --git a/core/modules/comment/lib/Drupal/comment/CommentStorageController.php b/core/modules/comment/lib/Drupal/comment/CommentStorageController.php index 77e441f..c005cb0 100644 --- a/core/modules/comment/lib/Drupal/comment/CommentStorageController.php +++ b/core/modules/comment/lib/Drupal/comment/CommentStorageController.php @@ -153,7 +153,7 @@ protected function preSave(EntityInterface $comment) { } // Add the values which aren't passed into the function. $comment->thread->value = $thread; - $comment->hostname->value = ip_address(); + $comment->hostname->value = \Drupal::request()->getClientIP(); } } diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentLinksTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentLinksTest.php index 7907464..5585650 100644 --- a/core/modules/comment/lib/Drupal/comment/Tests/CommentLinksTest.php +++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentLinksTest.php @@ -145,7 +145,7 @@ function setEnvironment(array $info) { 'uid' => 0, 'status' => COMMENT_PUBLISHED, 'subject' => $this->randomName(), - 'hostname' => ip_address(), + 'hostname' => '127.0.0.1', 'langcode' => LANGUAGE_NOT_SPECIFIED, 'comment_body' => array(LANGUAGE_NOT_SPECIFIED => array($this->randomName())), )); diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentNewIndicatorTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentNewIndicatorTest.php index 8009f88..818227e 100644 --- a/core/modules/comment/lib/Drupal/comment/Tests/CommentNewIndicatorTest.php +++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentNewIndicatorTest.php @@ -52,7 +52,7 @@ public function testCommentNewCommentsIndicator() { 'uid' => $this->loggedInUser->uid, 'status' => COMMENT_PUBLISHED, 'subject' => $this->randomName(), - 'hostname' => ip_address(), + 'hostname' => '127.0.0.1', 'langcode' => LANGUAGE_NOT_SPECIFIED, 'comment_body' => array(LANGUAGE_NOT_SPECIFIED => array($this->randomName())), )); diff --git a/core/modules/config/config.admin.inc b/core/modules/config/config.admin.inc index e81c582..51e5f8e 100644 --- a/core/modules/config/config.admin.inc +++ b/core/modules/config/config.admin.inc @@ -182,8 +182,8 @@ function config_admin_diff_page($config_file) { // Return AJAX requests as a dialog. // @todo: Set up separate content callbacks for the non-JS and dialog versions - // of this page using the router system. See http://drupal.org/node/1944472. - if (Drupal::service('request')->isXmlHttpRequest()) { + // of this page using the router system. See http://drupal.org/node/1944472. + if (Drupal::request()->isXmlHttpRequest()) { // Add class to the close link. $output['back']['#attributes']['class'][] = 'dialog-cancel'; diff --git a/core/modules/dblog/lib/Drupal/dblog/Tests/DBLogTest.php b/core/modules/dblog/lib/Drupal/dblog/Tests/DBLogTest.php index 1769605..9fcc1ee 100644 --- a/core/modules/dblog/lib/Drupal/dblog/Tests/DBLogTest.php +++ b/core/modules/dblog/lib/Drupal/dblog/Tests/DBLogTest.php @@ -137,7 +137,7 @@ private function generateLogEntries($count, $type = 'custom', $severity = WATCHD 'uid' => isset($this->big_user->uid) ? $this->big_user->uid : 0, 'request_uri' => $base_root . request_uri(), 'referer' => $_SERVER['HTTP_REFERER'], - 'ip' => ip_address(), + 'ip' => '127.0.0.1', 'timestamp' => REQUEST_TIME, ); $message = 'Log entry added to test the dblog row limit. Entry #'; @@ -424,7 +424,7 @@ protected function testDBLogAddAndClear() { 'uid' => isset($this->big_user->uid) ? $this->big_user->uid : 0, 'request_uri' => $base_root . request_uri(), 'referer' => $_SERVER['HTTP_REFERER'], - 'ip' => ip_address(), + 'ip' => '127.0.0.1', 'timestamp' => REQUEST_TIME, ); // Add a watchdog entry. diff --git a/core/modules/openid/openid.module b/core/modules/openid/openid.module index 6d31124..79858fd 100644 --- a/core/modules/openid/openid.module +++ b/core/modules/openid/openid.module @@ -1066,7 +1066,7 @@ function openid_verify_assertion_nonce($service, $response) { return TRUE; } else { - watchdog('openid', 'Nonce replay attempt blocked from @ip, nonce: @nonce.', array('@ip' => ip_address(), '@nonce' => $response['openid.response_nonce']), WATCHDOG_CRITICAL); + watchdog('openid', 'Nonce replay attempt blocked from @ip, nonce: @nonce.', array('@ip' => Drupal::request()->getClientIP(), '@nonce' => $response['openid.response_nonce']), WATCHDOG_CRITICAL); return FALSE; } } diff --git a/core/modules/system/lib/Drupal/system/Tests/Bootstrap/IpAddressTest.php b/core/modules/system/lib/Drupal/system/Tests/Bootstrap/IpAddressTest.php deleted file mode 100644 index c062aa6..0000000 --- a/core/modules/system/lib/Drupal/system/Tests/Bootstrap/IpAddressTest.php +++ /dev/null @@ -1,111 +0,0 @@ - 'IP address and HTTP_HOST test', - 'description' => 'Get the IP address from the current visitor from the server variables, check hostname validation.', - 'group' => 'Bootstrap' - ); - } - - function setUp() { - $this->oldserver = $_SERVER; - - $this->remote_ip = '127.0.0.1'; - $this->proxy_ip = '127.0.0.2'; - $this->proxy2_ip = '127.0.0.3'; - $this->forwarded_ip = '127.0.0.4'; - $this->cluster_ip = '127.0.0.5'; - $this->untrusted_ip = '0.0.0.0'; - - drupal_static_reset('ip_address'); - - $_SERVER['REMOTE_ADDR'] = $this->remote_ip; - unset($_SERVER['HTTP_X_FORWARDED_FOR']); - unset($_SERVER['HTTP_X_CLUSTER_CLIENT_IP']); - - parent::setUp(); - } - - function tearDown() { - $_SERVER = $this->oldserver; - drupal_static_reset('ip_address'); - parent::tearDown(); - } - - /** - * Tests IP address and hostname. - */ - function testIPAddressHost() { - // Test the normal IP address. - $this->assertTrue( - ip_address() == $this->remote_ip, - 'Got remote IP address.' - ); - - // Proxy forwarding on but no proxy addresses defined. - $this->settingsSet('reverse_proxy', 1); - $this->assertTrue( - ip_address() == $this->remote_ip, - 'Proxy forwarding without trusted proxies got remote IP address.' - ); - - // Proxy forwarding on and proxy address not trusted. - $this->settingsSet('reverse_proxy_addresses', array($this->proxy_ip, $this->proxy2_ip)); - drupal_static_reset('ip_address'); - $_SERVER['REMOTE_ADDR'] = $this->untrusted_ip; - $this->assertTrue( - ip_address() == $this->untrusted_ip, - 'Proxy forwarding with untrusted proxy got remote IP address.' - ); - - // Proxy forwarding on and proxy address trusted. - $_SERVER['REMOTE_ADDR'] = $this->proxy_ip; - $_SERVER['HTTP_X_FORWARDED_FOR'] = $this->forwarded_ip; - drupal_static_reset('ip_address'); - $this->assertTrue( - ip_address() == $this->forwarded_ip, - 'Proxy forwarding with trusted proxy got forwarded IP address.' - ); - - // Multi-tier architecture with comma separated values in header. - $_SERVER['REMOTE_ADDR'] = $this->proxy_ip; - $_SERVER['HTTP_X_FORWARDED_FOR'] = implode(', ', array($this->untrusted_ip, $this->forwarded_ip, $this->proxy2_ip)); - drupal_static_reset('ip_address'); - $this->assertTrue( - ip_address() == $this->forwarded_ip, - 'Proxy forwarding with trusted 2-tier proxy got forwarded IP address.' - ); - - // Custom client-IP header. - $this->settingsSet('reverse_proxy_header', 'HTTP_X_CLUSTER_CLIENT_IP'); - $_SERVER['HTTP_X_CLUSTER_CLIENT_IP'] = $this->cluster_ip; - drupal_static_reset('ip_address'); - $this->assertTrue( - ip_address() == $this->cluster_ip, - 'Cluster environment got cluster client IP.' - ); - - // Verifies that drupal_valid_http_host() prevents invalid characters. - $this->assertFalse(drupal_valid_http_host('security/.drupal.org:80'), 'HTTP_HOST with / is invalid'); - $this->assertFalse(drupal_valid_http_host('security\\.drupal.org:80'), 'HTTP_HOST with \\ is invalid'); - $this->assertFalse(drupal_valid_http_host('security<.drupal.org:80'), 'HTTP_HOST with < is invalid'); - $this->assertFalse(drupal_valid_http_host('security..drupal.org:80'), 'HTTP_HOST with .. is invalid'); - // IPv6 loopback address - $this->assertTrue(drupal_valid_http_host('[::1]:80'), 'HTTP_HOST containing IPv6 loopback is valid'); - } -} diff --git a/core/modules/system/lib/Drupal/system/Tests/System/FloodTest.php b/core/modules/system/lib/Drupal/system/Tests/System/FloodTest.php index 6af396b..02bb177 100644 --- a/core/modules/system/lib/Drupal/system/Tests/System/FloodTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/System/FloodTest.php @@ -8,11 +8,20 @@ namespace Drupal\system\Tests\System; use Drupal\simpletest\WebTestBase; +use Symfony\Component\HttpFoundation\Request; /** * Functional tests for the flood control mechanism. */ class FloodTest extends WebTestBase { + + /** + * The Request object that flood classes should use. + * + * @var \Symfony\Component\HttpFoundation\Request + */ + protected $request; + public static function getInfo() { return array( 'name' => 'Flood control mechanism', @@ -21,6 +30,16 @@ public static function getInfo() { ); } + public function setUp() { + parent::setUp(); + + // Flood backends need a request object. Create a dummy one and insert it + // to the container. + $this->request = Request::create('http://example.com/'); + $this->request->server->set('REMOTE_ADDR', '3.3.3.3'); + $this->container->set('request', $this->request); + } + /** * Test flood control mechanism clean-up. */ @@ -55,7 +74,7 @@ function testMemoryBackend() { $window_expired = -1; $name = 'flood_test_cleanup'; - $flood = new \Drupal\Core\Flood\MemoryBackend; + $flood = new \Drupal\Core\Flood\MemoryBackend($this->request); // Register expired event. $flood->register($name, $window_expired); // Verify event is not allowed. diff --git a/core/modules/system/lib/Drupal/system/Tests/Upgrade/UpgradePathTestBase.php b/core/modules/system/lib/Drupal/system/Tests/Upgrade/UpgradePathTestBase.php index 74c9923..31fcf04 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Upgrade/UpgradePathTestBase.php +++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/UpgradePathTestBase.php @@ -11,6 +11,7 @@ use Drupal\simpletest\WebTestBase; use Exception; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; +use Symfony\Component\HttpFoundation\Request; /** * Perform end-to-end tests of the upgrade path. @@ -43,6 +44,12 @@ * Prepares the appropriate session for the release of Drupal being upgraded. */ protected function prepareD8Session() { + // We need an IP when storing sessions + // so add a dummy request in the container. + $request = Request::create('http://example.com/'); + $request->server->set('REMOTE_ADDR', '3.3.3.3'); + $this->container->set('request', $request); + // Generate and set a D7-compatible session cookie. $this->curlInitialize(); $sid = drupal_hash_base64(uniqid(mt_rand(), TRUE) . drupal_random_bytes(55)); diff --git a/core/modules/user/user.module b/core/modules/user/user.module index 46f8807..c76b680 100644 --- a/core/modules/user/user.module +++ b/core/modules/user/user.module @@ -1330,7 +1330,7 @@ function user_login_authenticate_validate($form, &$form_state) { // The default identifier is a combination of uid and IP address. This // is less secure but more resistant to denial-of-service attacks that // could lock out all users with public user names. - $identifier = $account->uid . '-' . ip_address(); + $identifier = $account->uid . '-' . Drupal::request()->getClientIP(); } $form_state['flood_control_user_identifier'] = $identifier; diff --git a/core/modules/views/views_ui/lib/Drupal/views_ui/ViewEditFormController.php b/core/modules/views/views_ui/lib/Drupal/views_ui/ViewEditFormController.php index 48d195a..9261c69 100644 --- a/core/modules/views/views_ui/lib/Drupal/views_ui/ViewEditFormController.php +++ b/core/modules/views/views_ui/lib/Drupal/views_ui/ViewEditFormController.php @@ -725,7 +725,7 @@ public function renderDisplayTop(ViewUI $view) { * should not yet redirect to the destination. */ public function submitDelayDestination($form, &$form_state) { - $query = \Drupal::service('request')->query; + $query = \Drupal::request()->query; // @todo: Revisit this when http://drupal.org/node/1668866 is in. $destination = $query->get('destination'); if (isset($destination) && $form_state['redirect'] !== FALSE) { diff --git a/core/tests/Drupal/Tests/Core/EventSubscriber/ReverseProxySubscriberUnitTest.php b/core/tests/Drupal/Tests/Core/EventSubscriber/ReverseProxySubscriberUnitTest.php new file mode 100644 index 0000000..e62befe --- /dev/null +++ b/core/tests/Drupal/Tests/Core/EventSubscriber/ReverseProxySubscriberUnitTest.php @@ -0,0 +1,114 @@ + 'Reverse proxy implementation', + 'description' => 'Unit test the reverse proxy event subscriber.', + 'group' => 'System' + ); + } + + /** + * Tests that subscriber does not act when reverse proxy is not set. + */ + public function testNoProxy() { + $settings = new Settings(array()); + $this->assertEquals(0, $settings->get('reverse_proxy')); + + $subscriber = new ReverseProxySubscriber($settings); + // Mock a request object. + $request = $this->getMock('Symfony\Component\HttpFoundation\Request', array('setTrustedHeaderName', 'setTrustedProxies')); + // setTrustedHeaderName() should never fire. + $request->expects($this->never()) + ->method('setTrustedHeaderName'); + // Mock a response event. + $event = $this->getMockedEvent($request); + // Actually call the check method. + $subscriber->onKernelRequestReverseProxyCheck($event); + } + + /** + * Tests that subscriber sets trusted headers when reverse proxy is set. + */ + public function testReverseProxyEnabled() { + $cases = array( + array( + 'reverse_proxy_header' => 'HTTP_X_FORWARDED_FOR', + 'reverse_proxy_addresses' => array(), + ), + array( + 'reverse_proxy_header' => 'X_FORWARDED_HOST', + 'reverse_proxy_addresses' => array('127.0.0.2', '127.0.0.3'), + ), + ); + foreach ($cases as $case) { + // Enable reverse proxy and add test values. + $settings = new Settings(array('reverse_proxy' => 1) + $case); + $this->trustedHeadersAreSet($settings); + } + } + + /** + * Tests that trusted header methods are called. + * + * \Symfony\Component\HttpFoundation\Request::setTrustedHeaderName() and + * \Symfony\Component\HttpFoundation\Request::setTrustedProxies() should + * always be called when reverse proxy settings are enabled. + * + * @param \Drupal\Component\Utility\Settings $settings + * The settings object that holds reverse proxy configuration. + */ + protected function trustedHeadersAreSet(Settings $settings) { + $subscriber = new ReverseProxySubscriber($settings); + $request = $this->getMock('Symfony\Component\HttpFoundation\Request', array('setTrustedHeaderName', 'setTrustedProxies')); + $request->staticExpects($this->at(0)) + ->method('setTrustedHeaderName') + ->with($this->equalTo($request::HEADER_CLIENT_IP), $this->equalTo($settings->get('reverse_proxy_header'))); + $request->staticExpects($this->at(1)) + ->method('setTrustedProxies') + ->with($this->equalTo($settings->get('reverse_proxy_addresses'))); + + $event = $this->getMockedEvent($request); + $subscriber->onKernelRequestReverseProxyCheck($event); + } + + /** + * Creates a mocked event. + * + * Mocks a \Symfony\Component\HttpKernel\Event\GetResponseEvent object + * and stubs its getRequest() method to return a mocked request object. + * + * @param \Symfony\Component\HttpFoundation\Request $request + * A mocked Request object. + * + * @return \Symfony\Component\HttpKernel\Event\GetResponseEvent + * The GetResponseEvent mocked object. + */ + protected function getMockedEvent($request) { + $event = $this->getMockBuilder('Symfony\Component\HttpKernel\Event\GetResponseEvent') + ->disableOriginalConstructor() + ->getMock(); + $event->expects($this->once()) + ->method('getRequest') + ->will($this->returnValue($request)); + return $event; + } +}