Skip to content
This repository has been archived by the owner on Jan 25, 2023. It is now read-only.

Commit

Permalink
implement authorization by cookie
Browse files Browse the repository at this point in the history
  • Loading branch information
uwej711 committed Oct 1, 2015
1 parent 2a833b3 commit 59db96b
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 38 deletions.
3 changes: 3 additions & 0 deletions DependencyInjection/Configuration.php
Expand Up @@ -41,6 +41,9 @@ public function getConfigTreeBuilder()
->variableNode('query')
->defaultValue(array())
->end()
->variableNode('cookie')
->defaultValue(array())
->end()
->scalarNode('route')
->defaultNull()
->end()
Expand Down
1 change: 1 addition & 0 deletions DependencyInjection/LexikMaintenanceExtension.php
Expand Up @@ -40,6 +40,7 @@ public function load(array $configs, ContainerBuilder $container)
$container->setParameter('lexik_maintenance.authorized.host', $config['authorized']['host']);
$container->setParameter('lexik_maintenance.authorized.ips', $config['authorized']['ips']);
$container->setParameter('lexik_maintenance.authorized.query', $config['authorized']['query']);
$container->setParameter('lexik_maintenance.authorized.cookie', $config['authorized']['cookie']);
$container->setParameter('lexik_maintenance.authorized.route', $config['authorized']['route']);
$container->setParameter('lexik_maintenance.authorized.attributes', $config['authorized']['attributes']);
$container->setParameter('lexik_maintenance.response.http_code', $config['response']['code']);
Expand Down
17 changes: 17 additions & 0 deletions Listener/MaintenanceListener.php
Expand Up @@ -52,6 +52,11 @@ class MaintenanceListener
*/
protected $query;

/**
* @var array
*/
protected $cookie;

/**
* @var null|String
*/
Expand Down Expand Up @@ -96,17 +101,20 @@ class MaintenanceListener
* @param String $host A regex for the host
* @param array $ips The list of IP addresses
* @param array $query Query arguments
* @param array $cookie Cookies
* @param String $route Route name
* @param array $attributes Attributes
* @param Int $http_code http status code for response
* @param String $http_status http status message for response
* @param bool $debug
*/
public function __construct(
DriverFactory $driverFactory,
$path = null,
$host = null,
$ips = null,
$query = array(),
$cookie = array(),
$route = null,
$attributes = array(),
$http_code = null,
Expand All @@ -118,6 +126,7 @@ public function __construct(
$this->host = $host;
$this->ips = $ips;
$this->query = $query;
$this->cookie = $cookie;
$this->route = $route;
$this->attributes = $attributes;
$this->http_code = $http_code;
Expand All @@ -144,6 +153,14 @@ public function onKernelRequest(GetResponseEvent $event)
}
}

if (is_array($this->cookie)) {
foreach ($this->cookie as $key => $pattern) {
if (!empty($pattern) && preg_match('{'.$pattern.'}', $request->cookies->get($key))) {
return;
}
}
}

if (is_array($this->attributes)) {
foreach ($this->attributes as $key => $pattern) {
if (!empty($pattern) && preg_match('{'.$pattern.'}', $request->attributes->get($key))) {
Expand Down
3 changes: 2 additions & 1 deletion Resources/config/services.xml
Expand Up @@ -6,7 +6,7 @@

<parameters>
<parameter key="lexik_maintenance.listener.class">Lexik\Bundle\MaintenanceBundle\Listener\MaintenanceListener</parameter>
<parameter key="lexik_maintenance.driver_factory.class">Lexik\Bundle\MaintenanceBundle\Drivers\DriverFactory</parameter>
<parameter key="lexik_maintenance.driver_factory.class">Lexik\Bundle\MaintenanceBundle\Drivers\DriverFactory</parameter>
</parameters>

<services>
Expand All @@ -24,6 +24,7 @@
<argument>%lexik_maintenance.authorized.host%</argument>
<argument>%lexik_maintenance.authorized.ips%</argument>
<argument>%lexik_maintenance.authorized.query%</argument>
<argument>%lexik_maintenance.authorized.cookie%</argument>
<argument>%lexik_maintenance.authorized.route%</argument>
<argument>%lexik_maintenance.authorized.attributes%</argument>
<argument>%lexik_maintenance.response.http_code%</argument>
Expand Down
69 changes: 35 additions & 34 deletions Resources/doc/index.md
Expand Up @@ -16,8 +16,8 @@ You must register in your autoloader:


<?php
// app/autoload.php

// app/autoload.php
$loader->registerNamespaces(array(
'Lexik' => __DIR__.'/../vendor/bundles',
// ...
Expand All @@ -31,7 +31,7 @@ line to your composer.json file

{
"require": {
"lexik/maintenance-bundle": "dev-master"
"lexik/maintenance-bundle": "dev-master"
}
}

Expand All @@ -49,14 +49,14 @@ composer.phar update lexik/maintenance-bundle # to only update the bundle
You must register the bundle in your kernel:

<?php
// app/AppKernel.php

// app/AppKernel.php
public function registerBundles()
{
$bundles = array(
// ...
$bundles = array(
// ...
new Lexik\Bundle\MaintenanceBundle\LexikMaintenanceBundle(),
);
);
// ...
}

Expand All @@ -78,37 +78,38 @@ The ttl (time to life) option is optional everywhere, it is used to indicate the
host: your-domain.com # Optional. Authorized domain, accepts regexs
ips: ['127.0.0.1', '172.123.10.14'] # Optional. Authorized ip addresses
query: { foo: bar } # Optional. Authorized request query parameter (GET/POST)
cookie: { bar: baz } # Optional. Authorized cookie
route: # Optional. Authorized route name
attributes: # Optional. Authorized route attributes
driver:
driver:
ttl: 3600 # Optional ttl option, can be not set
# File driver
class: '\Lexik\Bundle\MaintenanceBundle\Drivers\FileDriver' # class for file driver

# File driver
class: '\Lexik\Bundle\MaintenanceBundle\Drivers\FileDriver' # class for file driver
options: {file_path: %kernel.root_dir%/cache/lock} # file_path is the complete path for create the file

# Shared memory driver
class: '\Lexik\Bundle\MaintenanceBundle\Drivers\ShmDriver' # class for shared memory driver
class: '\Lexik\Bundle\MaintenanceBundle\Drivers\ShmDriver' # class for shared memory driver

# MemCache driver
class: Lexik\Bundle\MaintenanceBundle\Drivers\MemCacheDriver # class for MemCache driver
class: Lexik\Bundle\MaintenanceBundle\Drivers\MemCacheDriver # class for MemCache driver
options: {key_name: 'maintenance', host: 127.0.0.1, port: 11211} # need to define a key_name, the host and port
# Database driver:

# Database driver:
class: 'Lexik\Bundle\MaintenanceBundle\Drivers\DatabaseDriver' # class for database driver
# Option 1 : for doctrine

# Option 1 : for doctrine
options: {connection: custom} # Optional. You can choice an other connection. Without option it's the doctrine default connection who will be used

# Option 2 : for dsn, you must have a column ttl type datetime in your table.
options: {dsn: "mysql:dbname=maintenance;host:localhost", table: maintenance, user: root, password: root} # the dsn configuration, name of table, user/password
options: {dsn: "mysql:dbname=maintenance;host:localhost", table: maintenance, user: root, password: root} # the dsn configuration, name of table, user/password

#Optional. response code and status of the maintenance page
response:
code: 503
status: "Service Temporarily Unavailable"
code: 503
status: "Service Temporarily Unavailable"


### Commands

There are two commands:
Expand All @@ -122,29 +123,29 @@ This command will enable the maintenance according with your configuration. You
This command will disable the maintenance

You can execute the lock without a warning message which you need to interact with:

lexik:maintenance:lock --no-interaction

Or (with the optional ttl overwriting)

lexik:maintenance:lock 3600 -n


---------------------

Custom error page 503
---------------------

In the listener, an exception is thrown when web site is under maintenance. This exception is a 'This exception is a 'HttpException' (status 503), to custom your error page
you need to create a error503.html.twig (if you use twig) in:
app/Resources/TwigBundle/views/Exception
app/Resources/TwigBundle/views/Exception

#### Important

.. note::

You must remember that this only works if Symfony2 works.
You must remember that this only works if Symfony2 works.

----------------------

Using with a Load Balancer
Expand Down Expand Up @@ -175,6 +176,6 @@ In your controller:
$this->get('session')->setFlash('maintenance', $message);

return new RedirectResponse($this->generateUrl('_demo'));


**Warning**: Make sure you have allowed IP addresses if you run maintenance from the backend, otherwise you will find yourself blocked on page 503.
44 changes: 41 additions & 3 deletions Tests/EventListener/MaintenanceListenerTest.php
Expand Up @@ -44,7 +44,7 @@ public function testBaseRequest()
$listener = new MaintenanceListenerTestWrapper($this->factory);
$this->assertTrue($listener->onKernelRequest($event), 'Permissive factory should approve without args');

$listener = new MaintenanceListenerTestWrapper($this->factory, 'path', 'host', array('ip'), array('query'), 'route');
$listener = new MaintenanceListenerTestWrapper($this->factory, 'path', 'host', array('ip'), array('query'), array('cookie'), 'route');
$this->assertTrue($listener->onKernelRequest($event), 'Permissive factory should approve with args');

$this->factory = new DriverFactory($this->getDatabaseDriver(true), $this->getTranslator(), $driverOptions);
Expand All @@ -53,7 +53,7 @@ public function testBaseRequest()
$listener = new MaintenanceListenerTestWrapper($this->factory);
$this->assertFalse($listener->onKernelRequest($event), 'Restrictive factory should deny without args');

$listener = new MaintenanceListenerTestWrapper($this->factory, null, null, array(), array(), null);
$listener = new MaintenanceListenerTestWrapper($this->factory, null, null, array(), array(), array(), null);
$this->assertFalse($listener->onKernelRequest($event), 'Restrictive factory should deny without args');
}

Expand Down Expand Up @@ -174,7 +174,7 @@ public function testRouteFilter($debug, $route, $expected)
$this->factory = new DriverFactory($this->getDatabaseDriver(true), $this->getTranslator(), $driverOptions);
$this->container->set('lexik_maintenance.driver.factory', $this->factory);

$listener = new MaintenanceListenerTestWrapper($this->factory, null, null, null, array(), $debug);
$listener = new MaintenanceListenerTestWrapper($this->factory, null, null, null, array(), array(), $debug);

$info = sprintf('Should be %s route %s with when we are %s debug env',
$expected === true ? 'allow' : 'deny',
Expand Down Expand Up @@ -244,6 +244,44 @@ public function testQueryFilter()
$this->assertTrue($listener->onKernelRequest($event), 'Restrictive factory should allow on non-matching path, host and ip and matching query');
}

/**
* Create request and test the listener
* for scenarios with permissive firewall
* and cookie filters
*/
public function testCookieFilter()
{
$driverOptions = array('class' => DriverFactory::DATABASE_DRIVER, 'options' => null);

$request = Request::create('http://test.com/foo', 'GET', array(), array('bar' => 'baz'));
$kernel = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface');
$event = new GetResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST);

$this->container = $this->initContainer();

$this->factory = new DriverFactory($this->getDatabaseDriver(true), $this->getTranslator(), $driverOptions);
$this->container->set('lexik_maintenance.driver.factory', $this->factory);

$listener = new MaintenanceListenerTestWrapper($this->factory, null, null, null, null, null);
$this->assertFalse($listener->onKernelRequest($event), 'Restrictive factory should deny without cookies');

$listener = new MaintenanceListenerTestWrapper($this->factory, null, null, null, null, array());
$this->assertFalse($listener->onKernelRequest($event), 'Restrictive factory should deny with empty cookies');

$listener = new MaintenanceListenerTestWrapper($this->factory, null, null, null, null, array('some' => 'attribute'));
$this->assertFalse($listener->onKernelRequest($event), 'Restrictive factory should deny on non matching cookie');

$listener = new MaintenanceListenerTestWrapper($this->factory, null, null, null, null, array('attribute'));
$this->assertFalse($listener->onKernelRequest($event), 'Restrictive factory should deny on non matching cookie');

$listener = new MaintenanceListenerTestWrapper($this->factory, null, null, null, null, array('bar' => 'baz'));
$this->assertTrue($listener->onKernelRequest($event), 'Restrictive factory should allow on matching cookie');

$listener = new MaintenanceListenerTestWrapper($this->factory, '/barfoo', 'google.com', array('8.8.1.1'), array('bar' => 'baz'), array('bar' => 'baz'));
$this->assertTrue($listener->onKernelRequest($event), 'Restrictive factory should allow on non-matching path, host, ip, query and matching cookie');
}


public function tearDown()
{
$this->container = null;
Expand Down

0 comments on commit 59db96b

Please sign in to comment.