Merge pull request #32400 from nextcloud/feat/public-dav-v2
commit
dc2066bc26
@ -0,0 +1,155 @@ |
||||
<?php |
||||
/** |
||||
* @copyright Copyright (c) 2016, ownCloud, Inc. |
||||
* |
||||
* @author Bjoern Schiessle <bjoern@schiessle.org> |
||||
* @author Björn Schießle <bjoern@schiessle.org> |
||||
* @author Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* @author Joas Schilling <coding@schilljs.com> |
||||
* @author Julius Härtl <jus@bitgrid.net> |
||||
* @author Lukas Reschke <lukas@statuscode.ch> |
||||
* @author Morris Jobke <hey@morrisjobke.de> |
||||
* @author Robin Appelman <robin@icewind.nl> |
||||
* @author Roeland Jago Douma <roeland@famdouma.nl> |
||||
* @author Thomas Müller <thomas.mueller@tmit.eu> |
||||
* @author Vincent Petry <vincent@nextcloud.com> |
||||
* |
||||
* @license AGPL-3.0 |
||||
* |
||||
* This code is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License, version 3, |
||||
* as published by the Free Software Foundation. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License, version 3, |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/> |
||||
* |
||||
*/ |
||||
|
||||
use OC\Files\Filesystem; |
||||
use OC\Files\Storage\Wrapper\PermissionsMask; |
||||
use OC\Files\View; |
||||
use OCA\DAV\Storage\PublicOwnerWrapper; |
||||
use OCA\FederatedFileSharing\FederatedShareProvider; |
||||
use OCP\EventDispatcher\IEventDispatcher; |
||||
use OCP\Files\Mount\IMountManager; |
||||
use OCP\IConfig; |
||||
use OCP\IDBConnection; |
||||
use OCP\IPreview; |
||||
use OCP\IRequest; |
||||
use OCP\ISession; |
||||
use OCP\ITagManager; |
||||
use OCP\IUserSession; |
||||
use OCP\L10N\IFactory; |
||||
use OCP\Security\Bruteforce\IThrottler; |
||||
use OCP\Share\IManager; |
||||
use Psr\Log\LoggerInterface; |
||||
use Sabre\DAV\Exception\NotAuthenticated; |
||||
use Sabre\DAV\Exception\NotFound; |
||||
|
||||
// load needed apps |
||||
$RUNTIME_APPTYPES = ['filesystem', 'authentication', 'logging']; |
||||
OC_App::loadApps($RUNTIME_APPTYPES); |
||||
OC_Util::obEnd(); |
||||
|
||||
$session = \OCP\Server::get(ISession::class); |
||||
$request = \OCP\Server::get(IRequest::class); |
||||
|
||||
$session->close(); |
||||
$requestUri = $request->getRequestUri(); |
||||
|
||||
// Backends |
||||
$authBackend = new OCA\DAV\Connector\Sabre\PublicAuth( |
||||
$request, |
||||
\OCP\Server::get(IManager::class), |
||||
$session, |
||||
\OCP\Server::get(IThrottler::class), |
||||
\OCP\Server::get(LoggerInterface::class) |
||||
); |
||||
$authPlugin = new \Sabre\DAV\Auth\Plugin($authBackend); |
||||
|
||||
$l10nFactory = \OCP\Server::get(IFactory::class); |
||||
$serverFactory = new OCA\DAV\Connector\Sabre\ServerFactory( |
||||
\OCP\Server::get(IConfig::class), |
||||
\OCP\Server::get(LoggerInterface::class), |
||||
\OCP\Server::get(IDBConnection::class), |
||||
\OCP\Server::get(IUserSession::class), |
||||
\OCP\Server::get(IMountManager::class), |
||||
\OCP\Server::get(ITagManager::class), |
||||
$request, |
||||
\OCP\Server::get(IPreview::class), |
||||
\OCP\Server::get(IEventDispatcher::class), |
||||
$l10nFactory->get('dav'), |
||||
); |
||||
|
||||
|
||||
$linkCheckPlugin = new \OCA\DAV\Files\Sharing\PublicLinkCheckPlugin(); |
||||
$filesDropPlugin = new \OCA\DAV\Files\Sharing\FilesDropPlugin(); |
||||
|
||||
// Define root url with /public.php/dav/files/TOKEN |
||||
/** @var string $baseuri defined in public.php */ |
||||
preg_match('/(^files\/\w+)/i', substr($requestUri, strlen($baseuri)), $match); |
||||
$baseuri = $baseuri . $match[0]; |
||||
|
||||
$server = $serverFactory->createServer($baseuri, $requestUri, $authPlugin, function (\Sabre\DAV\Server $server) use ($authBackend, $linkCheckPlugin, $filesDropPlugin) { |
||||
$isAjax = (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest'); |
||||
$federatedShareProvider = \OCP\Server::get(FederatedShareProvider::class); |
||||
if ($federatedShareProvider->isOutgoingServer2serverShareEnabled() === false && !$isAjax) { |
||||
// this is what is thrown when trying to access a non-existing share |
||||
throw new NotAuthenticated(); |
||||
} |
||||
|
||||
$share = $authBackend->getShare(); |
||||
$owner = $share->getShareOwner(); |
||||
$isReadable = $share->getPermissions() & \OCP\Constants::PERMISSION_READ; |
||||
$fileId = $share->getNodeId(); |
||||
|
||||
// FIXME: should not add storage wrappers outside of preSetup, need to find a better way |
||||
/** @psalm-suppress InternalMethod */ |
||||
$previousLog = Filesystem::logWarningWhenAddingStorageWrapper(false); |
||||
|
||||
/** @psalm-suppress MissingClosureParamType */ |
||||
Filesystem::addStorageWrapper('sharePermissions', function ($mountPoint, $storage) use ($share) { |
||||
return new PermissionsMask(['storage' => $storage, 'mask' => $share->getPermissions() | \OCP\Constants::PERMISSION_SHARE]); |
||||
}); |
||||
|
||||
/** @psalm-suppress MissingClosureParamType */ |
||||
Filesystem::addStorageWrapper('shareOwner', function ($mountPoint, $storage) use ($share) { |
||||
return new PublicOwnerWrapper(['storage' => $storage, 'owner' => $share->getShareOwner()]); |
||||
}); |
||||
|
||||
/** @psalm-suppress InternalMethod */ |
||||
Filesystem::logWarningWhenAddingStorageWrapper($previousLog); |
||||
|
||||
OC_Util::tearDownFS(); |
||||
OC_Util::setupFS($owner); |
||||
$ownerView = new View('/'. $owner . '/files'); |
||||
$path = $ownerView->getPath($fileId); |
||||
$fileInfo = $ownerView->getFileInfo($path); |
||||
|
||||
if ($fileInfo === false) { |
||||
throw new NotFound(); |
||||
} |
||||
|
||||
$linkCheckPlugin->setFileInfo($fileInfo); |
||||
|
||||
// If not readble (files_drop) enable the filesdrop plugin |
||||
if (!$isReadable) { |
||||
$filesDropPlugin->enable(); |
||||
} |
||||
|
||||
$view = new View($ownerView->getAbsolutePath($path)); |
||||
$filesDropPlugin->setView($view); |
||||
|
||||
return $view; |
||||
}); |
||||
|
||||
$server->addPlugin($linkCheckPlugin); |
||||
$server->addPlugin($filesDropPlugin); |
||||
|
||||
// And off we go! |
||||
$server->exec(); |
||||
@ -0,0 +1,239 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
/** |
||||
* @copyright Copyright (c) 2016, ownCloud, Inc. |
||||
* |
||||
* @author Björn Schießle <bjoern@schiessle.org> |
||||
* @author Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* @author Joas Schilling <coding@schilljs.com> |
||||
* @author Lukas Reschke <lukas@statuscode.ch> |
||||
* @author Maxence Lange <maxence@artificial-owl.com> |
||||
* @author Robin Appelman <robin@icewind.nl> |
||||
* @author Roeland Jago Douma <roeland@famdouma.nl> |
||||
* @author Thomas Müller <thomas.mueller@tmit.eu> |
||||
* @author Vincent Petry <vincent@nextcloud.com> |
||||
* |
||||
* @license AGPL-3.0 |
||||
* |
||||
* This code is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License, version 3, |
||||
* as published by the Free Software Foundation. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License, version 3, |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/> |
||||
* |
||||
*/ |
||||
|
||||
namespace OCA\DAV\Connector\Sabre; |
||||
|
||||
use OCP\IRequest; |
||||
use OCP\ISession; |
||||
use OCP\Security\Bruteforce\IThrottler; |
||||
use OCP\Share\Exceptions\ShareNotFound; |
||||
use OCP\Share\IManager; |
||||
use OCP\Share\IShare; |
||||
use Psr\Log\LoggerInterface; |
||||
use Sabre\DAV\Auth\Backend\AbstractBasic; |
||||
use Sabre\DAV\Exception\NotAuthenticated; |
||||
use Sabre\DAV\Exception\NotFound; |
||||
use Sabre\DAV\Exception\ServiceUnavailable; |
||||
use Sabre\HTTP; |
||||
use Sabre\HTTP\RequestInterface; |
||||
use Sabre\HTTP\ResponseInterface; |
||||
|
||||
/** |
||||
* Class PublicAuth |
||||
* |
||||
* @package OCA\DAV\Connector |
||||
*/ |
||||
class PublicAuth extends AbstractBasic { |
||||
private const BRUTEFORCE_ACTION = 'public_dav_auth'; |
||||
public const DAV_AUTHENTICATED = 'public_link_authenticated'; |
||||
|
||||
private ?IShare $share = null; |
||||
private IManager $shareManager; |
||||
private ISession $session; |
||||
private IRequest $request; |
||||
private IThrottler $throttler; |
||||
private LoggerInterface $logger; |
||||
|
||||
public function __construct(IRequest $request, |
||||
IManager $shareManager, |
||||
ISession $session, |
||||
IThrottler $throttler, |
||||
LoggerInterface $logger) { |
||||
$this->request = $request; |
||||
$this->shareManager = $shareManager; |
||||
$this->session = $session; |
||||
$this->throttler = $throttler; |
||||
$this->logger = $logger; |
||||
|
||||
// setup realm |
||||
$defaults = new \OCP\Defaults(); |
||||
$this->realm = $defaults->getName(); |
||||
} |
||||
|
||||
/** |
||||
* @param RequestInterface $request |
||||
* @param ResponseInterface $response |
||||
* |
||||
* @return array |
||||
* @throws NotAuthenticated |
||||
* @throws ServiceUnavailable |
||||
*/ |
||||
public function check(RequestInterface $request, ResponseInterface $response): array { |
||||
try { |
||||
$this->throttler->sleepDelayOrThrowOnMax($this->request->getRemoteAddress(), self::BRUTEFORCE_ACTION); |
||||
|
||||
$auth = new HTTP\Auth\Basic( |
||||
$this->realm, |
||||
$request, |
||||
$response |
||||
); |
||||
|
||||
$userpass = $auth->getCredentials(); |
||||
// If authentication provided, checking its validity |
||||
if ($userpass && !$this->validateUserPass($userpass[0], $userpass[1])) { |
||||
return [false, 'Username or password was incorrect']; |
||||
} |
||||
|
||||
return $this->checkToken(); |
||||
} catch (NotAuthenticated $e) { |
||||
throw $e; |
||||
} catch (\Exception $e) { |
||||
$class = get_class($e); |
||||
$msg = $e->getMessage(); |
||||
$this->logger->error($e->getMessage(), ['exception' => $e]); |
||||
throw new ServiceUnavailable("$class: $msg"); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Extract token from request url |
||||
* @return string |
||||
* @throws NotFound |
||||
*/ |
||||
private function getToken(): string { |
||||
$path = $this->request->getPathInfo() ?: ''; |
||||
// ['', 'dav', 'files', 'token'] |
||||
$splittedPath = explode('/', $path); |
||||
|
||||
if (count($splittedPath) < 4 || $splittedPath[3] === '') { |
||||
throw new NotFound(); |
||||
} |
||||
|
||||
return $splittedPath[3]; |
||||
} |
||||
|
||||
/** |
||||
* Check token validity |
||||
* @return array |
||||
* @throws NotFound |
||||
* @throws NotAuthenticated |
||||
*/ |
||||
private function checkToken(): array { |
||||
$token = $this->getToken(); |
||||
|
||||
try { |
||||
/** @var IShare $share */ |
||||
$share = $this->shareManager->getShareByToken($token); |
||||
} catch (ShareNotFound $e) { |
||||
$this->throttler->registerAttempt(self::BRUTEFORCE_ACTION, $this->request->getRemoteAddress()); |
||||
throw new NotFound(); |
||||
} |
||||
|
||||
$this->share = $share; |
||||
\OC_User::setIncognitoMode(true); |
||||
|
||||
// If already authenticated |
||||
if ($this->session->exists(self::DAV_AUTHENTICATED) |
||||
&& $this->session->get(self::DAV_AUTHENTICATED) === $share->getId()) { |
||||
return [true, $this->principalPrefix . $token]; |
||||
} |
||||
|
||||
// If the share is protected but user is not authenticated |
||||
if ($share->getPassword() !== null) { |
||||
$this->throttler->registerAttempt(self::BRUTEFORCE_ACTION, $this->request->getRemoteAddress()); |
||||
throw new NotAuthenticated(); |
||||
} |
||||
|
||||
return [true, $this->principalPrefix . $token]; |
||||
} |
||||
|
||||
/** |
||||
* Validates a username and password |
||||
* |
||||
* This method should return true or false depending on if login |
||||
* succeeded. |
||||
* |
||||
* @param string $username |
||||
* @param string $password |
||||
* |
||||
* @return bool |
||||
* @throws NotAuthenticated |
||||
*/ |
||||
protected function validateUserPass($username, $password) { |
||||
$this->throttler->sleepDelayOrThrowOnMax($this->request->getRemoteAddress(), self::BRUTEFORCE_ACTION); |
||||
|
||||
$token = $this->getToken(); |
||||
try { |
||||
$share = $this->shareManager->getShareByToken($token); |
||||
} catch (ShareNotFound $e) { |
||||
$this->throttler->registerAttempt(self::BRUTEFORCE_ACTION, $this->request->getRemoteAddress()); |
||||
return false; |
||||
} |
||||
|
||||
$this->share = $share; |
||||
\OC_User::setIncognitoMode(true); |
||||
|
||||
// check if the share is password protected |
||||
if ($share->getPassword() !== null) { |
||||
if ($share->getShareType() === IShare::TYPE_LINK |
||||
|| $share->getShareType() === IShare::TYPE_EMAIL |
||||
|| $share->getShareType() === IShare::TYPE_CIRCLE) { |
||||
if ($this->shareManager->checkPassword($share, $password)) { |
||||
// If not set, set authenticated session cookie |
||||
if (!$this->session->exists(self::DAV_AUTHENTICATED) |
||||
|| $this->session->get(self::DAV_AUTHENTICATED) !== $share->getId()) { |
||||
$this->session->set(self::DAV_AUTHENTICATED, $share->getId()); |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
if ($this->session->exists(PublicAuth::DAV_AUTHENTICATED) |
||||
&& $this->session->get(PublicAuth::DAV_AUTHENTICATED) === $share->getId()) { |
||||
return true; |
||||
} |
||||
|
||||
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; |
||||
} |
||||
|
||||
$this->throttler->registerAttempt(self::BRUTEFORCE_ACTION, $this->request->getRemoteAddress()); |
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
public function getShare(): IShare { |
||||
assert($this->share !== null); |
||||
return $this->share; |
||||
} |
||||
} |
||||
@ -0,0 +1,425 @@ |
||||
<?php |
||||
/** |
||||
* @copyright Copyright (c) 2016, ownCloud, Inc. |
||||
* |
||||
* @author Bjoern Schiessle <bjoern@schiessle.org> |
||||
* @author Joas Schilling <coding@schilljs.com> |
||||
* @author Lukas Reschke <lukas@statuscode.ch> |
||||
* @author Morris Jobke <hey@morrisjobke.de> |
||||
* @author Roeland Jago Douma <roeland@famdouma.nl> |
||||
* @author Thomas Müller <thomas.mueller@tmit.eu> |
||||
* |
||||
* @license AGPL-3.0 |
||||
* |
||||
* This code is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License, version 3, |
||||
* as published by the Free Software Foundation. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License, version 3, |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/> |
||||
* |
||||
*/ |
||||
namespace OCA\DAV\Tests\unit\Connector; |
||||
|
||||
use OCP\IRequest; |
||||
use OCP\ISession; |
||||
use OCP\Security\Bruteforce\IThrottler; |
||||
use OCP\Share\Exceptions\ShareNotFound; |
||||
use OCP\Share\IManager; |
||||
use OCP\Share\IShare; |
||||
use Psr\Log\LoggerInterface; |
||||
|
||||
/** |
||||
* Class PublicAuthTest |
||||
* |
||||
* @group DB |
||||
* |
||||
* @package OCA\DAV\Tests\unit\Connector |
||||
*/ |
||||
class PublicAuthTest extends \Test\TestCase { |
||||
|
||||
/** @var ISession|MockObject */ |
||||
private $session; |
||||
/** @var IRequest|MockObject */ |
||||
private $request; |
||||
/** @var IManager|MockObject */ |
||||
private $shareManager; |
||||
/** @var PublicAuth */ |
||||
private $auth; |
||||
/** @var IThrottler|MockObject */ |
||||
private $throttler; |
||||
/** @var LoggerInterface|MockObject */ |
||||
private $logger; |
||||
|
||||
/** @var string */ |
||||
private $oldUser; |
||||
|
||||
protected function setUp(): void { |
||||
parent::setUp(); |
||||
|
||||
$this->session = $this->createMock(ISession::class); |
||||
$this->request = $this->createMock(IRequest::class); |
||||
$this->shareManager = $this->createMock(IManager::class); |
||||
$this->throttler = $this->createMock(IThrottler::class); |
||||
$this->logger = $this->createMock(LoggerInterface::class); |
||||
|
||||
$this->auth = new \OCA\DAV\Connector\Sabre\PublicAuth( |
||||
$this->request, |
||||
$this->shareManager, |
||||
$this->session, |
||||
$this->throttler, |
||||
$this->logger, |
||||
); |
||||
|
||||
// Store current user |
||||
$this->oldUser = \OC_User::getUser(); |
||||
} |
||||
|
||||
protected function tearDown(): void { |
||||
\OC_User::setIncognitoMode(false); |
||||
|
||||
// Set old user |
||||
\OC_User::setUserId($this->oldUser); |
||||
\OC_Util::setupFS($this->oldUser); |
||||
|
||||
parent::tearDown(); |
||||
} |
||||
|
||||
public function testGetToken(): void { |
||||
$this->request->method('getPathInfo') |
||||
->willReturn('/dav/files/GX9HSGQrGE'); |
||||
|
||||
$result = $this->invokePrivate($this->auth, 'getToken'); |
||||
|
||||
$this->assertSame('GX9HSGQrGE', $result); |
||||
} |
||||
|
||||
public function testGetTokenInvalid(): void { |
||||
$this->request->method('getPathInfo') |
||||
->willReturn('/dav/files'); |
||||
|
||||
$this->expectException(\Sabre\DAV\Exception\NotFound::class); |
||||
$this->invokePrivate($this->auth, 'getToken'); |
||||
} |
||||
|
||||
public function testCheckTokenValidShare(): void { |
||||
$this->request->method('getPathInfo') |
||||
->willReturn('/dav/files/GX9HSGQrGE'); |
||||
|
||||
$share = $this->getMockBuilder(IShare::class) |
||||
->disableOriginalConstructor() |
||||
->getMock(); |
||||
$share->method('getPassword')->willReturn(null); |
||||
|
||||
$this->shareManager->expects($this->once()) |
||||
->method('getShareByToken') |
||||
->with('GX9HSGQrGE') |
||||
->willReturn($share); |
||||
|
||||
$result = $this->invokePrivate($this->auth, 'checkToken'); |
||||
$this->assertSame([true, 'principals/GX9HSGQrGE'], $result); |
||||
} |
||||
|
||||
public function testCheckTokenInvalidShare(): void { |
||||
$this->request->method('getPathInfo') |
||||
->willReturn('/dav/files/GX9HSGQrGE'); |
||||
|
||||
$this->shareManager |
||||
->expects($this->once()) |
||||
->method('getShareByToken') |
||||
->with('GX9HSGQrGE') |
||||
->will($this->throwException(new ShareNotFound())); |
||||
|
||||
$this->expectException(\Sabre\DAV\Exception\NotFound::class); |
||||
$this->invokePrivate($this->auth, 'checkToken'); |
||||
} |
||||
|
||||
public function testCheckTokenAlreadyAuthenticated(): void { |
||||
$this->request->method('getPathInfo') |
||||
->willReturn('/dav/files/GX9HSGQrGE'); |
||||
|
||||
$share = $this->getMockBuilder(IShare::class) |
||||
->disableOriginalConstructor() |
||||
->getMock(); |
||||
$share->method('getShareType')->willReturn(42); |
||||
|
||||
$this->shareManager->expects($this->once()) |
||||
->method('getShareByToken') |
||||
->with('GX9HSGQrGE') |
||||
->willReturn($share); |
||||
|
||||
$this->session->method('exists')->with('public_link_authenticated')->willReturn(true); |
||||
$this->session->method('get')->with('public_link_authenticated')->willReturn('42'); |
||||
|
||||
$result = $this->invokePrivate($this->auth, 'checkToken'); |
||||
$this->assertSame([true, 'principals/GX9HSGQrGE'], $result); |
||||
} |
||||
|
||||
public function testCheckTokenPasswordNotAuthenticated(): void { |
||||
$this->request->method('getPathInfo') |
||||
->willReturn('/dav/files/GX9HSGQrGE'); |
||||
|
||||
$share = $this->getMockBuilder(IShare::class) |
||||
->disableOriginalConstructor() |
||||
->getMock(); |
||||
$share->method('getPassword')->willReturn('password'); |
||||
$share->method('getShareType')->willReturn(42); |
||||
|
||||
$this->shareManager->expects($this->once()) |
||||
->method('getShareByToken') |
||||
->with('GX9HSGQrGE') |
||||
->willReturn($share); |
||||
|
||||
$this->session->method('exists')->with('public_link_authenticated')->willReturn(false); |
||||
|
||||
$this->expectException(\Sabre\DAV\Exception\NotAuthenticated::class); |
||||
$this->invokePrivate($this->auth, 'checkToken'); |
||||
} |
||||
|
||||
public function testCheckTokenPasswordAuthenticatedWrongShare(): void { |
||||
$this->request->method('getPathInfo') |
||||
->willReturn('/dav/files/GX9HSGQrGE'); |
||||
|
||||
$share = $this->getMockBuilder(IShare::class) |
||||
->disableOriginalConstructor() |
||||
->getMock(); |
||||
$share->method('getPassword')->willReturn('password'); |
||||
$share->method('getShareType')->willReturn(42); |
||||
|
||||
$this->shareManager->expects($this->once()) |
||||
->method('getShareByToken') |
||||
->with('GX9HSGQrGE') |
||||
->willReturn($share); |
||||
|
||||
$this->session->method('exists')->with('public_link_authenticated')->willReturn(false); |
||||
$this->session->method('get')->with('public_link_authenticated')->willReturn('43'); |
||||
|
||||
$this->expectException(\Sabre\DAV\Exception\NotAuthenticated::class); |
||||
$this->invokePrivate($this->auth, 'checkToken'); |
||||
} |
||||
|
||||
public function testNoShare(): void { |
||||
$this->request->method('getPathInfo') |
||||
->willReturn('/dav/files/GX9HSGQrGE'); |
||||
|
||||
$this->shareManager->expects($this->once()) |
||||
->method('getShareByToken') |
||||
->with('GX9HSGQrGE') |
||||
->willThrowException(new ShareNotFound()); |
||||
|
||||
$result = $this->invokePrivate($this->auth, 'validateUserPass', ['username', 'password']); |
||||
|
||||
$this->assertFalse($result); |
||||
} |
||||
|
||||
public function testShareNoPassword(): void { |
||||
$this->request->method('getPathInfo') |
||||
->willReturn('/dav/files/GX9HSGQrGE'); |
||||
|
||||
$share = $this->getMockBuilder(IShare::class) |
||||
->disableOriginalConstructor() |
||||
->getMock(); |
||||
$share->method('getPassword')->willReturn(null); |
||||
|
||||
$this->shareManager->expects($this->once()) |
||||
->method('getShareByToken') |
||||
->with('GX9HSGQrGE') |
||||
->willReturn($share); |
||||
|
||||
$result = $this->invokePrivate($this->auth, 'validateUserPass', ['username', 'password']); |
||||
|
||||
$this->assertTrue($result); |
||||
} |
||||
|
||||
public function testSharePasswordFancyShareType(): void { |
||||
$this->request->method('getPathInfo') |
||||
->willReturn('/dav/files/GX9HSGQrGE'); |
||||
|
||||
$share = $this->getMockBuilder(IShare::class) |
||||
->disableOriginalConstructor() |
||||
->getMock(); |
||||
$share->method('getPassword')->willReturn('password'); |
||||
$share->method('getShareType')->willReturn(42); |
||||
|
||||
$this->shareManager->expects($this->once()) |
||||
->method('getShareByToken') |
||||
->with('GX9HSGQrGE') |
||||
->willReturn($share); |
||||
|
||||
$result = $this->invokePrivate($this->auth, 'validateUserPass', ['username', 'password']); |
||||
|
||||
$this->assertFalse($result); |
||||
} |
||||
|
||||
|
||||
public function testSharePasswordRemote(): void { |
||||
$this->request->method('getPathInfo') |
||||
->willReturn('/dav/files/GX9HSGQrGE'); |
||||
|
||||
$share = $this->getMockBuilder(IShare::class) |
||||
->disableOriginalConstructor() |
||||
->getMock(); |
||||
$share->method('getPassword')->willReturn('password'); |
||||
$share->method('getShareType')->willReturn(IShare::TYPE_REMOTE); |
||||
|
||||
$this->shareManager->expects($this->once()) |
||||
->method('getShareByToken') |
||||
->with('GX9HSGQrGE') |
||||
->willReturn($share); |
||||
|
||||
$result = $this->invokePrivate($this->auth, 'validateUserPass', ['username', 'password']); |
||||
|
||||
$this->assertTrue($result); |
||||
} |
||||
|
||||
public function testSharePasswordLinkValidPassword(): void { |
||||
$this->request->method('getPathInfo') |
||||
->willReturn('/dav/files/GX9HSGQrGE'); |
||||
|
||||
$share = $this->getMockBuilder(IShare::class) |
||||
->disableOriginalConstructor() |
||||
->getMock(); |
||||
$share->method('getPassword')->willReturn('password'); |
||||
$share->method('getShareType')->willReturn(IShare::TYPE_LINK); |
||||
|
||||
$this->shareManager->expects($this->once()) |
||||
->method('getShareByToken') |
||||
->with('GX9HSGQrGE') |
||||
->willReturn($share); |
||||
|
||||
$this->shareManager->expects($this->once()) |
||||
->method('checkPassword')->with( |
||||
$this->equalTo($share), |
||||
$this->equalTo('password') |
||||
)->willReturn(true); |
||||
|
||||
$result = $this->invokePrivate($this->auth, 'validateUserPass', ['username', 'password']); |
||||
|
||||
$this->assertTrue($result); |
||||
} |
||||
|
||||
public function testSharePasswordMailValidPassword(): void { |
||||
$this->request->method('getPathInfo') |
||||
->willReturn('/dav/files/GX9HSGQrGE'); |
||||
|
||||
$share = $this->getMockBuilder(IShare::class) |
||||
->disableOriginalConstructor() |
||||
->getMock(); |
||||
$share->method('getPassword')->willReturn('password'); |
||||
$share->method('getShareType')->willReturn(IShare::TYPE_EMAIL); |
||||
|
||||
$this->shareManager->expects($this->once()) |
||||
->method('getShareByToken') |
||||
->with('GX9HSGQrGE') |
||||
->willReturn($share); |
||||
|
||||
$this->shareManager->expects($this->once()) |
||||
->method('checkPassword')->with( |
||||
$this->equalTo($share), |
||||
$this->equalTo('password') |
||||
)->willReturn(true); |
||||
|
||||
$result = $this->invokePrivate($this->auth, 'validateUserPass', ['username', 'password']); |
||||
|
||||
$this->assertTrue($result); |
||||
} |
||||
|
||||
public function testInvalidSharePasswordLinkValidSession(): void { |
||||
$this->request->method('getPathInfo') |
||||
->willReturn('/dav/files/GX9HSGQrGE'); |
||||
|
||||
$share = $this->getMockBuilder(IShare::class) |
||||
->disableOriginalConstructor() |
||||
->getMock(); |
||||
$share->method('getPassword')->willReturn('password'); |
||||
$share->method('getShareType')->willReturn(IShare::TYPE_LINK); |
||||
$share->method('getId')->willReturn('42'); |
||||
|
||||
$this->shareManager->expects($this->once()) |
||||
->method('getShareByToken') |
||||
->with('GX9HSGQrGE') |
||||
->willReturn($share); |
||||
|
||||
$this->shareManager->expects($this->once()) |
||||
->method('checkPassword') |
||||
->with( |
||||
$this->equalTo($share), |
||||
$this->equalTo('password') |
||||
)->willReturn(false); |
||||
|
||||
$this->session->method('exists')->with('public_link_authenticated')->willReturn(true); |
||||
$this->session->method('get')->with('public_link_authenticated')->willReturn('42'); |
||||
|
||||
$result = $this->invokePrivate($this->auth, 'validateUserPass', ['username', 'password']); |
||||
|
||||
$this->assertTrue($result); |
||||
} |
||||
|
||||
public function testSharePasswordLinkInvalidSession(): void { |
||||
$this->request->method('getPathInfo') |
||||
->willReturn('/dav/files/GX9HSGQrGE'); |
||||
|
||||
$share = $this->getMockBuilder(IShare::class) |
||||
->disableOriginalConstructor() |
||||
->getMock(); |
||||
$share->method('getPassword')->willReturn('password'); |
||||
$share->method('getShareType')->willReturn(IShare::TYPE_LINK); |
||||
$share->method('getId')->willReturn('42'); |
||||
|
||||
$this->shareManager->expects($this->once()) |
||||
->method('getShareByToken') |
||||
->with('GX9HSGQrGE') |
||||
->willReturn($share); |
||||
|
||||
$this->shareManager->expects($this->once()) |
||||
->method('checkPassword') |
||||
->with( |
||||
$this->equalTo($share), |
||||
$this->equalTo('password') |
||||
)->willReturn(false); |
||||
|
||||
$this->session->method('exists')->with('public_link_authenticated')->willReturn(true); |
||||
$this->session->method('get')->with('public_link_authenticated')->willReturn('43'); |
||||
|
||||
$result = $this->invokePrivate($this->auth, 'validateUserPass', ['username', 'password']); |
||||
|
||||
$this->assertFalse($result); |
||||
} |
||||
|
||||
|
||||
public function testSharePasswordMailInvalidSession(): void { |
||||
$this->request->method('getPathInfo') |
||||
->willReturn('/dav/files/GX9HSGQrGE'); |
||||
|
||||
$share = $this->getMockBuilder(IShare::class) |
||||
->disableOriginalConstructor() |
||||
->getMock(); |
||||
$share->method('getPassword')->willReturn('password'); |
||||
$share->method('getShareType')->willReturn(IShare::TYPE_EMAIL); |
||||
$share->method('getId')->willReturn('42'); |
||||
|
||||
$this->shareManager->expects($this->once()) |
||||
->method('getShareByToken') |
||||
->with('GX9HSGQrGE') |
||||
->willReturn($share); |
||||
|
||||
$this->shareManager->expects($this->once()) |
||||
->method('checkPassword') |
||||
->with( |
||||
$this->equalTo($share), |
||||
$this->equalTo('password') |
||||
)->willReturn(false); |
||||
|
||||
$this->session->method('exists')->with('public_link_authenticated')->willReturn(true); |
||||
$this->session->method('get')->with('public_link_authenticated')->willReturn('43'); |
||||
|
||||
$result = $this->invokePrivate($this->auth, 'validateUserPass', ['username', 'password']); |
||||
|
||||
$this->assertFalse($result); |
||||
} |
||||
} |
||||
Loading…
Reference in new issue