Skip to content

Commit 7db5157

Browse files
committed
feat(auth): Implement stateless auth ticket system to speed up API requests
Signed-off-by: Marcel Klehr <mklehr@gmx.net>
1 parent e28b709 commit 7db5157

3 files changed

Lines changed: 76 additions & 0 deletions

File tree

lib/AppInfo/Application.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
use OCA\Bookmarks\Hooks\BeforeTemplateRenderedListener;
2626
use OCA\Bookmarks\Hooks\UsersGroupsCirclesListener;
2727
use OCA\Bookmarks\Middleware\ExceptionMiddleware;
28+
use OCA\Bookmarks\Middleware\TicketMiddleware;
2829
use OCA\Bookmarks\Reference\BookmarkReferenceProvider;
2930
use OCA\Bookmarks\Search\Provider;
3031
use OCA\Bookmarks\Service\TreeCacheManager;
@@ -104,6 +105,7 @@ public function register(IRegistrationContext $context): void {
104105
$context->registerEventListener(BeforeTemplateRenderedEvent::class, BeforeTemplateRenderedListener::class);
105106

106107
$context->registerMiddleware(ExceptionMiddleware::class);
108+
$context->registerMiddleware(TicketMiddleware::class);
107109

108110
$context->registerEventListener(ContentProviderRegisterEvent::class, ContextChatProvider::class);
109111
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
/*
4+
* Copyright (c) 2021. The Nextcloud Bookmarks contributors.
5+
*
6+
* This file is licensed under the Affero General Public License version 3 or later. See the COPYING file.
7+
*/
8+
9+
namespace OCA\Bookmarks\Middleware;
10+
11+
use OCA\Bookmarks\Controller\BookmarkController;
12+
use OCA\Bookmarks\Controller\FoldersController;
13+
use OCA\Bookmarks\Controller\InternalBookmarkController;
14+
use OCA\Bookmarks\Controller\InternalFoldersController;
15+
use OCA\Bookmarks\Controller\TagsController;
16+
use OCA\Bookmarks\Db\Folder;
17+
use OCA\Bookmarks\Exception\UnauthenticatedError;
18+
use OCA\Bookmarks\Service\Authorizer;
19+
use OCP\AppFramework\Controller;
20+
use OCP\AppFramework\Http;
21+
use OCP\AppFramework\Http\DataResponse;
22+
use OCP\AppFramework\Http\Response;
23+
use OCP\AppFramework\Middleware;
24+
25+
class TicketMiddleware extends Middleware {
26+
27+
public function __construct(private Authorizer $authorizer, private \OCP\IRequest $request) {
28+
}
29+
30+
public function afterController(Controller $controller, string $methodName, Response $response): Response {
31+
if ($controller instanceof FoldersController || $controller instanceof BookmarkController) {
32+
if ($this->authorizer->getUserId() !== null && !str_starts_with($this->request->getHeader('Authorization'), 'Bearer')) {
33+
if ($response instanceof DataResponse || $response instanceof Http\JSONResponse) {
34+
$data = $response->getData();
35+
if (is_array($data)) {
36+
$data['ticket'] = $this->authorizer->generateTicket($this->authorizer->getUserId());
37+
$response->setData($data);
38+
}
39+
}
40+
}
41+
}
42+
return $response;
43+
}
44+
}

lib/Service/Authorizer.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020
use OCP\AppFramework\Db\DoesNotExistException;
2121
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
2222
use OCP\IRequest;
23+
use OCP\IUserManager;
2324
use OCP\IUserSession;
25+
use OCP\Security\ICrypto;
2426

2527
class Authorizer {
2628
public const PERM_NONE = 0;
@@ -44,6 +46,8 @@ public function __construct(
4446
private TreeMapper $treeMapper,
4547
private IUserSession $userSession,
4648
private SharedFolderMapper $sharedFolderMapper,
49+
private ICrypto $crypto,
50+
private IUserManager $userManager,
4751
) {
4852
}
4953

@@ -68,6 +72,12 @@ public function setCredentials(IRequest $request): void {
6872
if ($auth !== null && $auth !== '') {
6973
[$type, $credentials] = explode(' ', $auth);
7074
if (strtolower($type) === 'bearer') {
75+
$userFromTicket = $this->checkTicket($credentials);
76+
if ($userFromTicket !== null) {
77+
$this->userSession->setUser($this->userManager->get($userFromTicket));
78+
$this->setUserId($userFromTicket);
79+
return;
80+
}
7181
$this->setToken($credentials);
7282
}
7383
}
@@ -313,4 +323,24 @@ public function getTokenPermissionsForFolder(string $token, int $folderId): int
313323
}
314324
return self::PERM_NONE;
315325
}
326+
327+
public function generateTicket(string $userId): string {
328+
return $this->crypto->encrypt(json_encode(['userId' => $userId, 'timestamp' => time()]));
329+
}
330+
331+
public function checkTicket(string $ticket): ?string {
332+
try {
333+
$data = json_decode($this->crypto->decrypt($ticket), true);
334+
} catch (\Exception $e) {
335+
return null;
336+
}
337+
if (!isset($data['userId'], $data['timestamp'])) {
338+
return null;
339+
}
340+
if (time() > $data['timestamp'] + 3600) {
341+
return null;
342+
}
343+
344+
return $data['userId'];
345+
}
316346
}

0 commit comments

Comments
 (0)