diff --git a/core/lib/Drupal/Core/Authentication/AuthenticationManager.php b/core/lib/Drupal/Core/Authentication/AuthenticationManager.php index 0553d0936b659a593da14126bf440e62dee8cc1f..c4c1df433ad85d9b368ac56e02f8863f9796e785 100644 --- a/core/lib/Drupal/Core/Authentication/AuthenticationManager.php +++ b/core/lib/Drupal/Core/Authentication/AuthenticationManager.php @@ -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; } } } + } diff --git a/core/lib/Drupal/Core/Routing/AccessAwareRouter.php b/core/lib/Drupal/Core/Routing/AccessAwareRouter.php index 1cf937c4f3ca0fc3e746fd9b29624974ffdff381..93a31c31b7796ff6e15071f0dec73d7148cd7f48 100644 --- a/core/lib/Drupal/Core/Routing/AccessAwareRouter.php +++ b/core/lib/Drupal/Core/Routing/AccessAwareRouter.php @@ -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. diff --git a/core/modules/config_translation/src/Tests/ConfigTranslationUiTest.php b/core/modules/config_translation/src/Tests/ConfigTranslationUiTest.php index 0fde6bc05d8b255e867e5847b85a67fcd0f12088..3bab5a61d3780dd1ef00d29767da72a651dd47c6 100644 --- a/core/modules/config_translation/src/Tests/ConfigTranslationUiTest.php +++ b/core/modules/config_translation/src/Tests/ConfigTranslationUiTest.php @@ -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', diff --git a/core/modules/system/src/Tests/System/AccessDeniedTest.php b/core/modules/system/src/Tests/System/AccessDeniedTest.php index 12f7cdc463d5efa5d371baaa877d5443f549c53c..a492c9174f36ea6c2969a2b773cf1c42e84650c3 100644 --- a/core/modules/system/src/Tests/System/AccessDeniedTest.php +++ b/core/modules/system/src/Tests/System/AccessDeniedTest.php @@ -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')); diff --git a/core/modules/system/src/Tests/System/PageNotFoundTest.php b/core/modules/system/src/Tests/System/PageNotFoundTest.php index 5745801ff0f438cd6bbeffc9e8a7a79873154cb8..26296b717ebfaa5a4cb5847b9b73a0f2f5e307ee 100644 --- a/core/modules/system/src/Tests/System/PageNotFoundTest.php +++ b/core/modules/system/src/Tests/System/PageNotFoundTest.php @@ -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')); diff --git a/core/modules/system/src/Tests/System/PageTitleTest.php b/core/modules/system/src/Tests/System/PageTitleTest.php index 4516a57bd487fadf954b9aa7e72f6ace25b819ec..98148cd06d5081d148189138f65168ab11628528 100644 --- a/core/modules/system/src/Tests/System/PageTitleTest.php +++ b/core/modules/system/src/Tests/System/PageTitleTest.php @@ -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); } diff --git a/core/modules/user/src/Access/LoginStatusCheck.php b/core/modules/user/src/Access/LoginStatusCheck.php index 56790cbfd0246d4cb1ac69cfd1b636ca3018d347..f31e0569ae9d2688a0d76c5d43f7a4011c20242f 100644 --- a/core/modules/user/src/Access/LoginStatusCheck.php +++ b/core/modules/user/src/Access/LoginStatusCheck.php @@ -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(); } } diff --git a/core/modules/user/src/EventSubscriber/AccessDeniedSubscriber.php b/core/modules/user/src/EventSubscriber/AccessDeniedSubscriber.php index 036b98e28bdd0f7c8d1f0421bad0afe664bd5d7e..361e7ceff8c4ec70bf244443e3d1b3534f6d1da3 100644 --- a/core/modules/user/src/EventSubscriber/AccessDeniedSubscriber.php +++ b/core/modules/user/src/EventSubscriber/AccessDeniedSubscriber.php @@ -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')); } } diff --git a/core/modules/user/src/EventSubscriber/MaintenanceModeSubscriber.php b/core/modules/user/src/EventSubscriber/MaintenanceModeSubscriber.php index 044c4b419602f03e36cb7ee1f1f2be9db0161d62..272307445fedf64ce835914cd630243fb2cb83eb 100644 --- a/core/modules/user/src/EventSubscriber/MaintenanceModeSubscriber.php +++ b/core/modules/user/src/EventSubscriber/MaintenanceModeSubscriber.php @@ -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; } diff --git a/core/modules/user/src/RegisterForm.php b/core/modules/user/src/RegisterForm.php index be73f39a9c9ad8973366acdbffb894522022b3ce..bbf131e3d399ed5577a42a8a30b578ca06e45bfb 100644 --- a/core/modules/user/src/RegisterForm.php +++ b/core/modules/user/src/RegisterForm.php @@ -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 diff --git a/core/modules/user/user.routing.yml b/core/modules/user/user.routing.yml index 2a31da2448fb7aae56fed23a3acca95ba1dbe30e..5f9cc9ad0e68200e5ae57591fa6e6364767359a1 100644 --- a/core/modules/user/user.routing.yml +++ b/core/modules/user/user.routing.yml @@ -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