diff options
Diffstat (limited to 'apps/federation/lib/Controller/OCSAuthAPIController.php')
-rw-r--r-- | apps/federation/lib/Controller/OCSAuthAPIController.php | 182 |
1 files changed, 70 insertions, 112 deletions
diff --git a/apps/federation/lib/Controller/OCSAuthAPIController.php b/apps/federation/lib/Controller/OCSAuthAPIController.php index dd9b94d0027..16b401be251 100644 --- a/apps/federation/lib/Controller/OCSAuthAPIController.php +++ b/apps/federation/lib/Controller/OCSAuthAPIController.php @@ -1,43 +1,28 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Bjoern Schiessle <bjoern@schiessle.org> - * @author Björn Schießle <bjoern@schiessle.org> - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Lukas Reschke <lukas@statuscode.ch> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <robin@icewind.nl> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OCA\Federation\Controller; use OCA\Federation\DbHandler; use OCA\Federation\TrustedServers; use OCP\AppFramework\Http; +use OCP\AppFramework\Http\Attribute\BruteForceProtection; +use OCP\AppFramework\Http\Attribute\NoCSRFRequired; +use OCP\AppFramework\Http\Attribute\OpenAPI; +use OCP\AppFramework\Http\Attribute\PublicPage; +use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\OCS\OCSForbiddenException; use OCP\AppFramework\OCSController; use OCP\AppFramework\Utility\ITimeFactory; use OCP\BackgroundJob\IJobList; -use OCP\ILogger; use OCP\IRequest; +use OCP\Security\Bruteforce\IThrottler; use OCP\Security\ISecureRandom; +use Psr\Log\LoggerInterface; /** * Class OCSAuthAPI @@ -46,103 +31,74 @@ use OCP\Security\ISecureRandom; * * @package OCA\Federation\Controller */ +#[OpenAPI(scope: OpenAPI::SCOPE_FEDERATION)] class OCSAuthAPIController extends OCSController { - - /** @var ISecureRandom */ - private $secureRandom; - - /** @var IJobList */ - private $jobList; - - /** @var TrustedServers */ - private $trustedServers; - - /** @var DbHandler */ - private $dbHandler; - - /** @var ILogger */ - private $logger; - - /** @var ITimeFactory */ - private $timeFactory; - - /** - * OCSAuthAPI constructor. - * - * @param string $appName - * @param IRequest $request - * @param ISecureRandom $secureRandom - * @param IJobList $jobList - * @param TrustedServers $trustedServers - * @param DbHandler $dbHandler - * @param ILogger $logger - * @param ITimeFactory $timeFactory - */ public function __construct( - $appName, + string $appName, IRequest $request, - ISecureRandom $secureRandom, - IJobList $jobList, - TrustedServers $trustedServers, - DbHandler $dbHandler, - ILogger $logger, - ITimeFactory $timeFactory + private ISecureRandom $secureRandom, + private IJobList $jobList, + private TrustedServers $trustedServers, + private DbHandler $dbHandler, + private LoggerInterface $logger, + private ITimeFactory $timeFactory, + private IThrottler $throttler, ) { parent::__construct($appName, $request); - - $this->secureRandom = $secureRandom; - $this->jobList = $jobList; - $this->trustedServers = $trustedServers; - $this->dbHandler = $dbHandler; - $this->logger = $logger; - $this->timeFactory = $timeFactory; } /** - * @NoCSRFRequired - * @PublicPage + * Request received to ask remote server for a shared secret, for legacy end-points * - * request received to ask remote server for a shared secret, for legacy end-points + * @param string $url URL of the server + * @param string $token Token of the server + * @return DataResponse<Http::STATUS_OK, list<empty>, array{}> + * @throws OCSForbiddenException Requesting shared secret is not allowed * - * @param string $url - * @param string $token - * @return Http\DataResponse - * @throws OCSForbiddenException + * 200: Shared secret requested successfully */ - public function requestSharedSecretLegacy($url, $token) { + #[NoCSRFRequired] + #[PublicPage] + #[BruteForceProtection(action: 'federationSharedSecret')] + public function requestSharedSecretLegacy(string $url, string $token): DataResponse { return $this->requestSharedSecret($url, $token); } /** - * @NoCSRFRequired - * @PublicPage + * Create shared secret and return it, for legacy end-points * - * create shared secret and return it, for legacy end-points + * @param string $url URL of the server + * @param string $token Token of the server + * @return DataResponse<Http::STATUS_OK, array{sharedSecret: string}, array{}> + * @throws OCSForbiddenException Getting shared secret is not allowed * - * @param string $url - * @param string $token - * @return Http\DataResponse - * @throws OCSForbiddenException + * 200: Shared secret returned */ - public function getSharedSecretLegacy($url, $token) { + #[NoCSRFRequired] + #[PublicPage] + #[BruteForceProtection(action: 'federationSharedSecret')] + public function getSharedSecretLegacy(string $url, string $token): DataResponse { return $this->getSharedSecret($url, $token); } /** - * @NoCSRFRequired - * @PublicPage + * Request received to ask remote server for a shared secret * - * request received to ask remote server for a shared secret + * @param string $url URL of the server + * @param string $token Token of the server + * @return DataResponse<Http::STATUS_OK, list<empty>, array{}> + * @throws OCSForbiddenException Requesting shared secret is not allowed * - * @param string $url - * @param string $token - * @return Http\DataResponse - * @throws OCSForbiddenException + * 200: Shared secret requested successfully */ - public function requestSharedSecret($url, $token) { + #[NoCSRFRequired] + #[PublicPage] + #[BruteForceProtection(action: 'federationSharedSecret')] + public function requestSharedSecret(string $url, string $token): DataResponse { if ($this->trustedServers->isTrustedServer($url) === false) { - $this->logger->error('remote server not trusted (' . $url . ') while requesting shared secret', ['app' => 'federation']); + $this->throttler->registerAttempt('federationSharedSecret', $this->request->getRemoteAddress()); + $this->logger->error('remote server not trusted (' . $url . ') while requesting shared secret'); throw new OCSForbiddenException(); } @@ -151,8 +107,7 @@ class OCSAuthAPIController extends OCSController { $localToken = $this->dbHandler->getToken($url); if (strcmp($localToken, $token) > 0) { $this->logger->info( - 'remote server (' . $url . ') presented lower token. We will initiate the exchange of the shared secret.', - ['app' => 'federation'] + 'remote server (' . $url . ') presented lower token. We will initiate the exchange of the shared secret.' ); throw new OCSForbiddenException(); } @@ -166,31 +121,34 @@ class OCSAuthAPIController extends OCSController { ] ); - return new Http\DataResponse(); + return new DataResponse(); } /** - * @NoCSRFRequired - * @PublicPage + * Create shared secret and return it * - * create shared secret and return it + * @param string $url URL of the server + * @param string $token Token of the server + * @return DataResponse<Http::STATUS_OK, array{sharedSecret: string}, array{}> + * @throws OCSForbiddenException Getting shared secret is not allowed * - * @param string $url - * @param string $token - * @return Http\DataResponse - * @throws OCSForbiddenException + * 200: Shared secret returned */ - public function getSharedSecret($url, $token) { + #[NoCSRFRequired] + #[PublicPage] + #[BruteForceProtection(action: 'federationSharedSecret')] + public function getSharedSecret(string $url, string $token): DataResponse { if ($this->trustedServers->isTrustedServer($url) === false) { - $this->logger->error('remote server not trusted (' . $url . ') while getting shared secret', ['app' => 'federation']); + $this->throttler->registerAttempt('federationSharedSecret', $this->request->getRemoteAddress()); + $this->logger->error('remote server not trusted (' . $url . ') while getting shared secret'); throw new OCSForbiddenException(); } if ($this->isValidToken($url, $token) === false) { + $this->throttler->registerAttempt('federationSharedSecret', $this->request->getRemoteAddress()); $expectedToken = $this->dbHandler->getToken($url); $this->logger->error( - 'remote server (' . $url . ') didn\'t send a valid token (got "' . $token . '" but expected "'. $expectedToken . '") while getting shared secret', - ['app' => 'federation'] + 'remote server (' . $url . ') didn\'t send a valid token (got "' . $token . '" but expected "' . $expectedToken . '") while getting shared secret' ); throw new OCSForbiddenException(); } @@ -199,12 +157,12 @@ class OCSAuthAPIController extends OCSController { $this->trustedServers->addSharedSecret($url, $sharedSecret); - return new Http\DataResponse([ + return new DataResponse([ 'sharedSecret' => $sharedSecret ]); } - protected function isValidToken($url, $token) { + protected function isValidToken(string $url, string $token): bool { $storedToken = $this->dbHandler->getToken($url); return hash_equals($storedToken, $token); } |