diff --git a/core/authorize.php b/core/authorize.php index f347ba5..fe39394 100644 --- a/core/authorize.php +++ b/core/authorize.php @@ -48,10 +48,12 @@ function authorize_access_denied_page() { * The killswitch in settings.php overrides all else, otherwise, the user must * have access to the 'administer software updates' permission. * - * @return + * @return bool * TRUE if the current user can run authorize.php, and FALSE if not. */ function authorize_access_allowed() { + require_once DRUPAL_ROOT . '/' . settings()->get('session_inc', 'core/includes/session.inc'); + drupal_session_initialize(); return settings()->get('allow_authorize_operations', TRUE) && user_access('administer software updates'); } @@ -65,7 +67,7 @@ function authorize_access_allowed() { // We prepare only a minimal bootstrap. This includes the database and // variables, however, so we have access to the class autoloader. -drupal_bootstrap(DRUPAL_BOOTSTRAP_SESSION); +drupal_bootstrap(DRUPAL_BOOTSTRAP_VARIABLES); // This must go after drupal_bootstrap(), which unsets globals! global $conf; diff --git a/core/core.services.yml b/core/core.services.yml index 04e6ec0..e70cd10 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -282,6 +282,10 @@ services: tags: - { name: event_subscriber } arguments: ['@settings'] + route_enhancer.authentication: + class: Drupal\Core\Routing\Enhancer\AuthenticationEnhancer + tags: + - { name: route_enhancer, priority: 1000 } route_enhancer.content_controller: class: Drupal\Core\Routing\Enhancer\ContentControllerEnhancer arguments: ['@content_negotiation'] @@ -519,3 +523,19 @@ services: class: Zend\Feed\Writer\Extension\Threading\Renderer\Entry feed.writer.wellformedwebrendererentry: class: Zend\Feed\Writer\Extension\WellFormedWeb\Renderer\Entry + authentication: + class: Drupal\Core\Authentication\AuthenticationManager + authentication.cookie: + class: Drupal\Core\Authentication\Provider\Cookie + tags: + - { name: authentication_provider, priority: 0 } + authentication.http_basic: + class: Drupal\Core\Authentication\Provider\HttpBasic + arguments: ['@config.factory'] + tags: + - { name: authentication_provider, priority: 100 } + authentication_subscriber: + class: Drupal\Core\EventSubscriber\AuthenticationSubscriber + tags: + - { name: event_subscriber } + arguments: ['@authentication'] diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index cf0e3dd..5fae68d 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -158,11 +158,6 @@ const DRUPAL_BOOTSTRAP_VARIABLES = 4; /** - * Sixth bootstrap phase: initialize session handling. - */ -const DRUPAL_BOOTSTRAP_SESSION = 5; - -/** * Eighth bootstrap phase: load code for subsystems and modules. */ const DRUPAL_BOOTSTRAP_CODE = 6; @@ -1770,7 +1765,6 @@ function drupal_anonymous_user() { * - DRUPAL_BOOTSTRAP_PAGE_CACHE: Tries to serve a cached page. * - DRUPAL_BOOTSTRAP_DATABASE: Initializes the database layer. * - DRUPAL_BOOTSTRAP_VARIABLES: Initializes the variable system. - * - DRUPAL_BOOTSTRAP_SESSION: Initializes session handling. * - DRUPAL_BOOTSTRAP_CODE: Loads code for subsystems and modules. * - DRUPAL_BOOTSTRAP_FULL: Fully loads Drupal. Validates and fixes input * data. @@ -1789,7 +1783,6 @@ function drupal_bootstrap($phase = NULL, $new_phase = TRUE) { DRUPAL_BOOTSTRAP_PAGE_CACHE, DRUPAL_BOOTSTRAP_DATABASE, DRUPAL_BOOTSTRAP_VARIABLES, - DRUPAL_BOOTSTRAP_SESSION, DRUPAL_BOOTSTRAP_CODE, DRUPAL_BOOTSTRAP_FULL, ); @@ -1839,11 +1832,6 @@ function drupal_bootstrap($phase = NULL, $new_phase = TRUE) { _drupal_bootstrap_variables(); break; - case DRUPAL_BOOTSTRAP_SESSION: - require_once DRUPAL_ROOT . '/' . settings()->get('session_inc', 'core/includes/session.inc'); - drupal_session_initialize(); - break; - case DRUPAL_BOOTSTRAP_CODE: require_once __DIR__ . '/common.inc'; _drupal_bootstrap_code(); @@ -1911,7 +1899,7 @@ function drupal_get_user_timezone() { global $user; $config = config('system.timezone'); - if ($config->get('user.configurable') && $user->uid && $user->timezone) { + if ($user && $config->get('user.configurable') && $user->uid && $user->timezone) { return $user->timezone; } else { diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index 1ecd819..5f2ccc7 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -1746,6 +1746,8 @@ function install_load_profile(&$install_state) { */ function install_bootstrap_full() { drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); + require_once DRUPAL_ROOT . '/' . settings()->get('session_inc', 'core/includes/session.inc'); + drupal_session_initialize(); } /** diff --git a/core/lib/Drupal/Core/Authentication/AuthenticationManager.php b/core/lib/Drupal/Core/Authentication/AuthenticationManager.php new file mode 100644 index 0000000..f458ffe --- /dev/null +++ b/core/lib/Drupal/Core/Authentication/AuthenticationManager.php @@ -0,0 +1,209 @@ +providers[$provider_id] = $provider; + $this->providerOrders[$priority][$provider_id] = $provider; + // Force the builders to be re-sorted. + $this->sortedProviders = NULL; + } + + /** + * {@inheritdoc} + */ + public function applies(Request $request) { + return TRUE; + } + + /** + * Authenticate user. + * + * Iterate the available providers according th their priority. + * + * @param \Symfony\Component\HttpFoundation\Request $request + * The request object. + * + * @return \Drupal\Core\Session\AccountInterface + * The account interface of the authenticated user. Defaults to a anonymous. + */ + public function authenticate(Request $request) { + global $user; + + $account = NULL; + + // Iterate the availlable providers. + foreach ($this->getSortedProviders() as $provider_id => $provider) { + if ($provider->applies($request)) { + // Provider felt responsible for this request – trigger authentication. + $account = $provider->authenticate($request); + $this->triggeredProviderId = $provider_id; + break; + } + } + + // No provider returned a valid account - assume anonymous. + if (!$account) { + $account = drupal_anonymous_user(); + } + + // No provider felt responsible – assume the one with the least priority + // should have. + if (!$this->triggeredProviderId) { + $this->triggeredProviderId = $this->defaultProviderId(); + } + + // Save the authenticated account for later access. The global $user object + // is included for backward compatibility only and should be considered + // deprecated. + $user = $account; + $request->attributes->set('session', $account); + + // Save the ID of the triggered provider to the request. + $request->attributes->set('_authentication_provider', $this->triggeredProviderId); + + return $account; + } + + /** + * Returns the default provider ID. + * + * The default provider is the one with the lowest registered priority. + * + * @return string + * The ID of the default provider. + */ + protected function defaultProviderId() { + $providers = $this->getSortedProviders(); + $provider_ids = array_keys($providers); + return end($provider_ids); + } + + /** + * Returns the sorted array of authentication providers. + * + * @return array + * An array of authentication provider objects. + */ + protected function getSortedProviders() { + if (!isset($this->sortedProviders)) { + // Sort the builders according to priority. + krsort($this->providerOrders); + // Merge nested providers from $this->providers into $this->sortedProviders. + $this->sortedProviders = array(); + foreach ($this->providerOrders as $providers) { + $this->sortedProviders = array_merge($this->sortedProviders, $providers); + } + } + return $this->sortedProviders; + } + + /** + * Cleans up the authentication. + * + * Allow the triggered provider to clean up before the response is sent, e.g. + * trigger a session commit. + * + * @param \Symfony\Component\HttpFoundation\Request $request + * The request object. + * + * @see \Drupal\Core\Authentication\Provider\Cookie::cleanup() + */ + public function cleanup(Request $request) { + if (empty($this->providers[$this->triggeredProviderId])) { + return; + } + $this->providers[$this->triggeredProviderId]->cleanup($request); + } + + /** + * {@inheritdoc} + */ + public function handleException(GetResponseForExceptionEvent $event) { + $request = $event->getRequest(); + + // Legacy routes won't have a Route object; they have drupal_menu_item + // instead. Assume those were authenticated by cookie, because the legacy + // router didn't support anything else. + // @todo Remove this check once the old router is fully removed. + if ($request->attributes->has('drupal_menu_item')) { + $auth_providers = array('cookie'); + } + else { + $route = $request->attributes->get(RouteObjectInterface::ROUTE_OBJECT); + $auth_providers = ($route && $route->getOption('_auth')) ? $route->getOption('_auth') : array($this->defaultProviderId()); + } + + // While any provider may authenticate a request, only the first listed + // by a route may give a challenge for a failed request to allow the user + // to login. + $allowed_providers = array_intersect($auth_providers, array_keys($this->providers)); + + if ($allowed_providers) { + $this->providers[current($allowed_providers)]->handleException($event); + } + } +} diff --git a/core/lib/Drupal/Core/Authentication/AuthenticationProviderInterface.php b/core/lib/Drupal/Core/Authentication/AuthenticationProviderInterface.php new file mode 100644 index 0000000..31aafe9 --- /dev/null +++ b/core/lib/Drupal/Core/Authentication/AuthenticationProviderInterface.php @@ -0,0 +1,67 @@ +get('session_inc', 'core/includes/session.inc'); + drupal_session_initialize(); + if (drupal_session_started()) { + return $user; + } + return NULL; + } + + /** + * {@inheritdoc} + */ + public function cleanup(Request $request) { + drupal_session_commit(); + } + + /** + * {@inheritdoc} + */ + public function handleException(GetResponseForExceptionEvent $event) { + return FALSE; + } +} diff --git a/core/lib/Drupal/Core/Authentication/Provider/HttpBasic.php b/core/lib/Drupal/Core/Authentication/Provider/HttpBasic.php new file mode 100644 index 0000000..50ca04f --- /dev/null +++ b/core/lib/Drupal/Core/Authentication/Provider/HttpBasic.php @@ -0,0 +1,86 @@ +configFactory = $config_factory; + } + + /** + * {@inheritdoc} + */ + public function applies(Request $request) { + $username = $request->headers->get('PHP_AUTH_USER'); + $password = $request->headers->get('PHP_AUTH_PW'); + return isset($username) && isset($password); + } + + /** + * {@inheritdoc} + */ + public function authenticate(Request $request) { + $username = $request->headers->get('PHP_AUTH_USER'); + $password = $request->headers->get('PHP_AUTH_PW'); + $uid = user_authenticate($username, $password); + if ($uid) { + return user_load($uid); + } + return NULL; + } + + /** + * {@inheritdoc} + */ + public function cleanup(Request $request) {} + + /** + * {@inheritdoc} + */ + public function handleException(GetResponseForExceptionEvent $event) { + $exception = $event->getException(); + if (user_is_anonymous() && $exception instanceof AccessDeniedHttpException) { + if (!$this->applies($event->getRequest())) { + $site_name = $this->configFactory->get('system.site')->get('name'); + global $base_url; + $challenge = String::format('Basic realm="@realm"', array( + '@realm' => !empty($site_name) ? $site_name : $base_url, + )); + $event->setException(new UnauthorizedHttpException($challenge, 'No authentication credentials provided.', $exception)); + } + return TRUE;; + } + return FALSE; + } +} diff --git a/core/lib/Drupal/Core/Controller/ExceptionController.php b/core/lib/Drupal/Core/Controller/ExceptionController.php index c9a661b..9e7d77e 100644 --- a/core/lib/Drupal/Core/Controller/ExceptionController.php +++ b/core/lib/Drupal/Core/Controller/ExceptionController.php @@ -42,12 +42,12 @@ public function __construct(ContentNegotiation $negotiation) { /** * Handles an exception on a request. * - * @param Symfony\Component\HttpKernel\Exception\FlattenException $exception + * @param \Symfony\Component\HttpKernel\Exception\FlattenException $exception * The flattened exception. - * @param Symfony\Component\HttpFoundation\Request $request + * @param \Symfony\Component\HttpFoundation\Request $request * The request that generated the exception. * - * @return Symfony\Component\HttpFoundation\Response + * @return \Symfony\Component\HttpFoundation\Response * A response object to be sent to the server. */ public function execute(FlattenException $exception, Request $request) { @@ -57,7 +57,7 @@ public function execute(FlattenException $exception, Request $request) { return $this->$method($exception, $request); } - return new Response('A fatal error occurred: ' . $exception->getMessage(), $exception->getStatusCode()); + return new Response('A fatal error occurred: ' . $exception->getMessage(), $exception->getStatusCode(), $exception->getHeaders()); } /** diff --git a/core/lib/Drupal/Core/CoreBundle.php b/core/lib/Drupal/Core/CoreBundle.php index 9af0c74..b5aaa93 100644 --- a/core/lib/Drupal/Core/CoreBundle.php +++ b/core/lib/Drupal/Core/CoreBundle.php @@ -18,6 +18,7 @@ use Drupal\Core\DependencyInjection\Compiler\RegisterServicesForDestructionPass; use Drupal\Core\DependencyInjection\Compiler\RegisterStringTranslatorsPass; use Drupal\Core\DependencyInjection\Compiler\RegisterBreadcrumbBuilderPass; +use Drupal\Core\DependencyInjection\Compiler\RegisterAuthenticationPass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Reference; @@ -67,6 +68,8 @@ public function build(ContainerBuilder $container) { // Add the compiler pass that will process the tagged breadcrumb builder // services. $container->addCompilerPass(new RegisterBreadcrumbBuilderPass()); + // Add the compiler pass that will process tagged authentication services. + $container->addCompilerPass(new RegisterAuthenticationPass()); } /** diff --git a/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterAuthenticationPass.php b/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterAuthenticationPass.php new file mode 100644 index 0000000..dd975a9 --- /dev/null +++ b/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterAuthenticationPass.php @@ -0,0 +1,44 @@ +hasDefinition('authentication')) { + return; + } + // Get the authentication manager. + $matcher = $container->getDefinition('authentication'); + // Iterate all autentication providers and add them to the manager. + foreach ($container->findTaggedServiceIds('authentication_provider') as $id => $attributes) { + $priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0; + $matcher->addMethodCall('addProvider', array( + $id, + new Reference($id), + $priority, + )); + } + } +} diff --git a/core/lib/Drupal/Core/EventSubscriber/AuthenticationSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/AuthenticationSubscriber.php new file mode 100644 index 0000000..f9cf972 --- /dev/null +++ b/core/lib/Drupal/Core/EventSubscriber/AuthenticationSubscriber.php @@ -0,0 +1,94 @@ +authenticationManager = $authentication_manager; + } + + /** + * Authenticates user on request. + * + * @see \Drupal\Core\Authentication\AuthenticationProviderInterface::authenticate() + */ + public function onKernelRequestAuthenticate(GetResponseEvent $event) { + if ($event->getRequestType() == HttpKernelInterface::MASTER_REQUEST) { + $request = $event->getRequest(); + $this->authenticationManager->authenticate($request); + } + } + + /** + * Triggers authentication clean up on response. + * + * @see \Drupal\Core\Authentication\AuthenticationProviderInterface::cleanup() + */ + public function onRespond(FilterResponseEvent $event) { + if ($event->getRequestType() == HttpKernelInterface::MASTER_REQUEST) { + $request = $event->getRequest(); + + $this->authenticationManager->cleanup($request); + } + } + + /** + * Pass exception handling to authentication manager. + * + * @param GetResponseForExceptionEvent $event + */ + public function onException(GetResponseForExceptionEvent $event) { + if ($event->getRequestType() == HttpKernelInterface::MASTER_REQUEST) { + $this->authenticationManager->handleException($event); + } + } + + /** + * {@inheritdoc} + * + * The priority for request must be higher than the highest event subscriber + * accessing the global $user. + * The priority for the response must be as low as possible allowing e.g the + * Cookie provider to send all relevant session data to the user. + */ + public static function getSubscribedEvents() { + // Priority must be higher than LanguageRequestSubscriber as LanguageManager + // access global $user in case language module enabled. + $events[KernelEvents::REQUEST][] = array('onKernelRequestAuthenticate', 300); + $events[KernelEvents::RESPONSE][] = array('onRespond', 0); + $events[KernelEvents::EXCEPTION][] = array('onException', 0); + return $events; + } +} diff --git a/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php index 0b9bbad..98eef05 100644 --- a/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php @@ -91,8 +91,6 @@ public function onRespond(FilterResponseEvent $event) { // @todo Revisit whether or not this is still appropriate now that the // Response object does its own cache control processing and we intend to // use partial page caching more extensively. - // Commit the user session, if needed. - drupal_session_commit(); // Attach globally-declared headers to the response object so that Symfony // can send them for us correctly. diff --git a/core/lib/Drupal/Core/Routing/Enhancer/AuthenticationEnhancer.php b/core/lib/Drupal/Core/Routing/Enhancer/AuthenticationEnhancer.php new file mode 100644 index 0000000..9a342fc --- /dev/null +++ b/core/lib/Drupal/Core/Routing/Enhancer/AuthenticationEnhancer.php @@ -0,0 +1,44 @@ +attributes->get('_authentication_provider'); + if (!empty($auth_provider_triggered)) { + $route = $request->attributes->get(RouteObjectInterface::ROUTE_OBJECT); + $auth_providers = ($route && $route->getOption('_auth')) ? $route->getOption('_auth') : array(); + if (!empty($auth_providers)) { + // If the request was authenticated with a non-permitted provider, + // force the user back to anonymous. + if (!in_array($auth_provider_triggered, $auth_providers)) { + $request->attributes->set('session', drupal_anonymous_user()); + } + } + } + return $defaults; + } + +} diff --git a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php index d3ba7b3..975788a 100644 --- a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php +++ b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php @@ -876,6 +876,7 @@ protected function prepareEnvironment() { $this->originalUser = isset($user) ? clone $user : NULL; // Ensure that the current session is not changed by the new environment. + require_once DRUPAL_ROOT . '/' . settings()->get('session_inc', 'core/includes/session.inc'); drupal_save_session(FALSE); // Run all tests as a anonymous user by default, web tests will replace that // during the test set up. diff --git a/core/modules/system/lib/Drupal/system/Tests/Authentication/HttpBasicTest.php b/core/modules/system/lib/Drupal/system/Tests/Authentication/HttpBasicTest.php new file mode 100644 index 0000000..dea9359 --- /dev/null +++ b/core/modules/system/lib/Drupal/system/Tests/Authentication/HttpBasicTest.php @@ -0,0 +1,86 @@ + 'HttpBasic authentication', + 'description' => 'Tests for HttpBasic authentication provider.', + 'group' => 'Authentication', + ); + } + + /** + * Test http basic authentication. + */ + public function testHttpBasic() { + $account = $this->drupalCreateUser(); + + $this->basicAuthGet('router_test/test11', $account->name, $account->pass_raw); + $this->assertText($account->name, 'Account name is displayed.'); + $this->assertResponse('200', 'HTTP response is OK'); + $this->curlClose(); + + $this->basicAuthGet('router_test/test11', $account->name, $this->randomName()); + $this->assertNoText($account->name, 'Bad basic auth credentials do not authenticate the user.'); + $this->assertResponse('200', 'HTTP response is OK'); + $this->curlClose(); + + $this->drupalGet('router_test/test11'); + $this->assertResponse('401', 'Not authenticated on the route that allows only http_basic. Prompt to authenticate received.'); + } + + /** + * Does HTTP basic auth request. + * + * We do not use \Drupal\simpletest\WebTestBase::drupalGet because we need to + * set curl settings for basic authentication. + * + * @param string $path + * The request path. + * @param string $username + * The user name to authenticate with. + * @param string $password + * The password. + * + * @return string + * Curl output. + */ + protected function basicAuthGet($path, $username, $password) { + $out = $this->curlExec( + array( + CURLOPT_HTTPGET => TRUE, + CURLOPT_URL => url($path, array('absolute' => TRUE)), + CURLOPT_NOBODY => FALSE, + CURLOPT_HTTPAUTH => CURLAUTH_BASIC, + CURLOPT_USERPWD => $username . ':' . $password, + ) + ); + + $this->verbose('GET request to: ' . $path . + '
' . $out); + + return $out; + } +} diff --git a/core/modules/system/lib/Drupal/system/Tests/Upgrade/UpgradePathTestBase.php b/core/modules/system/lib/Drupal/system/Tests/Upgrade/UpgradePathTestBase.php index b613121..9de96b0 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Upgrade/UpgradePathTestBase.php +++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/UpgradePathTestBase.php @@ -93,6 +93,10 @@ protected function setUp() { // Load the Update API. require_once DRUPAL_ROOT . '/core/includes/update.inc'; + // Load Session API. + require_once DRUPAL_ROOT . '/core/includes/session.inc'; + drupal_session_initialize(); + // Reset flags. $this->upgradedSite = FALSE; $this->upgradeErrors = array(); diff --git a/core/modules/system/tests/modules/router_test/lib/Drupal/router_test/TestContent.php b/core/modules/system/tests/modules/router_test/lib/Drupal/router_test/TestContent.php index 56d567b..22a07cf 100644 --- a/core/modules/system/tests/modules/router_test/lib/Drupal/router_test/TestContent.php +++ b/core/modules/system/tests/modules/router_test/lib/Drupal/router_test/TestContent.php @@ -19,4 +19,15 @@ public function test1() { return 'abcde'; } + /** + * Provides example content for route specific authentication. + * + * @returns string + * The user name of the current logged in user. + */ + public function test11() { + global $user; + return isset($user->name) ? $user->name : ''; + } + } diff --git a/core/modules/system/tests/modules/router_test/router_test.routing.yml b/core/modules/system/tests/modules/router_test/router_test.routing.yml index 2a989df..9e481de 100644 --- a/core/modules/system/tests/modules/router_test/router_test.routing.yml +++ b/core/modules/system/tests/modules/router_test/router_test.routing.yml @@ -60,3 +60,10 @@ router_test_10: _content: '\Drupal\router_test\TestContent::test1' requirements: _access: 'TRUE' + +router_test_11: + pattern: '/router_test/test11' + options: + _auth: [ 'http_basic' ] + defaults: + _content: '\Drupal\router_test\TestContent::test11' diff --git a/core/modules/system/tests/modules/session_test/lib/Drupal/session_test/EventSubscriber/SessionTestSubscriber.php b/core/modules/system/tests/modules/session_test/lib/Drupal/session_test/EventSubscriber/SessionTestSubscriber.php index 45234a8..44e2882 100644 --- a/core/modules/system/tests/modules/session_test/lib/Drupal/session_test/EventSubscriber/SessionTestSubscriber.php +++ b/core/modules/system/tests/modules/session_test/lib/Drupal/session_test/EventSubscriber/SessionTestSubscriber.php @@ -65,7 +65,7 @@ public function onKernelResponseSessionTest(FilterResponseEvent $event) { */ static function getSubscribedEvents() { $events[KernelEvents::RESPONSE][] = array('onKernelResponseSessionTest', 300); - $events[KernelEvents::REQUEST][] = array('onKernelRequestSessionTest', 300); + $events[KernelEvents::REQUEST][] = array('onKernelRequestSessionTest', 100); return $events; } diff --git a/core/modules/user/lib/Drupal/user/Access/RoleAccessCheck.php b/core/modules/user/lib/Drupal/user/Access/RoleAccessCheck.php index 7940bf3..928af4d 100644 --- a/core/modules/user/lib/Drupal/user/Access/RoleAccessCheck.php +++ b/core/modules/user/lib/Drupal/user/Access/RoleAccessCheck.php @@ -34,9 +34,7 @@ public function access(Route $route, Request $request) { // Requirements just allow strings, so this might be a comma separated list. $rid_string = $route->getRequirement('_role'); - // @todo Replace the role check with a correctly injected and session-using - // alternative. - $account = $GLOBALS['user']; + $account = $request->attributes->get('session'); $explode_and = array_filter(array_map('trim', explode('+', $rid_string))); if (count($explode_and) > 1) { diff --git a/core/modules/user/user.module b/core/modules/user/user.module index e7ee37a..e9785f6 100644 --- a/core/modules/user/user.module +++ b/core/modules/user/user.module @@ -470,7 +470,9 @@ function user_access($string, AccountInterface $account = NULL) { global $user; if (!isset($account)) { - $account = $user; + // In the installer request session is not set, so we have to fall back + // to the global $user. In all other cases the session key is preferred. + $account = Drupal::request()->attributes->get('session') ?: $user; } // Make sure we are working with the BC decorator. diff --git a/core/update.php b/core/update.php index b73e3ce..f97a973 100644 --- a/core/update.php +++ b/core/update.php @@ -427,7 +427,9 @@ function update_check_requirements($skip_warnings = FALSE) { update_prepare_d8_bootstrap(); // Determine if the current user has access to run update.php. -drupal_bootstrap(DRUPAL_BOOTSTRAP_SESSION); +drupal_bootstrap(DRUPAL_BOOTSTRAP_VARIABLES); +require_once DRUPAL_ROOT . '/' . settings()->get('session_inc', 'core/includes/session.inc'); +drupal_session_initialize(); // A request object from the HTTPFoundation to tell us about the request. // @todo These two lines were copied from index.php which has its own todo about