Verified Commit 2420d38b authored by Alex Pott's avatar Alex Pott
Browse files

Issue #3274867 by longwave, jungle, andypost, alexpott, smustgrave: Add TrustedCallback attribute

parent f06e188e
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
<?php

namespace Drupal\Core\Security\Attribute;

/**
 * Attribute to tell that a method is a trusted callback.
 */
#[\Attribute(\Attribute::TARGET_METHOD)]
class TrustedCallback {}
+13 −3
Original line number Diff line number Diff line
@@ -2,9 +2,12 @@

namespace Drupal\Core\Security;

use Drupal\Core\Security\Attribute\TrustedCallback;

/**
 * Ensures that TrustedCallbackInterface can be enforced for callback methods.
 * Ensures that only predefined methods can be used as callback methods.
 *
 * @see \Drupal\Core\Security\Attribute\TrustedCallback
 * @see \Drupal\Core\Security\TrustedCallbackInterface
 */
trait DoTrustedCallbackTrait {
@@ -13,8 +16,10 @@ trait DoTrustedCallbackTrait {
   * Performs a callback.
   *
   * If the callback is trusted the callback will occur. Trusted callbacks must
   * be methods of a class that implements
   * \Drupal\Core\Security\TrustedCallbackInterface or $extra_trusted_interface
   * be methods that are tagged with the
   * \Drupal\Core\Security\Attribute\TrustedCallback attribute, or be methods of
   * a class that implements
   * \Drupal\Core\Security\TrustedCallbackInterface or $extra_trusted_interface,
   * or be an anonymous function. If the callback is not trusted then whether or
   * not the callback is called and what type of error is thrown depends on
   * $error_type. To provide time for dependent code to use trusted callbacks
@@ -46,6 +51,7 @@ trait DoTrustedCallbackTrait {
   *   Exception thrown if the callback is not trusted and $error_type equals
   *   TrustedCallbackInterface::THROW_EXCEPTION.
   *
   * @see \Drupal\Core\Security\Attribute\TrustedCallback
   * @see \Drupal\Core\Security\TrustedCallbackInterface
   */
  public function doTrustedCallback(callable $callback, array $args, $message, $error_type = TrustedCallbackInterface::THROW_EXCEPTION, $extra_trusted_interface = NULL) {
@@ -72,6 +78,10 @@ public function doTrustedCallback(callable $callback, array $args, $message, $er
        }
        $safe_callback = in_array($method_name, $methods, TRUE);
      }
      if (!$safe_callback) {
        $method = new \ReflectionMethod($object_or_classname, $method_name);
        $safe_callback = (bool) $method->getAttributes(TrustedCallback::class);
      }
    }
    elseif ($callback instanceof \Closure) {
      $safe_callback = TRUE;
+8 −0
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@

namespace Drupal\Tests\Core\Security;

use Drupal\Core\Security\Attribute\TrustedCallback;
use Drupal\Core\Security\TrustedCallbackInterface;
use Drupal\Core\Security\DoTrustedCallbackTrait;
use Drupal\Core\Security\UntrustedCallbackException;
@@ -33,8 +34,10 @@ public function providerTestTrustedCallbacks() {

    $tests['closure'] = [$closure];
    $tests['TrustedCallbackInterface_object'] = [[new TrustedMethods(), 'callback'], TrustedInterface::class];
    $tests['TrustedCallbackInterface_object_attribute'] = [[new TrustedMethods(), 'attributeCallback'], TrustedInterface::class];
    $tests['TrustedCallbackInterface_static_string'] = ['\Drupal\Tests\Core\Security\TrustedMethods::callback', TrustedInterface::class];
    $tests['TrustedCallbackInterface_static_array'] = [[TrustedMethods::class, 'callback'], TrustedInterface::class];
    $tests['TrustedCallbackInterface_static_array_attribute'] = [[TrustedMethods::class, 'attributeCallback'], TrustedInterface::class];
    $tests['extra_trusted_interface_object'] = [[new TrustedObject(), 'callback'], TrustedInterface::class];
    $tests['extra_trusted_interface_static_string'] = ['\Drupal\Tests\Core\Security\TrustedObject::callback', TrustedInterface::class];
    $tests['extra_trusted_interface_static_array'] = [[TrustedObject::class, 'callback'], TrustedInterface::class];
@@ -140,6 +143,11 @@ public static function callback() {
    return 'test';
  }

  #[TrustedCallback]
  public static function attributeCallback() {
    return 'test';
  }

  public static function unTrustedCallback() {
    return 'test';
  }