Core and composer updates
This commit is contained in:
parent
a82634bb98
commit
62cac30480
1118 changed files with 21770 additions and 6306 deletions
|
@ -40,8 +40,20 @@ class FileAccessControlHandler extends EntityAccessControlHandler {
|
|||
}
|
||||
elseif ($entity->getOwnerId() == $account->id()) {
|
||||
// This case handles new nodes, or detached files. The user who uploaded
|
||||
// the file can always access if it's not yet used.
|
||||
return AccessResult::allowed();
|
||||
// the file can access it even if it's not yet used.
|
||||
if ($account->isAnonymous()) {
|
||||
// For anonymous users, only the browser session that uploaded the
|
||||
// file is positively allowed access to it. See file_save_upload().
|
||||
// @todo Implement \Drupal\Core\Entity\EntityHandlerInterface so that
|
||||
// services can be more properly injected.
|
||||
$allowed_fids = \Drupal::service('session')->get('anonymous_allowed_file_ids', []);
|
||||
if (!empty($allowed_fids[$entity->id()])) {
|
||||
return AccessResult::allowed();
|
||||
}
|
||||
}
|
||||
else {
|
||||
return AccessResult::allowed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,9 +91,24 @@ class FileAccessControlHandler extends EntityAccessControlHandler {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
protected function checkFieldAccess($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, FieldItemListInterface $items = NULL) {
|
||||
// No user can edit the status of a file. Prevents saving a new file as
|
||||
// persistent before even validating it.
|
||||
if ($field_definition->getName() === 'status' && $operation === 'edit') {
|
||||
// Deny access to fields that should only be set on file creation, and
|
||||
// "status" which should only be changed based on a file's usage.
|
||||
$create_only_fields = [
|
||||
'uri',
|
||||
'filemime',
|
||||
'filesize',
|
||||
];
|
||||
// The operation is 'edit' when the entity is being created or updated.
|
||||
// Determine if the entity is being updated by checking if it is new.
|
||||
$field_name = $field_definition->getName();
|
||||
if ($operation === 'edit' && $items && ($entity = $items->getEntity()) && !$entity->isNew() && in_array($field_name, $create_only_fields, TRUE)) {
|
||||
return AccessResult::forbidden();
|
||||
}
|
||||
// Regardless of whether the entity exists access should be denied to the
|
||||
// status field as this is managed via other APIs, for example:
|
||||
// - \Drupal\file\FileUsage\FileUsageBase::add()
|
||||
// - \Drupal\file\Plugin\EntityReferenceSelection\FileSelection::createNewEntity()
|
||||
if ($operation === 'edit' && $field_name === 'status') {
|
||||
return AccessResult::forbidden();
|
||||
}
|
||||
return parent::checkFieldAccess($operation, $field_definition, $account, $items);
|
||||
|
|
|
@ -25,8 +25,8 @@ interface FileUsageInterface {
|
|||
* The name of the module using the file.
|
||||
* @param string $type
|
||||
* The type of the object that contains the referenced file.
|
||||
* @param int $id
|
||||
* The unique, numeric ID of the object containing the referenced file.
|
||||
* @param string $id
|
||||
* The unique ID of the object containing the referenced file.
|
||||
* @param int $count
|
||||
* (optional) The number of references to add to the object. Defaults to 1.
|
||||
*/
|
||||
|
@ -43,10 +43,10 @@ interface FileUsageInterface {
|
|||
* (optional) The type of the object that contains the referenced file. May
|
||||
* be omitted if all module references to a file are being deleted. Defaults
|
||||
* to NULL.
|
||||
* @param int $id
|
||||
* (optional) The unique, numeric ID of the object containing the referenced
|
||||
* file. May be omitted if all module references to a file are being
|
||||
* deleted. Defaults to NULL.
|
||||
* @param string $id
|
||||
* (optional) The unique ID of the object containing the referenced file.
|
||||
* May be omitted if all module references to a file are being deleted.
|
||||
* Defaults to NULL.
|
||||
* @param int $count
|
||||
* (optional) The number of references to delete from the object. Defaults
|
||||
* to 1. Zero may be specified to delete all references to the file within a
|
||||
|
|
|
@ -6,6 +6,7 @@ use Drupal\Core\Entity\Plugin\Validation\Constraint\ReferenceAccessConstraint;
|
|||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\file\Entity\File;
|
||||
use Drupal\node\Entity\NodeType;
|
||||
use Drupal\user\RoleInterface;
|
||||
|
||||
/**
|
||||
* Uploads a test to a private node and checks access.
|
||||
|
@ -110,6 +111,118 @@ class FilePrivateTest extends FileFieldTestBase {
|
|||
$this->drupalLogin($account);
|
||||
$this->drupalGet($file_url);
|
||||
$this->assertResponse(403, 'Confirmed that access is denied for another user to the temporary file.');
|
||||
|
||||
// As an anonymous user, create a temporary file with no references and
|
||||
// confirm that only the session that uploaded it may view it.
|
||||
$this->drupalLogout();
|
||||
user_role_change_permissions(
|
||||
RoleInterface::ANONYMOUS_ID,
|
||||
[
|
||||
"create $type_name content" => TRUE,
|
||||
'access content' => TRUE,
|
||||
]
|
||||
);
|
||||
$test_file = $this->getTestFile('text');
|
||||
$this->drupalGet('node/add/' . $type_name);
|
||||
$edit = ['files[' . $field_name . '_0]' => drupal_realpath($test_file->getFileUri())];
|
||||
$this->drupalPostForm(NULL, $edit, t('Upload'));
|
||||
/** @var \Drupal\file\FileStorageInterface $file_storage */
|
||||
$file_storage = $this->container->get('entity.manager')->getStorage('file');
|
||||
$files = $file_storage->loadByProperties(['uid' => 0]);
|
||||
$this->assertEqual(1, count($files), 'Loaded one anonymous file.');
|
||||
$file = end($files);
|
||||
$this->assertTrue($file->isTemporary(), 'File is temporary.');
|
||||
$usage = $this->container->get('file.usage')->listUsage($file);
|
||||
$this->assertFalse($usage, 'No file usage found.');
|
||||
$file_url = file_create_url($file->getFileUri());
|
||||
$this->drupalGet($file_url);
|
||||
$this->assertResponse(200, 'Confirmed that the anonymous uploader has access to the temporary file.');
|
||||
// Close the prior connection and remove the session cookie.
|
||||
$this->curlClose();
|
||||
$this->curlCookies = [];
|
||||
$this->cookies = [];
|
||||
$this->drupalGet($file_url);
|
||||
$this->assertResponse(403, 'Confirmed that another anonymous user cannot access the temporary file.');
|
||||
|
||||
// As an anonymous user, create a permanent file, then remove all
|
||||
// references to the file (so that it becomes temporary again) and confirm
|
||||
// that only the session that uploaded it may view it.
|
||||
$test_file = $this->getTestFile('text');
|
||||
$this->drupalGet('node/add/' . $type_name);
|
||||
$edit = [];
|
||||
$edit['title[0][value]'] = $this->randomMachineName();
|
||||
$edit['files[' . $field_name . '_0]'] = drupal_realpath($test_file->getFileUri());
|
||||
$this->drupalPostForm(NULL, $edit, t('Save'));
|
||||
$new_node = $this->drupalGetNodeByTitle($edit['title[0][value]']);
|
||||
$file_id = $new_node->{$field_name}->target_id;
|
||||
$file = File::load($file_id);
|
||||
$this->assertTrue($file->isPermanent(), 'File is permanent.');
|
||||
// Remove the reference to this file.
|
||||
$new_node->{$field_name} = [];
|
||||
$new_node->save();
|
||||
$file = File::load($file_id);
|
||||
$this->assertTrue($file->isTemporary(), 'File is temporary.');
|
||||
$usage = $this->container->get('file.usage')->listUsage($file);
|
||||
$this->assertFalse($usage, 'No file usage found.');
|
||||
$file_url = file_create_url($file->getFileUri());
|
||||
$this->drupalGet($file_url);
|
||||
$this->assertResponse(200, 'Confirmed that the anonymous uploader has access to the file whose references were removed.');
|
||||
// Close the prior connection and remove the session cookie.
|
||||
$this->curlClose();
|
||||
$this->curlCookies = [];
|
||||
$this->cookies = [];
|
||||
$this->drupalGet($file_url);
|
||||
$this->assertResponse(403, 'Confirmed that another anonymous user cannot access the file whose references were removed.');
|
||||
|
||||
// As an anonymous user, create a permanent file that is referenced by a
|
||||
// published node and confirm that all anonymous users may view it.
|
||||
$test_file = $this->getTestFile('text');
|
||||
$this->drupalGet('node/add/' . $type_name);
|
||||
$edit = [];
|
||||
$edit['title[0][value]'] = $this->randomMachineName();
|
||||
$edit['files[' . $field_name . '_0]'] = drupal_realpath($test_file->getFileUri());
|
||||
$this->drupalPostForm(NULL, $edit, t('Save'));
|
||||
$new_node = $this->drupalGetNodeByTitle($edit['title[0][value]']);
|
||||
$file = File::load($new_node->{$field_name}->target_id);
|
||||
$this->assertTrue($file->isPermanent(), 'File is permanent.');
|
||||
$usage = $this->container->get('file.usage')->listUsage($file);
|
||||
$this->assertTrue($usage, 'File usage found.');
|
||||
$file_url = file_create_url($file->getFileUri());
|
||||
$this->drupalGet($file_url);
|
||||
$this->assertResponse(200, 'Confirmed that the anonymous uploader has access to the permanent file that is referenced by a published node.');
|
||||
// Close the prior connection and remove the session cookie.
|
||||
$this->curlClose();
|
||||
$this->curlCookies = [];
|
||||
$this->cookies = [];
|
||||
$this->drupalGet($file_url);
|
||||
$this->assertResponse(200, 'Confirmed that another anonymous user also has access to the permanent file that is referenced by a published node.');
|
||||
|
||||
// As an anonymous user, create a permanent file that is referenced by an
|
||||
// unpublished node and confirm that no anonymous users may view it (even
|
||||
// the session that uploaded the file) because they cannot view the
|
||||
// unpublished node.
|
||||
$test_file = $this->getTestFile('text');
|
||||
$this->drupalGet('node/add/' . $type_name);
|
||||
$edit = [];
|
||||
$edit['title[0][value]'] = $this->randomMachineName();
|
||||
$edit['files[' . $field_name . '_0]'] = drupal_realpath($test_file->getFileUri());
|
||||
$this->drupalPostForm(NULL, $edit, t('Save'));
|
||||
$new_node = $this->drupalGetNodeByTitle($edit['title[0][value]']);
|
||||
$new_node->setPublished(FALSE);
|
||||
$new_node->save();
|
||||
$file = File::load($new_node->{$field_name}->target_id);
|
||||
$this->assertTrue($file->isPermanent(), 'File is permanent.');
|
||||
$usage = $this->container->get('file.usage')->listUsage($file);
|
||||
$this->assertTrue($usage, 'File usage found.');
|
||||
$file_url = file_create_url($file->getFileUri());
|
||||
$this->drupalGet($file_url);
|
||||
$this->assertResponse(403, 'Confirmed that the anonymous uploader cannot access the permanent file when it is referenced by an unpublished node.');
|
||||
// Close the prior connection and remove the session cookie.
|
||||
$this->curlClose();
|
||||
$this->curlCookies = [];
|
||||
$this->cookies = [];
|
||||
$this->drupalGet($file_url);
|
||||
$this->assertResponse(403, 'Confirmed that another anonymous user cannot access the permanent file when it is referenced by an unpublished node.');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Reference in a new issue