Problem/Motivation
Discovered while working on #2737719: EntityResource: Provide comprehensive test coverage: for every entity type, every format, every method. See #2737719-91: EntityResource: Provide comprehensive test coverage: for every entity type, every format, every method.
Updating an entity via REST fails when the entity has a certain field value that the current user may not set, even if the PATCH request does NOT modify that field.
For example: node body uses a certain format that user A is not allowed to use, but when user A PATCHes only the node title, they still get a validation error.
Proposed resolution
If a REST request sends a field that the user has access to but is unchanged from the current field value the validation should not be run on this field.
Of course, we need to be careful to not disclose information too: we don't want to make it possible to guess the current invalid value of a field if the user is sending a single field in a PATCH request: if we respond with a 200 then because there's nothing to change, we've disclosed the value of a field that is inaccessible to the user (pointed out by @tstoeckler in #95!).
A generic example through which we can explain the desired behavior:: an entity with a reference field that contains a reference to a since then deleted entity.
- If user A sends the current value of that field, but is not allowed to view the reference field, then they should still get a validation error (because otherwise information disclosure).
- But if user B sends that same request body, and is allowed to view the reference field, then they should not get a validation error (because they're allowed to see the value, and are simply sending the current value, which means nothing is being changed, even if the current value is invalid).
All of this of course needs full test coverage, and the patch does :)
Remaining tasks
None.
User interface changes
None.
API changes
None.
Data model changes
None.
| Comment | File | Size | Author |
|---|---|---|---|
| #109 | 2821077-109.patch | 12.06 KB | tedbow |
| #109 | interdiff-105-109.txt | 3.56 KB | tedbow |
| #105 | 2821077-105.patch | 13.87 KB | wim leers |
| #105 | interdiff.txt | 874 bytes | wim leers |
| #101 | 2821077-100.patch | 13.85 KB | wim leers |
Comments
Comment #2
wim leersComment #4
dawehnerHere is some quick start for that.
Comment #5
wim leersOhhh! That looks easier than I expected! Thanks, great start :)
Also, it looks like this might not be blocked on #2824851: EntityResource::patch() makes an incorrect assumption about entity keys, hence results in incorrect behavior, which is what I thought at first. I was actually planning to mark this postponed because of that. Happy to be wrong!
Comment #6
dawehnerThis really just reuses the methods which have been also used for the HTML form, see
\Drupal\Core\Entity\Entity\EntityFormDisplay::validateFormValues.In general though this should have some form of security review. Its something which should be better safe than sorry.
Comment #7
wim leersComment #8
wim leersThis needs Entity/Field API maintainer feedback. Summoning @tstoeckler :)
Comment #9
tstoecklerYes, conceptually this makes sense. Like #6 says, this is equivalent to the form handling. See also
\Drupal\Core\Entity\ContentEntityForm::validateForm()for another usage. Thus, unassigning.Some notes on the actual patch:
Let's actually use
$changed_fields;-)So passing an empty list list of fields actually does no filtering at all. That kind of makes sense, but is also somewhat confusing so I think we should at least document this. Alternatively we could do some NULL vs. [] dance, but not sure that is better...
Why do we need to do this "workaround" of fetching the entity-level violations? Why is
$violations->filterByFields($changed_fields)not sufficient?Comment #10
dawehnerGood point. Let's refactor the code to no longer require this weird dance ...
Heh fair point.
As far as I understand its used in the form to be able to separate the violations which have to apply to certain widgets from other errors.
Comment #11
wim leersAwesome, so glad to see this moving forward!
This will become even better once #2456257: [PP-1] Normalizers must set $entity->_restSubmittedFields for entity POSTing/PATCHing to work lands, which in turn depends on #2862574: Add ability to track an entity object's dirty fields (and see if it has changed). And that last issue makes me wonder whether we should actually be updating
\Drupal\Core\Entity\ContentEntityBase::validate()instead? Shouldn't that code be responsible for only validating fields that were actually modified?Comment #12
dawehnerWe could do that in a follow up IMHO, given that the BC evaluation would be a different one.
Comment #13
wim leers+1
Comment #14
wim leersI think #9 addressed .
Comment #15
dawehnerHere is some test coverage.
Turns out the implementation was wrong. It filters out entries rather does what
array_filterdoes, aka. keep elements unless they meet a certain condition.Comment #16
dawehnerI accidentally had some test cases commented out
Comment #18
dawehnerLet's fix some failing tests ...
Comment #20
dawehnerThat's file it against 8.4.x
Comment #22
dawehnerJust a reroll
Comment #24
dawehnerThis could fix a lot of the problems ...
Comment #25
wim leersLet's please keep this as strict as it currently is. We can do the recursive
ksort()that e.g. #2768651: Let TimestampItem (de)normalize to/from RFC3339 timestamps, not UNIX timestamps, for better DX also does.All nits I addressed myself. Once the above is fixed, I think this is RTBC.
Comment #26
dawehner+1
Who can we ping to ensure this is fine? I think either berdir or tstoeckler would be fine.
Fago would be nice as well, but
Comment #27
wim leersNW for #25.
Comment #28
wim leersComment #30
wim leers#2824851: EntityResource::patch() makes an incorrect assumption about entity keys, hence results in incorrect behavior landed, this needs a reroll.
Comment #31
dawehnerWorking on this reroll right now
Comment #32
dawehnerComment #34
dawehnerFixing some test failures ...
Comment #36
dawehnerLet's see whether this fixes more.
Comment #37
wim leers@dawehner++
Why was this sufficient in the past (in #25)…
.
… and now we need all of these?
Ideally, we'd be able to avoid this, because it'd causes REST test failures for contrib/custom entity types.
Comment #38
dawehnerWe could check for
$this->entity->hasField('rest_test_validation')or so ..., what do you think?Comment #39
wim leersSounds good!
Comment #40
dawehnerLet's get this started then.
Comment #41
wim leersOh, interesting, so that means we're now only testing it against
\Drupal\Tests\rest\Functional\EntityResource\EntityTest\EntityTestResourceTestBase.Yay!
Comment #42
dawehnerWell you either test against all or again one or none :P So you suggest we add this field to all the core entities?
Comment #43
wim leersI think testing it with one entity type is sufficient, but the risk is that if we remove the
entity_testentity type, we lose this test coverage. That seems extremely unlikely though, so I'm fine with this. I'd also be fine with adding this field to every entity type.I don't feel very strongly about this.
But the reason I'm surprised is A) it was being added to every entity type before #40, and B)
These bits of code suggest it's applied to multiple entity types.
Otherwise, we could just hardcode this to
Comment #44
dawehnerI could easily imagine that we want to add this test coverage potentially to more than one entity type, which is why I went with that particular solution.
Comment #45
wim leersSo that probably means we should go back to doing this for every entity type then?
Comment #46
dawehnerWhat about adding it to all core entity types, but ensure that contrib tests not fail?
Comment #47
wim leersSounds good. But isn't it possible to do this for all entity types (contrib or core), and just automatically expand the expected normalization?
That's what this is doing, and that used to work fine in #25?
I think that should still work fine?
Comment #48
dawehnerLet's give it a try ...
Comment #49
wim leersThis looks great! I'd RTBC, but I have a few nits, and one relatively big thing (see point 1), which you will have to approve:
I just realized this belongs in
\Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase::setUp(), where we already create thefield_rest_testfield. Another field for testing purposes.(And #2800873: Add XML GET REST test coverage, work around XML encoder quirks is also adding one.)
So I set out to do this … except I couldn't get it to work :( After extensive debugging, I encountered this gem in the docs of
\Drupal\Core\Field\FieldConfigInterface::addConstraint():🤔😭😡🤷♂️
This does not make any sense. The constraint should be stored in the
FieldConfigconfig entity.Created #2905890: FieldConfigBase does not store constraints for that.
i.e. we already have this, might as well create the field there just like the other one!
Nit: one unnecessary blank line here.
Comment #50
dawehnerRight, this is exactly what I added it as a base field.
Comment #51
wim leersI should've known you knew about these edge cases :) But I suspect you agree with the approach in #49?
Comment #52
wim leersComment #53
dawehnerFor me both approaches are equal.
Maybe one could argue that testing the capability with custom added base fields is actually some level of test coverage which is worth dealing with.
Comment #54
wim leersCan you explain this a bit more?
Comment #55
dawehnerWe have quite some test coverage around entities and their basefields as well as configurable fields. We don't have yet an example of a base field added via a hook in rest API. I know this is a small detail, but you never know, there are infinite ways how something could break.
Comment #56
wim leersFair point!
Reverting #49.1. That means that compared to @dawehner's last patch in #48, the changes I made are now only whitespace nits (see
interdiff-48-55.txt).RTBC 🎉
Comment #57
wim leersIS updated.
Comment #58
wim leersCreated the follow-up @dawehner suggested in #12. Removing issue tag. Added to the patch.
Comment #59
tedbowThis review starts from #55 I didn't see patches past that. Will check
In this comment we say that we will prove that the validation will run by changing it and setting it to "ALWAYS_FAIL". This does seem to prove that.
But then we say
But we change the value of
rest_test_validationtoNULL.So I look at RestTestConstraintValidator and it has
So regardless of the whether
rest_test_validationwas modified or not the NULL value in the field would never trigger this violation because it is empty, correct?So I am not sure what this proves or at least that the comment is correct.
UPDATE:
I read this line incorrectly
$valid_request_body = array_diff_key($valid_request_body, ['rest_test_validation' => NULL]);I thought it was setting the field value to NULL when in fact it is removing the
rest_test_validationkey from the array because we are not all entities will have this field.But a few lines before this code we have the comment:
Which is actually not true in the case that the entity has the field
rest_test_validationin which case we are not sending all fields because we just removed 1 from the request.I think what tripped me up on this is the first comment I mentioned above says:
When in fact it is actually not sent so it is confusing to say it is not modified which read to mean sent but has the current value.
Nit related to my confusion:
Could we change
$valid_request_body = array_diff_key($valid_request_body, ['rest_test_validation' => NULL]);to
unset($valid_request_body['rest_test_validation']);For me that would be much clear as to what is happening.
The phpdoc says
But actually this is called as
$this->validateWithFilteredFields($original_entity, $entity->_restSubmittedFields);So when I first saw
$changed_fieldsI assumed since this issue fields that were modified from their current values, probably since this issue deals with "unmodified fields".Would it make sense to change
$changed_fieldsto$submitted_fields?So is this suppose to mean that with this patch user A should be able to send an unchanged body field back in the patch and even if the user doesn't have access to the current format, say
full_htmlthe patch should still work?If so I don't think this patch fixes the problem. I tried this locally and it does not work.
I still get
Or is it suppose to mean that User A can patch the entity has long has they do not send back the body field which does work?
This at least needs an issue summary update to describe what the desired functionality is.
Comment #60
wim leers#59
Great catch.
The problem is that the current patch assumes
$entity->_restSubmittedFieldsonly contains changed fields, which is not actually the case. This is once again where #2862574: Add ability to track an entity object's dirty fields (and see if it has changed) would come in very handy.Fortunately, #2824851: EntityResource::patch() makes an incorrect assumption about entity keys, hence results in incorrect behavior should allow us to work around this.
But first, let's remove that line so that we're testing what we should be testing (effectively removing a single line from the patch). This should pass tests in theory, but in practice it will fail, due to the use of
$entity->_restSubmittedFields. Thanks, eagle-eyed Ted! 🦅$changed_fields.OTOH, you're saying that you're not modifying anything. Well, if you're not modifying anything, then #2824851: EntityResource::patch() makes an incorrect assumption about entity keys, hence results in incorrect behavior should already be ensuring that it works fine:
So I'm not sure what's going on there?
P.S.: why ?
Comment #61
wim leersTurns out there were two things wrong:
$entity->_restSubmittedfieldsas I already identified in #60.ALWAYS_FAIL, then doing a PATCH request and expecting it to fail. But if it's already set to that value, then it should not fail! So the order was simply wrong.So, less complicated than I feared :)
Comment #62
wim leersTwo nits that I noticed while doing this:
Needs a
@todoto remove this.This runs unconditionally, so…
… we can also remove this condition.
Comment #64
tedbowBecause we moved this
$this->entity->save()to after the expected failed patch request and we removed this line if the previous patchThen now we are truly testing sending back an unmodfied field that would fail on validation if validation were called! 🙌
This address the type of the problem described in the issue summary regarding a format for the body field.
I tested this manually and now it works! 🎉
This looks good so we validate but filter unchanged fields! So the test should pass!
Comment #65
wim leersSo:
Comment #66
tedbowYeah follow up was mistake because I had the form up open when you removed the tag.
Added a single sentence to the Issue Summary to described desired behavior.
RTBC 😃
Comment #67
amateescu commentedInstead of splitting this method into 4 other methods, wouldn't it be simpler to simply add a new
$filter_fields = []parameter which, if provided, would callfilterByFields()on the violations list?Comment #68
wim leers#67 Thanks for the review! You got me wondering why we were doing it this seemingly convoluted way, because what you suggest indeed sounds much simpler!
Fun fact: what you suggest is exactly what the patch in #4 did! But based on @tstoeckler's feedback in #9.2, @dawehner ended up with the current approach in #10.
We could easily go back on this, but what you suggest is what @tstoeckler found confusing in #9.
I don't have a strong opinion. Whatever you and @tstoeckler agree upon is fine by me.
Comment #69
dawehnerOne reason I went with the 4 methods is that their intensions are really clear by their name.
Comment #70
amateescu commentedReading #9.2 again, @tstoeckler actually wanted just better documentation for the new
$changed_fieldsparameter, to make it clear that passing an empty array means that no filtering is done on the violations list.In addition to that, #9.3 was not really addressed properly with the answer from #10:
@dawehner based his initial code and the reply from #10 on the code from
\Drupal\Core\Entity\ContentEntityForm::flagViolations(), but that code is actually just a helper method for deciding who is responsible for converting entity validation errors to form errors. The form itself is responsible for reporting entity-level violations and field widget are responsible for reporting field-level violations.Instead, we should base REST's code on
\Drupal\Core\Entity\ContentEntityForm::validateForm(), which gets the full list of violations and then filters it by field access and fields that were actually changed by the form.This means that we can simplify the
validateWithFilteredFields()method to this:Note that I also removed the
instanceofcheck becausedoValidation()already has it. Now.. doesn't this look exactly likevalidate()with an addedfilterByFields()call? It sure does to me, which made me wonder if we really need a different method for this. My answer was "no", so if we mergevalidateWithFilteredFields()withvalidate(), then the newdoValidation()doesn't make sense on its own, so we can inline it as well in the parentvalidate()method.This brings us to only two methods,
validate()andprocessViolations(). Now, the doxygen block fromvalidate()says that it throws anUnprocessableEntityHttpExceptionif validation errors are found, but it's actuallyprocessViolations()the one who throws that exception (and doesn't document it in the docs), so, in my mind, there's no need for that additional call to a different method just to throw an exception that should've been thrown by the parent call.In conclusion, I think the code from #4 was way better than the changes from #10, and @tstoeckler concerns could easily be addressed by documenting the new
$changed_fieldsparam better.The patch from #62 does not apply to HEAD anymore because #2824851: EntityResource::patch() makes an incorrect assumption about entity keys, hence results in incorrect behavior was reverted, but here's an interdiff for it which brings us back to one method and also addresses @tstoeckler's review from #9.
Comment #71
dawehnerI'm trying a reroll now and then address @amateescu latest patch ...
@amateescu I like how your interdiff simplifies things ...
Comment #72
dawehnerI would actually suggest to postpone this on #2824851: EntityResource::patch() makes an incorrect assumption about entity keys, hence results in incorrect behavior given the test code conflicts quite heavily ...
Comment #73
wim leers#70++ Thank you! ❤️
#71: I completely agree!
#72: :( This is exactly what I feared that the revert of #2824851: EntityResource::patch() makes an incorrect assumption about entity keys, hence results in incorrect behavior would cause :(
Comment #74
wim leers#2824851: EntityResource::patch() makes an incorrect assumption about entity keys, hence results in incorrect behavior is in, this is unblocked again!
Comment #75
wim leersStraight rebase #62. Had to resolve some conflicts. The only actual change in implementation is in
EntityResource, because #2824851: EntityResource::patch() makes an incorrect assumption about entity keys, hence results in incorrect behavior changed that pretty significantly. Fortunately, the logic is still identical.Comment #76
wim leersI also noticed this opportunity for simplification, which also makes this patch a bit smaller (because more pure additions rather than changing existing lines of code)
Comment #77
wim leersAnd now applied @amateescu's #70 interdiff. @dawehner said in #71 he liked how it simplifies things, and I can only wholeheartedly agree with that! :)
It even makes the patch smaller!
@amateescu++
Comment #79
wim leersOkay, so going from #76 to #77 by applying @amateescu's #70 interdiff causes more failures. Interesting.
But, #75/#76 also contain failures, unlike the last green patch they're equivalent to, in #62. Let's fix those failures first. Most of the failures seem to be in XML test coverage. XML test coverage didn't exist yet when #62 was green, which explains it.
Making this new
rest_test_validationfield that this patch is adding behave the same as thefield_rest_testorfield_rest_test_multivaluefields solves that.(Note: we should probably still rename it to
field_rest_test_validationfor consistency with the other test fields.)Comment #80
wim leersThe changes in #79 prevented the
PATCHrequest body from actually containing a value for the validation test field. Enforce this.Comment #81
wim leersAnd then finally: there is one subtle change that @amateescu's #70 introduces: it calls
->filterByFields()if$changed_fieldsis not empty. But we're specifically testing the case where we do send values without them being different. So$changed_fields = [], which means that subtle change in #70 ends up causing unmodified fields to still throw validation errors. But only if there are zero unmodified fields.The solution is simple.
(This one was pretty tricky to debug — I spent at least 30 minutes pulling my hair over this :D)
Comment #85
wim leers@gabesullice just pointed out how similar this is to #2968972: Cannot PATCH an entity with dangling references in an ER field in JSON API; it's essentially the same solution!
Comment #86
wim leersAlso, let's get this going again. Rebased #81; one file has been moved in the past 5 months.
Comment #88
wim leersComment #89
wim leers#88 should make all failing
testPost()tests pass again.This should make the tests involving
EntityTestentities pass again. (There was an obsolete leftover — see #41+#42 and related comments.)Comment #90
tstoecklerSo
::checkPatchFieldAccess()contains this:I feel like we should just change that to:
(and adapt the comment accordingly. Then we can save the if in the calling code. That will mean we will no longer call
->set()on field items that are equal, but we already decided in #2824851: EntityResource::patch() makes an incorrect assumption about entity keys, hence results in incorrect behavior that that's not a behavior change because->set()is not a no-op for equal fields that's a bug.Comment #92
wim leersI think #89 will be down to one fail, this should bring it to zero!
Comment #93
wim leersYay, a @tstoeckler review! 🎉 😀 Thanks, Tobias! :)
My first reaction is: I do not want to touch that code if at all possible, because it took months to get #2824851: EntityResource::patch() makes an incorrect assumption about entity keys, hence results in incorrect behavior (which contained it) to land!
Second reaction: I should take a closer look nonetheless. [… does that …] Yep, it's still about changing code that was extremely tricky to get just right.
I have an alternative idea:
That's even less work! Otherwise we're still triggering the validating and saving of something that we already know to be the same.
What do you think?
Comment #95
tstoecklerI was about to write a lengthy comment on the reasoning for #90 but in the process I realized one thing. #90 was just about suggesting a different "placement" of the code with no functional change relative to the patch.
However, I am now convinced that the patch itself contains a funtional bug. Given how the #2824851: EntityResource::patch() makes an incorrect assumption about entity keys, hence results in incorrect behavior I would not be surprised for @cburschka (or anyone else, for that matter) to prove me wrong on this, but for now I am convinced nonetheless 😉.
The issue summary reads:
The sublety lies with the word "access". Per #2824851: EntityResource::patch() makes an incorrect assumption about entity keys, hence results in incorrect behavior and given that a user does not have access to edit a given field we do not allow submitting that field even if it is unchanged if the user does not have view access on it. As discussed at length in that issue this prevents information disclosure as otherwise the user could just submit a bunch of different values to this field and as soon as they would not get a 403 for a response they would have found out the current field value - in effect having "viewed" it.
This issue is now about running field validation, but I think a similar logic applies there, as well, in a sort of "reverse" way. If a user has "edit" access to a field, but not "view" access, the current patch would not run field validation of the field value matches the current way. That way the resulting response depends (or at least may depend) on the current value which in turn may allow the user to figure the field value.
It is a bit far-fetched - but not impossible - to conjure up an actual "exploit" with this. In particular, if the current value of a field is invalid for whatever reason. This is (not normally the case, but) entirely possible because while forms and Rest do perform validation by default, it is not enforced when saving an entity manually and even through forms there can be situations where not all fields are valid. An attacker (that - again - has edit but not view access to this field) could then try to PATCH all kinds of invalid values to this field and if they hit the current one, a 200 response would be returned, which would neatly inform them of the current (invalid) field value, in effect having granted them view access.
So I think we actually need to check view access before excluding fields from validation because they are unchanged. Luckily, this will not be a very invasive change. In fact, we can just switch the order of the two if-hunks in
::checkPatchFieldAccess()(and I guess we will have to update the respective comments a bit). Then we can just remove the if that the current patch adds entirely and just populate$changed_fieldsiff we call::set().Tagging "Needs tests" because I think we want something along the lines of the above "attack scenario" so that we do not regress here.
The idea in #93 is actually quite neat, I think, but I don't understand how it's related to the suggestion in #90, to be honest, and it also doesn't fix the above. That doesn't mean we shouldn't add it, though, in fact I really see reason not to.
Comment #96
wim leers🙉🙈😱
Well-spotted!
Comment #97
wim leersFortunately, the test coverage already being added by this patch made it trivial to test this :)
This should fail! Instead of the expected 422 (to not disclose the current value), we get a 200 (which does disclose the current value).
Comment #98
wim leersAnd the fix!
Comment #99
tstoecklerWow, thanks for the quick turnaround! Looks really good, only minor points.
Could just be
if($changed_fields)I know this comment is there because I explicitly requested it, but looking at the code now again, I'm not actually sure it is true?! If
$changed_fieldsis empty, all fields will be passed tofilterByFields()which means that no (field-level) violations will be reported at all, unless I'm mistaken.Seems this is no longer true?
Unnecessary empty line.
Comment #101
wim leersfilterByFields()is confusing. 😅 I also added logic now to prevent that nonsensical case, which is possible thanks to #93!Comment #102
tstoecklerThanks, looks great to me. Still needs an issue summary update, but I wouldn't RTBC regardless, because another pair of eyes wouldn't hurt.
Comment #103
wim leers#59.3 tagged this as needing an IS update. I cannot reproduce the problem in #59.3. The bit it cited in the IS as being problematic is actually correct. #64.1 confirmed this. :) @tedbow even updated the IS in #66! He just forgot to remove the tag :p
That being said, since then, quite a few changes happened. So, updated the IS for those.
Comment #104
tedbowNeeds work to remove the todo.
The other point may just be me forgetting the details of this issue.
#2906129: [PP-1] Update ContentEntityBase::validate() to only validate dirty fields issue was closed as "Works as designed" by @amateescu. So we should probably remove this @todo.
If the user doesn't have access to view the field should return a 422 response code but not return the actual message. Would there ever be a case where the validation message gives away the current value?
For instance what if in content_moderation you have transitions
draft -> publish
publish -> draft
but not
publish -> publish
i.e. you can't actually make any changes to entity without take it out of published status.
Would the message "published to publish not a valid transition" give away the current value.?
We want to run validation to prevent disclosure but for the user without access to view the field what is value of displaying the actually validate message to that user?
Comment #105
wim leersYou're talking about the use case where the user can neither edit nor view. HEAD already has explicit test coverage for that:
(Added in #2824851: EntityResource::patch() makes an incorrect assumption about entity keys, hence results in incorrect behavior.)
Comment #106
tedbow@Wim Leers thanks for the explanation. Re-reading the issue and patch that looks good!
🎉RTBC!🎉
Comment #108
alexpottI think this name could be improved. I.e. be
$fields_to_validateAs the point here is that this is a list of fields to validate. And we should document the default behaviour is to validate all fields.Also I'm concerned about BC since I think not providing the value should continue with todays behaviour of validating all the fields. So I think the exception thrown here might be an API break.
Comment #109
tedbow@alexpott I think these changes sound good.
$fields_to_validate.validate()these is just generic list of field names now I removed the logic of not calling\Drupal\Core\Entity\EntityConstraintViolationListInterface::filterByFields()if the entity is new. This logic only made sense if these were "changed" fields. This should not make a difference because the only place this method is being called with a value for this optional parameter is\Drupal\rest\Plugin\rest\resource\EntityResource::patch()and because it isPATCHrequest this will never be new entity.The documentation of
$fields_to_validateprovides documentation now but I added more documentation for the method.But I also added a bit about fields the users has access to since the default behavior is not to validate all fields.
I have remove this exception. I don't think it will cause any test fails but will see.
I could see where this could be a BC break. If you created a decouple entity entity form.
If we threw an exception here that would be a BC break that app would not know how to handle.
Also maybe the user was just saving the form with no changes to update "
changed" field(or another computed field) to get the entity at the top of a list ordered by that field. So it actually could make sense to save with no changes.Comment #110
wim leersComment #112
alexpottCommitted and pushed 73769ef5f8 to 8.7.x and 55ffe4fa1f to 8.6.x. Thanks!
Backporting to 8.6.x as an important bug fix for API first. AFAICS the changes here are totally BC compatible and the behaviour changes should only benefit real sites.
Comment #115
wim leersGreat! 🎉
Now we can move forward with #2979945 — see #2979945-4: Port #2821077 to JSON API: limit validation of fields in PATCH requests to fields *changed*.