Skip to content
Snippets Groups Projects
Commit b5a2be09 authored by Jess's avatar Jess Committed by catch
Browse files

SA-CORE-2021-006 by azinck, seanB, effulgentsia, marcoscano, larowlan,...

SA-CORE-2021-006 by azinck, seanB, effulgentsia, marcoscano, larowlan, phenaproxima, xjm, mcdruid, drumm, briantschu
parent 500af4bd
No related branches found
No related tags found
No related merge requests found
......@@ -472,6 +472,9 @@
uuid: this.data.attributes['data-entity-uuid'],
},
dataType: 'html',
headers: {
'X-Drupal-MediaPreview-CSRF-Token': editor.config.drupalMedia_previewCsrfToken,
},
success: (previewHtml, textStatus, jqXhr) => {
this.element.setHtml(previewHtml);
this.setData(
......
......@@ -311,6 +311,9 @@
uuid: this.data.attributes['data-entity-uuid']
},
dataType: 'html',
headers: {
'X-Drupal-MediaPreview-CSRF-Token': editor.config.drupalMedia_previewCsrfToken
},
success: function success(previewHtml, textStatus, jqXhr) {
_this3.element.setHtml(previewHtml);
......
......@@ -7,10 +7,12 @@
use Drupal\Core\Entity\ContentEntityStorageInterface;
use Drupal\Core\Entity\EntityRepositoryInterface;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\filter\FilterFormatInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
......@@ -93,6 +95,8 @@ public static function create(ContainerInterface $container) {
* @see \Drupal\editor\EditorController::getUntransformedText
*/
public function preview(Request $request, FilterFormatInterface $filter_format) {
self::checkCsrf($request, \Drupal::currentUser());
$text = $request->query->get('text');
$uuid = $request->query->get('uuid');
if ($text == '' || $uuid == '') {
......@@ -140,4 +144,30 @@ public static function formatUsesMediaEmbedFilter(FilterFormatInterface $filter_
->addCacheableDependency($filter_format);
}
/**
* Throws an AccessDeniedHttpException if the request fails CSRF validation.
*
* This is used instead of \Drupal\Core\Access\CsrfAccessCheck, in order to
* allow access for anonymous users.
*
* @todo Refactor this to an access checker.
*/
private static function checkCsrf(Request $request, AccountInterface $account) {
$header = 'X-Drupal-MediaPreview-CSRF-Token';
if (!$request->headers->has($header)) {
throw new AccessDeniedHttpException();
}
if ($account->isAnonymous()) {
// For anonymous users, just the presence of the custom header is
// sufficient protection.
return;
}
// For authenticated users, validate the token value.
$token = $request->headers->get($header);
if (!\Drupal::csrfToken()->validate($token, $header)) {
throw new AccessDeniedHttpException();
}
}
}
......@@ -98,7 +98,9 @@ public function getFile() {
* {@inheritdoc}
*/
public function getConfig(Editor $editor) {
return [];
return [
'drupalMedia_previewCsrfToken' => \Drupal::csrfToken()->get('X-Drupal-MediaPreview-CSRF-Token'),
];
}
/**
......
......@@ -4,7 +4,6 @@
use Drupal\Component\Utility\Html;
use Drupal\Core\Entity\Entity\EntityViewDisplay;
use Drupal\Core\Url;
use Drupal\editor\Entity\Editor;
use Drupal\field\Entity\FieldConfig;
use Drupal\file\Entity\File;
......@@ -1037,14 +1036,13 @@ public function linkabilityProvider() {
* @dataProvider previewAccessProvider
*/
public function testEmbedPreviewAccess($media_embed_enabled, $can_use_format) {
$format = FilterFormat::create([
'format' => $this->randomMachineName(),
'name' => $this->randomString(),
'filters' => [
'filter_align' => ['status' => TRUE],
'filter_caption' => ['status' => TRUE],
'media_embed' => ['status' => $media_embed_enabled],
],
// Reconfigure the host entity's text format to suit our needs.
/** @var \Drupal\filter\FilterFormatInterface $format */
$format = FilterFormat::load($this->host->body->format);
$format->set('filters', [
'filter_align' => ['status' => TRUE],
'filter_caption' => ['status' => TRUE],
'media_embed' => ['status' => $media_embed_enabled],
]);
$format->save();
......@@ -1055,24 +1053,28 @@ public function testEmbedPreviewAccess($media_embed_enabled, $can_use_format) {
$permissions[] = $format->getPermissionName();
}
$this->drupalLogin($this->drupalCreateUser($permissions));
$text = '<drupal-media data-caption="baz" data-entity-type="media" data-entity-uuid="' . $this->media->uuid() . '"></drupal-media>';
$route_parameters = ['filter_format' => $format->id()];
$options = [
'query' => [
'text' => $text,
'uuid' => $this->media->uuid(),
],
];
$this->drupalGet(Url::fromRoute('media.filter.preview', $route_parameters, $options));
$this->drupalGet($this->host->toUrl('edit-form'));
$assert_session = $this->assertSession();
if ($media_embed_enabled && $can_use_format) {
$assert_session->elementExists('css', 'img');
$assert_session->responseContains('baz');
if ($can_use_format) {
$this->waitForEditor();
$this->assignNameToCkeditorIframe();
$this->getSession()->switchToIFrame('ckeditor');
if ($media_embed_enabled) {
// The preview rendering, which in this test will use Classy's
// media.html.twig template, will fail without the CSRF token/header.
// @see ::testEmbeddedMediaPreviewWithCsrfToken()
$this->assertNotEmpty($assert_session->waitForElementVisible('css', 'article.media'));
}
else {
// If the filter isn't enabled, there won't be an error, but the
// preview shouldn't be rendered.
$assert_session->assertWaitOnAjaxRequest();
$assert_session->elementNotExists('css', 'article.media');
}
}
else {
$assert_session->responseContains('You are not authorized to access this page.');
$assert_session->pageTextContains('This field has been disabled because you do not have sufficient permissions to edit it.');
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment