Commit a8b92fe4 authored by alexpott's avatar alexpott

Issue #2332983 by dawehner: Replace ban event subscriber with a ban stack.

parent 535c5909
......@@ -4,8 +4,10 @@ services:
arguments: ['@database']
tags:
- { name: backend_overridable }
ban.subscriber:
class: Drupal\ban\EventSubscriber\BanSubscriber
tags:
- { name: event_subscriber }
ban.middleware:
class: Drupal\ban\BanMiddleware
arguments: ['@ban.ip_manager']
tags:
# Ensure to come before page caching, so you don't serve cached pages to
# banned users.
- { name: http_middleware, priority: 250 }
<?php
/**
* @file
* Contains \Drupal\ban\BanMiddleware.
*/
namespace Drupal\ban;
use Drupal\Component\Utility\String;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\HttpKernelInterface;
/**
* Provides a HTTP middleware to implement IP based banning.
*/
class BanMiddleware implements HttpKernelInterface {
/**
* The decorated kernel.
*
* @var \Symfony\Component\HttpKernel\HttpKernelInterface
*/
protected $httpKernel;
/**
* The ban IP manager.
*
* @var \Drupal\ban\BanIpManagerInterface
*/
protected $banIpManager;
/**
* Constructs a BanMiddleware object.
*
* @param \Symfony\Component\HttpKernel\HttpKernelInterface $http_kernel
* The decorated kernel.
* @param \Drupal\ban\BanIpManagerInterface $manager
* The ban IP manager.
*/
public function __construct(HttpKernelInterface $http_kernel, BanIpManagerInterface $manager) {
$this->httpKernel = $http_kernel;
$this->banIpManager = $manager;
}
/**
* {@inheritdoc}
*/
public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = TRUE) {
$ip = $request->getClientIp();
if ($this->banIpManager->isBanned($ip)) {
return new Response(String::format('Sorry @ip has been banned', ['@ip' => $ip]), 403);
}
return $this->httpKernel->handle($request, $type, $catch);
}
}
<?php
/**
* @file
* Definition of Drupal\ban\EventSubscriber\BanSubscriber.
*/
namespace Drupal\ban\EventSubscriber;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Drupal\ban\BanIpManagerInterface;
use Drupal\Component\Utility\String;
/**
* Ban subscriber for controller requests.
*/
class BanSubscriber implements EventSubscriberInterface {
/**
* The manager used to check the IP against.
*
* @var \Drupal\ban\BanIpManagerInterface
*/
protected $manager;
/**
* Construct the BanSubscriber.
*
* @param \Drupal\ban\BanIpManagerInterface $manager
* The manager used to check the IP against.
*/
public function __construct(BanIpManagerInterface $manager) {
$this->manager = $manager;
}
/**
* Response with 403 if the visitor's IP address is banned.
*
* @param Symfony\Component\HttpKernel\Event\GetResponseEvent $event
* The Event to process.
*/
public function onKernelRequestBannedIpCheck(GetResponseEvent $event) {
$ip = $event->getRequest()->getClientIp();
if ($this->manager->isBanned($ip)) {
$response = new Response('Sorry, ' . String::checkPlain($ip) . ' has been banned.', 403);
$event->setResponse($response);
}
}
/**
* Registers the methods in this class that should be listeners.
*
* @return array
* An array of event listener definitions.
*/
static function getSubscribedEvents() {
$events[KernelEvents::REQUEST][] = array('onKernelRequestBannedIpCheck', 40);
return $events;
}
}
<?php
/**
* @file
* Contains \Drupal\ban\Tests\BanMiddlewareTest.
*/
namespace Drupal\ban\Tests;
use Drupal\ban\BanMiddleware;
use Drupal\Tests\UnitTestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\HttpKernelInterface;
/**
* @coversDefaultClass \Drupal\ban\BanMiddleware
* @group ban
*/
class BanMiddlewareTest extends UnitTestCase {
/**
* The mocked wrapped kernel.
*
* @var \Symfony\Component\HttpKernel\HttpKernelInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $kernel;
/**
* The mocked ban IP manager.
*
* @var \Drupal\ban\BanIpManagerInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $banManager;
/**
* The tested ban middleware.
*
* @var \Drupal\ban\BanMiddleware
*/
protected $banMiddleware;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->kernel = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface');
$this->banManager = $this->getMock('Drupal\ban\BanIpManagerInterface');
$this->banMiddleware = new BanMiddleware($this->kernel, $this->banManager);
}
/**
* Tests a banned IP.
*/
public function testBannedIp() {
$banned_ip = '17.0.0.2';
$this->banManager->expects($this->once())
->method('isBanned')
->with($banned_ip)
->willReturn(TRUE);
$this->kernel->expects($this->never())
->method('handle');
$request = Request::create('/test-path');
$request->server->set('REMOTE_ADDR', $banned_ip);
$response = $this->banMiddleware->handle($request);
$this->assertEquals(403, $response->getStatusCode());
}
/**
* Tests an unbanned IP.
*/
public function testUnbannedIp() {
$unbanned_ip = '18.0.0.2';
$this->banManager->expects($this->once())
->method('isBanned')
->with($unbanned_ip)
->willReturn(FALSE);
$request = Request::create('/test-path');
$request->server->set('REMOTE_ADDR', $unbanned_ip);
$expected_response = new Response(200);
$this->kernel->expects($this->once())
->method('handle')
->with($request, HttpKernelInterface::MASTER_REQUEST, TRUE)
->willReturn($expected_response);
$response = $this->banMiddleware->handle($request);
$this->assertSame($expected_response, $response);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment