In order to satisfy a security audit, I need to implement a feature where a user can have at most 3 attempts of login per 5 minutes
fortunately, it is now built-in Symfony 5.2: https://symfony.com/blog/new-in-symfony-5-2-login-throttling
As the parameter max_attempts
is not enough for me (it's per 1 minute), I want to use the second option to provide my owner limiter
so I use this https://symfony.com/blog/new-in-symfony-5-2-rate-limiter-component
my configuration looks like this
framework:
rate_limiter:
max_login_failure:
policy: fixed_window
limit: 3
interval: '10 minutes'
security:
firewalls:
admins:
host: admin.*
pattern: ^/
provider: admins
login_throttling:
limiter: limiter.max_login_failure
but it fails with the error
Argument 2 passed to Symfony\Component\Security\Http\EventListener\LoginThrottlingListener::__construct() must be an instance of Symfony\Component\HttpFoundation\RateLimiter\RequestRateLimiterInterface, instance of Symfony\Component\RateLimiter\RateLimiterFactory given,
My understanding is that I'm giving it a factory instead of an instance of what I want, but there's nowhere in the doc where I can find how to get an instance from the factory
If you want to use a custom limiter you need to create an own limiter. Then define as service in services.yml An example that works for me
<?php
declare(strict_types=1);
namespace App\Limiter;
use Symfony\Component\HttpFoundation\RateLimiter\RequestRateLimiterInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\RateLimiter\LimiterInterface;
use Symfony\Component\RateLimiter\RateLimit;
use Symfony\Component\RateLimiter\RateLimiterFactory;
class CustomLimiter implements RequestRateLimiterInterface
{
/**
* @var LimiterInterface
*/
private $limiter;
public function __construct(RateLimiterFactory $factory)
{
$this->limiter = $factory->create('a_unique_identifier');
}
public function consume(Request $request): RateLimit
{
return $this->limiter->consume();
}
public function reset(Request $request): void
{
$this->limiter->reset();
}
}
In services.yml define a custom limiter. You should pass as an argument your max_limiter configuration
app.custom.limiter:
class: App\Limiter\CustomLimiter
arguments:
- '@limiter.max_login_failure'
In the end, you should paste your new limiter to the security configuration
security:
firewalls:
admins:
host: admin.*
pattern: ^/
provider: admins
login_throttling:
limiter: app.custom.limiter
That's all! I hope this helps you