diff --git a/apps/dav/lib/Connector/LegacyPublicAuth.php b/apps/dav/lib/Connector/LegacyPublicAuth.php index 03d18853de0c6..171d623ef71bd 100644 --- a/apps/dav/lib/Connector/LegacyPublicAuth.php +++ b/apps/dav/lib/Connector/LegacyPublicAuth.php @@ -16,6 +16,7 @@ use OCP\Share\IManager; use OCP\Share\IShare; use Sabre\DAV\Auth\Backend\AbstractBasic; +use Sabre\DAV\Exception\NotAuthenticated; /** * Class PublicAuth @@ -69,22 +70,29 @@ protected function validateUserPass($username, $password) { if ($share->getShareType() === IShare::TYPE_LINK || $share->getShareType() === IShare::TYPE_EMAIL || $share->getShareType() === IShare::TYPE_CIRCLE) { + // Validate password if provided if ($this->shareManager->checkPassword($share, $password)) { + // If not set, set authenticated session cookie + if (!$this->isShareInSession($share)) { + $this->addShareToSession($share); + } return true; - } elseif ($this->session->exists(PublicAuth::DAV_AUTHENTICATED) - && $this->session->get(PublicAuth::DAV_AUTHENTICATED) === $share->getId()) { + } + + // We are already authenticated for this share in the session + if ($this->isShareInSession($share)) { return true; - } else { - if (in_array('XMLHttpRequest', explode(',', $this->request->getHeader('X-Requested-With')))) { - // do not re-authenticate over ajax, use dummy auth name to prevent browser popup - http_response_code(401); - header('WWW-Authenticate: DummyBasic realm="' . $this->realm . '"'); - throw new \Sabre\DAV\Exception\NotAuthenticated('Cannot authenticate over ajax calls'); - } + } - $this->throttler->registerAttempt(self::BRUTEFORCE_ACTION, $this->request->getRemoteAddress()); - return false; + if (in_array('XMLHttpRequest', explode(',', $this->request->getHeader('X-Requested-With')))) { + // do not re-authenticate over ajax, use dummy auth name to prevent browser popup + http_response_code(401); + header('WWW-Authenticate: DummyBasic realm="' . $this->realm . '"'); + throw new NotAuthenticated('Cannot authenticate over ajax calls'); } + + $this->throttler->registerAttempt(self::BRUTEFORCE_ACTION, $this->request->getRemoteAddress()); + return false; } elseif ($share->getShareType() === IShare::TYPE_REMOTE) { return true; } else { @@ -95,6 +103,29 @@ protected function validateUserPass($username, $password) { return true; } + private function addShareToSession(IShare $share): void { + $allowedShareIds = $this->session->get(PublicAuth::DAV_AUTHENTICATED) ?? []; + if (!is_array($allowedShareIds)) { + $allowedShareIds = []; + } + + $allowedShareIds[] = $share->getId(); + $this->session->set(PublicAuth::DAV_AUTHENTICATED, $allowedShareIds); + } + + private function isShareInSession(IShare $share): bool { + if (!$this->session->exists(PublicAuth::DAV_AUTHENTICATED)) { + return false; + } + + $allowedShareIds = $this->session->get(PublicAuth::DAV_AUTHENTICATED); + if (!is_array($allowedShareIds)) { + return false; + } + + return in_array($share->getId(), $allowedShareIds); + } + public function getShare(): IShare { assert($this->share !== null); return $this->share; diff --git a/apps/dav/tests/unit/Connector/LegacyPublicAuthTest.php b/apps/dav/tests/unit/Connector/LegacyPublicAuthTest.php index 2bb683741627e..0ac4e98a16a5f 100644 --- a/apps/dav/tests/unit/Connector/LegacyPublicAuthTest.php +++ b/apps/dav/tests/unit/Connector/LegacyPublicAuthTest.php @@ -196,7 +196,7 @@ public function testInvalidSharePasswordLinkValidSession(): void { )->willReturn(false); $this->session->method('exists')->with('public_link_authenticated')->willReturn(true); - $this->session->method('get')->with('public_link_authenticated')->willReturn('42'); + $this->session->method('get')->with('public_link_authenticated')->willReturn(['42']); $result = $this->invokePrivate($this->auth, 'validateUserPass', ['username', 'password']); @@ -222,7 +222,7 @@ public function testSharePasswordLinkInvalidSession(): void { )->willReturn(false); $this->session->method('exists')->with('public_link_authenticated')->willReturn(true); - $this->session->method('get')->with('public_link_authenticated')->willReturn('43'); + $this->session->method('get')->with('public_link_authenticated')->willReturn(['43']); $result = $this->invokePrivate($this->auth, 'validateUserPass', ['username', 'password']); @@ -249,7 +249,7 @@ public function testSharePasswordMailInvalidSession(): void { )->willReturn(false); $this->session->method('exists')->with('public_link_authenticated')->willReturn(true); - $this->session->method('get')->with('public_link_authenticated')->willReturn('43'); + $this->session->method('get')->with('public_link_authenticated')->willReturn(['43']); $result = $this->invokePrivate($this->auth, 'validateUserPass', ['username', 'password']);