Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
JanTvrdik committed May 7, 2016
1 parent 4494892 commit a3c0862
Show file tree
Hide file tree
Showing 2 changed files with 241 additions and 0 deletions.
142 changes: 142 additions & 0 deletions src/SecuredRouter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
<?php


namespace Nextras\Application\UI;

use Nette;
use Nette\Application\IPresenterFactory;
use Nette\Application\IRouter;
use Nette\Application\Request;
use Nette\Application\UI\Presenter;
use Nette\Http\Session;
use ReflectionMethod;


class SecuredRouter implements IRouter
{
/** @var IRouter */
private $inner;

/** @var IPresenterFactory */
private $presenterFactory;

/** @var Session */
private $session;


/**
* @param IRouter $inner
* @param IPresenterFactory $presenterFactory
* @param Session $session
*/
public function __construct(IRouter $inner, IPresenterFactory $presenterFactory, Session $session)
{
$this->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);
}
}
99 changes: 99 additions & 0 deletions src/SecuredRouterFlagBased.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<?php


namespace Nextras\Application\UI;

use Nette;
use Nette\Application\IPresenterFactory;
use Nette\Application\IRouter;
use Nette\Application\Request;
use Nette\Http\Session;


class SecuredRouterFlagBased implements IRouter
{

/** signed flag */
const SIGNED = 'signed';

/** @var IRouter */
private $inner;

/** @var IPresenterFactory */
private $presenterFactory;

/** @var Session */
private $session;


/**
* @param IRouter $inner
* @param IPresenterFactory $presenterFactory
* @param Session $session
*/
public function __construct(IRouter $inner, IPresenterFactory $presenterFactory, Session $session)
{
$this->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);
}
}

0 comments on commit a3c0862

Please sign in to comment.