Skip to content

Commit

Permalink
Merge pull request #12 from cercos/master
Browse files Browse the repository at this point in the history
Add IP white listing
  • Loading branch information
HavokInspiration authored Nov 7, 2017
2 parents c3e62b3 + 230985b commit 00518cd
Show file tree
Hide file tree
Showing 5 changed files with 215 additions and 16 deletions.
61 changes: 58 additions & 3 deletions src/Middleware/MaintenanceMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use Cake\Core\Configure;
use Cake\Core\InstanceConfigTrait;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Wrench\Mode\Exception\MissingModeException;
use Wrench\Mode\Mode;

Expand Down Expand Up @@ -44,7 +45,8 @@ class MaintenanceMiddleware
'mode' => [
'className' => 'Wrench\Mode\Redirect',
'config' => []
]
],
'whitelist' => []
];

/**
Expand Down Expand Up @@ -76,7 +78,11 @@ public function __construct($config = [])
}

/**
* Serve assets if the path matches one.
* Serve the maintenance mode if it is enabled and properly configured.
* If the Configure parameter `Wrench.enable` is set to `false`, the maintenance mode will not be served.
* If it is set to `true` but the IP of the client is in the (optional) whitelist, the maintenance mode will not be
* served. The gives the opportunity for an application maintainer to see the application running normally in case
* the maintenance mode is enabled.
*
* @param \Psr\Http\Message\ServerRequestInterface $request The request.
* @param \Psr\Http\Message\ResponseInterface $response The response.
Expand All @@ -85,7 +91,8 @@ public function __construct($config = [])
*/
public function __invoke($request, $response, $next)
{
if (!Configure::read('Wrench.enable')) {
$clientIp = $this->getClientIp($request);
if (!Configure::read('Wrench.enable') || $this->isWhitelisted($clientIp)) {
return $next($request, $response);
}

Expand Down Expand Up @@ -126,4 +133,52 @@ public function mode($mode = null, $config = [])

return $this->_mode = $mode;
}

/**
* Checks the whitelist against the current session IP.
*
* @param string $ip IP the client is using to connect to the app.
* @return bool True if the IP should bypass the maintenance mode.
*/
protected function isWhitelisted($ip)
{
foreach ($this->_config['whitelist'] as $bypassIp) {
if ($ip === $bypassIp) {
return true;
}
}

return false;
}

/**
* Gets the client IP.
*
* @param \Psr\Http\Message\ServerRequestInterface $request Request used.
* @return string IP of the client.
*/
protected function getClientIp($request)
{
if (method_exists($request, 'clientIp')) {
return $request->clientIp();
}

// @codeCoverageIgnoreStart
if ($request instanceof ServerRequestInterface) {
$ip = '';
$serverParams = $request->getServerParams();
if (!empty($serverParams['HTTP_CLIENT_IP'])) {
$ip = $serverParams['HTTP_CLIENT_IP'];
} elseif (!empty($serverParams['HTTP_X_FORWARDED_FOR'])) {
$ip = $serverParams['HTTP_X_FORWARDED_FOR'];
} elseif (!empty($serverParams['REMOTE_ADDR'])) {
$ip = $serverParams['REMOTE_ADDR'];
}

return $ip;
}
// @codeCoverageIgnoreEnd

return '';
}
}
53 changes: 49 additions & 4 deletions tests/TestCase/Mode/CallbackTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ public function testMaintenanceModeCallback()
Configure::write('Wrench.enable', true);
$request = ServerRequestFactory::fromGlobals([
'HTTP_HOST' => 'localhost',
'REQUEST_URI' => '/'
'REQUEST_URI' => '/',
'REMOTE_ADDR' => '127.0.0.1'
]);
$response = new Response();
$next = function ($req, $res) {
Expand Down Expand Up @@ -71,17 +72,18 @@ public function testMaintenanceModeCallback()
}

/**
* Test the Callback filter mode
* @return void
* Test the Callback filter mode with a wrong callable
*
* @return void
* @expectedException \InvalidArgumentException
*/
public function testMaintenanceModeCallbackException()
{
Configure::write('Wrench.enable', true);
$request = ServerRequestFactory::fromGlobals([
'HTTP_HOST' => 'localhost',
'REQUEST_URI' => '/'
'REQUEST_URI' => '/',
'REMOTE_ADDR' => '127.0.0.1'
]);
$response = new Response();
$next = function ($req, $res) {
Expand All @@ -98,4 +100,47 @@ public function testMaintenanceModeCallbackException()

$middleware($request, $response, $next);
}

/**
* Test the Callback filter mode when using the "whitelist" option. Meaning the maintenance mode should not be shown
* if the client IP is whitelisted.
*
* @return void
*/
public function testMaintenanceModeCallbackWhitelist()
{
Configure::write('Wrench.enable', true);
$request = ServerRequestFactory::fromGlobals([
'HTTP_HOST' => 'localhost',
'REQUEST_URI' => '/',
'REMOTE_ADDR' => '127.0.0.1'
]);
$response = new Response();
$next = function ($req, $res) {
return $res;
};
$middleware = new MaintenanceMiddleware([
'whitelist' => ['127.0.0.1'],
'mode' => [
'className' => 'Wrench\Mode\Callback',
'config' => [
'callback' => function ($request, $response) {
$string = 'Some content from a callback';

$stream = new Stream(fopen('php://memory', 'r+'));
$stream->write($string);
$response = $response->withBody($stream);
$response = $response->withStatus(503);
$response = $response->withHeader('someHeader', 'someValue');

return $response;
}
]
]
]);
$middlewareResponse = $middleware($request, $response, $next);

$this->assertEquals('', (string)$middlewareResponse->getBody());
$this->assertEquals(200, $middlewareResponse->getStatusCode());
}
}
40 changes: 37 additions & 3 deletions tests/TestCase/Mode/OutputTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ public function testOutputModeNoParams()
Configure::write('Wrench.enable', true);
$request = ServerRequestFactory::fromGlobals([
'HTTP_HOST' => 'localhost',
'REQUEST_URI' => '/'
'REQUEST_URI' => '/',
'REMOTE_ADDR' => '127.0.0.1'
]);
$response = new Response();
$next = function ($req, $res) {
Expand Down Expand Up @@ -66,7 +67,8 @@ public function testMaintenanceModeFilterOutputHeaders()
Configure::write('Wrench.enable', true);
$request = ServerRequestFactory::fromGlobals([
'HTTP_HOST' => 'localhost',
'REQUEST_URI' => '/'
'REQUEST_URI' => '/',
'REMOTE_ADDR' => '127.0.0.1'
]);
$response = new Response();
$next = function ($req, $res) {
Expand Down Expand Up @@ -103,7 +105,8 @@ public function testOutputModeCustomParams()
Configure::write('Wrench.enable', true);
$request = ServerRequestFactory::fromGlobals([
'HTTP_HOST' => 'localhost',
'REQUEST_URI' => '/'
'REQUEST_URI' => '/',
'REMOTE_ADDR' => '127.0.0.1'
]);
$response = new Response();
$next = function ($req, $res) {
Expand All @@ -119,4 +122,35 @@ public function testOutputModeCustomParams()
]);
$middleware($request, $response, $next);
}

/**
* Test the Output filter mode without params when using the "whitelist" option. Meaning the maintenance mode should
* not be shown if the client IP is whitelisted.
*
* @return void
*/
public function testOutputModeWhitelist()
{
Configure::write('Wrench.enable', true);
$request = ServerRequestFactory::fromGlobals([
'HTTP_HOST' => 'localhost',
'REQUEST_URI' => '/',
'REMOTE_ADDR' => '127.0.0.1'
]);
$response = new Response();
$next = function ($req, $res) {
return $res;
};
$middleware = new MaintenanceMiddleware([
'whitelist' => ['127.0.0.1'],
'mode' => [
'className' => 'Wrench\Mode\Output'
]
]);
$res = $middleware($request, $response, $next);

$this->assertEquals(200, $res->getStatusCode());

$this->assertEquals($res->getBody(), '');
}
}
35 changes: 32 additions & 3 deletions tests/TestCase/Mode/RedirectTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ public function testRedirectModeNoParams()
Configure::write('Wrench.enable', true);
$request = ServerRequestFactory::fromGlobals([
'HTTP_HOST' => 'localhost',
'REQUEST_URI' => '/'
'REQUEST_URI' => '/',
'REMOTE_ADDR' => '127.0.0.1'
]);
$response = new Response();
$next = function ($req, $res) {
Expand All @@ -60,7 +61,8 @@ public function testRedirectModeCustomParams()
Configure::write('Wrench.enable', true);
$request = ServerRequestFactory::fromGlobals([
'HTTP_HOST' => 'localhost',
'REQUEST_URI' => '/'
'REQUEST_URI' => '/',
'REMOTE_ADDR' => '127.0.0.1'
]);
$response = new Response();
$next = function ($req, $res) {
Expand Down Expand Up @@ -91,7 +93,8 @@ public function testMaintenanceModeFilterRedirectHeaders()
Configure::write('Wrench.enable', true);
$request = ServerRequestFactory::fromGlobals([
'HTTP_HOST' => 'localhost',
'REQUEST_URI' => '/'
'REQUEST_URI' => '/',
'REMOTE_ADDR' => '127.0.0.1'
]);
$response = new Response();
$next = function ($req, $res) {
Expand All @@ -115,4 +118,30 @@ public function testMaintenanceModeFilterRedirectHeaders()
$this->assertEquals('someValue', $middlewareResponse->getHeaderLine('someHeader'));
$this->assertEquals('additionalValue', $middlewareResponse->getHeaderLine('additionalHeader'));
}

/**
* Test the Redirect filter mode without params when using the "whitelist" option. Meaning the maintenance mode
* should not be shown if the client IP is whitelisted.
*
* @return void
*/
public function testRedirectModeWhitelist()
{
Configure::write('Wrench.enable', true);
$request = ServerRequestFactory::fromGlobals([
'HTTP_HOST' => 'localhost',
'REQUEST_URI' => '/',
'REMOTE_ADDR' => '127.0.0.1'
]);
$response = new Response();
$next = function ($req, $res) {
return $res;
};
$middleware = new MaintenanceMiddleware([
'whitelist' => ['127.0.0.1'],
]);
$middlewareResponse = $middleware($request, $response, $next);

$this->assertEquals(200, $middlewareResponse->getStatusCode());
}
}
42 changes: 39 additions & 3 deletions tests/TestCase/Mode/ViewTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ public function testViewModeNoParams()
Configure::write('Wrench.enable', true);
$request = ServerRequestFactory::fromGlobals([
'HTTP_HOST' => 'localhost',
'REQUEST_URI' => '/'
'REQUEST_URI' => '/',
'REMOTE_ADDR' => '127.0.0.1'
]);
$response = new Response();
$next = function ($req, $res) {
Expand Down Expand Up @@ -80,7 +81,8 @@ public function testViewModeCustomParams()

$request = ServerRequestFactory::fromGlobals([
'HTTP_HOST' => 'localhost',
'REQUEST_URI' => '/'
'REQUEST_URI' => '/',
'REMOTE_ADDR' => '127.0.0.1'
]);
$response = new Response();
$next = function ($req, $res) {
Expand Down Expand Up @@ -118,7 +120,8 @@ public function testViewModeCustomParamsPlugin()

$request = ServerRequestFactory::fromGlobals([
'HTTP_HOST' => 'localhost',
'REQUEST_URI' => '/'
'REQUEST_URI' => '/',
'REMOTE_ADDR' => '127.0.0.1'
]);
$response = new Response();
$next = function ($req, $res) {
Expand Down Expand Up @@ -187,4 +190,37 @@ public function testViewModeCustomParamsPlugin()
$this->assertEquals('someValue', $middlewareResponse->getHeaderLine('someHeader'));
$this->assertEquals('additionalValue', $middlewareResponse->getHeaderLine('additionalHeader'));
}

/**
* Test the View filter mode without params when using the "whitelist" option. Meaning the maintenance mode
* should not be shown if the client IP is whitelisted.
*
* @return void
*/
public function testViewModeNoParamsWhitelist()
{
Configure::write('Wrench.enable', true);
$request = ServerRequestFactory::fromGlobals([
'HTTP_HOST' => 'localhost',
'REQUEST_URI' => '/',
'REMOTE_ADDR' => '127.0.0.1'
]);
$response = new Response();
$next = function ($req, $res) {
return $res;
};
$middleware = new MaintenanceMiddleware([
'whitelist' => ['127.0.0.1'],
'mode' => [
'className' => 'Wrench\Mode\View',
'config' => [
'headers' => ['someHeader' => 'someValue', 'additionalHeader' => 'additionalValue']
]
]
]);
$middlewareResponse = $middleware($request, $response, $next);

$this->assertEquals('', (string)$middlewareResponse->getBody());
$this->assertEquals(200, $middlewareResponse->getStatusCode());
}
}

0 comments on commit 00518cd

Please sign in to comment.