aboutsummaryrefslogtreecommitdiffstats
path: root/apps/oauth2
diff options
context:
space:
mode:
authorJulien Veyssier <julien-nc@posteo.net>2023-06-20 11:54:43 +0200
committerJulien Veyssier <julien-nc@posteo.net>2023-10-05 14:24:02 +0200
commit807f173dec7288945fca98548e80e43d3e401d12 (patch)
tree72918c69010f20e6f70b2dd0215bc8bea051cc9f /apps/oauth2
parentf3f2d9b9784ef3a9304543969a0a88cd1f1054d8 (diff)
downloadnextcloud-server-807f173dec7288945fca98548e80e43d3e401d12.tar.gz
nextcloud-server-807f173dec7288945fca98548e80e43d3e401d12.zip
make oauth2 authorization code expire after 10 minutes
Signed-off-by: Julien Veyssier <julien-nc@posteo.net>
Diffstat (limited to 'apps/oauth2')
-rw-r--r--apps/oauth2/composer/composer/autoload_classmap.php1
-rw-r--r--apps/oauth2/composer/composer/autoload_static.php1
-rw-r--r--apps/oauth2/lib/Controller/OauthApiController.php34
-rw-r--r--apps/oauth2/lib/Db/AccessToken.php5
-rw-r--r--apps/oauth2/lib/Migration/Version011603Date20230620111039.php57
-rw-r--r--apps/oauth2/tests/Controller/OauthApiControllerTest.php6
6 files changed, 97 insertions, 7 deletions
diff --git a/apps/oauth2/composer/composer/autoload_classmap.php b/apps/oauth2/composer/composer/autoload_classmap.php
index ffc00e254de..77068f4e9c0 100644
--- a/apps/oauth2/composer/composer/autoload_classmap.php
+++ b/apps/oauth2/composer/composer/autoload_classmap.php
@@ -21,5 +21,6 @@ return array(
'OCA\\OAuth2\\Migration\\Version010402Date20190107124745' => $baseDir . '/../lib/Migration/Version010402Date20190107124745.php',
'OCA\\OAuth2\\Migration\\Version011601Date20230522143227' => $baseDir . '/../lib/Migration/Version011601Date20230522143227.php',
'OCA\\OAuth2\\Migration\\Version011602Date20230613160650' => $baseDir . '/../lib/Migration/Version011602Date20230613160650.php',
+ 'OCA\\OAuth2\\Migration\\Version011603Date20230620111039' => $baseDir . '/../lib/Migration/Version011603Date20230620111039.php',
'OCA\\OAuth2\\Settings\\Admin' => $baseDir . '/../lib/Settings/Admin.php',
);
diff --git a/apps/oauth2/composer/composer/autoload_static.php b/apps/oauth2/composer/composer/autoload_static.php
index 759e4fc3b79..2fb8a4f17a9 100644
--- a/apps/oauth2/composer/composer/autoload_static.php
+++ b/apps/oauth2/composer/composer/autoload_static.php
@@ -36,6 +36,7 @@ class ComposerStaticInitOAuth2
'OCA\\OAuth2\\Migration\\Version010402Date20190107124745' => __DIR__ . '/..' . '/../lib/Migration/Version010402Date20190107124745.php',
'OCA\\OAuth2\\Migration\\Version011601Date20230522143227' => __DIR__ . '/..' . '/../lib/Migration/Version011601Date20230522143227.php',
'OCA\\OAuth2\\Migration\\Version011602Date20230613160650' => __DIR__ . '/..' . '/../lib/Migration/Version011602Date20230613160650.php',
+ 'OCA\\OAuth2\\Migration\\Version011603Date20230620111039' => __DIR__ . '/..' . '/../lib/Migration/Version011603Date20230620111039.php',
'OCA\\OAuth2\\Settings\\Admin' => __DIR__ . '/..' . '/../lib/Settings/Admin.php',
);
diff --git a/apps/oauth2/lib/Controller/OauthApiController.php b/apps/oauth2/lib/Controller/OauthApiController.php
index af1205be0d7..443db314f2a 100644
--- a/apps/oauth2/lib/Controller/OauthApiController.php
+++ b/apps/oauth2/lib/Controller/OauthApiController.php
@@ -39,6 +39,7 @@ use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\JSONResponse;
use OCP\AppFramework\Utility\ITimeFactory;
+use OCP\DB\Exception;
use OCP\IRequest;
use OCP\Security\Bruteforce\IThrottler;
use OCP\Security\ICrypto;
@@ -46,6 +47,8 @@ use OCP\Security\ISecureRandom;
use Psr\Log\LoggerInterface;
class OauthApiController extends Controller {
+ // the authorization code expires after 10 minutes
+ private const AUTHORIZATION_CODE_EXPIRES_AFTER = 10 * 60;
public function __construct(
string $appName,
@@ -57,7 +60,8 @@ class OauthApiController extends Controller {
private ISecureRandom $secureRandom,
private ITimeFactory $time,
private LoggerInterface $logger,
- private IThrottler $throttler
+ private IThrottler $throttler,
+ private ITimeFactory $timeFactory,
) {
parent::__construct($appName, $request);
}
@@ -70,16 +74,20 @@ class OauthApiController extends Controller {
* Get a token
*
* @param string $grant_type Token type that should be granted
- * @param string $code Code of the flow
- * @param string $refresh_token Refresh token
- * @param string $client_id Client ID
- * @param string $client_secret Client secret
+ * @param string|null $code Code of the flow
+ * @param string|null $refresh_token Refresh token
+ * @param string|null $client_id Client ID
+ * @param string|null $client_secret Client secret
+ * @throws Exception
* @return JSONResponse<Http::STATUS_OK, array{access_token: string, token_type: string, expires_in: int, refresh_token: string, user_id: string}, array{}>|JSONResponse<Http::STATUS_BAD_REQUEST, array{error: string}, array{}>
*
* 200: Token returned
* 400: Getting token is not possible
*/
- public function getToken($grant_type, $code, $refresh_token, $client_id, $client_secret): JSONResponse {
+ public function getToken(
+ string $grant_type, ?string $code, ?string $refresh_token,
+ ?string $client_id, ?string $client_secret
+ ): JSONResponse {
// We only handle two types
if ($grant_type !== 'authorization_code' && $grant_type !== 'refresh_token') {
@@ -105,6 +113,20 @@ class OauthApiController extends Controller {
return $response;
}
+ // check authorization code expiration
+ if ($grant_type === 'authorization_code') {
+ $now = $this->timeFactory->now()->getTimestamp();
+ $tokenCreatedAt = $accessToken->getCreatedAt();
+ if ($tokenCreatedAt < $now - self::AUTHORIZATION_CODE_EXPIRES_AFTER) {
+ $response = new JSONResponse([
+ 'error' => 'invalid_request',
+ ], Http::STATUS_BAD_REQUEST);
+ $expiredSince = $now - self::AUTHORIZATION_CODE_EXPIRES_AFTER - $tokenCreatedAt;
+ $response->throttle(['invalid_request' => 'authorization_code_expired', 'expired_since' => $expiredSince]);
+ return $response;
+ }
+ }
+
try {
$client = $this->clientMapper->getByUid($accessToken->getClientId());
} catch (ClientNotFoundException $e) {
diff --git a/apps/oauth2/lib/Db/AccessToken.php b/apps/oauth2/lib/Db/AccessToken.php
index 26c830c64ad..99404850e4f 100644
--- a/apps/oauth2/lib/Db/AccessToken.php
+++ b/apps/oauth2/lib/Db/AccessToken.php
@@ -34,6 +34,8 @@ use OCP\AppFramework\Db\Entity;
* @method void setEncryptedToken(string $token)
* @method string getHashedCode()
* @method void setHashedCode(string $token)
+ * @method int getCreatedAt()
+ * @method void setCreatedAt(int $createdAt)
*/
class AccessToken extends Entity {
/** @var int */
@@ -44,6 +46,8 @@ class AccessToken extends Entity {
protected $hashedCode;
/** @var string */
protected $encryptedToken;
+ /** @var int */
+ protected $createdAt;
public function __construct() {
$this->addType('id', 'int');
@@ -51,5 +55,6 @@ class AccessToken extends Entity {
$this->addType('clientId', 'int');
$this->addType('hashedCode', 'string');
$this->addType('encryptedToken', 'string');
+ $this->addType('created_at', 'int');
}
}
diff --git a/apps/oauth2/lib/Migration/Version011603Date20230620111039.php b/apps/oauth2/lib/Migration/Version011603Date20230620111039.php
new file mode 100644
index 00000000000..279bf6cffaa
--- /dev/null
+++ b/apps/oauth2/lib/Migration/Version011603Date20230620111039.php
@@ -0,0 +1,57 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright 2023, Julien Veyssier <julien-nc@posteo.net>
+ *
+ * @author Julien Veyssier <julien-nc@posteo.net>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OCA\OAuth2\Migration;
+
+use Closure;
+use OCP\DB\ISchemaWrapper;
+use OCP\DB\Types;
+use OCP\Migration\IOutput;
+use OCP\Migration\SimpleMigrationStep;
+
+class Version011603Date20230620111039 extends SimpleMigrationStep {
+
+ public function __construct(
+ ) {
+ }
+
+ public function changeSchema(IOutput $output, Closure $schemaClosure, array $options) {
+ /** @var ISchemaWrapper $schema */
+ $schema = $schemaClosure();
+
+ if ($schema->hasTable('oauth2_access_tokens')) {
+ $table = $schema->getTable('oauth2_access_tokens');
+ if (!$table->hasColumn('created_at')) {
+ $table->addColumn('created_at', Types::BIGINT, [
+ 'notnull' => true,
+ 'default' => 0,
+ ]);
+ return $schema;
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/apps/oauth2/tests/Controller/OauthApiControllerTest.php b/apps/oauth2/tests/Controller/OauthApiControllerTest.php
index a7dc35943f0..e8ee03cb6e4 100644
--- a/apps/oauth2/tests/Controller/OauthApiControllerTest.php
+++ b/apps/oauth2/tests/Controller/OauthApiControllerTest.php
@@ -70,6 +70,8 @@ class OauthApiControllerTest extends TestCase {
private $throttler;
/** @var LoggerInterface|\PHPUnit\Framework\MockObject\MockObject */
private $logger;
+ /** @var ITimeFactory|\PHPUnit\Framework\MockObject\MockObject */
+ private $timeFactory;
/** @var OauthApiController */
private $oauthApiController;
@@ -85,6 +87,7 @@ class OauthApiControllerTest extends TestCase {
$this->time = $this->createMock(ITimeFactory::class);
$this->throttler = $this->createMock(IThrottler::class);
$this->logger = $this->createMock(LoggerInterface::class);
+ $this->timeFactory = $this->createMock(ITimeFactory::class);
$this->oauthApiController = new OauthApiController(
'oauth2',
@@ -96,7 +99,8 @@ class OauthApiControllerTest extends TestCase {
$this->secureRandom,
$this->time,
$this->logger,
- $this->throttler
+ $this->throttler,
+ $this->timeFactory
);
}