зеркало из https://github.com/nextcloud/server.git
feat(core): Add OCS endpoint for confirming the user password
Signed-off-by: provokateurin <kate@provokateurin.de>
This commit is contained in:
Родитель
d95e500e45
Коммит
6243a9471d
|
@ -31,7 +31,9 @@ namespace OC\Core\Controller;
|
|||
use OC\Authentication\Events\AppPasswordCreatedEvent;
|
||||
use OC\Authentication\Token\IProvider;
|
||||
use OC\Authentication\Token\IToken;
|
||||
use OC\User\Session;
|
||||
use OCP\AppFramework\Http;
|
||||
use OCP\AppFramework\Http\Attribute\UseSession;
|
||||
use OCP\AppFramework\Http\DataResponse;
|
||||
use OCP\AppFramework\OCS\OCSForbiddenException;
|
||||
use OCP\Authentication\Exceptions\CredentialsUnavailableException;
|
||||
|
@ -41,6 +43,8 @@ use OCP\Authentication\LoginCredentials\IStore;
|
|||
use OCP\EventDispatcher\IEventDispatcher;
|
||||
use OCP\IRequest;
|
||||
use OCP\ISession;
|
||||
use OCP\IUserManager;
|
||||
use OCP\Security\Bruteforce\IThrottler;
|
||||
use OCP\Security\ISecureRandom;
|
||||
|
||||
class AppPasswordController extends \OCP\AppFramework\OCSController {
|
||||
|
@ -52,6 +56,9 @@ class AppPasswordController extends \OCP\AppFramework\OCSController {
|
|||
private IProvider $tokenProvider,
|
||||
private IStore $credentialStore,
|
||||
private IEventDispatcher $eventDispatcher,
|
||||
private Session $userSession,
|
||||
private IUserManager $userManager,
|
||||
private IThrottler $throttler,
|
||||
) {
|
||||
parent::__construct($appName, $request);
|
||||
}
|
||||
|
@ -165,4 +172,33 @@ class AppPasswordController extends \OCP\AppFramework\OCSController {
|
|||
'apppassword' => $newToken,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm the user password
|
||||
*
|
||||
* @NoAdminRequired
|
||||
* @BruteForceProtection(action=sudo)
|
||||
*
|
||||
* @param string $password The password of the user
|
||||
*
|
||||
* @return DataResponse<Http::STATUS_OK, array{lastLogin: int}, array{}>|DataResponse<Http::STATUS_FORBIDDEN, array<empty>, array{}>
|
||||
*
|
||||
* 200: Password confirmation succeeded
|
||||
* 403: Password confirmation failed
|
||||
*/
|
||||
#[UseSession]
|
||||
public function confirmUserPassword(string $password): DataResponse {
|
||||
$loginName = $this->userSession->getLoginName();
|
||||
$loginResult = $this->userManager->checkPassword($loginName, $password);
|
||||
if ($loginResult === false) {
|
||||
$response = new DataResponse([], Http::STATUS_FORBIDDEN);
|
||||
$response->throttle(['loginName' => $loginName]);
|
||||
return $response;
|
||||
}
|
||||
|
||||
$confirmTimestamp = time();
|
||||
$this->session->set('last-password-confirm', $confirmTimestamp);
|
||||
$this->throttler->resetDelay($this->request->getRemoteAddress(), 'sudo', ['loginName' => $loginName]);
|
||||
return new DataResponse(['lastLogin' => $confirmTimestamp], Http::STATUS_OK);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2475,6 +2475,113 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/ocs/v2.php/core/apppassword/confirm": {
|
||||
"put": {
|
||||
"operationId": "app_password-confirm-user-password",
|
||||
"summary": "Confirm the user password",
|
||||
"tags": [
|
||||
"app_password"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"bearer_auth": []
|
||||
},
|
||||
{
|
||||
"basic_auth": []
|
||||
}
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "password",
|
||||
"in": "query",
|
||||
"description": "The password of the user",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "OCS-APIRequest",
|
||||
"in": "header",
|
||||
"description": "Required to be true for the API request to pass",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Password confirmation succeeded",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"lastLogin"
|
||||
],
|
||||
"properties": {
|
||||
"lastLogin": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "Password confirmation failed",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ocs/v2.php/hovercard/v1/{userId}": {
|
||||
"get": {
|
||||
"operationId": "hover_card-get-user",
|
||||
|
|
|
@ -123,6 +123,7 @@ $application->registerRoutes($this, [
|
|||
['root' => '/core', 'name' => 'AppPassword#getAppPassword', 'url' => '/getapppassword', 'verb' => 'GET'],
|
||||
['root' => '/core', 'name' => 'AppPassword#rotateAppPassword', 'url' => '/apppassword/rotate', 'verb' => 'POST'],
|
||||
['root' => '/core', 'name' => 'AppPassword#deleteAppPassword', 'url' => '/apppassword', 'verb' => 'DELETE'],
|
||||
['root' => '/core', 'name' => 'AppPassword#confirmUserPassword', 'url' => '/apppassword/confirm', 'verb' => 'PUT'],
|
||||
|
||||
['root' => '/hovercard', 'name' => 'HoverCard#getUser', 'url' => '/v1/{userId}', 'verb' => 'GET'],
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ use OC\Authentication\Exceptions\InvalidTokenException;
|
|||
use OC\Authentication\Token\IProvider;
|
||||
use OC\Authentication\Token\IToken;
|
||||
use OC\Core\Controller\AppPasswordController;
|
||||
use OC\User\Session;
|
||||
use OCP\AppFramework\Http\DataResponse;
|
||||
use OCP\AppFramework\OCS\OCSForbiddenException;
|
||||
use OCP\Authentication\Exceptions\CredentialsUnavailableException;
|
||||
|
@ -38,6 +39,8 @@ use OCP\Authentication\LoginCredentials\IStore;
|
|||
use OCP\EventDispatcher\IEventDispatcher;
|
||||
use OCP\IRequest;
|
||||
use OCP\ISession;
|
||||
use OCP\IUserManager;
|
||||
use OCP\Security\Bruteforce\IThrottler;
|
||||
use OCP\Security\ISecureRandom;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use Test\TestCase;
|
||||
|
@ -61,6 +64,15 @@ class AppPasswordControllerTest extends TestCase {
|
|||
/** @var IEventDispatcher|\PHPUnit\Framework\MockObject\MockObject */
|
||||
private $eventDispatcher;
|
||||
|
||||
/** @var Session|MockObject */
|
||||
private $userSession;
|
||||
|
||||
/** @var IUserManager|MockObject */
|
||||
private $userManager;
|
||||
|
||||
/** @var IThrottler|MockObject */
|
||||
private $throttler;
|
||||
|
||||
/** @var AppPasswordController */
|
||||
private $controller;
|
||||
|
||||
|
@ -73,6 +85,9 @@ class AppPasswordControllerTest extends TestCase {
|
|||
$this->credentialStore = $this->createMock(IStore::class);
|
||||
$this->request = $this->createMock(IRequest::class);
|
||||
$this->eventDispatcher = $this->createMock(IEventDispatcher::class);
|
||||
$this->userSession = $this->createMock(Session::class);
|
||||
$this->userManager = $this->createMock(IUserManager::class);
|
||||
$this->throttler = $this->createMock(IThrottler::class);
|
||||
|
||||
$this->controller = new AppPasswordController(
|
||||
'core',
|
||||
|
@ -81,7 +96,10 @@ class AppPasswordControllerTest extends TestCase {
|
|||
$this->random,
|
||||
$this->tokenProvider,
|
||||
$this->credentialStore,
|
||||
$this->eventDispatcher
|
||||
$this->eventDispatcher,
|
||||
$this->userSession,
|
||||
$this->userManager,
|
||||
$this->throttler
|
||||
);
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче