core
core copied to clipboard
When event_listeners_backward_compatibility_layer is disabled I can't pass URI variables into a Voter in security property.
API Platform version(s) affected: 3.2.3
Description
I have a resource where I pass a URI variable into a voter. But when I set event_listeners_backward_compatibility_layer
to false
and request GET /users/{user_id}/stats
I get this error:
Variable "user_id" is not valid around position 87 for expression `is_granted('ROLE_ADMIN') or is_granted('ROLE_USER') and is_granted('USER_STATS_VIEW', user_id)`.
How to reproduce
- Have some resource with uriTemplate
- Set
event_listeners_backward_compatibility_layer
tofalse
- Pass uriTemplate to a voter in security property
- Get the error
Possible Solution
I think it has something to do with what providers are called after $uriVariables = $this->getOperationUriVariables...
in ReadListener.php
and in MainController.php
Additional Context
I do not know if that's by design so I kept event_listeners_backward_compatibility_layer
set to false
and now pass request
variable to Voter and get user_id
from it and this works fine.
Resource config for the original issue:
...
#[ApiResource(
shortName: 'Stat',
operations: [
new Get(
uriTemplate: '/users/{user_id}/stats/{id}.{_format}',
uriVariables: [
'user_id' => new Link(
toProperty: 'user',
fromClass: User::class,
),
'id' => new Link(
fromProperty: 'id',
fromClass: Stat::class
),
],
),
new GetCollection(
uriTemplate: '/users/{user_id}/stats.{_format}',
uriVariables: [
'user_id' => new Link(fromClass: User::class),
],
)
],
security: "is_granted('ROLE_ADMIN') or is_granted('ROLE_USER') and is_granted('USER_STATS_VIEW', user_id)",
provider: StatsProvider::class
)]
class Stat
{
...
Stack Trace:
Symfony\Component\ExpressionLanguage\SyntaxError:
Variable "user_id" is not valid around position 87 for expression `is_granted('ROLE_ADMIN') or is_granted('ROLE_USER') and is_granted('USER_STATS_VIEW', user_id)`.
at vendor/symfony/expression-language/Parser.php:249
at Symfony\Component\ExpressionLanguage\Parser->parsePrimaryExpression()
(vendor/symfony/expression-language/Parser.php:180)
at Symfony\Component\ExpressionLanguage\Parser->getPrimary()
(vendor/symfony/expression-language/Parser.php:138)
at Symfony\Component\ExpressionLanguage\Parser->parseExpression()
(vendor/symfony/expression-language/Parser.php:433)
at Symfony\Component\ExpressionLanguage\Parser->parseArguments()
(vendor/symfony/expression-language/Parser.php:245)
at Symfony\Component\ExpressionLanguage\Parser->parsePrimaryExpression()
(vendor/symfony/expression-language/Parser.php:180)
at Symfony\Component\ExpressionLanguage\Parser->getPrimary()
(vendor/symfony/expression-language/Parser.php:138)
at Symfony\Component\ExpressionLanguage\Parser->parseExpression(16)
(vendor/symfony/expression-language/Parser.php:144)
at Symfony\Component\ExpressionLanguage\Parser->parseExpression(11)
(vendor/symfony/expression-language/Parser.php:144)
at Symfony\Component\ExpressionLanguage\Parser->parseExpression()
(vendor/symfony/expression-language/Parser.php:123)
at Symfony\Component\ExpressionLanguage\Parser->doParse(object(TokenStream), array('auth_checker', 'object', 'previous_object', 'request', 'roles', 'token', 'trust_resolver', 'user'))
(vendor/symfony/expression-language/Parser.php:98)
at Symfony\Component\ExpressionLanguage\Parser->parse(object(TokenStream), array('auth_checker', 'object', 'previous_object', 'request', 'roles', 'token', 'trust_resolver', 'user'))
(vendor/symfony/expression-language/ExpressionLanguage.php:81)
at Symfony\Component\ExpressionLanguage\ExpressionLanguage->parse('is_granted(\'ROLE_ADMIN\') or is_granted(\'ROLE_USER\') and is_granted(\'USER_STATS_VIEW\', user_id)', array('auth_checker', 'object', 'previous_object', 'request', 'roles', 'token', 'trust_resolver', 'user'))
(vendor/symfony/expression-language/ExpressionLanguage.php:59)
at Symfony\Component\ExpressionLanguage\ExpressionLanguage->evaluate('is_granted(\'ROLE_ADMIN\') or is_granted(\'ROLE_USER\') and is_granted(\'USER_STATS_VIEW\', user_id)', array('object' => array(object(Stat)), 'previous_object' => array(object(Stat)), 'request' => object(Request), 'trust_resolver' => object(AuthenticationTrustResolver), 'auth_checker' => object(AuthorizationChecker), 'token' => object(UsernamePasswordToken), 'user' => object(User), 'roles' => array('ROLE_ADMIN', 'ROLE_USER')))
(vendor/api-platform/core/src/Symfony/Security/ResourceAccessChecker.php:56)
at ApiPlatform\Symfony\Security\ResourceAccessChecker->isGranted('App\\ApiResource\\Stat', 'is_granted(\'ROLE_ADMIN\') or is_granted(\'ROLE_USER\') and is_granted(\'USER_STATS_VIEW\', user_id)', array('object' => array(object(Stat)), 'previous_object' => array(object(Stat)), 'request' => object(Request)))
(vendor/api-platform/core/src/Symfony/Security/State/AccessCheckerProvider.php:78)
at ApiPlatform\Symfony\Security\State\AccessCheckerProvider->provide(object(GetCollection), array('user_id' => 1), array('request' => object(Request), 'uri_variables' => array('user_id' => 1), 'resource_class' => 'App\\ApiResource\\Stat'))
(vendor/api-platform/core/src/State/Provider/DeserializeProvider.php:47)
at ApiPlatform\State\Provider\DeserializeProvider->provide(object(GetCollection), array('user_id' => 1), array('request' => object(Request), 'uri_variables' => array('user_id' => 1), 'resource_class' => 'App\\ApiResource\\Stat'))
(vendor/api-platform/core/src/Symfony/Security/State/AccessCheckerProvider.php:53)
at ApiPlatform\Symfony\Security\State\AccessCheckerProvider->provide(object(GetCollection), array('user_id' => 1), array('request' => object(Request), 'uri_variables' => array('user_id' => 1), 'resource_class' => 'App\\ApiResource\\Stat'))
(vendor/api-platform/core/src/Symfony/Validator/State/QueryParameterValidateProvider.php:54)
at ApiPlatform\Symfony\Validator\State\QueryParameterValidateProvider->provide(object(GetCollection), array('user_id' => 1), array('request' => object(Request), 'uri_variables' => array('user_id' => 1), 'resource_class' => 'App\\ApiResource\\Stat'))
(vendor/api-platform/core/src/Symfony/Validator/State/ValidateProvider.php:32)
at ApiPlatform\Symfony\Validator\State\ValidateProvider->provide(object(GetCollection), array('user_id' => 1), array('request' => object(Request), 'uri_variables' => array('user_id' => 1), 'resource_class' => 'App\\ApiResource\\Stat'))
(vendor/api-platform/core/src/Symfony/Security/State/AccessCheckerProvider.php:53)
at ApiPlatform\Symfony\Security\State\AccessCheckerProvider->provide(object(GetCollection), array('user_id' => 1), array('request' => object(Request), 'uri_variables' => array('user_id' => 1), 'resource_class' => 'App\\ApiResource\\Stat'))
(vendor/api-platform/core/src/State/Provider/ContentNegotiationProvider.php:56)
at ApiPlatform\State\Provider\ContentNegotiationProvider->provide(object(GetCollection), array('user_id' => 1), array('request' => object(Request), 'uri_variables' => array('user_id' => 1), 'resource_class' => 'App\\ApiResource\\Stat'))
(vendor/api-platform/core/src/Symfony/Controller/MainController.php:74)
at ApiPlatform\Symfony\Controller\MainController->__invoke(object(Request))
(vendor/symfony/http-kernel/HttpKernel.php:181)
at Symfony\Component\HttpKernel\HttpKernel->handleRaw(object(Request), 1)
(vendor/symfony/http-kernel/HttpKernel.php:76)
at Symfony\Component\HttpKernel\HttpKernel->handle(object(Request), 1, true)
(vendor/symfony/http-kernel/Kernel.php:197)
at Symfony\Component\HttpKernel\Kernel->handle(object(Request))
(vendor/symfony/runtime/Runner/Symfony/HttpKernelRunner.php:35)
at Symfony\Component\Runtime\Runner\Symfony\HttpKernelRunner->run()
(vendor/autoload_runtime.php:29)
at require_once('/Users/nick/Developer/UPWZ/0000/job-search-api/vendor/autoload_runtime.php')
(public/index.php:5)
Additionally, values like _api_resource_class
can also not be used anymore and produce the same error as above.
Update
I was able to work around my problem using request.get('_api_resource_class')
instead of _api_resource_class
only.
security: "is_granted('custom:format', request.get('_api_resource_class'))"
Definitely a bug, good catch. I'll see for this to be resolved and tested.
Hi, any news on this? It looks like it still persist on version API Platform 3.2.16. Or please help me with a work around.
L.E. the above approach with request.get('id') seems to work.