You are here

class CspTest in Content-Security-Policy 8

Test manipulating directives in a policy.

@coversDefaultClass \Drupal\csp\Csp @group csp

Hierarchy

Expanded class hierarchy of CspTest

File

tests/src/Unit/CspTest.php, line 14

Namespace

Drupal\Tests\csp\Unit
View source
class CspTest extends UnitTestCase {

  /**
   * Test calculating hash values.
   *
   * @covers ::calculateHash
   */
  public function testHash() {
    $this
      ->assertEquals('sha256-BnZSlC9IkS7BVcseRf0CAOmLntfifZIosT2C1OMQ088=', Csp::calculateHash('alert("Hello World");'));
    $this
      ->assertEquals('sha256-BnZSlC9IkS7BVcseRf0CAOmLntfifZIosT2C1OMQ088=', Csp::calculateHash('alert("Hello World");', 'sha256'));
    $this
      ->assertEquals('sha384-iZxROpttQr5JcGhwPlHbUPBm+IHbO2CwTxLGhVoZXCIIpjSZo+Ourcmqw1QHOpGM', Csp::calculateHash('alert("Hello World");', 'sha384'));
    $this
      ->assertEquals('sha512-6/WbXCJEH9R1/effxooQuXLAsm6xIsfGMK6nFa7TG76VuHZJVRZHIirKrXi/Pib8QbQmkzpo5K/3Ye+cD46ADQ==', Csp::calculateHash('alert("Hello World");', 'sha512'));
  }

  /**
   * Test specifying an invalid hash algorithm.
   *
   * @covers ::calculateHash
   */
  public function testInvalidHashAlgo() {
    $this
      ->expectException(\InvalidArgumentException::class);
    Csp::calculateHash('alert("Hello World");', 'md5');
  }

  /**
   * Test that changing the policy's report-only flag updates the header name.
   *
   * @covers ::reportOnly
   * @covers ::isReportOnly
   * @covers ::getHeaderName
   */
  public function testReportOnly() {
    $policy = new Csp();
    $this
      ->assertFalse($policy
      ->isReportOnly());
    $this
      ->assertEquals("Content-Security-Policy", $policy
      ->getHeaderName());
    $policy
      ->reportOnly();
    $this
      ->assertTrue($policy
      ->isReportOnly());
    $this
      ->assertEquals("Content-Security-Policy-Report-Only", $policy
      ->getHeaderName());
    $policy
      ->reportOnly(FALSE);
    $this
      ->assertFalse($policy
      ->isReportOnly());
    $this
      ->assertEquals("Content-Security-Policy", $policy
      ->getHeaderName());
  }

  /**
   * Test that invalid directive names cause an exception.
   *
   * @covers ::setDirective
   * @covers ::isValidDirectiveName
   * @covers ::validateDirectiveName
   */
  public function testSetInvalidPolicy() {
    $this
      ->expectException(\InvalidArgumentException::class);
    $policy = new Csp();
    $policy
      ->setDirective('foo', Csp::POLICY_SELF);
  }

  /**
   * Test that invalid directive names cause an exception.
   *
   * @covers ::appendDirective
   * @covers ::isValidDirectiveName
   * @covers ::validateDirectiveName
   */
  public function testAppendInvalidPolicy() {
    $this
      ->expectException(\InvalidArgumentException::class);
    $policy = new Csp();
    $policy
      ->appendDirective('foo', Csp::POLICY_SELF);
  }

  /**
   * Test setting a single value to a directive.
   *
   * @covers ::setDirective
   * @covers ::hasDirective
   * @covers ::getDirective
   * @covers ::isValidDirectiveName
   * @covers ::validateDirectiveName
   * @covers ::getHeaderValue
   */
  public function testSetSingle() {
    $policy = new Csp();
    $policy
      ->setDirective('default-src', Csp::POLICY_SELF);
    $this
      ->assertTrue($policy
      ->hasDirective('default-src'));
    $this
      ->assertEquals($policy
      ->getDirective('default-src'), [
      "'self'",
    ]);
    $this
      ->assertEquals("default-src 'self'", $policy
      ->getHeaderValue());
  }

  /**
   * Test appending a single value to an uninitialized directive.
   *
   * @covers ::appendDirective
   * @covers ::hasDirective
   * @covers ::getDirective
   * @covers ::isValidDirectiveName
   * @covers ::validateDirectiveName
   * @covers ::getHeaderValue
   */
  public function testAppendSingle() {
    $policy = new Csp();
    $policy
      ->appendDirective('default-src', Csp::POLICY_SELF);
    $this
      ->assertTrue($policy
      ->hasDirective('default-src'));
    $this
      ->assertEquals($policy
      ->getDirective('default-src'), [
      "'self'",
    ]);
    $this
      ->assertEquals("default-src 'self'", $policy
      ->getHeaderValue());
  }

  /**
   * Test that a directive is overridden when set with a new value.
   *
   * @covers ::setDirective
   * @covers ::isValidDirectiveName
   * @covers ::getHeaderValue
   */
  public function testSetMultiple() {
    $policy = new Csp();
    $policy
      ->setDirective('default-src', Csp::POLICY_ANY);
    $policy
      ->setDirective('default-src', [
      Csp::POLICY_SELF,
      'one.example.com',
    ]);
    $policy
      ->setDirective('script-src', Csp::POLICY_SELF . ' two.example.com');
    $policy
      ->setDirective('upgrade-insecure-requests', TRUE);
    $policy
      ->setDirective('report-uri', 'example.com/report-uri');
    $this
      ->assertEquals("upgrade-insecure-requests; default-src 'self' one.example.com; script-src 'self' two.example.com; report-uri example.com/report-uri", $policy
      ->getHeaderValue());
  }

  /**
   * Test that appending to a directive extends the existing value.
   *
   * @covers ::appendDirective
   * @covers ::isValidDirectiveName
   * @covers ::getHeaderValue
   */
  public function testAppendMultiple() {
    $policy = new Csp();
    $policy
      ->appendDirective('default-src', Csp::POLICY_SELF);
    $policy
      ->appendDirective('script-src', [
      Csp::POLICY_SELF,
      'two.example.com',
    ]);
    $policy
      ->appendDirective('default-src', 'one.example.com');
    $this
      ->assertEquals("default-src 'self' one.example.com; script-src 'self' two.example.com", $policy
      ->getHeaderValue());
  }

  /**
   * Test that setting an empty value removes a directive.
   *
   * @covers ::setDirective
   * @covers ::isValidDirectiveName
   * @covers ::getHeaderValue
   */
  public function testSetEmpty() {
    $policy = new Csp();
    $policy
      ->setDirective('default-src', Csp::POLICY_SELF);
    $policy
      ->setDirective('script-src', [
      Csp::POLICY_SELF,
    ]);
    $policy
      ->setDirective('script-src', []);
    $this
      ->assertEquals("default-src 'self'", $policy
      ->getHeaderValue());
    $policy = new Csp();
    $policy
      ->setDirective('default-src', Csp::POLICY_SELF);
    $policy
      ->setDirective('script-src', [
      Csp::POLICY_SELF,
    ]);
    $policy
      ->setDirective('script-src', '');
    $this
      ->assertEquals("default-src 'self'", $policy
      ->getHeaderValue());
  }

  /**
   * Test that appending an empty value doesn't change the directive.
   *
   * @covers ::appendDirective
   * @covers ::isValidDirectiveName
   * @covers ::getHeaderValue
   */
  public function testAppendEmpty() {
    $policy = new Csp();
    $policy
      ->appendDirective('default-src', Csp::POLICY_SELF);
    $this
      ->assertEquals("default-src 'self'", $policy
      ->getHeaderValue());
    $policy
      ->appendDirective('default-src', '');
    $policy
      ->appendDirective('script-src', []);
    $this
      ->assertEquals("default-src 'self'", $policy
      ->getHeaderValue());
  }

  /**
   * Appending to a directive if it or a fallback is enabled.
   *
   * @covers ::fallbackAwareAppendIfEnabled
   */
  public function testFallbackAwareAppendIfEnabled() {

    // If no relevant directives are enabled, they should not change.
    $policy = new Csp();
    $policy
      ->setDirective('style-src', Csp::POLICY_SELF);
    $policy
      ->fallbackAwareAppendIfEnabled('script-src-attr', Csp::POLICY_UNSAFE_INLINE);
    $this
      ->assertFalse($policy
      ->hasDirective('default-src'));
    $this
      ->assertFalse($policy
      ->hasDirective('script-src'));
    $this
      ->assertFalse($policy
      ->hasDirective('script-src-attr'));

    // Script-src-attr should copy value from default-src.  Script-src should
    // not be changed.
    $policy = new Csp();
    $policy
      ->setDirective('default-src', Csp::POLICY_SELF);
    $policy
      ->fallbackAwareAppendIfEnabled('script-src-attr', Csp::POLICY_UNSAFE_INLINE);
    $this
      ->assertEquals([
      Csp::POLICY_SELF,
    ], $policy
      ->getDirective('default-src'));
    $this
      ->assertFalse($policy
      ->hasDirective('script-src'));
    $this
      ->assertEquals([
      Csp::POLICY_SELF,
      Csp::POLICY_UNSAFE_INLINE,
    ], $policy
      ->getDirective('script-src-attr'));

    // Script-src-attr should copy value from script-src.
    $policy = new Csp();
    $policy
      ->setDirective('script-src', Csp::POLICY_SELF);
    $policy
      ->fallbackAwareAppendIfEnabled('script-src-attr', Csp::POLICY_UNSAFE_INLINE);
    $this
      ->assertFalse($policy
      ->hasDirective('default-src'));
    $this
      ->assertEquals([
      Csp::POLICY_SELF,
    ], $policy
      ->getDirective('script-src'));
    $this
      ->assertEquals([
      Csp::POLICY_SELF,
      Csp::POLICY_UNSAFE_INLINE,
    ], $policy
      ->getDirective('script-src-attr'));

    // Script-src-attr should only append to existing value if enabled.
    $policy = new Csp();
    $policy
      ->setDirective('script-src', Csp::POLICY_SELF);
    $policy
      ->setDirective('script-src-attr', []);
    $policy
      ->fallbackAwareAppendIfEnabled('script-src-attr', Csp::POLICY_UNSAFE_INLINE);
    $this
      ->assertFalse($policy
      ->hasDirective('default-src'));
    $this
      ->assertEquals([
      Csp::POLICY_SELF,
    ], $policy
      ->getDirective('script-src'));
    $this
      ->assertEquals([
      Csp::POLICY_UNSAFE_INLINE,
    ], $policy
      ->getDirective('script-src-attr'));
  }

  /**
   * Appending to a directive if its fallback includes 'none'.
   *
   * @covers ::fallbackAwareAppendIfEnabled
   */
  public function testFallbackAwareAppendIfEnabledNone() {

    // New directive should be enabled with only provided value.
    $policy = new Csp();
    $policy
      ->setDirective('default-src', Csp::POLICY_NONE);
    $policy
      ->fallbackAwareAppendIfEnabled('script-src-attr', Csp::POLICY_UNSAFE_INLINE);
    $this
      ->assertEquals([
      Csp::POLICY_NONE,
    ], $policy
      ->getDirective('default-src'));
    $this
      ->assertFalse($policy
      ->hasDirective('script-src'));
    $this
      ->assertEquals([
      Csp::POLICY_UNSAFE_INLINE,
    ], $policy
      ->getDirective('script-src-attr'));

    // Additional values in fallback should be ignored if 'none' is present.
    $policy = new Csp();
    $policy
      ->setDirective('script-src', [
      Csp::POLICY_NONE,
      'https://example.org',
    ]);
    $policy
      ->fallbackAwareAppendIfEnabled('script-src-attr', Csp::POLICY_UNSAFE_INLINE);
    $this
      ->assertEquals([
      Csp::POLICY_UNSAFE_INLINE,
    ], $policy
      ->getDirective('script-src-attr'));
  }

  /**
   * Test that removed directives are not output in the header.
   *
   * @covers ::removeDirective
   * @covers ::isValidDirectiveName
   * @covers ::getHeaderValue
   */
  public function testRemove() {
    $policy = new Csp();
    $policy
      ->setDirective('default-src', [
      Csp::POLICY_SELF,
    ]);
    $policy
      ->setDirective('script-src', 'example.com');
    $policy
      ->removeDirective('script-src');
    $this
      ->assertEquals("default-src 'self'", $policy
      ->getHeaderValue());
  }

  /**
   * Test that removing an invalid directive name causes an exception.
   *
   * @covers ::removeDirective
   * @covers ::isValidDirectiveName
   * @covers ::validateDirectiveName
   */
  public function testRemoveInvalid() {
    $this
      ->expectException(\InvalidArgumentException::class);
    $policy = new Csp();
    $policy
      ->removeDirective('foo');
  }

  /**
   * Test that invalid directive values cause an exception.
   *
   * @covers ::appendDirective
   */
  public function testInvalidValue() {
    $this
      ->expectException(\InvalidArgumentException::class);
    $policy = new Csp();
    $policy
      ->appendDirective('default-src', 12);
  }

  /**
   * @covers ::__toString
   */
  public function testToString() {
    $policy = new Csp();
    $policy
      ->setDirective('default-src', Csp::POLICY_SELF);
    $policy
      ->setDirective('script-src', [
      Csp::POLICY_SELF,
      'example.com',
    ]);
    $this
      ->assertEquals("Content-Security-Policy: default-src 'self'; script-src 'self' example.com", $policy
      ->__toString());
  }

}

Members

Namesort descending Modifiers Type Description Overrides
CspTest::testAppendEmpty public function Test that appending an empty value doesn't change the directive.
CspTest::testAppendInvalidPolicy public function Test that invalid directive names cause an exception.
CspTest::testAppendMultiple public function Test that appending to a directive extends the existing value.
CspTest::testAppendSingle public function Test appending a single value to an uninitialized directive.
CspTest::testFallbackAwareAppendIfEnabled public function Appending to a directive if it or a fallback is enabled.
CspTest::testFallbackAwareAppendIfEnabledNone public function Appending to a directive if its fallback includes 'none'.
CspTest::testHash public function Test calculating hash values.
CspTest::testInvalidHashAlgo public function Test specifying an invalid hash algorithm.
CspTest::testInvalidValue public function Test that invalid directive values cause an exception.
CspTest::testRemove public function Test that removed directives are not output in the header.
CspTest::testRemoveInvalid public function Test that removing an invalid directive name causes an exception.
CspTest::testReportOnly public function Test that changing the policy's report-only flag updates the header name.
CspTest::testSetEmpty public function Test that setting an empty value removes a directive.
CspTest::testSetInvalidPolicy public function Test that invalid directive names cause an exception.
CspTest::testSetMultiple public function Test that a directive is overridden when set with a new value.
CspTest::testSetSingle public function Test setting a single value to a directive.
CspTest::testToString public function @covers ::__toString
PhpunitCompatibilityTrait::getMock Deprecated public function Returns a mock object for the specified class using the available method.
PhpunitCompatibilityTrait::setExpectedException Deprecated public function Compatibility layer for PHPUnit 6 to support PHPUnit 4 code.
UnitTestCase::$randomGenerator protected property The random generator.
UnitTestCase::$root protected property The app root. 1
UnitTestCase::assertArrayEquals protected function Asserts if two arrays are equal by sorting them first.
UnitTestCase::getBlockMockWithMachineName Deprecated protected function Mocks a block with a block plugin. 1
UnitTestCase::getClassResolverStub protected function Returns a stub class resolver.
UnitTestCase::getConfigFactoryStub public function Returns a stub config factory that behaves according to the passed array.
UnitTestCase::getConfigStorageStub public function Returns a stub config storage that returns the supplied configuration.
UnitTestCase::getContainerWithCacheTagsInvalidator protected function Sets up a container with a cache tags invalidator.
UnitTestCase::getRandomGenerator protected function Gets the random generator for the utility methods.
UnitTestCase::getStringTranslationStub public function Returns a stub translation manager that just returns the passed string.
UnitTestCase::randomMachineName public function Generates a unique random string containing letters and numbers.
UnitTestCase::setUp protected function 340