diff --git a/core/modules/hal/lib/Drupal/hal/Normalizer/EntityNormalizer.php b/core/modules/hal/lib/Drupal/hal/Normalizer/EntityNormalizer.php index 751de28..ba15b25 100644 --- a/core/modules/hal/lib/Drupal/hal/Normalizer/EntityNormalizer.php +++ b/core/modules/hal/lib/Drupal/hal/Normalizer/EntityNormalizer.php @@ -100,6 +100,10 @@ public function denormalize($data, $class, $format = NULL, array $context = arra } $entity = entity_create($typed_data_ids['entity_type'], array('langcode' => $langcode, 'type' => $typed_data_ids['bundle'])); + // Make sure that we are always dealing with the real NG object here, + // otherwise unexpected things happen when setting fields on the BC + // decorator. + $entity = $entity->getNGEntity(); // Special handling for PATCH: destroy all possible default values that // might have been set on entity creation. We want an "empty" entity that diff --git a/core/modules/hal/lib/Drupal/hal/Tests/NodeTest.php b/core/modules/hal/lib/Drupal/hal/Tests/NodeTest.php new file mode 100644 index 0000000..a5b7c89 --- /dev/null +++ b/core/modules/hal/lib/Drupal/hal/Tests/NodeTest.php @@ -0,0 +1,93 @@ + 'Node Denormalization Test', + 'description' => 'Test that nodes can be denormalized from HAL.', + 'group' => 'HAL', + ); + } + + /** + * {@inheritdoc} + */ + function setUp() { + parent::setUp(); + + // Create the test field with cardinality one. + $field = entity_create('field_entity', array( + 'field_name' => 'field_test', + 'type' => 'text_long', + 'cardinality' => 1, + 'translatable' => FALSE, + 'entity_types' => array('node'), + )); + $field->save(); + + $instance = entity_create('field_instance', array( + 'field_name' => 'field_test', + 'label' => 'Test', + 'entity_type' => 'node', + 'bundle' => 'page', + 'settings' => array('text_processing' => 1), + 'required' => FALSE, + )); + $instance->save(); + + // We need a valid and existent content type for testing the entity + // denormalizer. + $node_type = entity_create('node_type', array( + 'type' => 'page', + )); + $node_type->save(); + } + + /** + * Tests that a text field with a cardinality of one can be denormalized. + */ + public function testLimitedFieldCardinality() { + $data = array( + '_links' => array( + 'type' => array( + 'href' => url('rest/type/node/page', array('absolute' => TRUE)), + ), + ), + 'field_test' => array( + 0 => array( + 'value' => 'testvalue', + 'format' => 'full_html', + ), + ), + ); + + $serializer = $this->container->get('serializer'); + $node = $serializer->denormalize($data, 'Drupal\node\Plugin\Core\Entity\Node', 'hal_json'); + $this->assertEqual(count($node->get('field_test')), 1, 'Exactly one field item was created.'); + $this->assertEqual($node->get('field_test')->getValue(), $data['field_test']); + } +} diff --git a/core/modules/rest/lib/Drupal/rest/Plugin/rest/resource/EntityResource.php b/core/modules/rest/lib/Drupal/rest/Plugin/rest/resource/EntityResource.php index a58cf89..2d2f353 100644 --- a/core/modules/rest/lib/Drupal/rest/Plugin/rest/resource/EntityResource.php +++ b/core/modules/rest/lib/Drupal/rest/Plugin/rest/resource/EntityResource.php @@ -149,17 +149,13 @@ public function patch($id, EntityInterface $entity = NULL) { // Overwrite the received properties. foreach ($entity as $field_name => $field) { if (isset($entity->{$field_name})) { - if (empty($entity->{$field_name})) { - if (!$original_entity->get($field_name)->access('delete')) { - throw new AccessDeniedHttpException(t('Access denied on deleting field @field.', array('@field' => $field_name))); - } - } - else { - if (!$original_entity->get($field_name)->access('update')) { - throw new AccessDeniedHttpException(t('Access denied on updating field @field.', array('@field' => $field_name))); - } + if ($field->isEmpty() && !$original_entity->get($field_name)->access('delete')) { + throw new AccessDeniedHttpException(t('Access denied on deleting field @field.', array('@field' => $field_name))); } $original_entity->set($field_name, $field->getValue()); + if (!$original_entity->get($field_name)->access('update')) { + throw new AccessDeniedHttpException(t('Access denied on updating field @field.', array('@field' => $field_name))); + } } } diff --git a/core/modules/rest/lib/Drupal/rest/Tests/CreateTest.php b/core/modules/rest/lib/Drupal/rest/Tests/CreateTest.php index 0a75cb3..618f663 100644 --- a/core/modules/rest/lib/Drupal/rest/Tests/CreateTest.php +++ b/core/modules/rest/lib/Drupal/rest/Tests/CreateTest.php @@ -80,8 +80,16 @@ public function testCreate() { $this->assertResponse(403); $this->assertFalse(entity_load_multiple($entity_type, NULL, TRUE), 'No entity has been created in the database.'); - // Restore the valid test value. + // Try to create a field with a text format this user has no access to. $entity->field_test_text->value = $entity_values['field_test_text'][0]['value']; + $entity->field_test_text->format = 'full_html'; + $serialized = $serializer->serialize($entity, $this->defaultFormat); + $this->httpRequest('entity/' . $entity_type, 'POST', $serialized, $this->defaultMimeType); + $this->assertResponse(403); + $this->assertFalse(entity_load_multiple($entity_type, NULL, TRUE), 'No entity has been created in the database.'); + + // Restore the valid test value. + $entity->field_test_text->format = 'plain_text'; $serialized = $serializer->serialize($entity, $this->defaultFormat); } diff --git a/core/modules/rest/lib/Drupal/rest/Tests/RESTTestBase.php b/core/modules/rest/lib/Drupal/rest/Tests/RESTTestBase.php index db8feb2..d6fc9f9 100644 --- a/core/modules/rest/lib/Drupal/rest/Tests/RESTTestBase.php +++ b/core/modules/rest/lib/Drupal/rest/Tests/RESTTestBase.php @@ -166,7 +166,10 @@ protected function entityValues($entity_type) { return array( 'name' => $this->randomName(), 'user_id' => 1, - 'field_test_text' => array(0 => array('value' => $this->randomString())), + 'field_test_text' => array(0 => array( + 'value' => $this->randomString(), + 'format' => 'plain_text', + )), ); case 'node': return array('title' => $this->randomString(), 'type' => 'resttest'); diff --git a/core/modules/rest/lib/Drupal/rest/Tests/UpdateTest.php b/core/modules/rest/lib/Drupal/rest/Tests/UpdateTest.php index b417f2a..827d7a4 100644 --- a/core/modules/rest/lib/Drupal/rest/Tests/UpdateTest.php +++ b/core/modules/rest/lib/Drupal/rest/Tests/UpdateTest.php @@ -51,7 +51,10 @@ public function testPatchUpdate() { $entity->save(); // Create a second stub entity for overwriting a field. - $patch_values['field_test_text'] = array(0 => array('value' => $this->randomString())); + $patch_values['field_test_text'] = array(0 => array( + 'value' => $this->randomString(), + 'format' => 'plain_text', + )); $patch_entity = entity_create($entity_type, $patch_values); // We don't want to overwrite the UUID. unset($patch_entity->uuid); @@ -90,7 +93,8 @@ public function testPatchUpdate() { // Enable access protection for the text field. // @see entity_test_entity_field_access() - $entity->field_test_text->value = 'no access value'; + $entity->field_test_text->value = 'no delete access value'; + $entity->field_test_text->format = 'plain_text'; $entity->save(); // Try to empty a field that is access protected. @@ -99,16 +103,26 @@ public function testPatchUpdate() { // Re-load the entity from the database. $entity = entity_load($entity_type, $entity->id(), TRUE); - $this->assertEqual($entity->field_test_text->value, 'no access value', 'Text field was not updated.'); + $this->assertEqual($entity->field_test_text->value, 'no delete access value', 'Text field was not deleted.'); // Try to update an access protected field. + $patch_entity->get('field_test_text')->value = 'no access value'; $serialized = $serializer->serialize($patch_entity, $this->defaultFormat); $this->httpRequest('entity/' . $entity_type . '/' . $entity->id(), 'PATCH', $serialized, $this->defaultMimeType); $this->assertResponse(403); // Re-load the entity from the database. $entity = entity_load($entity_type, $entity->id(), TRUE); - $this->assertEqual($entity->field_test_text->value, 'no access value', 'Text field was not updated.'); + $this->assertEqual($entity->field_test_text->value, 'no delete access value', 'Text field was not updated.'); + + // Try to update the field with a text format this user has no access to. + $patch_entity->set('field_test_text', array( + 'value' => 'test', + 'format' => 'full_html', + )); + $serialized = $serializer->serialize($patch_entity, $this->defaultFormat); + $this->httpRequest('entity/' . $entity_type . '/' . $entity->id(), 'PATCH', $serialized, $this->defaultMimeType); + $this->assertResponse(403); // Restore the valid test value. $entity->field_test_text->value = $this->randomString(); diff --git a/core/modules/text/lib/Drupal/text/Plugin/field/field_type/TextItem.php b/core/modules/text/lib/Drupal/text/Plugin/field/field_type/TextItem.php index 644a2a9..4fa2ccb 100644 --- a/core/modules/text/lib/Drupal/text/Plugin/field/field_type/TextItem.php +++ b/core/modules/text/lib/Drupal/text/Plugin/field/field_type/TextItem.php @@ -25,7 +25,8 @@ * "text_processing" = "0" * }, * default_widget = "text_textfield", - * default_formatter = "text_default" + * default_formatter = "text_default", + * list_class = "Drupal\text\TextField" * ) */ class TextItem extends TextItemBase { diff --git a/core/modules/text/lib/Drupal/text/Plugin/field/field_type/TextWithSummaryItem.php b/core/modules/text/lib/Drupal/text/Plugin/field/field_type/TextWithSummaryItem.php index 8d5c9fb..61141ea 100644 --- a/core/modules/text/lib/Drupal/text/Plugin/field/field_type/TextWithSummaryItem.php +++ b/core/modules/text/lib/Drupal/text/Plugin/field/field_type/TextWithSummaryItem.php @@ -23,7 +23,8 @@ * "display_summary" = "0" * }, * default_widget = "text_textarea_with_summary", - * default_formatter = "text_default" + * default_formatter = "text_default", + * list_class = "Drupal\text\TextField" * ) */ class TextWithSummaryItem extends TextItemBase { diff --git a/core/modules/text/lib/Drupal/text/Tests/AccessTest.php b/core/modules/text/lib/Drupal/text/Tests/AccessTest.php new file mode 100644 index 0000000..782eff5 --- /dev/null +++ b/core/modules/text/lib/Drupal/text/Tests/AccessTest.php @@ -0,0 +1,89 @@ + 'Text Field Access', + 'description' => 'Tests the text field access method.', + 'group' => 'Field types', + ); + } + + function setUp() { + parent::setUp(); + + $this->installSchema('user', 'users_roles'); + entity_test_install(); + + // Create Filtered HTML format. + $filtered_html_format = entity_create('filter_format', array( + 'format' => 'filtered_html', + 'name' => 'Filtered HTML', + 'filters' => array( + 'filter_html' => array( + 'status' => 1, + 'settings' => array( + 'allowed_html' => '


', + ), + ), + ) + )); + $filtered_html_format->save(); + + // Create Full HTML format. + $full_html_format = entity_create('filter_format', array( + 'format' => 'full_html', + 'name' => 'Full HTML', + 'weight' => 1, + 'filters' => array(), + )); + $full_html_format->save(); + + // Create a user 1, which we don't want to use in our access-sensitive + // tests. + $this->createUser(); + } + + /** + * Checks that filter format access is respected on text fields. + */ + public function testAccess() { + $entity = entity_create('entity_test', array('field_test_text' => array('value' => 'test', 'format' => 'filtered_html'))); + $unpriviledged_user = $this->createUser(array(), array('administer entity_test content', 'use text format filtered_html')); + $priviledged_user = $this->createUser(array(), array('administer entity_test content', 'use text format filtered_html', 'use text format full_html')); + + $this->assertTrue($entity->get('field_test_text')->access('create', $unpriviledged_user), 'Unpriviledged user is allowed to create field with filtered_html'); + $this->assertTrue($entity->get('field_test_text')->access('create', $priviledged_user), 'Priviledged user is allowed to create field with filtered_html'); + + $this->assertTrue($entity->get('field_test_text')->access('update', $unpriviledged_user), 'Unpriviledged user is allowed to update field with filtered_html'); + $this->assertTrue($entity->get('field_test_text')->access('update', $priviledged_user), 'Priviledged user is allowed to update field with filtered_html'); + + $entity->set('field_test_text', array('value' => 'test', 'format' => 'full_html')); + $this->assertFalse($entity->get('field_test_text')->access('create', $unpriviledged_user), 'Unpriviledged user is not allowed to create field with full_html'); + $this->assertTrue($entity->get('field_test_text')->access('create', $priviledged_user), 'Priviledged user is allowed to create field with full_html'); + + $this->assertFalse($entity->get('field_test_text')->access('update', $unpriviledged_user), 'Unpriviledged user is not allowed to update field with full_html'); + $this->assertTrue($entity->get('field_test_text')->access('update', $priviledged_user), 'Priviledged user is allowed to update field with full_html'); + } + +} diff --git a/core/modules/text/lib/Drupal/text/TextField.php b/core/modules/text/lib/Drupal/text/TextField.php new file mode 100644 index 0000000..4b7d239 --- /dev/null +++ b/core/modules/text/lib/Drupal/text/TextField.php @@ -0,0 +1,47 @@ +isEmpty()) { + return TRUE; + } + if ($account == NULL) { + $account = \Drupal::request()->attributes->get('_account'); + } + // Iterate over all field items, if one uses a not allowed format return + // FALSE immediately. + foreach ($this as $item) { + $format_name = $item->get('format')->getValue(); + $format = filter_format_load($format_name); + if (!$format || !filter_access($format, $account)) { + return FALSE; + } + } + // All formats in all items are allowed for this user, so we can grant + // access. + return TRUE; + } + +}