diff options
Diffstat (limited to 'apps/oauth2/lib')
3 files changed, 74 insertions, 6 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/lib/Migration/Version011601Date20230522143227.php b/apps/oauth2/lib/Migration/Version011601Date20230522143227.php index e258224bb39..43e3a2e26e3 100644 --- a/apps/oauth2/lib/Migration/Version011601Date20230522143227.php +++ b/apps/oauth2/lib/Migration/Version011601Date20230522143227.php @@ -49,7 +49,7 @@ class Version011601Date20230522143227 extends SimpleMigrationStep { $table = $schema->getTable('oauth2_clients'); if ($table->hasColumn('secret')) { $column = $table->getColumn('secret'); - $column->setLength(256); + $column->setLength(512); return $schema; } } diff --git a/apps/oauth2/lib/Migration/Version011602Date20230613160650.php b/apps/oauth2/lib/Migration/Version011602Date20230613160650.php new file mode 100644 index 00000000000..3e6ddf0ec50 --- /dev/null +++ b/apps/oauth2/lib/Migration/Version011602Date20230613160650.php @@ -0,0 +1,56 @@ +<?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\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; + +class Version011602Date20230613160650 extends SimpleMigrationStep { + + public function __construct( + ) { + } + + public function changeSchema(IOutput $output, Closure $schemaClosure, array $options) { + /** @var ISchemaWrapper $schema */ + $schema = $schemaClosure(); + + if ($schema->hasTable('oauth2_clients')) { + $table = $schema->getTable('oauth2_clients'); + if ($table->hasColumn('secret')) { + $column = $table->getColumn('secret'); + // we still change the column length in case Version011601Date20230522143227 + // has run before it was changed to set the length to 512 + $column->setLength(512); + return $schema; + } + } + + return null; + } +} |