 core/modules/edit/edit.routing.yml                 |    5 +-
 .../edit/Tests/EditEntityAccessCheckTest.php       |   68 +++++++++++++++++++
 .../edit/Tests/EditEntityFieldAccessCheckTest.php  |   71 ++++++++++++++++++++
 .../edit/lib/Drupal/edit/Tests/EditLoadingTest.php |   28 ++++++++
 4 files changed, 171 insertions(+), 1 deletion(-)

diff --git a/core/modules/edit/edit.routing.yml b/core/modules/edit/edit.routing.yml
index b709d0a..adef7f1 100644
--- a/core/modules/edit/edit.routing.yml
+++ b/core/modules/edit/edit.routing.yml
@@ -16,15 +16,18 @@ edit_field_form:
   pattern: '/edit/form/{entity_type}/{entity}/{field_name}/{langcode}/{view_mode_id}'
   defaults:
     _controller: '\Drupal\edit\EditController::fieldForm'
+  options:
+    _access_mode: 'ALL'
   requirements:
     _permission: 'access in-place editing'
     _access_edit_entity_field: 'TRUE'
 
-
 edit_entity_save:
   pattern: '/edit/entity/{entity_type}/{entity}'
   defaults:
     _controller: '\Drupal\edit\EditController::entitySave'
+  options:
+    _access_mode: 'ALL'
   requirements:
     _permission: 'access in-place editing'
     _access_edit_entity: 'TRUE'
diff --git a/core/modules/edit/lib/Drupal/edit/Tests/EditEntityAccessCheckTest.php b/core/modules/edit/lib/Drupal/edit/Tests/EditEntityAccessCheckTest.php
new file mode 100644
index 0000000..59700ee
--- /dev/null
+++ b/core/modules/edit/lib/Drupal/edit/Tests/EditEntityAccessCheckTest.php
@@ -0,0 +1,68 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\edit\Tests\EditEntityAccessCheckTest.
+ */
+
+namespace Drupal\edit\Tests;
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Routing\Route;
+use Drupal\edit\Access\EditEntityAccessCheck;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * Tests the edit entity access controller.
+ *
+ * @group Edit
+ */
+class EditEntityAccessCheckTest extends UnitTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Edit entity access check test',
+      'description' => 'Unit test of edit entity access check.',
+      'group' => 'Edit'
+    );
+  }
+
+  /**
+   * Tests the appliesTo method for the access checker.
+   */
+  public function testAppliesTo() {
+    $entity_access = new EditEntityAccessCheck();
+    $this->assertEquals($entity_access->appliesTo(), array('_access_edit_entity'), 'Access checker returned the expected appliesTo() array.');
+  }
+
+  /**
+   * Tests the method for checking access to routes.
+   */
+  public function testAccess() {
+    $route = new Route('/edit/entity/node/1', array(), array('_access_edit_entity' => 'TRUE'));
+    $request = new Request();
+
+    $editable_node = $this->getMockBuilder('Drupal\node\Plugin\Core\Entity\Node')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $editable_node->expects($this->any())
+      ->method('access')
+      ->will($this->returnValue(TRUE));
+    $access_check = new EditEntityAccessCheck();
+    $request->attributes->set('entity', $editable_node);
+    $access = $access_check->access($route, $request);
+    $this->assertEquals(TRUE, $access);
+
+    $readonly_node = $this->getMockBuilder('Drupal\node\Plugin\Core\Entity\Node')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $readonly_node->expects($this->any())
+      ->method('access')
+      ->will($this->returnValue(FALSE));
+    $access_check = new EditEntityAccessCheck();
+    $request->attributes->set('entity', $readonly_node);
+    $access = $access_check->access($route, $request);
+    $this->assertEquals(FALSE, $access);
+  }
+
+}
diff --git a/core/modules/edit/lib/Drupal/edit/Tests/EditEntityFieldAccessCheckTest.php b/core/modules/edit/lib/Drupal/edit/Tests/EditEntityFieldAccessCheckTest.php
new file mode 100644
index 0000000..e9dd413
--- /dev/null
+++ b/core/modules/edit/lib/Drupal/edit/Tests/EditEntityFieldAccessCheckTest.php
@@ -0,0 +1,71 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\edit\Tests\EditEntityFieldAccessCheckTest.
+ */
+
+namespace Drupal\edit\Tests;
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Routing\Route;
+use Drupal\edit\Access\EditEntityFieldAccessCheck;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * Tests the edit entity field access controller.
+ *
+ * @group Edit
+ */
+class EditEntityFieldAccessCheckTest extends UnitTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Edit entity field access check test',
+      'description' => 'Unit test of edit entity field access check.',
+      'group' => 'Edit'
+    );
+  }
+
+  /**
+   * Tests the appliesTo method for the access checker.
+   */
+  public function testAppliesTo() {
+    $entity_access = new EditEntityFieldAccessCheck();
+    $this->assertEquals($entity_access->appliesTo(), array('_access_edit_entity_field'), 'Access checker returned the expected appliesTo() array.');
+  }
+
+  /**
+   * Tests the method for checking access to routes.
+   */
+  public function testAccess() {
+    $route = new Route('/edit/form/node/1/body/und/full', array(), array('_access_edit_entity_field' => 'TRUE'));
+    $request = new Request();
+
+    // @todo Until field_access(), field_info_field(), field_info_instance() and
+    // field_valid_language() are no longer global functions, it is nigh
+    // impossible to provide full test coverage for EditEntityFieldAccessCheck.
+    /*
+    $editable_node = $this->getMockBuilder('Drupal\node\Plugin\Core\Entity\Node')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $editable_node->expects($this->any())
+      ->method('access')
+      ->will($this->returnValue(TRUE));
+    $editable_field = 'TODO';
+    $access_check = new EditEntityFieldAccessCheck();
+    $request->attributes->set('entity', $editable_node);
+    $request->attributes->set('entity_type', 'node');
+    $request->attributes->set('field_name', 'body');
+    $request->attributes->set('langcode', 'und');
+    $access = $access_check->access($route, $request);
+    $this->assertEquals(TRUE, $access);
+
+    // Add the 3 other permutations:
+    //  - editable entity, non-editable field
+    //  - non-editable entity, editable field
+    //  - non-editable entity, non-editable field
+    */
+  }
+
+}
diff --git a/core/modules/edit/lib/Drupal/edit/Tests/EditLoadingTest.php b/core/modules/edit/lib/Drupal/edit/Tests/EditLoadingTest.php
index e7e2571..7b01ade 100644
--- a/core/modules/edit/lib/Drupal/edit/Tests/EditLoadingTest.php
+++ b/core/modules/edit/lib/Drupal/edit/Tests/EditLoadingTest.php
@@ -89,6 +89,34 @@ function testUserWithoutPermission() {
     $response = $this->retrieveMetadata(array('node/1/body/und/full'));
     $this->assertIdentical('{}', $response);
     $this->assertResponse(403);
+
+    // Edit's JavaScript would never hit these endpoints if the metadata was
+    // empty as above, but we need to make sure that malicious users aren't able
+    // to use any of the other endpoints either.
+    $response = $this->retrieveAttachments(array('form'));
+    // @todo Uncomment the below once https://drupal.org/node/2063303 is fixed.
+    // $this->assertIdentical('[]', $response);
+    $this->assertResponse(403);
+    $response = $this->retrieveFieldForm('node/1/body/und/full');
+    // @todo Uncomment the below once https://drupal.org/node/2063303 is fixed.
+    // $this->assertIdentical('[]', $response);
+    $this->assertResponse(403);
+    $edit = array();
+    $edit['form_id'] = 'edit_field_form';
+    $edit['form_token'] = 'xIOzMjuc-PULKsRn_KxFn7xzNk5Bx7XKXLfQfw1qOnA';
+    $edit['form_build_id'] = 'form-kVmovBpyX-SJfTT5kY0pjTV35TV-znor--a64dEnMR8';
+    $edit['body[und][0][summary]'] = '';
+    $edit['body[und][0][value]'] = '<p>Malicious content.</p>';
+    $edit['body[und][0][format]'] = 'filtered_html';
+    $edit['op'] = t('Save');
+    $response = $this->submitFieldForm('node/1/body/und/full', $edit);
+    // @todo Uncomment the below once https://drupal.org/node/2063303 is fixed.
+    // $this->assertIdentical('[]', $response);
+    $this->assertResponse(403);
+    $response = $this->saveEntity('node/1');
+    // @todo Uncomment the below once https://drupal.org/node/2063303 is fixed.
+    // $this->assertIdentical('[]', $response);
+    $this->assertResponse(403);
   }
 
   /**
