mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
BUG Fix flushing on live mode (#7241)
* BUG Fix flushing on live mode Fixes #7217 * Clarify injector service documentation
This commit is contained in:
parent
4dbc2a99e5
commit
0681567102
@ -3,6 +3,7 @@ Name: requestprocessors
|
|||||||
---
|
---
|
||||||
SilverStripe\Core\Injector\Injector:
|
SilverStripe\Core\Injector\Injector:
|
||||||
SilverStripe\Control\Director:
|
SilverStripe\Control\Director:
|
||||||
|
# Note: Don't add 'class' config here, as it will affect ErrorDirector as well
|
||||||
properties:
|
properties:
|
||||||
Middlewares:
|
Middlewares:
|
||||||
TrustedProxyMiddleware: '%$SilverStripe\Control\Middleware\TrustedProxyMiddleware'
|
TrustedProxyMiddleware: '%$SilverStripe\Control\Middleware\TrustedProxyMiddleware'
|
||||||
@ -16,3 +17,11 @@ SilverStripe\Core\Injector\Injector:
|
|||||||
SilverStripe\Control\TrustedProxyMiddleware:
|
SilverStripe\Control\TrustedProxyMiddleware:
|
||||||
properties:
|
properties:
|
||||||
TrustedProxyIPs: "`SS_TRUSTED_PROXY_IPS`"
|
TrustedProxyIPs: "`SS_TRUSTED_PROXY_IPS`"
|
||||||
|
---
|
||||||
|
Name: errorrequestprocessors
|
||||||
|
After:
|
||||||
|
- requestprocessors
|
||||||
|
---
|
||||||
|
SilverStripe\Core\Injector\Injector:
|
||||||
|
# Note: If Director config changes, take note it will affect this config too
|
||||||
|
SilverStripe\Core\Startup\ErrorDirector: '%$SilverStripe\Control\Director'
|
||||||
|
@ -252,11 +252,31 @@ assign a reference to that service.
|
|||||||
:::yaml
|
:::yaml
|
||||||
Injector:
|
Injector:
|
||||||
JSONServiceDefinition:
|
JSONServiceDefinition:
|
||||||
|
class: JSONServiceImplementor
|
||||||
properties:
|
properties:
|
||||||
Serialiser: JSONSerialiser
|
Serialiser: JSONSerialiser
|
||||||
GZIPJSONProvider: %$JSONServiceDefinition
|
GZIPJSONProvider: %$JSONServiceDefinition
|
||||||
|
|
||||||
|
|
||||||
|
`Injector::inst()->get('GZIPJSONProvider')` will then be an instance of `JSONServiceImplementor` with the injected
|
||||||
|
properties.
|
||||||
|
|
||||||
|
It is important here to note that the 'class' property of the parent service will be inherited directly as well.
|
||||||
|
If class is not specified, then the class will be inherited from the outer service name, not the inner service name.
|
||||||
|
|
||||||
|
For example with this config:
|
||||||
|
|
||||||
|
:::yaml
|
||||||
|
Injector:
|
||||||
|
Connector:
|
||||||
|
properties:
|
||||||
|
AsString: true
|
||||||
|
ServiceConnector: %$Connector
|
||||||
|
|
||||||
|
|
||||||
|
Both `Connector` and `ServiceConnector` will have the `AsString` property set to true, but the resulting
|
||||||
|
instances will be classes which match their respective service names, due to the lack of a `class` specification.
|
||||||
|
|
||||||
## Testing with Injector
|
## Testing with Injector
|
||||||
|
|
||||||
In situations where injector states must be temporarily overridden, it is possible to create nested Injector instances
|
In situations where injector states must be temporarily overridden, it is possible to create nested Injector instances
|
||||||
|
@ -442,6 +442,9 @@ Upgrade subclasses
|
|||||||
-class MyClass extends Object
|
-class MyClass extends Object
|
||||||
-{
|
-{
|
||||||
-}
|
-}
|
||||||
|
+use SilverStripe\Core\Extensible;
|
||||||
|
+use SilverStripe\Core\Injector\Injectable;
|
||||||
|
+use SilverStripe\Core\Config\Configurable;
|
||||||
+class MyClass
|
+class MyClass
|
||||||
+{
|
+{
|
||||||
+ use Extensible;
|
+ use Extensible;
|
||||||
|
@ -6,9 +6,8 @@ use SilverStripe\Control\Director;
|
|||||||
use SilverStripe\Control\HTTPRequest;
|
use SilverStripe\Control\HTTPRequest;
|
||||||
use SilverStripe\Control\HTTPResponse;
|
use SilverStripe\Control\HTTPResponse;
|
||||||
use SilverStripe\Control\HTTPResponse_Exception;
|
use SilverStripe\Control\HTTPResponse_Exception;
|
||||||
use SilverStripe\Core\Application;
|
|
||||||
use SilverStripe\Control\Middleware\HTTPMiddleware;
|
use SilverStripe\Control\Middleware\HTTPMiddleware;
|
||||||
use SilverStripe\Security\Permission;
|
use SilverStripe\Core\Application;
|
||||||
use SilverStripe\Security\Security;
|
use SilverStripe\Security\Security;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -87,9 +86,10 @@ class ErrorControlChainMiddleware implements HTTPMiddleware
|
|||||||
// Ensure session is started
|
// Ensure session is started
|
||||||
$request->getSession()->init($request);
|
$request->getSession()->init($request);
|
||||||
|
|
||||||
// Next, check if we're in dev mode, or the database doesn't have any security data, or we are admin
|
// Request with ErrorDirector
|
||||||
if (Director::isDev() || !Security::database_is_ready() || Permission::check('ADMIN')) {
|
$result = ErrorDirector::singleton()->handleRequestWithToken($request, $reloadToken, $this->getApplication()->getKernel());
|
||||||
return $reloadToken->reloadWithToken();
|
if ($result) {
|
||||||
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fail and redirect the user to the login page
|
// Fail and redirect the user to the login page
|
||||||
|
47
src/Core/Startup/ErrorDirector.php
Normal file
47
src/Core/Startup/ErrorDirector.php
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\Core\Startup;
|
||||||
|
|
||||||
|
use SilverStripe\Control\Director;
|
||||||
|
use SilverStripe\Control\HTTPRequest;
|
||||||
|
use SilverStripe\Control\HTTPResponse;
|
||||||
|
use SilverStripe\Core\Injector\Injector;
|
||||||
|
use SilverStripe\Core\Kernel;
|
||||||
|
use SilverStripe\Security\Permission;
|
||||||
|
use SilverStripe\Security\Security;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specialised Director class used by ErrorControlChain to handle error and redirect conditions
|
||||||
|
*
|
||||||
|
* @internal This class is experimental API and may change without warning
|
||||||
|
*/
|
||||||
|
class ErrorDirector extends Director
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Redirect with token if allowed, or null if not allowed
|
||||||
|
*
|
||||||
|
* @param HTTPRequest $request
|
||||||
|
* @param ParameterConfirmationToken $token
|
||||||
|
* @param Kernel $kernel
|
||||||
|
* @return null|HTTPResponse Redirection response, or null if not able to redirect
|
||||||
|
*/
|
||||||
|
public function handleRequestWithToken(HTTPRequest $request, ParameterConfirmationToken $token, Kernel $kernel)
|
||||||
|
{
|
||||||
|
Injector::inst()->registerService($request, HTTPRequest::class);
|
||||||
|
|
||||||
|
// Next, check if we're in dev mode, or the database doesn't have any security data, or we are admin
|
||||||
|
$reload = function (HTTPRequest $request) use ($token, $kernel) {
|
||||||
|
if ($kernel->getEnvironment() === Kernel::DEV || !Security::database_is_ready() || Permission::check('ADMIN')) {
|
||||||
|
return $token->reloadWithToken();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
return $this->callMiddleware($request, $reload);
|
||||||
|
} finally {
|
||||||
|
// Ensure registered request is un-registered
|
||||||
|
Injector::inst()->unregisterNamedObject(HTTPRequest::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -498,7 +498,7 @@ class DirectorTest extends SapphireTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @covers \SilverStripe\Control\Director::extract_request_headers()
|
* @covers \SilverStripe\Control\HTTPRequestBuilder::extractRequestHeaders()
|
||||||
*/
|
*/
|
||||||
public function testExtractRequestHeaders()
|
public function testExtractRequestHeaders()
|
||||||
{
|
{
|
||||||
|
77
tests/php/Core/Startup/ErrorControlChainMiddlewareTest.php
Normal file
77
tests/php/Core/Startup/ErrorControlChainMiddlewareTest.php
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\Core\Tests\Startup;
|
||||||
|
|
||||||
|
use SilverStripe\Control\Cookie;
|
||||||
|
use SilverStripe\Control\HTTPApplication;
|
||||||
|
use SilverStripe\Control\HTTPRequest;
|
||||||
|
use SilverStripe\Control\HTTPResponse;
|
||||||
|
use SilverStripe\Control\Session;
|
||||||
|
use SilverStripe\Core\Kernel;
|
||||||
|
use SilverStripe\Core\Startup\ErrorControlChainMiddleware;
|
||||||
|
use SilverStripe\Core\Tests\Startup\ErrorControlChainMiddlewareTest\BlankKernel;
|
||||||
|
use SilverStripe\Dev\SapphireTest;
|
||||||
|
use SilverStripe\Security\Security;
|
||||||
|
|
||||||
|
class ErrorControlChainMiddlewareTest extends SapphireTest
|
||||||
|
{
|
||||||
|
protected $usesDatabase = true;
|
||||||
|
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
Security::force_database_is_ready(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function tearDown()
|
||||||
|
{
|
||||||
|
Security::clear_database_is_ready();
|
||||||
|
parent::tearDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testLiveFlushAdmin()
|
||||||
|
{
|
||||||
|
// Mock admin
|
||||||
|
$adminID = $this->logInWithPermission('ADMIN');
|
||||||
|
$this->logOut();
|
||||||
|
|
||||||
|
// Mock app
|
||||||
|
$app = new HTTPApplication(new BlankKernel(BASE_PATH));
|
||||||
|
$app->getKernel()->setEnvironment(Kernel::LIVE);
|
||||||
|
|
||||||
|
// Test being logged in as admin
|
||||||
|
$chain = new ErrorControlChainMiddleware($app);
|
||||||
|
$request = new HTTPRequest('GET', '/', ['flush' => 1]);
|
||||||
|
$request->setSession(new Session(['loggedInAs' => $adminID]));
|
||||||
|
$result = $chain->process($request, function () {
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->assertInstanceOf(HTTPResponse::class, $result);
|
||||||
|
$location = $result->getHeader('Location');
|
||||||
|
$this->assertContains('?flush=1&flushtoken=', $location);
|
||||||
|
$this->assertNotContains('Security/login', $location);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testLiveFlushUnauthenticated()
|
||||||
|
{
|
||||||
|
// Mock app
|
||||||
|
$app = new HTTPApplication(new BlankKernel(BASE_PATH));
|
||||||
|
$app->getKernel()->setEnvironment(Kernel::LIVE);
|
||||||
|
|
||||||
|
// Test being logged in as no one
|
||||||
|
Security::setCurrentUser(null);
|
||||||
|
$chain = new ErrorControlChainMiddleware($app);
|
||||||
|
$request = new HTTPRequest('GET', '/', ['flush' => 1]);
|
||||||
|
$request->setSession(new Session(['loggedInAs' => 0]));
|
||||||
|
$result = $chain->process($request, function () {
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Should be directed to login, not to flush
|
||||||
|
$this->assertInstanceOf(HTTPResponse::class, $result);
|
||||||
|
$location = $result->getHeader('Location');
|
||||||
|
$this->assertNotContains('?flush=1&flushtoken=', $location);
|
||||||
|
$this->assertContains('Security/login', $location);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\Core\Tests\Startup\ErrorControlChainMiddlewareTest;
|
||||||
|
|
||||||
|
use SilverStripe\Core\CoreKernel;
|
||||||
|
|
||||||
|
class BlankKernel extends CoreKernel
|
||||||
|
{
|
||||||
|
public function __construct($basePath)
|
||||||
|
{
|
||||||
|
// Noop
|
||||||
|
}
|
||||||
|
|
||||||
|
public function boot($flush = false)
|
||||||
|
{
|
||||||
|
// Noop
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user