Skip to content

Commit 09113e8

Browse files
Merge pull request #8234 from nextcloud/chore/improve-session-validation
chore: Improve session validation
2 parents 95ea143 + 8ac6e10 commit 09113e8

File tree

3 files changed

+123
-2
lines changed

3 files changed

+123
-2
lines changed

lib/Controller/WorkspaceController.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,9 @@ public function publicFolder(string $shareToken, string $path = '/'): DataRespon
132132
/** @psalm-suppress RedundantConditionGivenDocblockType */
133133
if ($share->getPassword() !== null) {
134134
$shareIds = $this->session->get('public_link_authenticated');
135-
if ($share->getId() !== $shareIds && (is_array($shareIds) && !in_array($share->getId(), $shareIds, true))) {
135+
$shareIds = is_array($shareIds) ? $shareIds : [$shareIds];
136+
137+
if (!in_array($share->getId(), $shareIds, true)) {
136138
throw new ShareNotFound();
137139
}
138140
}

lib/Middleware/SessionMiddleware.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,9 @@ private function assertUserOrShareToken(ISessionAwareController $controller): vo
144144

145145
if ($share->getPassword() !== null) {
146146
$shareIds = $this->session->get('public_link_authenticated');
147-
if ($share->getId() !== $shareIds && (is_array($shareIds) && !in_array($share->getId(), $shareIds, true))) {
147+
$shareIds = is_array($shareIds) ? $shareIds : [$shareIds];
148+
149+
if (!in_array($share->getId(), $shareIds, true)) {
148150
throw new InvalidSessionException();
149151
}
150152
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
<?php
2+
3+
namespace OCA\Text\Tests;
4+
5+
use OCA\Text\Controller\ISessionAwareController;
6+
use OCA\Text\Exception\InvalidSessionException;
7+
use OCA\Text\Middleware\SessionMiddleware;
8+
use OCA\Text\Service\DocumentService;
9+
use OCA\Text\Service\SessionService;
10+
use OCP\Files\Folder;
11+
use OCP\Files\IRootFolder;
12+
use OCP\IL10N;
13+
use OCP\IRequest;
14+
use OCP\ISession;
15+
use OCP\IUserSession;
16+
use OCP\Share\IManager;
17+
use OCP\Share\IShare;
18+
use Test\TestCase;
19+
20+
class SessionMiddlewareTest extends TestCase {
21+
private SessionMiddleware $middleware;
22+
private IRequest $request;
23+
private ISession $session;
24+
private IUserSession $userSession;
25+
private IRootFolder $rootFolder;
26+
private IManager $shareManager;
27+
28+
protected function setUp(): void {
29+
parent::setUp();
30+
31+
$this->request = $this->createMock(IRequest::class);
32+
$this->session = $this->createMock(ISession::class);
33+
$this->userSession = $this->createMock(IUserSession::class);
34+
$this->rootFolder = $this->createMock(IRootFolder::class);
35+
$this->shareManager = $this->createMock(IManager::class);
36+
37+
$this->middleware = new SessionMiddleware(
38+
$this->request,
39+
$this->createMock(SessionService::class),
40+
$this->createMock(DocumentService::class),
41+
$this->session,
42+
$this->userSession,
43+
$this->rootFolder,
44+
$this->shareManager,
45+
$this->createMock(IL10N::class),
46+
);
47+
}
48+
49+
public function testUnauthenticatedAccessBlocked(): void {
50+
$this->expectException(InvalidSessionException::class);
51+
52+
$share = $this->createPasswordProtectedShare('42');
53+
$this->session->method('get')->with('public_link_authenticated')->willReturn(null);
54+
55+
$this->invokeMiddleware($share);
56+
}
57+
58+
public function testAuthenticatedSingleIdAllowed(): void {
59+
$share = $this->createPasswordProtectedShare('42');
60+
$this->session->method('get')->with('public_link_authenticated')->willReturn('42');
61+
62+
$this->invokeMiddleware($share);
63+
$this->assertTrue(true);
64+
}
65+
66+
public function testAuthenticatedArrayAllowed(): void {
67+
$share = $this->createPasswordProtectedShare('42');
68+
$this->session->method('get')->with('public_link_authenticated')->willReturn(['40', '42', '44']);
69+
70+
$this->invokeMiddleware($share);
71+
$this->assertTrue(true);
72+
}
73+
74+
public function testWrongSingleIdBlocked(): void {
75+
$this->expectException(InvalidSessionException::class);
76+
77+
$share = $this->createPasswordProtectedShare('42');
78+
$this->session->method('get')->with('public_link_authenticated')->willReturn('99');
79+
80+
$this->invokeMiddleware($share);
81+
}
82+
83+
public function testWrongArrayBlocked(): void {
84+
$this->expectException(InvalidSessionException::class);
85+
86+
$share = $this->createPasswordProtectedShare('42');
87+
$this->session->method('get')->with('public_link_authenticated')->willReturn(['10', '20', '30']);
88+
89+
$this->invokeMiddleware($share);
90+
}
91+
92+
private function createPasswordProtectedShare(string $id): IShare {
93+
$share = $this->createMock(IShare::class);
94+
$share->method('getId')->willReturn($id);
95+
$share->method('getPassword')->willReturn('password');
96+
$share->method('getPermissions')->willReturn(\OCP\Constants::PERMISSION_READ);
97+
$share->method('getShareOwner')->willReturn('owner');
98+
$share->method('getAttributes')->willReturn(null);
99+
return $share;
100+
}
101+
102+
private function invokeMiddleware(IShare $share): void {
103+
$this->request->method('getParam')->willReturnMap([
104+
['documentId', null, 999],
105+
['shareToken', null, 'token'],
106+
]);
107+
$this->userSession->method('getUser')->willReturn(null);
108+
$this->shareManager->method('getShareByToken')->willReturn($share);
109+
110+
$folder = $this->createMock(Folder::class);
111+
$folder->method('getFirstNodeById')->willReturn($this->createMock(\OCP\Files\File::class));
112+
$this->rootFolder->method('getUserFolder')->willReturn($folder);
113+
114+
$controller = $this->createMock(ISessionAwareController::class);
115+
self::invokePrivate($this->middleware, 'assertUserOrShareToken', [$controller]);
116+
}
117+
}

0 commit comments

Comments
 (0)