3 namespace Drupal\Tests\system\Functional\System;
5 use Drupal\Component\Render\FormattableMarkup;
6 use Drupal\Core\Site\Settings;
7 use Drupal\Core\StringTranslation\StringTranslationTrait;
8 use Drupal\Tests\BrowserTestBase;
11 * Tests Drupal permissions hardening of /sites subdirectories.
15 class SitesDirectoryHardeningTest extends BrowserTestBase {
16 use StringTranslationTrait;
19 * Tests the default behavior to restrict directory permissions is enforced.
21 * Checks both the the current sites directory and settings.php.
23 public function testSitesDirectoryHardening() {
24 $site_path = $this->kernel->getSitePath();
25 $settings_file = $this->settingsFile($site_path);
27 // First, we check based on what the initial install has set.
28 $this->assertTrue(drupal_verify_install_file($site_path, FILE_NOT_WRITABLE, 'dir'), new FormattableMarkup('Verified permissions for @file.', ['@file' => $site_path]));
30 // We intentionally don't check for settings.local.php as that file is
31 // not created by Drupal.
32 $this->assertTrue(drupal_verify_install_file($settings_file, FILE_EXIST | FILE_READABLE | FILE_NOT_WRITABLE), new FormattableMarkup('Verified permissions for @file.', ['@file' => $settings_file]));
34 $this->makeWritable($site_path);
35 $this->checkSystemRequirements();
37 $this->assertTrue(drupal_verify_install_file($site_path, FILE_NOT_WRITABLE, 'dir'), new FormattableMarkup('Verified permissions for @file after manual permissions change.', ['@file' => $site_path]));
38 $this->assertTrue(drupal_verify_install_file($settings_file, FILE_EXIST | FILE_READABLE | FILE_NOT_WRITABLE), new FormattableMarkup('Verified permissions for @file after manual permissions change.', ['@file' => $settings_file]));
42 * Tests writable files remain writable when directory hardening is disabled.
44 public function testSitesDirectoryHardeningConfig() {
45 $site_path = $this->kernel->getSitePath();
46 $settings_file = $this->settingsFile($site_path);
48 // Disable permissions enforcement.
49 $settings = Settings::getAll();
50 $settings['skip_permissions_hardening'] = TRUE;
51 new Settings($settings);
52 $this->assertTrue(Settings::get('skip_permissions_hardening'), 'Able to set skip permissions hardening to true.');
53 $this->makeWritable($site_path);
55 // Manually trigger the requirements check.
56 $requirements = $this->checkSystemRequirements();
57 $this->assertEqual(REQUIREMENT_WARNING, $requirements['configuration_files']['severity'], 'Warning severity is properly set.');
58 $this->assertEquals('Protection disabled', (string) $requirements['configuration_files']['value']);
59 $description = strip_tags(\Drupal::service('renderer')->renderPlain($requirements['configuration_files']['description']));
60 $this->assertContains('settings.php is not protected from modifications and poses a security risk.', $description);
61 $this->assertContains('services.yml is not protected from modifications and poses a security risk.', $description);
63 $this->assertTrue(is_writable($site_path), 'Site directory remains writable when automatically fixing permissions is disabled.');
64 $this->assertTrue(is_writable($settings_file), 'settings.php remains writable when automatically fixing permissions is disabled.');
66 // Re-enable permissions enforcement.
67 $settings = Settings::getAll();
68 $settings['skip_permissions_hardening'] = FALSE;
69 new Settings($settings);
71 // Manually trigger the requirements check.
72 $requirements = $this->checkSystemRequirements();
73 $this->assertEquals('Protected', (string) $requirements['configuration_files']['value']);
75 $this->assertFalse(is_writable($site_path), 'Site directory is protected when automatically fixing permissions is enabled.');
76 $this->assertFalse(is_writable($settings_file), 'settings.php is protected when automatically fixing permissions is enabled.');
80 * Checks system runtime requirements.
83 * An array of system requirements.
85 protected function checkSystemRequirements() {
86 module_load_install('system');
87 return system_requirements('runtime');
91 * Makes the given path and settings file writable.
93 * @param string $site_path
94 * The sites directory path, such as 'sites/default'.
96 protected function makeWritable($site_path) {
97 chmod($site_path, 0755);
98 chmod($this->settingsFile($site_path), 0644);
102 * Returns the path to settings.php
104 * @param string $site_path
105 * The sites subdirectory path.
108 * The path to settings.php.
110 protected function settingsFile($site_path) {
111 $settings_file = $site_path . '/settings.php';
112 return $settings_file;