Commit 5ddf7c26 authored by alexpott's avatar alexpott

Issue #2288911 by znerol, effulgentsia: Use route name instead of system path...

Issue #2288911 by znerol, effulgentsia: Use route name instead of system path in user maintenance mode subscriber
parent a5c5b25d
......@@ -7,9 +7,9 @@
namespace Drupal\Core\Authentication;
use Drupal\Core\Routing\RouteMatch;
use Drupal\Core\Session\AnonymousUserSession;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
/**
......@@ -89,8 +89,8 @@ public function authenticate(Request $request) {
$account = NULL;
// Iterate the available providers.
foreach ($this->getSortedProviders() as $provider_id => $provider) {
// Iterate the allowed providers.
foreach ($this->filterProviders($this->getSortedProviders(), $request) as $provider_id => $provider) {
if ($provider->applies($request)) {
// Try to authenticate with this provider, skipping all others.
$account = $provider->authenticate($request);
......@@ -155,6 +155,36 @@ public function getSortedProviders() {
return $this->sortedProviders;
}
/**
* Filters a list of providers and only return those allowed on the request.
*
* @param \Drupal\Core\Authentication\AuthenticationProviderInterface[] $providers
* An array of authentication provider objects.
* @param Request $request
* The request object.
*
* @return \Drupal\Core\Authentication\AuthenticationProviderInterface[]
* The filtered array authentication provider objects.
*/
protected function filterProviders(array $providers, Request $request) {
$route = RouteMatch::createFromRequest($request)->getRouteObject();
$allowed_providers = array();
if ($route && $route->hasOption('_auth')) {
$allowed_providers = $route->getOption('_auth');
}
elseif ($default_provider = $this->defaultProviderId()) {
// @todo Mirrors the defective behavior of AuthenticationEnhancer and
// restricts the list of allowed providers to the default provider if no
// _auth was specified on the current route.
//
// This restriction will be removed by https://www.drupal.org/node/2286971
// See also https://www.drupal.org/node/2283637
$allowed_providers = array($default_provider);
}
return array_intersect_key($providers, array_flip($allowed_providers));
}
/**
* Cleans up the authentication.
*
......@@ -177,18 +207,11 @@ public function cleanup(Request $request) {
* {@inheritdoc}
*/
public function handleException(GetResponseForExceptionEvent $event) {
$request = $event->getRequest();
$route = $request->attributes->get(RouteObjectInterface::ROUTE_OBJECT);
$active_providers = ($route && $route->getOption('_auth')) ? $route->getOption('_auth') : array($this->defaultProviderId());
// Get the sorted list of active providers for the given route.
$providers = array_intersect($active_providers, array_keys($this->getSortedProviders()));
foreach ($providers as $provider_id) {
if ($this->providers[$provider_id]->handleException($event) == TRUE) {
foreach ($this->filterProviders($this->getSortedProviders(), $event->getRequest()) as $provider) {
if ($provider->handleException($event) === TRUE) {
break;
}
}
}
}
......@@ -88,6 +88,10 @@ public function getContext() {
public function matchRequest(Request $request) {
$parameters = $this->chainRouter->matchRequest($request);
$request->attributes->add($parameters);
// Trigger a session start and authentication by accessing any property of
// the current user.
// @todo This will be removed in https://www.drupal.org/node/2229145.
$this->account->id();
$this->checkAccess($request);
// We can not return $parameters because the access check can change the
// request attributes.
......
......@@ -67,6 +67,7 @@ protected function setUp() {
array(
'administer languages',
'administer site configuration',
'link to any page',
'administer contact forms',
'access site-wide contact form',
'access contextual links',
......
......@@ -29,7 +29,7 @@ protected function setUp() {
parent::setUp();
// Create an administrative user.
$this->admin_user = $this->drupalCreateUser(array('access administration pages', 'administer site configuration', 'administer blocks'));
$this->admin_user = $this->drupalCreateUser(array('access administration pages', 'administer site configuration', 'link to any page', 'administer blocks'));
user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array('access user profiles'));
user_role_grant_permissions(DRUPAL_AUTHENTICATED_RID, array('access user profiles'));
......
......@@ -21,7 +21,7 @@ protected function setUp() {
parent::setUp();
// Create an administrative user.
$this->admin_user = $this->drupalCreateUser(array('administer site configuration'));
$this->admin_user = $this->drupalCreateUser(array('administer site configuration', 'link to any page'));
user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array('access user profiles'));
user_role_grant_permissions(DRUPAL_AUTHENTICATED_RID, array('access user profiles'));
......
......@@ -37,7 +37,7 @@ protected function setUp() {
$this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
$this->content_user = $this->drupalCreateUser(array('create page content', 'access content', 'administer themes', 'administer site configuration'));
$this->content_user = $this->drupalCreateUser(array('create page content', 'access content', 'administer themes', 'administer site configuration', 'link to any page'));
$this->drupalLogin($this->content_user);
}
......
......@@ -10,6 +10,7 @@
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Routing\Access\AccessInterface;
use Drupal\Core\Session\AccountInterface;
use Symfony\Component\Routing\Route;
/**
* Determines access to routes based on login status of current user.
......@@ -21,12 +22,16 @@ class LoginStatusCheck implements AccessInterface {
*
* @param \Drupal\Core\Session\AccountInterface $account
* The currently logged in account.
* @param \Symfony\Component\Routing\Route $route
* The route to check against.
*
* @return \Drupal\Core\Access\AccessResultInterface
* The access result.
*/
public function access(AccountInterface $account) {
return AccessResult::allowedIf($account->isAuthenticated())->cachePerRole();
public function access(AccountInterface $account, Route $route) {
$required_status = filter_var($route->getRequirement('_user_is_logged_in'), FILTER_VALIDATE_BOOLEAN);
$actual_status = $account->isAuthenticated();
return AccessResult::allowedIf($required_status === $actual_status)->cachePerRole();
}
}
......@@ -17,7 +17,12 @@
use Symfony\Component\HttpKernel\KernelEvents;
/**
* Redirects anonymous users from user.page to user.login.
* Redirects users when access is denied.
*
* Anonymous users are taken to the login page when attempting to access the
* user profile pages. Authenticated users are redirected from the login form to
* their profile page and from the user registration form to their profile edit
* form.
*/
class AccessDeniedSubscriber implements EventSubscriberInterface {
......@@ -44,7 +49,7 @@ public function __construct(AccountInterface $account, URLGeneratorInterface $ur
}
/**
* Redirects anonymous users from user.page to user.login.
* Redirects users when access is denied.
*
* @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event
* The event to process.
......@@ -53,7 +58,20 @@ public function onException(GetResponseForExceptionEvent $event) {
$exception = $event->getException();
if ($exception instanceof AccessDeniedHttpException) {
$route_name = RouteMatch::createFromRequest($event->getRequest())->getRouteName();
if ($route_name == 'user.page' && !$this->account->isAuthenticated()) {
if ($this->account->isAuthenticated()) {
switch ($route_name) {
case 'user.login';
// Redirect an authenticated user to the profile page.
$event->setResponse($this->redirect('entity.user.canonical', ['user' => $this->account->id()]));
break;
case 'user.register';
// Redirect an authenticated user to the profile form.
$event->setResponse($this->redirect('entity.user.edit_form', ['user' => $this->account->id()]));
break;
}
}
elseif ($route_name === 'user.page') {
$event->setResponse($this->redirect('user.login'));
}
}
......
......@@ -12,7 +12,6 @@
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Site\MaintenanceModeInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
......@@ -51,7 +50,7 @@ public function __construct(MaintenanceModeInterface $maintenance_mode, AccountI
}
/**
* Determine whether the page is configured to be offline.
* Logout users if site is in maintenance mode.
*
* @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
* The event to process.
......@@ -59,26 +58,12 @@ public function __construct(MaintenanceModeInterface $maintenance_mode, AccountI
public function onKernelRequestMaintenance(GetResponseEvent $event) {
$request = $event->getRequest();
$route_match = RouteMatch::createFromRequest($request);
$path = $request->attributes->get('_system_path');
if ($this->maintenanceMode->applies($route_match)) {
// If the site is offline, log out unprivileged users.
if ($this->account->isAuthenticated() && !$this->maintenanceMode->exempt($this->account)) {
user_logout();
// Redirect to homepage.
$event->setResponse(new RedirectResponse($this->url('<front>', [], ['absolute' => TRUE])));
return;
}
}
if ($this->account->isAuthenticated()) {
if ($path == 'user/login') {
// If the user is already logged in, redirect to their profile page.
$event->setResponse($this->redirect('entity.user.canonical', ['user' => $this->account->id()]));
return;
}
if ($path == 'user/register') {
// If the user is already registered, redirect to their edit page.
$event->setResponse(new RedirectResponse($this->url('entity.user.edit_form', ['user' => $this->account->id()], ['absolute' => TRUE])));
return;
$event->setResponse($this->redirect($this->url('<front>')));
}
}
}
......@@ -87,7 +72,7 @@ public function onKernelRequestMaintenance(GetResponseEvent $event) {
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
$events[KernelEvents::REQUEST][] = array('onKernelRequestMaintenance', 35);
$events[KernelEvents::REQUEST][] = ['onKernelRequestMaintenance', 31];
return $events;
}
......
......@@ -11,8 +11,6 @@
use Drupal\Core\Entity\Query\QueryFactory;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Url;
use Symfony\Component\HttpFoundation\RedirectResponse;
/**
* Form controller for the user register forms.
......@@ -42,11 +40,6 @@ public function form(array $form, FormStateInterface $form_state) {
'#value' => $admin,
);
// If we aren't admin but already logged on, go to the user page instead.
if (!$admin && $user->isAuthenticated()) {
return new RedirectResponse($this->url('entity.user.canonical', ['user' => \Drupal::currentUser()->id()], array('absolute' => TRUE)));
}
$form['#attached']['library'][] = 'core/drupal.form';
// For non-admin users, populate the form fields using data from the
......
......@@ -147,7 +147,7 @@ user.login:
_form: '\Drupal\user\Form\UserLoginForm'
_title: 'Log in'
requirements:
_access: 'TRUE'
_user_is_logged_in: 'FALSE'
options:
_maintenance_access: TRUE
......
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