aboutsummaryrefslogtreecommitdiffstats
path: root/apps/federation/lib/Controller/OCSAuthAPIController.php
diff options
context:
space:
mode:
Diffstat (limited to 'apps/federation/lib/Controller/OCSAuthAPIController.php')
-rw-r--r--apps/federation/lib/Controller/OCSAuthAPIController.php182
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);
}