Unverified Commit a2856d11 authored by Alex Pott's avatar Alex Pott
Browse files

Issue #3151094 by dww, jungle, ravi.shankar, alexpott: Replace use of...

Issue #3151094 by dww, jungle, ravi.shankar, alexpott: Replace use of whitelist/blacklist in \Drupal\Core\Template classes and their tests
parent b4dbfc16
Loading
Loading
Loading
Loading
+14 −1
Changes for core/lib/Drupal/Core/Site/Settings.php: 14 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -37,7 +37,20 @@ final class Settings {
   *
   * @see self::handleDeprecations()
   */
  private static $deprecatedSettings = [];
  private static $deprecatedSettings = [
    'twig_sandbox_whitelisted_classes' => [
      'replacement' => 'twig_sandbox_allowed_classes',
      'message' => 'The "twig_sandbox_whitelisted_classes" setting is deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Use "twig_sandbox_allowed_classes" instead. See https://www.drupal.org/node/3162897.',
    ],
    'twig_sandbox_whitelisted_methods' => [
      'replacement' => 'twig_sandbox_allowed_methods',
      'message' => 'The "twig_sandbox_whitelisted_methods" setting is deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Use "twig_sandbox_allowed_methods" instead. See https://www.drupal.org/node/3162897.',
    ],
    'twig_sandbox_whitelisted_prefixes' => [
      'replacement' => 'twig_sandbox_allowed_prefixes',
      'message' => 'The "twig_sandbox_whitelisted_prefixes" setting is deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Use "twig_sandbox_allowed_prefixes" instead. See https://www.drupal.org/node/3162897.',
    ],
  ];

  /**
   * Constructor.
+1 −1
Changes for core/lib/Drupal/Core/Template/Loader/StringLoader.php: 1 added line, 1 removed line.
Original line number Diff line number Diff line
@@ -8,7 +8,7 @@
/**
 * Loads string templates, also known as inline templates.
 *
 * This loader is intended to be used in a Twig loader chain and whitelists
 * This loader is intended to be used in a Twig loader chain and only loads
 * string templates that begin with the following comment:
 * @code
 * {# inline_template_start #}
+20 −19
Changes for core/lib/Drupal/Core/Template/TwigSandboxPolicy.php: 20 added lines, 19 removed lines.
Original line number Diff line number Diff line
@@ -12,48 +12,48 @@
 * Twig's sandbox extension is usually used to evaluate untrusted code by
 * limiting access to potentially unsafe properties or methods. Since we do not
 * use ViewModels when passing objects to Twig templates, we limit what those
 * objects can do by whitelisting certain classes, method names, and method
 * objects can do by only loading certain classes, method names, and method
 * names with an allowed prefix. All object properties may be accessed.
 */
class TwigSandboxPolicy implements SecurityPolicyInterface {

  /**
   * An array of whitelisted methods in the form of methodName => TRUE.
   * An array of allowed methods in the form of methodName => TRUE.
   *
   * @var array
   */
  protected $whitelisted_methods;
  protected $allowed_methods;

  /**
   * An array of whitelisted method prefixes -- any method starting with one of
   * An array of allowed method prefixes -- any method starting with one of
   * these prefixes will be allowed.
   *
   * @var array
   */
  protected $whitelisted_prefixes;
  protected $allowed_prefixes;

  /**
   * An array of class names for which any method calls are allowed.
   *
   * @var array
   */
  protected $whitelisted_classes;
  protected $allowed_classes;

  /**
   * Constructs a new TwigSandboxPolicy object.
   */
  public function __construct() {
    // Allow settings.php to override our default whitelisted classes, methods,
    // and prefixes.
    $whitelisted_classes = Settings::get('twig_sandbox_whitelisted_classes', [
    // Allow settings.php to override our default allowed classes, methods, and
    // prefixes.
    $allowed_classes = Settings::get('twig_sandbox_allowed_classes', [
      // Allow any operations on the Attribute object as it is intended to be
      // changed from a Twig template, for example calling addClass().
      'Drupal\Core\Template\Attribute',
    ]);
    // Flip the arrays so we can check using isset().
    $this->whitelisted_classes = array_flip($whitelisted_classes);
    // Flip the array so we can check using isset().
    $this->allowed_classes = array_flip($allowed_classes);

    $whitelisted_methods = Settings::get('twig_sandbox_whitelisted_methods', [
    $allowed_methods = Settings::get('twig_sandbox_allowed_methods', [
      // Only allow idempotent methods.
      'id',
      'label',
@@ -62,9 +62,10 @@ public function __construct() {
      '__toString',
      'toString',
    ]);
    $this->whitelisted_methods = array_flip($whitelisted_methods);
    // Flip the array so we can check using isset().
    $this->allowed_methods = array_flip($allowed_methods);

    $this->whitelisted_prefixes = Settings::get('twig_sandbox_whitelisted_prefixes', [
    $this->allowed_prefixes = Settings::get('twig_sandbox_allowed_prefixes', [
      'get',
      'has',
      'is',
@@ -85,20 +86,20 @@ public function checkPropertyAllowed($obj, $property) {}
   * {@inheritdoc}
   */
  public function checkMethodAllowed($obj, $method) {
    foreach ($this->whitelisted_classes as $class => $key) {
    foreach ($this->allowed_classes as $class => $key) {
      if ($obj instanceof $class) {
        return TRUE;
      }
    }

    // Return quickly for an exact match of the method name.
    if (isset($this->whitelisted_methods[$method])) {
    if (isset($this->allowed_methods[$method])) {
      return TRUE;
    }

    // If the method name starts with a whitelisted prefix, allow it.
    // Note: strpos() is between 3x and 7x faster than preg_match in this case.
    foreach ($this->whitelisted_prefixes as $prefix) {
    // If the method name starts with an allowed prefix, allow it. Note:
    // strpos() is between 3x and 7x faster than preg_match() in this case.
    foreach ($this->allowed_prefixes as $prefix) {
      if (strpos($method, $prefix) === 0) {
        return TRUE;
      }
+27 −0
Changes for core/tests/Drupal/Tests/Core/Site/SettingsTest.php: 27 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -272,4 +272,31 @@ public function providerTestFakeDeprecatedSettings(): array {
    ];
  }

  /**
   * Tests legacy twig_sandbox_* settings.
   *
   * @runInSeparateProcess
   *
   * @group legacy
   *
   * @expectedDeprecation The "twig_sandbox_whitelisted_classes" setting is deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Use "twig_sandbox_allowed_classes" instead. See https://www.drupal.org/node/3162897.
   * @expectedDeprecation The "twig_sandbox_whitelisted_methods" setting is deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Use "twig_sandbox_allowed_methods" instead. See https://www.drupal.org/node/3162897.
   * @expectedDeprecation The "twig_sandbox_whitelisted_prefixes" setting is deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Use "twig_sandbox_allowed_prefixes" instead. See https://www.drupal.org/node/3162897.
   */
  public function testLegacyTwigSandboxSettings(): void {
    $settings = <<<'EOD'
<?php
$settings['twig_sandbox_whitelisted_classes'] = ['a', 'b'];
$settings['twig_sandbox_whitelisted_methods'] = ['aFoo', 'bBar'];
$settings['twig_sandbox_whitelisted_prefixes'] = ['aPrefix', 'bPrefix'];
EOD;
    $class_loader = NULL;
    $vfs_root = vfsStream::setup('root');
    $sites_directory = vfsStream::newDirectory('sites')->at($vfs_root);
    vfsStream::newFile('settings.php')
      ->at($sites_directory)
      ->setContent($settings);
    Settings::initialize(vfsStream::url('root'), 'sites', $class_loader);
  }

}