class UserRouteEventSubscriber in Username Enumeration Prevention 8
Modifies user-related routes to respond with 404 rather than 403.
@package Drupal\username_enumeration_prevention
Hierarchy
- class \Drupal\username_enumeration_prevention\UserRouteEventSubscriber implements \Symfony\Component\EventDispatcher\EventSubscriberInterface
Expanded class hierarchy of UserRouteEventSubscriber
1 string reference to 'UserRouteEventSubscriber'
1 service uses UserRouteEventSubscriber
File
- src/
UserRouteEventSubscriber.php, line 23
Namespace
Drupal\username_enumeration_preventionView source
class UserRouteEventSubscriber implements EventSubscriberInterface {
/**
* Cache CID with user route IDS.
*/
const ROUTE_CID = 'username_enumeration_prevention_user_route_ids';
/**
* Route provider.
*
* @var \Drupal\Core\Routing\RouteProviderInterface
*/
protected $routeProvider;
/**
* Entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* A cache backend.
*
* @var \Drupal\Core\Cache\CacheBackendInterface
*/
protected $cache;
/**
* {@inheritdoc}
*/
public function __construct(RouteProviderInterface $routeProvider, EntityTypeManagerInterface $entityTypeManager, CacheBackendInterface $cache) {
$this->routeProvider = $routeProvider;
$this->entityTypeManager = $entityTypeManager;
$this->cache = $cache;
}
/**
* {@inheritdoc}
*/
public function onException(GetResponseForExceptionEvent $event) {
$routeMatch = RouteMatch::createFromRequest($event
->getRequest());
if ($event
->getException() instanceof AccessDeniedHttpException && in_array($routeMatch
->getRouteName(), $this
->getUserRoutes())) {
$event
->setException(new NotFoundHttpException());
}
}
/**
* Get an array of user route IDs.
*
* @return array
* An array of user route IDs.
*/
protected function getUserRoutes() : array {
$userRouteIds = $this->cache
->get(static::ROUTE_CID);
if ($userRouteIds !== FALSE) {
return $userRouteIds->data;
}
$userLinkTemplates = $this->entityTypeManager
->getDefinition('user')
->getLinkTemplates();
$routes = new RouteCollection();
foreach ($userLinkTemplates as $path) {
$routes
->addCollection($this->routeProvider
->getRoutesByPattern($path));
}
$userRouteIds = array_keys(array_filter(iterator_to_array($routes), function (Route $route) : bool {
$parameters = $route
->getOption('parameters') ?? [];
if (is_array($parameters)) {
foreach ($parameters as $parameter) {
// This captures most routes, however some legacy routes don't have
// parameters, especially views.
if ($parameter['type'] ?? NULL === 'entity:user') {
return TRUE;
}
}
}
return strpos($route
->getPath(), '{user}') !== FALSE;
}));
$userRouteIds[] = 'user.cancel_confirm';
$userRouteIds[] = 'shortcut.set_switch';
$this->cache
->set(static::ROUTE_CID, $userRouteIds, Cache::PERMANENT, [
'routes',
]);
return $userRouteIds;
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
$events[KernelEvents::EXCEPTION] = 'onException';
return $events;
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
UserRouteEventSubscriber:: |
protected | property | A cache backend. | |
UserRouteEventSubscriber:: |
protected | property | Entity type manager. | |
UserRouteEventSubscriber:: |
protected | property | Route provider. | |
UserRouteEventSubscriber:: |
public static | function | Returns an array of event names this subscriber wants to listen to. | |
UserRouteEventSubscriber:: |
protected | function | Get an array of user route IDs. | |
UserRouteEventSubscriber:: |
public | function | ||
UserRouteEventSubscriber:: |
constant | Cache CID with user route IDS. | ||
UserRouteEventSubscriber:: |
public | function |