From a3c086261d8ead146af09c52a06a1b86f8e37215 Mon Sep 17 00:00:00 2001 From: Jan Tvrdik Date: Sat, 7 May 2016 20:09:08 +0200 Subject: [PATCH] WIP --- src/SecuredRouter.php | 142 +++++++++++++++++++++++++++++++++ src/SecuredRouterFlagBased.php | 99 +++++++++++++++++++++++ 2 files changed, 241 insertions(+) create mode 100644 src/SecuredRouter.php create mode 100644 src/SecuredRouterFlagBased.php diff --git a/src/SecuredRouter.php b/src/SecuredRouter.php new file mode 100644 index 0000000..cf4f4d9 --- /dev/null +++ b/src/SecuredRouter.php @@ -0,0 +1,142 @@ +inner = $inner; + $this->presenterFactory = $presenterFactory; + $this->session = $session; + } + + + /** + * @inheritdoc + */ + public function match(Nette\Http\IRequest $httpRequest) + { + $appRequest = $this->inner->match($httpRequest); + + if ($appRequest !== NULL && $this->isSignatureRequired($appRequest) && !$this->isSignatureValid($appRequest)) { + return NULL; + } + + return $appRequest; + } + + + /** + * @inheritdoc + */ + public function constructUrl(Request $appRequest, Nette\Http\Url $refUrl) + { + if ($this->isSignatureRequired($appRequest)) { + $signature = $this->getSignature($appRequest); + $appRequest->setParameters(['_sec' => $signature] + $appRequest->getParameters()); + } + + return $this->inner->constructUrl($appRequest, $refUrl); + } + + + /** + * @param Request $appRequest + * @return bool + */ + protected function isSignatureRequired(Request $appRequest) + { + $presenterName = $appRequest->getPresenterName(); + $presenterClass = $this->presenterFactory->getPresenterClass($presenterName); + + if (!is_a($presenterClass, Presenter::class)) { + return FALSE; + } + + $params = $appRequest->getParameters(); + + if (isset($params['action'])) { + $methodName = $presenterClass::formatActionMethod($params['action']); + $methodRef = new ReflectionMethod($presenterClass, $methodName); + if ($this->isSecured($methodRef)) { + return TRUE; + } + } + + if (isset($params['do'])) { + $methodName = $presenterClass::formatSignalMethod($params['do']); + $methodRef = new ReflectionMethod($presenterClass, $methodName); + if ($this->isSecured($methodRef)) { + return TRUE; + } + } + + return FALSE; + } + + + /** + * @param ReflectionMethod $ref + * @return bool + */ + public function isSecured(ReflectionMethod $ref) + { + return (bool) preg_match('#^[ \t*]*@secured(\s|$)#m', $ref->getDocComment()); + } + + + /** + * @param Request $appRequest + * @return bool + */ + private function isSignatureValid(Request $appRequest) + { + $signature = $appRequest->getParameter('_sec'); + return ($signature !== NULL && hash_equals($this->getSignature($appRequest), $signature)); + } + + + /** + * @param Request $appRequest + * @return string + */ + private function getSignature(Request $appRequest) + { + $sessionSection = $this->session->getSection('Nextras.Application.UI.SecuredLinksPresenterTrait'); + if (!isset($sessionSection->token)) { + $sessionSection->token = function_exists('random_bytes') + ? random_bytes(16) + : Nette\Utils\Random::generate(16, "\x00-\xFF"); + } + + $data = [$this->session->getId(), $appRequest->getPresenterName(), $appRequest->getParameters()]; + $hash = hash_hmac('sha1', serialize($data), $sessionSection->token); + return substr($hash, 0, 6); + } +} diff --git a/src/SecuredRouterFlagBased.php b/src/SecuredRouterFlagBased.php new file mode 100644 index 0000000..002daac --- /dev/null +++ b/src/SecuredRouterFlagBased.php @@ -0,0 +1,99 @@ +inner = $inner; + $this->presenterFactory = $presenterFactory; + $this->session = $session; + } + + + /** + * @inheritdoc + */ + public function match(Nette\Http\IRequest $httpRequest) + { + $appRequest = $this->inner->match($httpRequest); + + if ($appRequest !== NULL && $this->isSignatureValid($appRequest)) { + $appRequest->setFlag(self::SIGNED); + } + + return $appRequest; + } + + + /** + * @inheritdoc + */ + public function constructUrl(Request $appRequest, Nette\Http\Url $refUrl) + { + if ($appRequest->hasFlag(self::SIGNED)) { + $signature = $this->getSignature($appRequest); + $appRequest->setParameters(['_sec' => $signature] + $appRequest->getParameters()); + } + + return $this->inner->constructUrl($appRequest, $refUrl); + } + + + /** + * @param Request $appRequest + * @return bool + */ + private function isSignatureValid(Request $appRequest) + { + $signature = $appRequest->getParameter('_sec'); + return ($signature !== NULL && hash_equals($this->getSignature($appRequest), $signature)); + } + + + /** + * @param Request $appRequest + * @return string + */ + private function getSignature(Request $appRequest) + { + $sessionSection = $this->session->getSection('Nextras.Application.UI.SecuredLinksPresenterTrait'); + if (!isset($sessionSection->token)) { + $sessionSection->token = function_exists('random_bytes') + ? random_bytes(16) + : Nette\Utils\Random::generate(16, "\x00-\xFF"); + } + + $data = [$this->session->getId(), $appRequest->getPresenterName(), $appRequest->getParameters()]; + $hash = hash_hmac('sha1', json_encode($data), $sessionSection->token); + return substr($hash, 0, 6); + } +}