annotate core/authorize.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 129ea1e6d783
children
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 /**
Chris@0 4 * @file
Chris@0 5 * Administrative script for running authorized file operations.
Chris@0 6 *
Chris@0 7 * Using this script, the site owner (the user actually owning the files on the
Chris@0 8 * webserver) can authorize certain file-related operations to proceed with
Chris@0 9 * elevated privileges, for example to deploy and upgrade modules or themes.
Chris@0 10 * Users should not visit this page directly, but instead use an administrative
Chris@0 11 * user interface which knows how to redirect the user to this script as part of
Chris@0 12 * a multistep process. This script actually performs the selected operations
Chris@0 13 * without loading all of Drupal, to be able to more gracefully recover from
Chris@0 14 * errors. Access to the script is controlled by a global killswitch in
Chris@0 15 * settings.php ('allow_authorize_operations') and via the 'administer software
Chris@0 16 * updates' permission.
Chris@0 17 *
Chris@0 18 * There are helper functions for setting up an operation to run via this
Chris@0 19 * system in modules/system/system.module. For more information, see:
Chris@0 20 * @link authorize Authorized operation helper functions @endlink
Chris@0 21 */
Chris@0 22
Chris@0 23 use Drupal\Core\DrupalKernel;
Chris@0 24 use Drupal\Core\Form\EnforcedResponseException;
Chris@0 25 use Drupal\Core\Url;
Chris@0 26 use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
Chris@0 27 use Symfony\Component\HttpFoundation\Request;
Chris@0 28 use Symfony\Component\HttpFoundation\Response;
Chris@0 29 use Drupal\Core\Site\Settings;
Chris@0 30
Chris@0 31 // Change the directory to the Drupal root.
Chris@0 32 chdir('..');
Chris@0 33
Chris@0 34 $autoloader = require_once 'autoload.php';
Chris@0 35
Chris@0 36 /**
Chris@0 37 * Global flag to identify update.php and authorize.php runs.
Chris@0 38 *
Chris@0 39 * Identifies update.php and authorize.php runs, avoiding unwanted operations
Chris@0 40 * such as css/js preprocessing and translation, and solves some theming issues.
Chris@0 41 * The flag is checked in other places in Drupal code (not just authorize.php).
Chris@0 42 */
Chris@0 43 const MAINTENANCE_MODE = 'update';
Chris@0 44
Chris@0 45 /**
Chris@0 46 * Determines if the current user is allowed to run authorize.php.
Chris@0 47 *
Chris@0 48 * The killswitch in settings.php overrides all else, otherwise, the user must
Chris@0 49 * have access to the 'administer software updates' permission.
Chris@0 50 *
Chris@0 51 * @param \Symfony\Component\HttpFoundation\Request $request
Chris@0 52 * The incoming request.
Chris@0 53 *
Chris@0 54 * @return bool
Chris@0 55 * TRUE if the current user can run authorize.php, and FALSE if not.
Chris@0 56 */
Chris@0 57 function authorize_access_allowed(Request $request) {
Chris@0 58 $account = \Drupal::service('authentication')->authenticate($request);
Chris@0 59 if ($account) {
Chris@0 60 \Drupal::currentUser()->setAccount($account);
Chris@0 61 }
Chris@0 62 return Settings::get('allow_authorize_operations', TRUE) && \Drupal::currentUser()->hasPermission('administer software updates');
Chris@0 63 }
Chris@0 64
Chris@0 65 try {
Chris@0 66 $request = Request::createFromGlobals();
Chris@0 67 $kernel = DrupalKernel::createFromRequest($request, $autoloader, 'prod');
Chris@0 68 $kernel->prepareLegacyRequest($request);
Chris@0 69 }
Chris@0 70 catch (HttpExceptionInterface $e) {
Chris@0 71 $response = new Response('', $e->getStatusCode());
Chris@0 72 $response->prepare($request)->send();
Chris@0 73 exit;
Chris@0 74 }
Chris@0 75
Chris@0 76 // We have to enable the user and system modules, even to check access and
Chris@0 77 // display errors via the maintenance theme.
Chris@0 78 \Drupal::moduleHandler()->addModule('system', 'core/modules/system');
Chris@0 79 \Drupal::moduleHandler()->addModule('user', 'core/modules/user');
Chris@0 80 \Drupal::moduleHandler()->load('system');
Chris@0 81 \Drupal::moduleHandler()->load('user');
Chris@0 82
Chris@0 83 // Initialize the maintenance theme for this administrative script.
Chris@0 84 drupal_maintenance_theme();
Chris@0 85
Chris@0 86 $content = [];
Chris@0 87 $show_messages = TRUE;
Chris@0 88
Chris@0 89 $is_allowed = authorize_access_allowed($request);
Chris@0 90
Chris@0 91 // Build content.
Chris@0 92 if ($is_allowed) {
Chris@0 93 // Load both the Form API and Batch API.
Chris@0 94 require_once __DIR__ . '/includes/form.inc';
Chris@0 95 require_once __DIR__ . '/includes/batch.inc';
Chris@0 96
Chris@0 97 if (isset($_SESSION['authorize_page_title'])) {
Chris@0 98 $page_title = $_SESSION['authorize_page_title'];
Chris@0 99 }
Chris@0 100 else {
Chris@0 101 $page_title = t('Authorize file system changes');
Chris@0 102 }
Chris@0 103
Chris@0 104 // See if we've run the operation and need to display a report.
Chris@0 105 if (isset($_SESSION['authorize_results']) && $results = $_SESSION['authorize_results']) {
Chris@0 106
Chris@0 107 // Clear the session out.
Chris@0 108 unset($_SESSION['authorize_results']);
Chris@0 109 unset($_SESSION['authorize_operation']);
Chris@0 110 unset($_SESSION['authorize_filetransfer_info']);
Chris@0 111
Chris@0 112 if (!empty($results['page_title'])) {
Chris@0 113 $page_title = $results['page_title'];
Chris@0 114 }
Chris@0 115 if (!empty($results['page_message'])) {
Chris@17 116 \Drupal::messenger()->addMessage($results['page_message']['message'], $results['page_message']['type']);
Chris@0 117 }
Chris@0 118
Chris@0 119 $content['authorize_report'] = [
Chris@0 120 '#theme' => 'authorize_report',
Chris@0 121 '#messages' => $results['messages'],
Chris@0 122 ];
Chris@0 123
Chris@0 124 if (is_array($results['tasks'])) {
Chris@0 125 $links = $results['tasks'];
Chris@0 126 }
Chris@0 127 else {
Chris@17 128 // Since this is being called outside of the primary front controller,
Chris@0 129 // the base_url needs to be set explicitly to ensure that links are
Chris@0 130 // relative to the site root.
Chris@0 131 // @todo Simplify with https://www.drupal.org/node/2548095
Chris@0 132 $default_options = [
Chris@0 133 '#type' => 'link',
Chris@0 134 '#options' => [
Chris@0 135 'absolute' => TRUE,
Chris@0 136 'base_url' => $GLOBALS['base_url'],
Chris@0 137 ],
Chris@0 138 ];
Chris@0 139 $links = [
Chris@0 140 $default_options + [
Chris@0 141 '#url' => Url::fromRoute('system.admin'),
Chris@0 142 '#title' => t('Administration pages'),
Chris@0 143 ],
Chris@0 144 $default_options + [
Chris@0 145 '#url' => Url::fromRoute('<front>'),
Chris@0 146 '#title' => t('Front page'),
Chris@0 147 ],
Chris@0 148 ];
Chris@0 149 }
Chris@0 150
Chris@0 151 $content['next_steps'] = [
Chris@0 152 '#theme' => 'item_list',
Chris@0 153 '#items' => $links,
Chris@0 154 '#title' => t('Next steps'),
Chris@0 155 ];
Chris@0 156 }
Chris@0 157 // If a batch is running, let it run.
Chris@0 158 elseif ($request->query->has('batch')) {
Chris@0 159 $content = _batch_page($request);
Chris@0 160 // If _batch_page() returns a response object (likely a JsonResponse for
Chris@0 161 // JavaScript-based batch processing), send it immediately.
Chris@0 162 if ($content instanceof Response) {
Chris@0 163 $content->send();
Chris@0 164 exit;
Chris@0 165 }
Chris@0 166 }
Chris@0 167 else {
Chris@0 168 if (empty($_SESSION['authorize_operation']) || empty($_SESSION['authorize_filetransfer_info'])) {
Chris@0 169 $content = ['#markup' => t('It appears you have reached this page in error.')];
Chris@0 170 }
Chris@0 171 elseif (!$batch = batch_get()) {
Chris@0 172 // We have a batch to process, show the filetransfer form.
Chris@0 173 try {
Chris@0 174 $content = \Drupal::formBuilder()->getForm('Drupal\Core\FileTransfer\Form\FileTransferAuthorizeForm');
Chris@0 175 }
Chris@0 176 catch (EnforcedResponseException $e) {
Chris@0 177 $e->getResponse()->send();
Chris@0 178 exit;
Chris@0 179 }
Chris@0 180 }
Chris@0 181 }
Chris@0 182 // We defer the display of messages until all operations are done.
Chris@0 183 $show_messages = !(($batch = batch_get()) && isset($batch['running']));
Chris@0 184 }
Chris@0 185 else {
Chris@0 186 \Drupal::logger('access denied')->warning('authorize.php');
Chris@0 187 $page_title = t('Access denied');
Chris@0 188 $content = ['#markup' => t('You are not allowed to access this page.')];
Chris@0 189 }
Chris@0 190
Chris@0 191 $bare_html_page_renderer = \Drupal::service('bare_html_page_renderer');
Chris@0 192 $response = $bare_html_page_renderer->renderBarePage($content, $page_title, 'maintenance_page', [
Chris@0 193 '#show_messages' => $show_messages,
Chris@0 194 ]);
Chris@0 195 if (!$is_allowed) {
Chris@0 196 $response->setStatusCode(403);
Chris@0 197 }
Chris@0 198 $response->send();