diff options
-rw-r--r-- | apps/oauth2/lib/Controller/OauthApiController.php | 22 | ||||
-rw-r--r-- | apps/oauth2/tests/Controller/OauthApiControllerTest.php | 6 | ||||
-rw-r--r-- | core/Command/User/Add.php | 10 | ||||
-rw-r--r-- | core/Command/User/AddAppPassword.php | 19 | ||||
-rw-r--r-- | core/Command/User/Delete.php | 11 | ||||
-rw-r--r-- | core/Command/User/Disable.php | 7 | ||||
-rw-r--r-- | core/Command/User/Enable.php | 7 | ||||
-rw-r--r-- | core/Command/User/Info.php | 10 | ||||
-rw-r--r-- | core/Command/User/LastSeen.php | 7 | ||||
-rw-r--r-- | core/Command/User/ListCommand.php | 11 | ||||
-rw-r--r-- | core/Command/User/Report.php | 11 | ||||
-rw-r--r-- | core/Command/User/ResetPassword.php | 10 | ||||
-rw-r--r-- | core/Command/User/Setting.php | 10 | ||||
-rw-r--r-- | package-lock.json | 14 | ||||
-rw-r--r-- | package.json | 2 |
15 files changed, 73 insertions, 84 deletions
diff --git a/apps/oauth2/lib/Controller/OauthApiController.php b/apps/oauth2/lib/Controller/OauthApiController.php index badafd3bb77..e07a2c2de15 100644 --- a/apps/oauth2/lib/Controller/OauthApiController.php +++ b/apps/oauth2/lib/Controller/OauthApiController.php @@ -64,6 +64,7 @@ class OauthApiController extends Controller { /** * @PublicPage * @NoCSRFRequired + * @BruteForceProtection(action=oauth2GetToken) * * @param string $grant_type * @param string $code @@ -76,9 +77,11 @@ class OauthApiController extends Controller { // We only handle two types if ($grant_type !== 'authorization_code' && $grant_type !== 'refresh_token') { - return new JSONResponse([ + $response = new JSONResponse([ 'error' => 'invalid_grant', ], Http::STATUS_BAD_REQUEST); + $response->throttle(['invalid_grant' => $grant_type]); + return $response; } // We handle the initial and refresh tokens the same way @@ -89,17 +92,21 @@ class OauthApiController extends Controller { try { $accessToken = $this->accessTokenMapper->getByCode($code); } catch (AccessTokenNotFoundException $e) { - return new JSONResponse([ + $response = new JSONResponse([ 'error' => 'invalid_request', ], Http::STATUS_BAD_REQUEST); + $response->throttle(['invalid_request' => 'token not found', 'code' => $code]); + return $response; } try { $client = $this->clientMapper->getByUid($accessToken->getClientId()); } catch (ClientNotFoundException $e) { - return new JSONResponse([ + $response = new JSONResponse([ 'error' => 'invalid_request', ], Http::STATUS_BAD_REQUEST); + $response->throttle(['invalid_request' => 'client not found', 'client_id' => $accessToken->getClientId()]); + return $response; } if (isset($this->request->server['PHP_AUTH_USER'])) { @@ -111,15 +118,18 @@ class OauthApiController extends Controller { $storedClientSecret = $this->crypto->decrypt($client->getSecret()); } catch (\Exception $e) { $this->logger->error('OAuth client secret decryption error', ['exception' => $e]); + // we don't throttle here because it might not be a bruteforce attack return new JSONResponse([ 'error' => 'invalid_client', ], Http::STATUS_BAD_REQUEST); } // The client id and secret must match. Else we don't provide an access token! if ($client->getClientIdentifier() !== $client_id || $storedClientSecret !== $client_secret) { - return new JSONResponse([ + $response = new JSONResponse([ 'error' => 'invalid_client', ], Http::STATUS_BAD_REQUEST); + $response->throttle(['invalid_client' => 'client ID or secret does not match']); + return $response; } $decryptedToken = $this->crypto->decrypt($accessToken->getEncryptedToken(), $code); @@ -132,9 +142,11 @@ class OauthApiController extends Controller { } catch (InvalidTokenException $e) { //We can't do anything... $this->accessTokenMapper->delete($accessToken); - return new JSONResponse([ + $response = new JSONResponse([ 'error' => 'invalid_request', ], Http::STATUS_BAD_REQUEST); + $response->throttle(['invalid_request' => 'token is invalid']); + return $response; } // Rotate the apptoken (so the old one becomes invalid basically) diff --git a/apps/oauth2/tests/Controller/OauthApiControllerTest.php b/apps/oauth2/tests/Controller/OauthApiControllerTest.php index eb9311dbbc7..c65302532a9 100644 --- a/apps/oauth2/tests/Controller/OauthApiControllerTest.php +++ b/apps/oauth2/tests/Controller/OauthApiControllerTest.php @@ -104,6 +104,7 @@ class OauthApiControllerTest extends TestCase { $expected = new JSONResponse([ 'error' => 'invalid_grant', ], Http::STATUS_BAD_REQUEST); + $expected->throttle(['invalid_grant' => 'foo']); $this->assertEquals($expected, $this->oauthApiController->getToken('foo', null, null, null, null)); } @@ -112,6 +113,7 @@ class OauthApiControllerTest extends TestCase { $expected = new JSONResponse([ 'error' => 'invalid_request', ], Http::STATUS_BAD_REQUEST); + $expected->throttle(['invalid_request' => 'token not found', 'code' => 'invalidcode']); $this->accessTokenMapper->method('getByCode') ->with('invalidcode') @@ -124,6 +126,7 @@ class OauthApiControllerTest extends TestCase { $expected = new JSONResponse([ 'error' => 'invalid_request', ], Http::STATUS_BAD_REQUEST); + $expected->throttle(['invalid_request' => 'token not found', 'code' => 'invalidrefresh']); $this->accessTokenMapper->method('getByCode') ->with('invalidrefresh') @@ -136,6 +139,7 @@ class OauthApiControllerTest extends TestCase { $expected = new JSONResponse([ 'error' => 'invalid_request', ], Http::STATUS_BAD_REQUEST); + $expected->throttle(['invalid_request' => 'client not found', 'client_id' => 42]); $accessToken = new AccessToken(); $accessToken->setClientId(42); @@ -169,6 +173,7 @@ class OauthApiControllerTest extends TestCase { $expected = new JSONResponse([ 'error' => 'invalid_client', ], Http::STATUS_BAD_REQUEST); + $expected->throttle(['invalid_client' => 'client ID or secret does not match']); $accessToken = new AccessToken(); $accessToken->setClientId(42); @@ -191,6 +196,7 @@ class OauthApiControllerTest extends TestCase { $expected = new JSONResponse([ 'error' => 'invalid_request', ], Http::STATUS_BAD_REQUEST); + $expected->throttle(['invalid_request' => 'token is invalid']); $accessToken = new AccessToken(); $accessToken->setClientId(42); diff --git a/core/Command/User/Add.php b/core/Command/User/Add.php index 24d11fbee6e..5e8ab92070d 100644 --- a/core/Command/User/Add.php +++ b/core/Command/User/Add.php @@ -39,13 +39,11 @@ use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Question\Question; class Add extends Command { - protected IUserManager $userManager; - protected IGroupManager $groupManager; - - public function __construct(IUserManager $userManager, IGroupManager $groupManager) { + public function __construct( + protected IUserManager $userManager, + protected IGroupManager $groupManager, + ) { parent::__construct(); - $this->userManager = $userManager; - $this->groupManager = $groupManager; } protected function configure() { diff --git a/core/Command/User/AddAppPassword.php b/core/Command/User/AddAppPassword.php index ec39cdc974e..8c506c8510e 100644 --- a/core/Command/User/AddAppPassword.php +++ b/core/Command/User/AddAppPassword.php @@ -41,19 +41,12 @@ use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Question\Question; class AddAppPassword extends Command { - protected IUserManager $userManager; - protected IProvider $tokenProvider; - private ISecureRandom $random; - private IEventDispatcher $eventDispatcher; - - public function __construct(IUserManager $userManager, - IProvider $tokenProvider, - ISecureRandom $random, - IEventDispatcher $eventDispatcher) { - $this->tokenProvider = $tokenProvider; - $this->userManager = $userManager; - $this->random = $random; - $this->eventDispatcher = $eventDispatcher; + public function __construct( + protected IUserManager $userManager, + protected IProvider $tokenProvider, + private ISecureRandom $random, + private IEventDispatcher $eventDispatcher, + ) { parent::__construct(); } diff --git a/core/Command/User/Delete.php b/core/Command/User/Delete.php index 9624f04fa18..94390a3f070 100644 --- a/core/Command/User/Delete.php +++ b/core/Command/User/Delete.php @@ -33,14 +33,9 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class Delete extends Base { - /** @var IUserManager */ - protected $userManager; - - /** - * @param IUserManager $userManager - */ - public function __construct(IUserManager $userManager) { - $this->userManager = $userManager; + public function __construct( + protected IUserManager $userManager, + ) { parent::__construct(); } diff --git a/core/Command/User/Disable.php b/core/Command/User/Disable.php index bc819f39e1d..3fdf6220f45 100644 --- a/core/Command/User/Disable.php +++ b/core/Command/User/Disable.php @@ -32,10 +32,9 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class Disable extends Base { - protected IUserManager $userManager; - - public function __construct(IUserManager $userManager) { - $this->userManager = $userManager; + public function __construct( + protected IUserManager $userManager, + ) { parent::__construct(); } diff --git a/core/Command/User/Enable.php b/core/Command/User/Enable.php index f4e16eec4af..2055bd30cec 100644 --- a/core/Command/User/Enable.php +++ b/core/Command/User/Enable.php @@ -32,10 +32,9 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class Enable extends Base { - protected IUserManager $userManager; - - public function __construct(IUserManager $userManager) { - $this->userManager = $userManager; + public function __construct( + protected IUserManager $userManager, + ) { parent::__construct(); } diff --git a/core/Command/User/Info.php b/core/Command/User/Info.php index 1e89a8d0911..a8fb62099e2 100644 --- a/core/Command/User/Info.php +++ b/core/Command/User/Info.php @@ -35,12 +35,10 @@ use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class Info extends Base { - protected IUserManager $userManager; - protected IGroupManager $groupManager; - - public function __construct(IUserManager $userManager, IGroupManager $groupManager) { - $this->userManager = $userManager; - $this->groupManager = $groupManager; + public function __construct( + protected IUserManager $userManager, + protected IGroupManager $groupManager, + ) { parent::__construct(); } diff --git a/core/Command/User/LastSeen.php b/core/Command/User/LastSeen.php index 5ea6c64d249..90ddb6992d9 100644 --- a/core/Command/User/LastSeen.php +++ b/core/Command/User/LastSeen.php @@ -34,10 +34,9 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class LastSeen extends Base { - protected IUserManager $userManager; - - public function __construct(IUserManager $userManager) { - $this->userManager = $userManager; + public function __construct( + protected IUserManager $userManager, + ) { parent::__construct(); } diff --git a/core/Command/User/ListCommand.php b/core/Command/User/ListCommand.php index bf4bf7f030e..f25d6c2dae9 100644 --- a/core/Command/User/ListCommand.php +++ b/core/Command/User/ListCommand.php @@ -33,13 +33,10 @@ use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class ListCommand extends Base { - protected IUserManager $userManager; - protected IGroupManager $groupManager; - - public function __construct(IUserManager $userManager, - IGroupManager $groupManager) { - $this->userManager = $userManager; - $this->groupManager = $groupManager; + public function __construct( + protected IUserManager $userManager, + protected IGroupManager $groupManager, + ) { parent::__construct(); } diff --git a/core/Command/User/Report.php b/core/Command/User/Report.php index e080a617258..74ab5c29cc1 100644 --- a/core/Command/User/Report.php +++ b/core/Command/User/Report.php @@ -41,13 +41,10 @@ use Symfony\Component\Console\Output\OutputInterface; class Report extends Command { public const DEFAULT_COUNT_DIRS_MAX_USERS = 500; - protected IUserManager $userManager; - private IConfig $config; - - public function __construct(IUserManager $userManager, - IConfig $config) { - $this->userManager = $userManager; - $this->config = $config; + public function __construct( + protected IUserManager $userManager, + private IConfig $config, + ) { parent::__construct(); } diff --git a/core/Command/User/ResetPassword.php b/core/Command/User/ResetPassword.php index 294cea38b71..6719f893be3 100644 --- a/core/Command/User/ResetPassword.php +++ b/core/Command/User/ResetPassword.php @@ -41,13 +41,11 @@ use Symfony\Component\Console\Question\ConfirmationQuestion; use Symfony\Component\Console\Question\Question; class ResetPassword extends Base { - protected IUserManager $userManager; - private IAppManager $appManager; - - public function __construct(IUserManager $userManager, IAppManager $appManager) { + public function __construct( + protected IUserManager $userManager, + private IAppManager $appManager, + ) { parent::__construct(); - $this->userManager = $userManager; - $this->appManager = $appManager; } protected function configure() { diff --git a/core/Command/User/Setting.php b/core/Command/User/Setting.php index fac5c3c976c..8a8736fdaa2 100644 --- a/core/Command/User/Setting.php +++ b/core/Command/User/Setting.php @@ -36,13 +36,11 @@ use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class Setting extends Base { - protected IUserManager $userManager; - protected IConfig $config; - - public function __construct(IUserManager $userManager, IConfig $config) { + public function __construct( + protected IUserManager $userManager, + protected IConfig $config, + ) { parent::__construct(); - $this->userManager = $userManager; - $this->config = $config; } protected function configure() { diff --git a/package-lock.json b/package-lock.json index ad8f605141f..413174b1e53 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,7 @@ "@nextcloud/capabilities": "^1.0.4", "@nextcloud/dialogs": "^4.0.1", "@nextcloud/event-bus": "^3.1.0", - "@nextcloud/files": "^3.0.0-beta.9", + "@nextcloud/files": "^3.0.0-beta.10", "@nextcloud/initial-state": "^2.0.0", "@nextcloud/l10n": "^2.1.0", "@nextcloud/logger": "^2.5.0", @@ -3429,9 +3429,9 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/@nextcloud/files": { - "version": "3.0.0-beta.9", - "resolved": "https://registry.npmjs.org/@nextcloud/files/-/files-3.0.0-beta.9.tgz", - "integrity": "sha512-K4k8wmxNmIeJz5VmLzGiYH9wc6rv0i9BcVOL9xuSHPwf/ukJZzw/hKHnE1ohBzIKfCZUS619dsa2hI/OjRa3Lg==", + "version": "3.0.0-beta.10", + "resolved": "https://registry.npmjs.org/@nextcloud/files/-/files-3.0.0-beta.10.tgz", + "integrity": "sha512-cAh2HWkFgktub/GW07qx/kYz9nR2E/D+Zk/qXF8JW7BL/+gNy4/wOJ7mfDisUZy0gCZKZTV0v5wtEkIHwNdTyA==", "dependencies": { "@nextcloud/auth": "^2.0.0", "@nextcloud/l10n": "^2.1.0", @@ -26595,9 +26595,9 @@ } }, "@nextcloud/files": { - "version": "3.0.0-beta.9", - "resolved": "https://registry.npmjs.org/@nextcloud/files/-/files-3.0.0-beta.9.tgz", - "integrity": "sha512-K4k8wmxNmIeJz5VmLzGiYH9wc6rv0i9BcVOL9xuSHPwf/ukJZzw/hKHnE1ohBzIKfCZUS619dsa2hI/OjRa3Lg==", + "version": "3.0.0-beta.10", + "resolved": "https://registry.npmjs.org/@nextcloud/files/-/files-3.0.0-beta.10.tgz", + "integrity": "sha512-cAh2HWkFgktub/GW07qx/kYz9nR2E/D+Zk/qXF8JW7BL/+gNy4/wOJ7mfDisUZy0gCZKZTV0v5wtEkIHwNdTyA==", "requires": { "@nextcloud/auth": "^2.0.0", "@nextcloud/l10n": "^2.1.0", diff --git a/package.json b/package.json index 6f771a0f097..e96e0fba95c 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "@nextcloud/capabilities": "^1.0.4", "@nextcloud/dialogs": "^4.0.1", "@nextcloud/event-bus": "^3.1.0", - "@nextcloud/files": "^3.0.0-beta.9", + "@nextcloud/files": "^3.0.0-beta.10", "@nextcloud/initial-state": "^2.0.0", "@nextcloud/l10n": "^2.1.0", "@nextcloud/logger": "^2.5.0", |