Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
0.00% |
0 / 1 |
|
90.00% |
9 / 10 |
CRAP | |
95.00% |
57 / 60 |
EnvCheckMiddleware | |
0.00% |
0 / 1 |
|
90.00% |
9 / 10 |
24 | |
95.00% |
57 / 60 |
__construct | |
100.00% |
1 / 1 |
1 | |
100.00% |
7 / 7 |
|||
beforeController | |
100.00% |
1 / 1 |
3 | |
100.00% |
7 / 7 |
|||
validateAndSetTokenBasedEnv | |
100.00% |
1 / 1 |
2 | |
100.00% |
9 / 9 |
|||
getShare | |
100.00% |
1 / 1 |
2 | |
100.00% |
7 / 7 |
|||
checkShareIsValid | |
100.00% |
1 / 1 |
3 | |
100.00% |
5 / 5 |
|||
checkItemType | |
100.00% |
1 / 1 |
2 | |
100.00% |
4 / 4 |
|||
checkAuthorisation | |
100.00% |
1 / 1 |
3 | |
100.00% |
6 / 6 |
|||
authenticate | |
0.00% |
0 / 1 |
2.50 | |
50.00% |
3 / 6 |
|||
checkPassword | |
100.00% |
1 / 1 |
3 | |
100.00% |
5 / 5 |
|||
checkSession | |
100.00% |
1 / 1 |
3 | |
100.00% |
4 / 4 |
<?php | |
/** | |
* Gallery | |
* | |
* This file is licensed under the Affero General Public License version 3 or | |
* later. See the COPYING file. | |
* | |
* @author Olivier Paroz <galleryapps@oparoz.com> | |
* @author Bernhard Posselt <dev@bernhard-posselt.com> | |
* @author Authors of \OCA\Files_Sharing\Helper | |
* | |
* @copyright Olivier Paroz 2014-2016 | |
* @copyright Bernhard Posselt 2012-2015 | |
* @copyright Authors of \OCA\Files_Sharing\Helper 2014-2016 | |
*/ | |
namespace OCA\Gallery\Middleware; | |
use OCP\IRequest; | |
use OCP\IURLGenerator; | |
use OCP\ISession; | |
use OCP\ILogger; | |
use OCP\Share; | |
use OCP\Share\IShare; | |
use OCP\Share\Exceptions\ShareNotFound; | |
use OCP\Security\IHasher; | |
use OCP\AppFramework\Http; | |
use OCP\AppFramework\Utility\IControllerMethodReflector; | |
use OCA\Gallery\Environment\Environment; | |
use OCP\Share\IManager; | |
/** | |
* Checks that we have a valid token linked to a valid resource and that the | |
* user is authorised to access it | |
* | |
* Once all checks have been passed, the environment is ready to use | |
* | |
* @package OCA\Gallery\Middleware | |
*/ | |
class EnvCheckMiddleware extends CheckMiddleware { | |
/** @var IHasher */ | |
private $hasher; | |
/** @var ISession */ | |
private $session; | |
/** @var Environment */ | |
private $environment; | |
/** @var IControllerMethodReflector */ | |
protected $reflector; | |
/** @var IManager */ | |
protected $shareManager; | |
/*** | |
* Constructor | |
* | |
* @param string $appName | |
* @param IRequest $request | |
* @param IHasher $hasher | |
* @param ISession $session | |
* @param Environment $environment | |
* @param IControllerMethodReflector $reflector | |
* @param IURLGenerator $urlGenerator | |
* @param ILogger $logger | |
* @param IManager $shareManager | |
*/ | |
public function __construct( | |
$appName, | |
IRequest $request, | |
IHasher $hasher, | |
ISession $session, | |
Environment $environment, | |
IControllerMethodReflector $reflector, | |
IURLGenerator $urlGenerator, | |
IManager $shareManager, | |
ILogger $logger | |
) { | |
parent::__construct( | |
$appName, | |
$request, | |
$urlGenerator, | |
$logger | |
); | |
$this->hasher = $hasher; | |
$this->session = $session; | |
$this->environment = $environment; | |
$this->reflector = $reflector; | |
$this->shareManager = $shareManager; | |
} | |
/** | |
* Checks that we have a valid token linked to a valid resource and that the | |
* user is authorised to access it | |
* | |
* Inspects the controller method annotations and if PublicPage is found | |
* it checks that we have a token and an optional password giving access to a valid resource. | |
* Once that's done, the environment is setup so that our services can find the resources they | |
* need. | |
* | |
* The checks are not performed on "guest" pages and the environment is not setup. Typical | |
* guest pages are anonymous error ages | |
* | |
* @inheritDoc | |
*/ | |
public function beforeController($controller, $methodName) { | |
if ($this->reflector->hasAnnotation('Guest')) { | |
return; | |
} | |
$isPublicPage = $this->reflector->hasAnnotation('PublicPage'); | |
if ($isPublicPage) { | |
$this->validateAndSetTokenBasedEnv(); | |
} else { | |
$this->environment->setStandardEnv(); | |
} | |
} | |
/** | |
* Checks that we have a token and an optional password giving access to a | |
* valid resource. Sets the token based environment after that | |
* | |
* @throws CheckException | |
*/ | |
private function validateAndSetTokenBasedEnv() { | |
$token = $this->request->getParam('token'); | |
if (!$token) { | |
throw new CheckException( | |
"Can't access a public resource without a token", Http::STATUS_NOT_FOUND | |
); | |
} else { | |
$share = $this->getShare($token); | |
$password = $this->request->getParam('password'); | |
// Let's see if the user needs to provide a password | |
$this->checkAuthorisation($share, $password); | |
$this->environment->setTokenBasedEnv($share); | |
} | |
} | |
/** | |
* Validates a token to make sure its linked to a valid resource | |
* | |
* Uses Share 2.0 | |
* | |
* @fixme setIncognitoMode in 8.1 https://github.com/owncloud/core/pull/12912 | |
* | |
* @param string $token | |
* | |
* @throws CheckException | |
* @return IShare | |
*/ | |
private function getShare($token) { | |
// Allows a logged in user to access public links | |
\OC_User::setIncognitoMode(true); | |
try { | |
$share = $this->shareManager->getShareByToken($token); | |
} catch (ShareNotFound $e) { | |
throw new CheckException($e->getMessage(), Http::STATUS_NOT_FOUND); | |
} | |
$this->checkShareIsValid($share, $token); | |
$this->checkItemType($share); | |
return $share; | |
} | |
/** | |
* Makes sure that the token contains all the information that we need | |
* | |
* @param IShare $share | |
* @param string $token | |
* | |
* @throws CheckException | |
*/ | |
private function checkShareIsValid($share, $token) { | |
if ($share->getShareOwner() === null | |
|| $share->getTarget() === null | |
) { | |
$message = | |
'Passed token seems to be valid, but it does not contain all necessary information . ("' | |
. $token . '")'; | |
throw new CheckException($message, Http::STATUS_NOT_FOUND); | |
} | |
} | |
/** | |
* Makes sure an item type was set for that token | |
* | |
* @param IShare $share | |
* | |
* @throws CheckException | |
*/ | |
private function checkItemType($share) { | |
if ($share->getNodeType() === null) { | |
$message = 'No item type set for share id: ' . $share->getId(); | |
throw new CheckException($message, Http::STATUS_NOT_FOUND); | |
} | |
} | |
/** | |
* Checks if a password is required or if the one supplied is working | |
* | |
* @param IShare $share | |
* @param string|null $password optional password | |
* | |
* @throws CheckException | |
*/ | |
private function checkAuthorisation($share, $password) { | |
$passwordRequired = $share->getPassword(); | |
if (isset($passwordRequired)) { | |
if ($password !== null) { | |
$this->authenticate($share, $password); | |
} else { | |
$this->checkSession($share); | |
} | |
} | |
} | |
/** | |
* Authenticate link item with the given password | |
* or with the session if no password was given. | |
* | |
* @param IShare $share | |
* @param string $password | |
* | |
* @return bool true if authorized, an exception is raised otherwise | |
* | |
* @throws CheckException | |
*/ | |
private function authenticate($share, $password) { | |
if ((int)$share->getShareType() === Share::SHARE_TYPE_LINK) { | |
$this->checkPassword($share, $password); | |
} else { | |
throw new CheckException( | |
'Unknown share type ' . $share->getShareType() . ' for share id ' | |
. $share->getId(), Http::STATUS_NOT_FOUND | |
); | |
} | |
return true; | |
} | |
/** | |
* Validates the given password | |
* | |
* @fixme @LukasReschke says: Migrate old hashes to new hash format | |
* Due to the fact that there is no reasonable functionality to update the password | |
* of an existing share no migration is yet performed there. | |
* The only possibility is to update the existing share which will result in a new | |
* share ID and is a major hack. | |
* | |
* In the future the migration should be performed once there is a proper method | |
* to update the share's password. (for example `$share->updatePassword($password)` | |
* | |
* @link https://github.com/owncloud/core/issues/10671 | |
* | |
* @param IShare $share | |
* @param string $password | |
* | |
* @throws CheckException | |
*/ | |
private function checkPassword($share, $password) { | |
$newHash = ''; | |
if ($this->shareManager->checkPassword($share, $password)) { | |
// Save item id in session for future requests | |
$this->session->set('public_link_authenticated', (string)$share->getId()); | |
// @codeCoverageIgnoreStart | |
if (!empty($newHash)) { | |
// For future use | |
} | |
// @codeCoverageIgnoreEnd | |
} else { | |
throw new CheckException("Wrong password", Http::STATUS_UNAUTHORIZED); | |
} | |
} | |
/** | |
* Makes sure the user is already properly authenticated when a password is required and none | |
* was provided | |
* | |
* @param IShare $share | |
* | |
* @throws CheckException | |
*/ | |
private function checkSession($share) { | |
// Not authenticated ? | |
if (!$this->session->exists('public_link_authenticated') | |
|| $this->session->get('public_link_authenticated') !== (string)$share->getId() | |
) { | |
throw new CheckException("Missing password", Http::STATUS_UNAUTHORIZED); | |
} | |
} | |
} |