aboutsummaryrefslogtreecommitdiffstats
path: root/core/Controller/ClientFlowLoginV2Controller.php
diff options
context:
space:
mode:
Diffstat (limited to 'core/Controller/ClientFlowLoginV2Controller.php')
-rw-r--r--core/Controller/ClientFlowLoginV2Controller.php118
1 files changed, 79 insertions, 39 deletions
diff --git a/core/Controller/ClientFlowLoginV2Controller.php b/core/Controller/ClientFlowLoginV2Controller.php
index 3c57b190593..19c1f9ce251 100644
--- a/core/Controller/ClientFlowLoginV2Controller.php
+++ b/core/Controller/ClientFlowLoginV2Controller.php
@@ -27,16 +27,20 @@ declare(strict_types=1);
*/
namespace OC\Core\Controller;
-use OC\Authentication\Exceptions\InvalidTokenException;
use OC\Core\Db\LoginFlowV2;
use OC\Core\Exception\LoginFlowV2NotFoundException;
use OC\Core\Service\LoginFlowV2Service;
+use OCA\Core\ResponseDefinitions;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\Attribute\FrontpageRoute;
+use OCP\AppFramework\Http\Attribute\OpenAPI;
+use OCP\AppFramework\Http\Attribute\UseSession;
use OCP\AppFramework\Http\JSONResponse;
use OCP\AppFramework\Http\RedirectResponse;
use OCP\AppFramework\Http\Response;
use OCP\AppFramework\Http\StandaloneTemplateResponse;
+use OCP\Authentication\Exceptions\InvalidTokenException;
use OCP\Defaults;
use OCP\IL10N;
use OCP\IRequest;
@@ -46,44 +50,42 @@ use OCP\IUser;
use OCP\IUserSession;
use OCP\Security\ISecureRandom;
+/**
+ * @psalm-import-type CoreLoginFlowV2Credentials from ResponseDefinitions
+ * @psalm-import-type CoreLoginFlowV2 from ResponseDefinitions
+ */
class ClientFlowLoginV2Controller extends Controller {
public const TOKEN_NAME = 'client.flow.v2.login.token';
public const STATE_NAME = 'client.flow.v2.state.token';
- private LoginFlowV2Service $loginFlowV2Service;
- private IURLGenerator $urlGenerator;
- private IUserSession $userSession;
- private ISession $session;
- private ISecureRandom $random;
- private Defaults $defaults;
- private ?string $userId;
- private IL10N $l10n;
-
- public function __construct(string $appName,
- IRequest $request,
- LoginFlowV2Service $loginFlowV2Service,
- IURLGenerator $urlGenerator,
- ISession $session,
- IUserSession $userSession,
- ISecureRandom $random,
- Defaults $defaults,
- ?string $userId,
- IL10N $l10n) {
+ public function __construct(
+ string $appName,
+ IRequest $request,
+ private LoginFlowV2Service $loginFlowV2Service,
+ private IURLGenerator $urlGenerator,
+ private ISession $session,
+ private IUserSession $userSession,
+ private ISecureRandom $random,
+ private Defaults $defaults,
+ private ?string $userId,
+ private IL10N $l10n,
+ ) {
parent::__construct($appName, $request);
- $this->loginFlowV2Service = $loginFlowV2Service;
- $this->urlGenerator = $urlGenerator;
- $this->session = $session;
- $this->userSession = $userSession;
- $this->random = $random;
- $this->defaults = $defaults;
- $this->userId = $userId;
- $this->l10n = $l10n;
}
/**
* @NoCSRFRequired
* @PublicPage
+ *
+ * Poll the login flow credentials
+ *
+ * @param string $token Token of the flow
+ * @return JSONResponse<Http::STATUS_OK, CoreLoginFlowV2Credentials, array{}>|JSONResponse<Http::STATUS_NOT_FOUND, array<empty>, array{}>
+ *
+ * 200: Login flow credentials returned
+ * 404: Login flow not found or completed
*/
+ #[FrontpageRoute(verb: 'POST', url: '/login/v2/poll')]
public function poll(string $token): JSONResponse {
try {
$creds = $this->loginFlowV2Service->poll($token);
@@ -91,14 +93,16 @@ class ClientFlowLoginV2Controller extends Controller {
return new JSONResponse([], Http::STATUS_NOT_FOUND);
}
- return new JSONResponse($creds);
+ return new JSONResponse($creds->jsonSerialize());
}
/**
* @NoCSRFRequired
* @PublicPage
- * @UseSession
*/
+ #[OpenAPI(scope: OpenAPI::SCOPE_IGNORE)]
+ #[UseSession]
+ #[FrontpageRoute(verb: 'GET', url: '/login/v2/flow/{token}')]
public function landing(string $token, $user = ''): Response {
if (!$this->loginFlowV2Service->startLoginFlow($token)) {
return $this->loginTokenForbiddenResponse();
@@ -114,8 +118,10 @@ class ClientFlowLoginV2Controller extends Controller {
/**
* @NoCSRFRequired
* @PublicPage
- * @UseSession
*/
+ #[OpenAPI(scope: OpenAPI::SCOPE_IGNORE)]
+ #[UseSession]
+ #[FrontpageRoute(verb: 'GET', url: '/login/v2/flow')]
public function showAuthPickerPage($user = ''): StandaloneTemplateResponse {
try {
$flow = $this->getFlowByLoginToken();
@@ -145,11 +151,16 @@ class ClientFlowLoginV2Controller extends Controller {
/**
* @NoAdminRequired
- * @UseSession
* @NoCSRFRequired
* @NoSameSiteCookieRequired
*/
- public function grantPage(string $stateToken): StandaloneTemplateResponse {
+ #[OpenAPI(scope: OpenAPI::SCOPE_IGNORE)]
+ #[UseSession]
+ #[FrontpageRoute(verb: 'GET', url: '/login/v2/grant')]
+ public function grantPage(?string $stateToken): StandaloneTemplateResponse {
+ if ($stateToken === null) {
+ return $this->stateTokenMissingResponse();
+ }
if (!$this->isValidStateToken($stateToken)) {
return $this->stateTokenForbiddenResponse();
}
@@ -181,7 +192,12 @@ class ClientFlowLoginV2Controller extends Controller {
/**
* @PublicPage
*/
- public function apptokenRedirect(string $stateToken, string $user, string $password) {
+ #[FrontpageRoute(verb: 'POST', url: '/login/v2/apptoken')]
+ public function apptokenRedirect(?string $stateToken, string $user, string $password) {
+ if ($stateToken === null) {
+ return $this->stateTokenMissingResponse();
+ }
+
if (!$this->isValidStateToken($stateToken)) {
return $this->stateTokenForbiddenResponse();
}
@@ -216,15 +232,19 @@ class ClientFlowLoginV2Controller extends Controller {
return $response;
}
- $result = $this->loginFlowV2Service->flowDoneWithAppPassword($loginToken, $this->getServerPath(), $this->userId, $password);
+ $result = $this->loginFlowV2Service->flowDoneWithAppPassword($loginToken, $this->getServerPath(), $token->getLoginName(), $password);
return $this->handleFlowDone($result);
}
/**
* @NoAdminRequired
- * @UseSession
*/
- public function generateAppPassword(string $stateToken): Response {
+ #[UseSession]
+ #[FrontpageRoute(verb: 'POST', url: '/login/v2/grant')]
+ public function generateAppPassword(?string $stateToken): Response {
+ if ($stateToken === null) {
+ return $this->stateTokenMissingResponse();
+ }
if (!$this->isValidStateToken($stateToken)) {
return $this->stateTokenForbiddenResponse();
}
@@ -271,7 +291,14 @@ class ClientFlowLoginV2Controller extends Controller {
/**
* @NoCSRFRequired
* @PublicPage
+ *
+ * Init a login flow
+ *
+ * @return JSONResponse<Http::STATUS_OK, CoreLoginFlowV2, array{}>
+ *
+ * 200: Login flow init returned
*/
+ #[FrontpageRoute(verb: 'POST', url: '/login/v2')]
public function init(): JSONResponse {
// Get client user agent
$userAgent = $this->request->getHeader('USER_AGENT');
@@ -297,6 +324,19 @@ class ClientFlowLoginV2Controller extends Controller {
return hash_equals($currentToken, $stateToken);
}
+ private function stateTokenMissingResponse(): StandaloneTemplateResponse {
+ $response = new StandaloneTemplateResponse(
+ $this->appName,
+ '403',
+ [
+ 'message' => $this->l10n->t('State token missing'),
+ ],
+ 'guest'
+ );
+ $response->setStatus(Http::STATUS_FORBIDDEN);
+ return $response;
+ }
+
private function stateTokenForbiddenResponse(): StandaloneTemplateResponse {
$response = new StandaloneTemplateResponse(
$this->appName,
@@ -339,9 +379,9 @@ class ClientFlowLoginV2Controller extends Controller {
private function getServerPath(): string {
$serverPostfix = '';
- if (strpos($this->request->getRequestUri(), '/index.php') !== false) {
+ if (str_contains($this->request->getRequestUri(), '/index.php')) {
$serverPostfix = substr($this->request->getRequestUri(), 0, strpos($this->request->getRequestUri(), '/index.php'));
- } elseif (strpos($this->request->getRequestUri(), '/login/v2') !== false) {
+ } elseif (str_contains($this->request->getRequestUri(), '/login/v2')) {
$serverPostfix = substr($this->request->getRequestUri(), 0, strpos($this->request->getRequestUri(), '/login/v2'));
}