From 6413dcbe75b76520bd3ed3244310617cc3ffcf33 Mon Sep 17 00:00:00 2001 From: Mathias STRASSER Date: Thu, 27 Sep 2018 17:45:31 +0200 Subject: [PATCH] [Security] add port in access_control --- .../Bundle/SecurityBundle/CHANGELOG.md | 1 + .../DependencyInjection/MainConfiguration.php | 1 + .../DependencyInjection/SecurityExtension.php | 9 ++++---- .../CompleteConfigurationTest.php | 6 ++--- .../Fixtures/php/container1.php | 2 +- .../Fixtures/xml/container1.xml | 2 +- .../Fixtures/yml/container1.yml | 2 +- .../Component/HttpFoundation/CHANGELOG.md | 1 + .../HttpFoundation/RequestMatcher.php | 22 ++++++++++++++++++- .../Tests/RequestMatcherTest.php | 15 +++++++++++++ 10 files changed, 50 insertions(+), 11 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md b/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md index 14ae3f6249b1c..042696e3a4301 100644 --- a/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md @@ -15,6 +15,7 @@ CHANGELOG and added an "auto" mode to their "secure" config option to make them secure on HTTPS automatically. * Deprecated the `simple_form` and `simple_preauth` authentication listeners, use Guard instead. * Deprecated the `SimpleFormFactory` and `SimplePreAuthenticationFactory` classes, use Guard instead. + * Added `port` in access_control 4.1.0 ----- diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php index 563673f2141be..e366d446fdba1 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php @@ -142,6 +142,7 @@ private function addAccessControlSection(ArrayNodeDefinition $rootNode) ->example('^/path to resource/') ->end() ->scalarNode('host')->defaultNull()->end() + ->integerNode('port')->defaultNull()->end() ->arrayNode('ips') ->beforeNormalization()->ifString()->then(function ($v) { return array($v); })->end() ->prototype('scalar')->end() diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index be72bf20620c3..8cfc185e3a150 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -172,6 +172,7 @@ private function createAuthorization($config, ContainerBuilder $container) $container, $access['path'], $access['host'], + $access['port'], $access['methods'], $access['ips'] ); @@ -275,7 +276,7 @@ private function createFirewall(ContainerBuilder $container, $id, $firewall, &$a $pattern = isset($firewall['pattern']) ? $firewall['pattern'] : null; $host = isset($firewall['host']) ? $firewall['host'] : null; $methods = isset($firewall['methods']) ? $firewall['methods'] : array(); - $matcher = $this->createRequestMatcher($container, $pattern, $host, $methods); + $matcher = $this->createRequestMatcher($container, $pattern, $host, null, $methods); } $config->replaceArgument(2, $matcher ? (string) $matcher : null); @@ -696,20 +697,20 @@ private function createExpression($container, $expression) return $this->expressions[$id] = new Reference($id); } - private function createRequestMatcher($container, $path = null, $host = null, $methods = array(), $ip = null, array $attributes = array()) + private function createRequestMatcher($container, $path = null, $host = null, int $port = null, $methods = array(), $ip = null, array $attributes = array()) { if ($methods) { $methods = array_map('strtoupper', (array) $methods); } - $id = '.security.request_matcher.'.ContainerBuilder::hash(array($path, $host, $methods, $ip, $attributes)); + $id = '.security.request_matcher.'.ContainerBuilder::hash(array($path, $host, $port, $methods, $ip, $attributes)); if (isset($this->requestMatchers[$id])) { return $this->requestMatchers[$id]; } // only add arguments that are necessary - $arguments = array($path, $host, $methods, $ip, $attributes); + $arguments = array($path, $host, $methods, $ip, $attributes, null, $port); while (\count($arguments) > 0 && !end($arguments)) { array_pop($arguments); } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php index d1ceac8ac8a17..6544f070523dc 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php @@ -84,7 +84,7 @@ public function testFirewalls() array( 'simple', 'security.user_checker', - '.security.request_matcher.6tndozi', + '.security.request_matcher.xmi9dcw', false, ), array( @@ -116,7 +116,7 @@ public function testFirewalls() array( 'host', 'security.user_checker', - '.security.request_matcher.and0kk1', + '.security.request_matcher.iw4hyjb', true, false, 'security.user.provider.concrete.default', @@ -238,7 +238,7 @@ public function testAccess() $this->assertEquals(array('ROLE_USER'), $attributes); $this->assertEquals('https', $channel); $this->assertEquals( - array('/blog/524', null, array('GET', 'POST')), + array('/blog/524', null, array('GET', 'POST'), array(), array(), null, 8000), $requestMatcher->getArguments() ); } elseif (2 === $i) { diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/container1.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/container1.php index 08aa19644ded6..c2952a1ad0cae 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/container1.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/container1.php @@ -90,7 +90,7 @@ ), 'access_control' => array( - array('path' => '/blog/524', 'role' => 'ROLE_USER', 'requires_channel' => 'https', 'methods' => array('get', 'POST')), + array('path' => '/blog/524', 'role' => 'ROLE_USER', 'requires_channel' => 'https', 'methods' => array('get', 'POST'), 'port' => 8000), array('path' => '/blog/.*', 'role' => 'IS_AUTHENTICATED_ANONYMOUSLY'), array('path' => '/blog/524', 'role' => 'IS_AUTHENTICATED_ANONYMOUSLY', 'allow_if' => "token.getUsername() matches '/^admin/'"), ), diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/container1.xml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/container1.xml index e73d3a6ecf8ab..f2b591c2833bb 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/container1.xml +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/container1.xml @@ -72,7 +72,7 @@ ROLE_USER,ROLE_ADMIN,ROLE_ALLOWED_TO_SWITCH ROLE_USER,ROLE_ADMIN - + diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/container1.yml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/container1.yml index c38bbb0e5aa0f..9a1535ebb2c9a 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/container1.yml +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/container1.yml @@ -76,7 +76,7 @@ security: ROLE_REMOTE: ROLE_USER,ROLE_ADMIN access_control: - - { path: /blog/524, role: ROLE_USER, requires_channel: https, methods: [get, POST]} + - { path: /blog/524, role: ROLE_USER, requires_channel: https, methods: [get, POST], port: 8000} - path: /blog/.* role: IS_AUTHENTICATED_ANONYMOUSLY diff --git a/src/Symfony/Component/HttpFoundation/CHANGELOG.md b/src/Symfony/Component/HttpFoundation/CHANGELOG.md index 73716f35aca17..e5eb335671ef3 100644 --- a/src/Symfony/Component/HttpFoundation/CHANGELOG.md +++ b/src/Symfony/Component/HttpFoundation/CHANGELOG.md @@ -8,6 +8,7 @@ CHANGELOG * the default value of the "$secure" and "$samesite" arguments of Cookie's constructor will respectively change from "false" to "null" and from "null" to "lax" in Symfony 5.0, you should define their values explicitly or use "Cookie::create()" instead. + * added `matchPort()` in RequestMatcher 4.1.3 ----- diff --git a/src/Symfony/Component/HttpFoundation/RequestMatcher.php b/src/Symfony/Component/HttpFoundation/RequestMatcher.php index 57fa48e40be3e..ab9434f43fd8f 100644 --- a/src/Symfony/Component/HttpFoundation/RequestMatcher.php +++ b/src/Symfony/Component/HttpFoundation/RequestMatcher.php @@ -28,6 +28,11 @@ class RequestMatcher implements RequestMatcherInterface */ private $host; + /** + * @var int|null + */ + private $port; + /** * @var string[] */ @@ -56,13 +61,14 @@ class RequestMatcher implements RequestMatcherInterface * @param array $attributes * @param string|string[]|null $schemes */ - public function __construct(string $path = null, string $host = null, $methods = null, $ips = null, array $attributes = array(), $schemes = null) + public function __construct(string $path = null, string $host = null, $methods = null, $ips = null, array $attributes = array(), $schemes = null, int $port = null) { $this->matchPath($path); $this->matchHost($host); $this->matchMethod($methods); $this->matchIps($ips); $this->matchScheme($schemes); + $this->matchPort($port); foreach ($attributes as $k => $v) { $this->matchAttribute($k, $v); @@ -89,6 +95,16 @@ public function matchHost($regexp) $this->host = $regexp; } + /** + * Adds a check for the the URL port. + * + * @param int|null $port The port number to connect to + */ + public function matchPort(int $port = null) + { + $this->port = $port; + } + /** * Adds a check for the URL path info. * @@ -167,6 +183,10 @@ public function matches(Request $request) return false; } + if (null !== $this->port && 0 < $this->port && $request->getPort() !== $this->port) { + return false; + } + if (IpUtils::checkIp($request->getClientIp(), $this->ips)) { return true; } diff --git a/src/Symfony/Component/HttpFoundation/Tests/RequestMatcherTest.php b/src/Symfony/Component/HttpFoundation/Tests/RequestMatcherTest.php index 10d764a776bba..cc35ad637bbf4 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/RequestMatcherTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/RequestMatcherTest.php @@ -78,6 +78,21 @@ public function testHost($pattern, $isMatch) $this->assertSame($isMatch, $matcher->matches($request)); } + public function testPort() + { + $matcher = new RequestMatcher(); + $request = Request::create('', 'get', array(), array(), array(), array('HTTP_HOST' => null, 'SERVER_PORT' => 8000)); + + $matcher->matchPort(8000); + $this->assertTrue($matcher->matches($request)); + + $matcher->matchPort(9000); + $this->assertFalse($matcher->matches($request)); + + $matcher = new RequestMatcher(null, null, null, null, array(), null, 8000); + $this->assertTrue($matcher->matches($request)); + } + public function getHostData() { return array(