Add XSRF to backend, simplify CMS controller run() method

runInternal has been removed because we do not want to blanket our response logic over every single response, only the happy path. This is because it is impossible to remove. So it is better to take the inverted approach, where if you want the CMS' headers in your custom response, add them yourself. This becomes easy via the new makeResponse() method
This commit is contained in:
Samuel Georges 2019-11-02 19:14:45 +11:00
parent 9d120ad66b
commit 63f65a3f25
4 changed files with 45 additions and 45 deletions

View File

@ -174,6 +174,13 @@ class Controller extends Extendable
return Response::make(Lang::get('system::lang.page.invalid_token.label'), 403);
}
if (
Config::get('cms.enableCsrfProtection', true) &&
Config::get('cms.enableXsrfCookies', true)
) {
$this->setResponseCookie($this->makeXsrfCookie());
}
/*
* Check forced HTTPS protocol.
* @see \System\Traits\SecurityController

View File

@ -138,27 +138,6 @@ class Controller
* @return BaseResponse Returns the response to the provided URL
*/
public function run($url = '/')
{
$response = $this->runInternal($url);
if (
Config::get('cms.enableCsrfProtection', true) &&
Config::get('cms.enableXsrfCookies', true) &&
$response instanceof BaseResponse
) {
$this->addXsrfCookie($response);
}
return $response;
}
/**
* Process the request internally
*
* @param string $url Specifies the requested page URL.
* @return BaseResponse Returns the response to the provided URL
*/
protected function runInternal($url = '/')
{
if ($url === null) {
$url = Request::path();
@ -176,6 +155,13 @@ class Controller
return Response::make(Lang::get('system::lang.page.invalid_token.label'), 403);
}
if (
Config::get('cms.enableCsrfProtection', true) &&
Config::get('cms.enableXsrfCookies', true)
) {
$this->setResponseCookie($this->makeXsrfCookie());
}
/*
* Hidden page
*/

View File

@ -1,7 +1,7 @@
<?php namespace System\Traits;
use Response;
use Symfony\Component\HttpFoundation\HeaderBag;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Component\HttpFoundation\Response as BaseResponse;
/**
@ -24,7 +24,7 @@ trait ResponseMaker
protected $responseOverride = null;
/**
* @var Symfony\Component\HttpFoundation\HeaderBag
* @var Symfony\Component\HttpFoundation\ResponseHeaderBag
*/
protected $responseHeaderBag = null;
@ -36,6 +36,7 @@ trait ResponseMaker
public function setStatusCode($code)
{
$this->statusCode = (int) $code;
return $this;
}
@ -57,6 +58,7 @@ trait ResponseMaker
public function setResponse($response)
{
$this->responseOverride = $response;
return $this;
}
@ -71,7 +73,7 @@ trait ResponseMaker
public function setResponseHeader($key, $values, $replace = true)
{
if ($this->responseHeaderBag === null) {
$this->responseHeaderBag = new HeaderBag;
$this->responseHeaderBag = new ResponseHeaderBag;
}
$this->responseHeaderBag->set($key, $values, $replace);
@ -88,7 +90,7 @@ trait ResponseMaker
public function setResponseCookie($cookie)
{
if ($this->responseHeaderBag === null) {
$this->responseHeaderBag = new HeaderBag;
$this->responseHeaderBag = new ResponseHeaderBag;
}
if (is_string($cookie) && function_exists('cookie')) {
@ -100,6 +102,15 @@ trait ResponseMaker
return $this;
}
/**
* Get the header response bag
* @return Symfony\Component\HttpFoundation\ResponseHeaderBag|null
*/
public function getResponseHeaders()
{
return $this->responseHeaderBag;
}
/**
* Prepares a response that considers overrides and custom responses.
* @param mixed $contents
@ -112,11 +123,12 @@ trait ResponseMaker
}
if (is_string($contents)) {
$contents = Response::make($contents, $this->statusCode);
$contents = Response::make($contents, $this->getStatusCode());
}
if ($contents instanceof BaseResponse && $this->responseHeaderBag !== null) {
$contents = $contents->withHeaders($this->responseHeaderBag);
$responseHeaders = $this->getResponseHeaders();
if ($responseHeaders && $contents instanceof BaseResponse) {
$contents = $contents->withHeaders($responseHeaders);
}
return $contents;

View File

@ -21,28 +21,23 @@ trait SecurityController
* Adds anti-CSRF cookie.
* Adds a cookie with a token for CSRF checks to the response.
*
* @param BaseResponse $response The response object to add the cookie to
* @return BaseResponse
* @return \Symfony\Component\HttpFoundation\Cookie
*/
protected function addXsrfCookie(BaseResponse $response)
protected function makeXsrfCookie()
{
$config = Config::get('session');
$response->headers->setCookie(
new Cookie(
'XSRF-TOKEN',
Session::token(),
Carbon::now()->addMinutes((int) $config['lifetime'])->getTimestamp(),
$config['path'],
$config['domain'],
$config['secure'],
false,
false,
$config['same_site'] ?? null
)
return new Cookie(
'XSRF-TOKEN',
Session::token(),
Carbon::now()->addMinutes((int) $config['lifetime'])->getTimestamp(),
$config['path'],
$config['domain'],
$config['secure'],
false,
false,
$config['same_site'] ?? null
);
return $response;
}
/**