]> source.dussan.org Git - nextcloud-server.git/commitdiff
feat(security): Allow to opt-out of ratelimit protection, e.g. for testing on CI
authorJoas Schilling <coding@schilljs.com>
Mon, 3 Apr 2023 05:23:34 +0000 (07:23 +0200)
committerbackportbot-nextcloud[bot] <backportbot-nextcloud[bot]@users.noreply.github.com>
Mon, 3 Apr 2023 12:48:50 +0000 (12:48 +0000)
Signed-off-by: Joas Schilling <coding@schilljs.com>
config/config.sample.php
lib/private/Security/RateLimiting/Backend/DatabaseBackend.php
lib/private/Security/RateLimiting/Backend/MemoryCacheBackend.php
lib/private/Server.php
tests/lib/Security/RateLimiting/Backend/MemoryCacheBackendTest.php

index 3371849957e943a227e3e6a7a9e52f90a3555a1e..cd6e35aee28df757261737e198471754e48cff9b 100644 (file)
@@ -284,7 +284,7 @@ $CONFIG = [
 
 /**
  * The interval at which token activity should be updated.
- * Increasing this value means that the last activty on the security page gets
+ * Increasing this value means that the last activity on the security page gets
  * more outdated.
  *
  * Tokens are still checked every 5 minutes for validity
index ea4bd87d6cd9ae676162336ec3b5284d52e33d94..d1631a8d0ae2d17d927ff3da88ad9f98b3baa830 100644 (file)
@@ -3,8 +3,10 @@
 declare(strict_types=1);
 
 /**
+ * @copyright Copyright (c) 2023 Joas Schilling <coding@schilljs.com>
  * @copyright Copyright (c) 2021 Lukas Reschke <lukas@statuscode.ch>
  *
+ * @author Joas Schilling <coding@schilljs.com>
  * @author Lukas Reschke <lukas@statuscode.ch>
  *
  * @license GNU AGPL version 3 or any later version
@@ -27,24 +29,25 @@ namespace OC\Security\RateLimiting\Backend;
 
 use OCP\AppFramework\Utility\ITimeFactory;
 use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCP\IConfig;
 use OCP\IDBConnection;
 
 class DatabaseBackend implements IBackend {
        private const TABLE_NAME = 'ratelimit_entries';
 
+       /** @var IConfig */
+       private $config;
        /** @var IDBConnection */
        private $dbConnection;
        /** @var ITimeFactory */
        private $timeFactory;
 
-       /**
-        * @param IDBConnection $dbConnection
-        * @param ITimeFactory $timeFactory
-        */
        public function __construct(
+               IConfig $config,
                IDBConnection $dbConnection,
                ITimeFactory $timeFactory
        ) {
+               $this->config = $config;
                $this->dbConnection = $dbConnection;
                $this->timeFactory = $timeFactory;
        }
@@ -115,7 +118,12 @@ class DatabaseBackend implements IBackend {
                        ->values([
                                'hash' => $qb->createNamedParameter($identifier, IQueryBuilder::PARAM_STR),
                                'delete_after' => $qb->createNamedParameter($deleteAfter, IQueryBuilder::PARAM_DATE),
-                       ])
-                       ->executeStatement();
+                       ]);
+
+               if (!$this->config->getSystemValueBool('ratelimit.protection.enabled', true)) {
+                       return;
+               }
+
+               $qb->executeStatement();
        }
 }
index f4880fb239c16ecd3c9a470a284f4dc86ff67a0a..4bcb459c64e0ff566b0924e5460132745e9c6437 100644 (file)
@@ -3,9 +3,11 @@
 declare(strict_types=1);
 
 /**
+ * @copyright Copyright (c) 2023 Joas Schilling <coding@schilljs.com>
  * @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch>
  *
  * @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Joas Schilling <coding@schilljs.com>
  * @author Lukas Reschke <lukas@statuscode.ch>
  * @author Morris Jobke <hey@morrisjobke.de>
  * @author Roeland Jago Douma <roeland@famdouma.nl>
@@ -31,6 +33,7 @@ namespace OC\Security\RateLimiting\Backend;
 use OCP\AppFramework\Utility\ITimeFactory;
 use OCP\ICache;
 use OCP\ICacheFactory;
+use OCP\IConfig;
 
 /**
  * Class MemoryCacheBackend uses the configured distributed memory cache for storing
@@ -39,17 +42,18 @@ use OCP\ICacheFactory;
  * @package OC\Security\RateLimiting\Backend
  */
 class MemoryCacheBackend implements IBackend {
+       /** @var IConfig */
+       private $config;
        /** @var ICache */
        private $cache;
        /** @var ITimeFactory */
        private $timeFactory;
 
-       /**
-        * @param ICacheFactory $cacheFactory
-        * @param ITimeFactory $timeFactory
-        */
-       public function __construct(ICacheFactory $cacheFactory,
-                                                               ITimeFactory $timeFactory) {
+       public function __construct(
+               IConfig $config,
+               ICacheFactory $cacheFactory,
+               ITimeFactory $timeFactory) {
+               $this->config = $config;
                $this->cache = $cacheFactory->createDistributed(__CLASS__);
                $this->timeFactory = $timeFactory;
        }
@@ -121,6 +125,11 @@ class MemoryCacheBackend implements IBackend {
 
                // Store the new attempt
                $existingAttempts[] = (string)($currentTime + $period);
+
+               if (!$this->config->getSystemValueBool('ratelimit.protection.enabled', true)) {
+                       return;
+               }
+
                $this->cache->set($identifier, json_encode($existingAttempts));
        }
 }
index d14ba471999348baa676af1d0bfe9b7c155f5044..9b6322548b2cb4f1c9d3f26517c1ecb9ebe0c8b5 100644 (file)
@@ -832,11 +832,13 @@ class Server extends ServerContainer implements IServerContainer {
                        $cacheFactory = $c->get(ICacheFactory::class);
                        if ($cacheFactory->isAvailable()) {
                                $backend = new \OC\Security\RateLimiting\Backend\MemoryCacheBackend(
+                                       $c->get(AllConfig::class),
                                        $this->get(ICacheFactory::class),
                                        new \OC\AppFramework\Utility\TimeFactory()
                                );
                        } else {
                                $backend = new \OC\Security\RateLimiting\Backend\DatabaseBackend(
+                                       $c->get(AllConfig::class),
                                        $c->get(IDBConnection::class),
                                        new \OC\AppFramework\Utility\TimeFactory()
                                );
index e7cb4a93a299ef97d58dca4555a7046cd560780a..a48b1211587b106f06d0eb1a2e92d83e053baa90 100644 (file)
@@ -28,9 +28,12 @@ use OC\Security\RateLimiting\Backend\MemoryCacheBackend;
 use OCP\AppFramework\Utility\ITimeFactory;
 use OCP\ICache;
 use OCP\ICacheFactory;
+use OCP\IConfig;
 use Test\TestCase;
 
 class MemoryCacheBackendTest extends TestCase {
+       /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */
+       private $config;
        /** @var ICacheFactory|\PHPUnit\Framework\MockObject\MockObject */
        private $cacheFactory;
        /** @var ITimeFactory|\PHPUnit\Framework\MockObject\MockObject */
@@ -43,6 +46,7 @@ class MemoryCacheBackendTest extends TestCase {
        protected function setUp(): void {
                parent::setUp();
 
+               $this->config = $this->createMock(IConfig::class);
                $this->cacheFactory = $this->createMock(ICacheFactory::class);
                $this->timeFactory = $this->createMock(ITimeFactory::class);
                $this->cache = $this->createMock(ICache::class);
@@ -53,7 +57,12 @@ class MemoryCacheBackendTest extends TestCase {
                        ->with('OC\Security\RateLimiting\Backend\MemoryCacheBackend')
                        ->willReturn($this->cache);
 
+               $this->config->method('getSystemValueBool')
+                       ->with('ratelimit.protection.enabled')
+                       ->willReturn(true);
+
                $this->memoryCache = new MemoryCacheBackend(
+                       $this->config,
                        $this->cacheFactory,
                        $this->timeFactory
                );