diff --git a/.circleci/config.yml b/.circleci/config.yml index eb18e2e04ee..62cf5ffa032 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -530,12 +530,10 @@ jobs: workflows: version: 2 - lint: + lint-and-coverage: jobs: - php-cs-fixer - phpstan - test-with-coverage: - jobs: - phpunit-coverage - behat-coverage - phpunit-mongodb-coverage diff --git a/composer.json b/composer.json index 38eb217000f..43d8612f470 100644 --- a/composer.json +++ b/composer.json @@ -70,7 +70,7 @@ "symfony/framework-bundle": "^4.2", "symfony/mercure-bundle": "*", "symfony/messenger": "^4.2", - "symfony/phpunit-bridge": "^3.4.5 || ^4.0.5", + "symfony/phpunit-bridge": "^4.3", "symfony/routing": "^3.4 || ^4.0", "symfony/security-bundle": "^3.4 || ^4.0", "symfony/security-core": "^3.4 || ^4.0", @@ -82,7 +82,8 @@ }, "conflict": { "doctrine/common": "<2.7", - "doctrine/mongodb-odm": "<2.0" + "doctrine/mongodb-odm": "<2.0", + "symfony/messenger": ">=4.3" }, "suggest": { "doctrine/mongodb-odm-bundle": "To support MongoDB. Only versions 4.0 and later are supported.", diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 79910e0a1ed..ce2c16a9f4e 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -74,6 +74,12 @@ parameters: - message: "#Call to function method_exists\\(\\) with 'Symfony\\\\\\\\Component.+' and '(removeBindings|addRemovedBindingIds)' will always evaluate to false\\.#" path: %currentWorkingDirectory%/tests/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php + - + message: "#Call to function method_exists\\(\\) with 'Symfony\\\\\\\\Component.+' and 'getReachableRoleNam.+' will always evaluate to false\\.#" + path: %currentWorkingDirectory%/tests/Security/EventListener/DenyAccessListenerTest.php + - + message: "#Call to function method_exists\\(\\) with 'Symfony\\\\\\\\Component.+' and 'getRoleNames' will always evaluate to false\\.#" + path: %currentWorkingDirectory%/tests/Security/EventListener/DenyAccessListenerTest.php - "#Call to method PHPUnit\\\\Framework\\\\Assert::assertSame\\(\\) with array\\('(collection_context|item_context|subresource_context)'\\) and array\\|bool\\|float\\|int\\|string\\|null will always evaluate to false\\.#" # https://github.com/doctrine/doctrine2/pull/7298/files - '#Strict comparison using === between null and int will always evaluate to false\.#' diff --git a/phpunit.xml.dist b/phpunit.xml.dist index aa9fd425f41..2f0a298995d 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -10,7 +10,7 @@ - + diff --git a/phpunit_mongodb.xml b/phpunit_mongodb.xml index ee2ce7fb67b..0afdb28354b 100644 --- a/phpunit_mongodb.xml +++ b/phpunit_mongodb.xml @@ -10,7 +10,7 @@ - + diff --git a/src/Security/ResourceAccessChecker.php b/src/Security/ResourceAccessChecker.php index c40c9518d8b..ace70df478a 100644 --- a/src/Security/ResourceAccessChecker.php +++ b/src/Security/ResourceAccessChecker.php @@ -67,17 +67,31 @@ public function isGranted(string $resourceClass, string $expression, array $extr */ private function getVariables(TokenInterface $token): array { - $roles = $this->roleHierarchy ? $this->roleHierarchy->getReachableRoles($token->getRoles()) : $token->getRoles(); - return [ 'token' => $token, 'user' => $token->getUser(), - 'roles' => array_map(function (Role $role) { - return $role->getRole(); - }, $roles), + 'roles' => $this->getEffectiveRoles($token), 'trust_resolver' => $this->authenticationTrustResolver, // needed for the is_granted expression function 'auth_checker' => $this->authorizationChecker, ]; } + + /** + * @return string[] + */ + private function getEffectiveRoles(TokenInterface $token): array + { + if (null === $this->roleHierarchy) { + return method_exists($token, 'getRoleNames') ? $token->getRoleNames() : array_map('strval', $token->getRoles()); + } + + if (method_exists($this->roleHierarchy, 'getReachableRoleNames')) { + return $this->roleHierarchy->getReachableRoleNames($token->getRoleNames()); + } + + return array_map(function (Role $role): string { + return $role->getRole(); + }, $this->roleHierarchy->getReachableRoles($token->getRoles())); + } } diff --git a/tests/Security/EventListener/DenyAccessListenerTest.php b/tests/Security/EventListener/DenyAccessListenerTest.php index 63de9ddb29d..9ff418728dd 100644 --- a/tests/Security/EventListener/DenyAccessListenerTest.php +++ b/tests/Security/EventListener/DenyAccessListenerTest.php @@ -23,10 +23,12 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface; +use Symfony\Component\Security\Core\Authentication\Token\AbstractToken; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; use Symfony\Component\Security\Core\Exception\AccessDeniedException; +use Symfony\Component\Security\Core\Role\RoleHierarchy; use Symfony\Component\Security\Core\Role\RoleHierarchyInterface; /** @@ -269,14 +271,14 @@ private function getLegacyListener(ResourceMetadataFactoryInterface $resourceMet $authenticationTrustResolverProphecy = $this->prophesize(AuthenticationTrustResolverInterface::class); $roleHierarchyInterfaceProphecy = $this->prophesize(RoleHierarchyInterface::class); - $roleHierarchyInterfaceProphecy->getReachableRoles(Argument::type('array'))->willReturn([]); + $roleHierarchyInterfaceProphecy->{method_exists(RoleHierarchy::class, 'getReachableRoleNames') ? 'getReachableRoleNames' : 'getReachableRoles'}(Argument::type('array'))->willReturn([]); - $tokenProphecy = $this->prophesize(TokenInterface::class); + $tokenProphecy = $this->prophesize(AbstractToken::class); $tokenProphecy->getUser()->willReturn('anon.'); - $tokenProphecy->getRoles()->willReturn([]); + $tokenProphecy->{method_exists(AbstractToken::class, 'getRoleNames') ? 'getRoleNames' : 'getRoles'}()->willReturn([]); $tokenStorageProphecy = $this->prophesize(TokenStorageInterface::class); - $tokenStorageProphecy->getToken()->willReturn($tokenProphecy->reveal())->shouldBeCalled(); + $tokenStorageProphecy->getToken()->willReturn($tokenProphecy)->shouldBeCalled(); $authorizationCheckerInterface = $this->prophesize(AuthorizationCheckerInterface::class);