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