I have encountered very unpleasant api platform behavior with security with custom providers.
I really need some explanation if this behavior is really intended or is it a security flaw.
During my testing I realized that custom provider is executed before security check.
That means the security check is performed AFTER the provide()
method was executed.
First the CallableProvider::provide()
is executed and then DenyAccessListener::onSecurity()
check is performed.
The response is correctly adjusted to 401/403.
However the provider can contain very delicate logic which should not be executed without user being authenticated/authorized.
Imagine doing some very expensive operation or throwing exceptions. So by throwing exception in the provider (i.e. when requested entity does not exist) the response is adjusted even for client without proper authentication.
I am aware I can bypass this by calling $this->security->isGranted()
in my provider, however promoting security in documentation can be very misleading in such scenario.
I have implemented by own CallableProvider
which does the security check prior to calling provide()
however I am not decided what is correct approach or best practise.
Example:
class MyProvider implements ProviderInterface
{
public function __construct(private readonly Security $security) {}
public function provide(Operation $operation, array $uriVariables = [], array $context = [])
{
var_dump($this->security->isGranted('ROLE_API'));
echo "this code should not be executed without security check";
die;
}
}
#[ApiResource(
operations: [
new Get(
uriTemplate: '/my-entity',
provider: MyProvider::class,
),
],
security: "is_granted('ROLE_API')",
)]
class MyEntity
{
public int $id;
}
Output:
curl -X 'GET'
'http://localhost/api/my-entity'
-H 'accept: application/json'
bool(false)
this code should not be executed without security check