diff --git a/core/modules/rest/src/Tests/RESTFileValidationTest.php b/core/modules/rest/src/Tests/RESTFileValidationTest.php
new file mode 100644
index 0000000..d5507db
--- /dev/null
+++ b/core/modules/rest/src/Tests/RESTFileValidationTest.php
@@ -0,0 +1,293 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\rest\Tests\RESTFileValidationTest.
+ */
+
+namespace Drupal\rest\Tests;
+
+use Drupal\Component\Serialization\Json;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\field\Entity\FieldConfig;
+use Drupal\field\Entity\FieldStorageConfig;
+use Drupal\node\Entity\Node;
+use Drupal\user\RoleInterface;
+
+/**
+ * Tests the validation of files attached via REST node creation.
+ *
+ * @group rest
+ */
+class RESTFileValidationTest extends RESTTestBase {
+
+  /**
+   * Modules to install.
+   *
+   * @var array
+   */
+  public static $modules = array('hal', 'rest', 'entity_test', 'node', 'file');
+
+  /**
+   * The 'serializer' service.
+   *
+   * @var \Symfony\Component\Serializer\Serializer
+   */
+  protected $serializer;
+
+  protected function setUp() {
+    parent::setUp();
+    // Get the 'serializer' service.
+    $this->serializer = $this->container->get('serializer');
+  }
+
+  /**
+   * Tests basic file field validations when attaching to nodes.
+   */
+  public function testCreateNodeWithFile() {
+    // Create a file which should be secret.
+
+    // Create a test entity type that contains the secret file.
+    $this->drupalCreateContentType(['type' => 'page']);
+
+    // Create a test content type that anonymous can post.
+    $this->drupalCreateContentType(['type' => 'article']);
+    $this->createFileField('field_public_file', 'node', 'article', ['uri_scheme' => 'public'], ['file_extensions' => 'txt']);
+    // Enables the REST service for 'node' entity type.
+    $this->enableService('entity:node', 'POST');
+    $permissions = ['create article content', 'restful post entity:node'];
+    user_role_grant_permissions(RoleInterface::ANONYMOUS_ID, $permissions);
+
+    // Create a private file and attach it to a node.
+    $this->createFileField('field_private_file', 'node', 'resttest', ['uri_scheme' => 'private'], ['file_extensions' => 'txt']);
+    $permissions = ['create resttest content'];
+    $account = $this->drupalCreateUser($permissions);
+    $this->drupalLogin($account);
+
+    $private_files = $this->drupalGetTestFiles('text', NULL, FALSE);
+    $edit = [
+      'title[0][value]' => 'Test private title',
+      'files[field_private_file_0]' => drupal_realpath($private_files[0]->uri),
+    ];
+    $this->drupalPostForm('node/add/resttest', $edit, t('Save'));
+    preg_match('@node/(\d+)@', $this->getUrl(), $matches);
+    $nid = $matches[1];
+    $node = Node::load($nid);
+    $this->drupalLogout();
+
+    $this->drupalGet(file_create_url($private_files[0]->uri));
+    $this->assertResponse(403);
+
+    // Verify that anonymous user file uploads fail when invalid.
+    // Populate some entity properties before creating the entity.
+    $entity = Node::create([
+      'title' => $this->randomString(),
+      'type' => 'article'
+    ]);
+
+    // Verify that user cannot create content when trying to write to fields
+    // where it is not possible.
+
+    $serialized = $this->serializer->serialize($entity, $this->defaultFormat, ['account' => $account]);
+    $this->httpRequest('entity/node', 'POST', $serialized, $this->defaultMimeType);
+    $this->assertResponse(403);
+    // Remove fields where non-administrative users cannot write.
+    $entity = $this->removeNodeFieldsForNonAdminUsers($entity);
+    $serialized = $this->serializer->serialize($entity, $this->defaultFormat, ['account' => $account]);
+    $this->httpRequest('entity/node', 'POST', $serialized, $this->defaultMimeType);
+    $this->assertResponse(201);
+
+    // The user should not be able to attach the private file.
+    $entity = $entity->createDuplicate();
+    $entity->field_public_file->target_id = $node->field_private_file->target_id;
+    $serialized = $this->serializer->serialize($entity, $this->defaultFormat, ['account' => $account]);
+    $this->httpRequest('entity/node', 'POST', $serialized, $this->defaultMimeType);
+    $this->assertResponse(403);
+
+    $this->drupalGet(file_create_url($private_files[0]->uri));
+    $this->assertResponse(403);
+  }
+
+  /**
+   * Creates a new file field.
+   *
+   * @param string $name
+   *   The name of the new field (all lowercase), exclude the "field_" prefix.
+   * @param string $entity_type
+   *   The entity type.
+   * @param string $bundle
+   *   The bundle that this field will be added to.
+   * @param array $storage_settings
+   *   A list of field storage settings that will be added to the defaults.
+   * @param array $field_settings
+   *   A list of instance settings that will be added to the instance defaults.
+   * @param array $widget_settings
+   *   A list of widget settings that will be added to the widget defaults.
+   *
+   * @return \Drupal\Core\Entity\EntityInterface
+   */
+  function createFileField($name, $entity_type, $bundle, $storage_settings = [], $field_settings = [], $widget_settings = []) {
+    $field_storage = FieldStorageConfig::create([
+      'entity_type' => $entity_type,
+      'field_name' => $name,
+      'type' => 'file',
+      'settings' => $storage_settings,
+      'cardinality' => !empty($storage_settings['cardinality']) ? $storage_settings['cardinality'] : 1,
+    ]);
+    $field_storage->save();
+
+    $this->attachFileField($name, $entity_type, $bundle, $field_settings, $widget_settings);
+    return $field_storage;
+  }
+
+  /**
+   * Attaches a file field to an entity.
+   *
+   * @param string $name
+   *   The name of the new field (all lowercase), exclude the "field_" prefix.
+   * @param string $entity_type
+   *   The entity type this field will be added to.
+   * @param string $bundle
+   *   The bundle this field will be added to.
+   * @param array $field_settings
+   *   A list of field settings that will be added to the defaults.
+   * @param array $widget_settings
+   *   A list of widget settings that will be added to the widget defaults.
+   */
+  function attachFileField($name, $entity_type, $bundle, $field_settings = [], $widget_settings = []) {
+    FieldConfig::create([
+      'field_name' => $name,
+      'label' => $name,
+      'entity_type' => $entity_type,
+      'bundle' => $bundle,
+      'required' => !empty($field_settings['required']),
+      'settings' => $field_settings,
+    ])->save();
+
+    entity_get_form_display($entity_type, $bundle, 'default')
+      ->setComponent($name, [
+        'type' => 'file_generic',
+        'settings' => $widget_settings,
+      ])
+      ->save();
+    // Assign display settings.
+    entity_get_display($entity_type, $bundle, 'default')
+      ->setComponent($name, [
+        'label' => 'hidden',
+        'type' => 'file_default',
+      ])
+      ->save();
+  }
+
+  /**
+   * Creates the entity over the REST API.
+   *
+   * @param string $entity_type
+   *   The type of the entity that should be created.
+   * @param string $serialized
+   *   The body for the POST request.
+   */
+  public function assertCreateEntityOverRestApi($entity_type, $serialized = NULL) {
+    // Note: this will fail with PHP 5.6 when always_populate_raw_post_data is
+    // set to something other than -1. See https://www.drupal.org/node/2456025.
+    $this->httpRequest('entity/' . $entity_type, 'POST', $serialized, $this->defaultMimeType);
+    $this->assertResponse(201);
+  }
+
+  /**
+   * Gets the new entity ID from the location header and tries to read it from
+   * the database.
+   *
+   * @param string $entity_type
+   *   Entity type we need to load the entity from DB.
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity we want to check that was inserted correctly.
+   * @param array $entity_values
+   *   The values of $entity.
+   */
+  public function assertReadEntityIdFromHeaderAndDb($entity_type, EntityInterface $entity, array $entity_values = array()) {
+    // Get the location from the HTTP response header.
+    $location_url = $this->drupalGetHeader('location');
+    $url_parts = explode('/', $location_url);
+    $id = end($url_parts);
+
+    // Get the entity using the ID found.
+    $loaded_entity = \Drupal::entityManager()->getStorage($entity_type)->load($id);
+    $this->assertNotIdentical(FALSE, $loaded_entity, 'The new ' . $entity_type . ' was found in the database.');
+    $this->assertEqual($entity->uuid(), $loaded_entity->uuid(), 'UUID of created entity is correct.');
+
+    // Verify that the field values sent and received from DB are the same.
+    foreach ($entity_values as $property => $value) {
+      $actual_value = $loaded_entity->get($property)->value;
+      $send_value = $entity->get($property)->value;
+      $this->assertEqual($send_value, $actual_value, 'Created property ' . $property . ' expected: ' . $send_value . ', actual: ' . $actual_value);
+    }
+
+    // Delete the entity loaded from DB.
+    $loaded_entity->delete();
+  }
+
+  /**
+   * Try to send invalid data that cannot be correctly deserialized.
+   *
+   * @param string $entity_type
+   *   The type of the entity that should be created.
+   */
+  public function assertCreateEntityInvalidData($entity_type) {
+    $this->httpRequest('entity/' . $entity_type, 'POST', 'kaboom!', $this->defaultMimeType);
+    $this->assertResponse(400);
+  }
+
+  /**
+   * Try to send no data at all, which does not make sense on POST requests.
+   *
+   * @param string $entity_type
+   *   The type of the entity that should be created.
+   */
+  public function assertCreateEntityNoData($entity_type) {
+    $this->httpRequest('entity/' . $entity_type, 'POST', NULL, $this->defaultMimeType);
+    $this->assertResponse(400);
+  }
+
+  /**
+   * Send an invalid UUID to trigger the entity validation.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity we want to check that was inserted correctly.
+   * @param string $entity_type
+   *   The type of the entity that should be created.
+   * @param array $context
+   *   Options normalizers/encoders have access to.
+   */
+  public function assertCreateEntityInvalidSerialized(EntityInterface $entity, $entity_type, array $context = array()) {
+    // Add a UUID that is too long.
+    $entity->set('uuid', $this->randomMachineName(129));
+    $invalid_serialized = $this->serializer->serialize($entity, $this->defaultFormat, $context);
+
+    $response = $this->httpRequest('entity/' . $entity_type, 'POST', $invalid_serialized, $this->defaultMimeType);
+
+    // Unprocessable Entity as response.
+    $this->assertResponse(422);
+
+    // Verify that the text of the response is correct.
+    $error = Json::decode($response);
+    $this->assertEqual($error['error'], "Unprocessable Entity: validation failed.\nuuid.0.value: <em class=\"placeholder\">UUID</em>: may not be longer than 128 characters.\n");
+  }
+
+  /**
+   * Try to create an entity without proper permissions.
+   *
+   * @param string $entity_type
+   *   The type of the entity that should be created.
+   * @param string $serialized
+   *   The body for the POST request.
+   */
+  public function assertCreateEntityWithoutProperPermissions($entity_type, $serialized = NULL) {
+    $this->drupalLogout();
+    $this->httpRequest('entity/' . $entity_type, 'POST', $serialized, $this->defaultMimeType);
+    // Forbidden Error as response.
+    $this->assertResponse(403);
+    $this->assertFalse(\Drupal::entityManager()->getStorage($entity_type)->loadMultiple(), 'No entity has been created in the database.');
+  }
+
+}
diff --git a/core/modules/simpletest/simpletest.module b/core/modules/simpletest/simpletest.module
index 69742cc..e970824 100644
--- a/core/modules/simpletest/simpletest.module
+++ b/core/modules/simpletest/simpletest.module
@@ -526,11 +526,13 @@ function simpletest_classloader_register() {
  *     the range of 0 to 31.
  *   - binary-text: The generated file contains random sequence of '0' and '1'
  *     values.
+ * @param bool $public
+ *   (optional) Whether the test files should be public or private.
  *
  * @return string
  *   The name of the file, including the path.
  */
-function simpletest_generate_file($filename, $width, $lines, $type = 'binary-text') {
+function simpletest_generate_file($filename, $width, $lines, $type = 'binary-text', $public = TRUE) {
   $text = '';
     for ($i = 0; $i < $lines; $i++) {
       // Generate $width - 1 characters to leave space for the "\n" character.
@@ -552,7 +554,7 @@ function simpletest_generate_file($filename, $width, $lines, $type = 'binary-tex
     }
 
   // Create filename.
-  file_put_contents('public://' . $filename . '.txt', $text);
+  file_put_contents(($public ? 'public://' : 'private://') . $filename . '.txt', $text);
   return $filename;
 }
 
diff --git a/core/modules/simpletest/src/WebTestBase.php b/core/modules/simpletest/src/WebTestBase.php
index 5b62c50..4b3c547 100644
--- a/core/modules/simpletest/src/WebTestBase.php
+++ b/core/modules/simpletest/src/WebTestBase.php
@@ -27,6 +27,7 @@
 use Drupal\Core\Session\AnonymousUserSession;
 use Drupal\Core\Session\UserSession;
 use Drupal\Core\Site\Settings;
+use Drupal\Core\StreamWrapper\PrivateStream;
 use Drupal\Core\StreamWrapper\PublicStream;
 use Drupal\Core\Url;
 use Drupal\node\Entity\NodeType;
@@ -510,27 +511,27 @@ protected function findBlockInstance(Block $block) {
    * @return
    *   List of files in public:// that match the filter(s).
    */
-  protected function drupalGetTestFiles($type, $size = NULL) {
+  protected function drupalGetTestFiles($type, $size = NULL, $public = TRUE) {
     if (empty($this->generatedTestFiles)) {
       // Generate binary test files.
       $lines = array(64, 1024);
       $count = 0;
       foreach ($lines as $line) {
-        simpletest_generate_file('binary-' . $count++, 64, $line, 'binary');
+        simpletest_generate_file('binary-' . $count++, 64, $line, 'binary', $public);
       }
 
       // Generate ASCII text test files.
       $lines = array(16, 256, 1024, 2048, 20480);
       $count = 0;
       foreach ($lines as $line) {
-        simpletest_generate_file('text-' . $count++, 64, $line, 'text');
+        simpletest_generate_file('text-' . $count++, 64, $line, 'text', $public);
       }
 
       // Copy other test files from simpletest.
       $original = drupal_get_path('module', 'simpletest') . '/files';
       $files = file_scan_directory($original, '/(html|image|javascript|php|sql)-.*/');
       foreach ($files as $file) {
-        file_unmanaged_copy($file->uri, PublicStream::basePath());
+        file_unmanaged_copy($file->uri, $public ? PublicStream::basePath() : PrivateStream::basePath());
       }
 
       $this->generatedTestFiles = TRUE;
@@ -539,7 +540,7 @@ protected function drupalGetTestFiles($type, $size = NULL) {
     $files = array();
     // Make sure type is valid.
     if (in_array($type, array('binary', 'html', 'image', 'javascript', 'php', 'sql', 'text'))) {
-      $files = file_scan_directory('public://', '/' . $type . '\-.*/');
+      $files = file_scan_directory($public ? 'public://' : 'private://', '/' . $type . '\-.*/');
 
       // If size is set then remove any files that are not of that size.
       if ($size !== NULL) {
