Skip to content

Commit cf58b54

Browse files
wouterjfabpot
authored andcommitted
[Security] Added login throttling feature
1 parent 04a475a commit cf58b54

File tree

3 files changed

+52
-36
lines changed

3 files changed

+52
-36
lines changed

DependencyInjection/Configuration.php

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1736,15 +1736,37 @@ private function addRateLimiterSection(ArrayNodeDefinition $rootNode)
17361736
->useAttributeAsKey('name')
17371737
->arrayPrototype()
17381738
->children()
1739-
->scalarNode('lock')->defaultValue('lock.factory')->end()
1740-
->scalarNode('storage')->defaultValue('cache.app')->end()
1741-
->scalarNode('strategy')->isRequired()->end()
1742-
->integerNode('limit')->isRequired()->end()
1743-
->scalarNode('interval')->end()
1739+
->scalarNode('lock_factory')
1740+
->info('The service ID of the lock factory used by this limiter')
1741+
->defaultValue('lock.factory')
1742+
->end()
1743+
->scalarNode('cache_pool')
1744+
->info('The cache pool to use for storing the current limiter state')
1745+
->defaultValue('cache.app')
1746+
->end()
1747+
->scalarNode('storage_service')
1748+
->info('The service ID of a custom storage implementation, this precedes any configured "cache_pool"')
1749+
->defaultNull()
1750+
->end()
1751+
->enumNode('strategy')
1752+
->info('The rate limiting algorithm to use for this rate')
1753+
->isRequired()
1754+
->values(['fixed_window', 'token_bucket'])
1755+
->end()
1756+
->integerNode('limit')
1757+
->info('The maximum allowed hits in a fixed interval or burst')
1758+
->isRequired()
1759+
->end()
1760+
->scalarNode('interval')
1761+
->info('Configures the fixed interval if "strategy" is set to "fixed_window". The value must be a number followed by "second", "minute", "hour", "day", "week" or "month" (or their plural equivalent).')
1762+
->end()
17441763
->arrayNode('rate')
1764+
->info('Configures the fill rate if "strategy" is set to "token_bucket"')
17451765
->children()
1746-
->scalarNode('interval')->isRequired()->end()
1747-
->integerNode('amount')->defaultValue(1)->end()
1766+
->scalarNode('interval')
1767+
->info('Configures the rate interval. The value must be a number followed by "second", "minute", "hour", "day", "week" or "month" (or their plural equivalent).')
1768+
->end()
1769+
->integerNode('amount')->info('Amount of tokens to add each interval')->defaultValue(1)->end()
17481770
->end()
17491771
->end()
17501772
->end()

DependencyInjection/FrameworkExtension.php

Lines changed: 20 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2190,38 +2190,31 @@ private function registerRateLimiterConfiguration(array $config, ContainerBuilde
21902190

21912191
$loader->load('rate_limiter.php');
21922192

2193-
$locks = [];
2194-
$storages = [];
21952193
foreach ($config['limiters'] as $name => $limiterConfig) {
2196-
$limiter = $container->setDefinition($limiterId = 'limiter.'.$name, new ChildDefinition('limiter'));
2197-
2198-
if (!isset($locks[$limiterConfig['lock']])) {
2199-
$locks[$limiterConfig['lock']] = new Reference($limiterConfig['lock']);
2200-
}
2201-
$limiter->addArgument($locks[$limiterConfig['lock']]);
2202-
unset($limiterConfig['lock']);
2203-
2204-
if (!isset($storages[$limiterConfig['storage']])) {
2205-
$storageId = $limiterConfig['storage'];
2206-
// cache pools are configured by the FrameworkBundle, so they
2207-
// exists in the scoped ContainerBuilder provided to this method
2208-
if ($container->has($storageId)) {
2209-
if ($container->findDefinition($storageId)->hasTag('cache.pool')) {
2210-
$container->register('limiter.storage.'.$storageId, CacheStorage::class)->addArgument(new Reference($storageId));
2211-
$storageId = 'limiter.storage.'.$storageId;
2212-
}
2213-
}
2194+
self::registerRateLimiter($container, $name, $limiterConfig);
2195+
}
2196+
}
22142197

2215-
$storages[$limiterConfig['storage']] = new Reference($storageId);
2216-
}
2217-
$limiter->replaceArgument(1, $storages[$limiterConfig['storage']]);
2218-
unset($limiterConfig['storage']);
2198+
public static function registerRateLimiter(ContainerBuilder $container, string $name, array $limiterConfig)
2199+
{
2200+
$limiter = $container->setDefinition($limiterId = 'limiter.'.$name, new ChildDefinition('limiter'));
22192201

2220-
$limiterConfig['id'] = $name;
2221-
$limiter->replaceArgument(0, $limiterConfig);
2202+
$limiter->addArgument(new Reference($limiterConfig['lock_factory']));
2203+
unset($limiterConfig['lock_factory']);
22222204

2223-
$container->registerAliasForArgument($limiterId, Limiter::class, $name.'.limiter');
2205+
$storageId = $limiterConfig['storage_service'] ?? null;
2206+
if (null === $storageId) {
2207+
$container->register($storageId = 'limiter.storage.'.$name, CacheStorage::class)->addArgument(new Reference($limiterConfig['cache_pool']));
22242208
}
2209+
2210+
$limiter->replaceArgument(1, new Reference($storageId));
2211+
unset($limiterConfig['storage']);
2212+
unset($limiterConfig['cache_pool']);
2213+
2214+
$limiterConfig['id'] = $name;
2215+
$limiter->replaceArgument(0, $limiterConfig);
2216+
2217+
$container->registerAliasForArgument($limiterId, Limiter::class, $name.'.limiter');
22252218
}
22262219

22272220
private function resolveTrustedHeaders(array $headers): int

Resources/config/schema/symfony-1.0.xsd

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -650,8 +650,9 @@
650650
<xsd:element name="rate" type="rate_limiter_rate" minOccurs="0" />
651651
</xsd:sequence>
652652
<xsd:attribute name="name" type="xsd:string" />
653-
<xsd:attribute name="lock" type="xsd:string" />
654-
<xsd:attribute name="storage" type="xsd:string" />
653+
<xsd:attribute name="lock-factory" type="xsd:string" />
654+
<xsd:attribute name="storage-service" type="xsd:string" />
655+
<xsd:attribute name="cache-pool" type="xsd:string" />
655656
<xsd:attribute name="strategy" type="xsd:string" />
656657
<xsd:attribute name="limit" type="xsd:int" />
657658
<xsd:attribute name="interval" type="xsd:string" />

0 commit comments

Comments
 (0)