Problem/Motivation
Right now in core there is no secure way to use entity autocomplete see the discussion in #2341357-12: Views entity area config is not deployable and missing dependencies. This fix will allow us to use selection plugin for entity autocompletes and selection plugin have proper access checks for all entities.
Proposed resolution
Remove $field_definition form EntityReferenceAutocomplete::getMatches()
Remaining tasks
See the interdiff in #2107243-25: Decouple entity reference selection plugins from field definitions
User interface changes
None
API changes
EntityReferenceAutocomplete::getMatches()
can be used without creating field.
Original report by @goldorak
Hello,
It would be nice if the selection handler from entity_reference module can be attachable directly on a form element without creating a field. For instance, when adding a new view, the form element 'tagged with' is the perfect use case for this kind of feature. We can implement this feature using a new property such as '#entity_reference' and fulfill it with all required settings needed by entity_reference module.
Beta phase evaluation
Issue category | Task because it is not a bug. Not a feature because it improve security |
---|---|
Issue priority | Not critical but it'll improve security |
Prioritized changes | The main goal of this issue is to improve usability and security of entity autocompletes field. |
Disruption | Disruptive for DER but can fix all the dirty workarounds (in other words PLEASE PLEASE PLEASE disrupt us) |
Comment | File | Size | Author |
---|---|---|---|
#66 | 1959806-66.patch | 69.38 KB | amateescu |
#51 | interdiff.txt | 6.76 KB | amateescu |
#51 | 1959806-51.patch | 69.34 KB | amateescu |
#46 | interdiff.txt | 5.18 KB | amateescu |
#46 | 1959806-46.patch | 69.14 KB | amateescu |
Comments
Comment #1
jkuma CreditAttribution: jkuma commentedHere is an attempt to solve this feature request. This patch only tackles the textfield form element.
The items bellow describes the list of accepted parameters for the '#entity_reference' property:
This is an exemple of implementation:
Comment #2
amateescu CreditAttribution: amateescu commentedHere's an initial review.
Implements ...
This comment should be moved to the doxygen block of
entity_reference_process_element
(and translated to english? :P).The process callback should be better named 'entity_reference_textfield_element_process'.
You don't care if #autocomplete_path is valid or not because you generate one in this process callback. Also the doxygen block should follow the coding standards.. see for example: http://drupalcode.org/project/drupal.git/blob/refs/heads/8.x:/core/modul...
The autocomplete path doesn't need to be passed through url().
drupal_container()->get() should be replaced with Drupal::service().
As the comment says, an empty line is needed at the end of the file :)
This basically duplicates both widget validation methods provided by ER.. can't we unify them instead?
This one duplicates a part of the existing handleAutocomplete() method. We should get the common parts and move them to a protected method instead.
Comment #3
jkuma CreditAttribution: jkuma commentedComment #4
jkuma CreditAttribution: jkuma commentedDear sir, thanks for the review, this is an another attempt for this feature request:
Sorry, my mistake, it's fixed.
Comment moved to the correct function. Spelling fixed.
Process callback renamed.
All your raised points have been fixed.
fixed.
It doesn't matter if we unify or not the widget validation callbacks... The problem is the widget classes are unreachable from entity_reference_textfield_element_process which is located in .module file. We can maybe register a new service in order to get an access to widget classes ?
I've created a new protected method called handle which implements the common part of both methods.
Comment #5
jkuma CreditAttribution: jkuma commentedComment #6
amateescu CreditAttribution: amateescu commentedSorry for slacking with the review here.. I'll give it another look this weekend :)
Comment #7
dawehnerI'm wondering whether instead there could be a element which for itself
It feels wrong to couple the nice service of entity reference autocompletion with formapi related code.
Comment #7.0
dawehnerspelling.
Comment #8
andypostWorking on #2211553: Allow usage of entity_reference field widget and formatter for base fields I found that
handle()
should acceptentity_type
andfieldDefinition
but base fields does not have bundle property #2213597: FieldDefinition for base fields should know it's bundleComment #9
amateescu CreditAttribution: amateescu commentedThis patch will be simplified a lot if we do #2107243: Decouple entity reference selection plugins from field definitions first, so postponing on that.
Comment #10
Wim Leers#2107243: Decouple entity reference selection plugins from field definitions landed, unpostponed!
Comment #11
amateescu CreditAttribution: amateescu commentedOn it :)
Comment #12
yched CreditAttribution: yched commentedDoes this allow us to move ER widgets out of e_r.module and into Core, like we did for formatters a bit earlier ?
Comment #13
jibranForm #2107243-15: Decouple entity reference selection plugins from field definitions
Because of this reason this is task.
Add BE and updated IS. Please improve.
Comment #14
amateescu CreditAttribution: amateescu commentedExactly! Let's see how big the initial patch will be and decide then if we want to do it in the same issue.
Comment #15
amateescu CreditAttribution: amateescu commentedI've been working on this in the past few days, trying to come up with a nice API for the generic form element, and I think I mostly succeeded based on how clean is the code for ER's field widgets now.
There are still a few open questions marked with @todo in the patch, so opinions are welcome! And I'll expand the test coverage a bit after the architectural discussions are over.
Comment #17
yched CreditAttribution: yched commentedLooks awesome :-)
Not an in-depth review, just a couple remarks and thoughts on @todos after a first cursory look
The function can currently return NULL (if several bundles eligible), what happens then ?
Sweet :-)
Was wondering that too, since there's no need to figure out a value for the last two if the first one is FALSE.
So maybe just
thanks for the static methods ;-)
definitely +1
Indent
Class is just being moved around, but a name nitpick is something I have a hard time resisting...
The service and class name do not really help understanding what the object is and does - it's not an "autocomplete" :-) AutocompleteMatcher maybe ?
Comment #18
Wim LeersAwesome work!
Comment #19
amateescu CreditAttribution: amateescu commentedJust fixing the patch for now, those fails are depressing.
Comment #21
amateescu CreditAttribution: amateescu commentedHm, that's not the correct fix, more cleanup coming tomorrow :)
Comment #22
amateescu CreditAttribution: amateescu commentedLet's see if I got them all properly this time.
Re #17, thanks for starting the reviews :)
No "autocreation" is happening in that case, that's why I put a @todo there that links to #2412569: Allow setting the auto-create bundle on entity reference fields with multiple target bundles.
Yep, that's exactly what I had in mind. The only problem is that I don't know where to document this stuff. If all the #autocreate_* keys are receiving default values in the form element class, at least people can go there and see them. Maybe there is a standard way of doing this and I have to find out which is it :)
Wouldn't have done it any other way :D
Done.
Yup, I like that name a lot. And renames like this are definitely needed for this patch.
Comment #23
amateescu CreditAttribution: amateescu commentedIt's a bit sad that we lose all those access denied exceptions in the controller, but I can't think of any good replacement for them. Maybe we could impose that the field widgets pass something like:
and then the controller could see if 'entity_form' is set and do all the "field exists" checks.
Comment #25
amateescu CreditAttribution: amateescu commentedconfig schema++
Comment #26
jibranReally amazing work on the patch. This is almost perfect.
Now we are using selection plugin name and settings in url so perhaps we should add an access method to
EntityReferenceSelection
plugins. I know we have access checks inbuildEntityQuery()
methods but this is just a suggestion.I think we need a new test for fapi element.
Pardon my ignorance, can you please explain what is the difference between
entity_reference_autocomplete_tags
andentity_reference_autocomplete
?We have to update API change section in IS and BE also need update.
Here is a minor review. I couldn't find anything alarming.
Why not reset($bundles) as third option for now until @todo is resolved?
I think we need a followup doc issue for fapi doc update.
I think it would be great if we can combine them in an array so +1 on that.
Comment #27
dawehnerHave you tried introducing a core.routing.yml file? I would not bet, but I could guess that it works.
We reference a system code in core.services.yml?
@tim and @dawe talked about that and we agreed it should be in Drupal\Core\Entity\Element instead
Comment #28
Wim LeersCursory review.
"Tags style" is a bit strange to mention, no? That's highly specific to one well-known example.
Perhaps something like "autocreate non-existing items" makes more sense?
Would throwing an exception be more appropriate?
Nit: s/
,$label
/, $label
/This can be removed everywhere because core only supports one autocomplete type?
s/helper/matcher/
as a JSON response
Why?
Matcher
s/Entity/entity/
"on instance"? I don't know what that means.
Could be more descriptive about what it returns. ("An array containing pairs of …".)
Comment #29
amateescu CreditAttribution: amateescu commentedThanks everyone for the interest in this issue :)
Re #26:
Those access checks have to brought back in the controller, not in the selection plugins.
Yes, I already said above I'm waiting until architectural reviews are done.
entity_reference_autocomplete
provides one for element for each field value, whileentity_reference_autocomplete_tags
provides a single element for all values.Done.
Yup, I just need to figure out how the fapi documentation on d.o works. Feel free to open the issue though :)
Done, #autocreate is now NULL by default and it's expected to be an array. Still not sure where to document this...
Re #27:
I just tried now, it doesn't work.
Fixed.
I'm a bit surprised that it works, but it's done :)
Re #28:
That's just the name of the widget. Also, tagging does not imply "autocreate non-existing items" :)
Why not, done.
Nope, that was part of the autocomplete path before, but not anymore.
Because I don't know another way of passing a PHP array as part of the autocomplete path / url :)
Have you forgotten D7 already? :P Removed that part, it wasn't needed anymore since #2107243: Decouple entity reference selection plugins from field definitions.
Sure, improved that doc a bit.
Comment #30
webchickNot positive, but I believe this blocks #2416987: Fix UI regression in the menu link form, making this critical as well.
Comment #31
andypostAlso this could be backported to https://www.drupal.org/project/references_dialog
Comment #32
amateescu CreditAttribution: amateescu commentedAdded full test coverage for the form element... I think we should be pretty much done here :)
Comment #33
amateescu CreditAttribution: amateescu commentedInterdiff requested by @dawehner on IRC.
Comment #35
amateescu CreditAttribution: amateescu commentedSilly me.
Comment #36
Dave ReidJust throwing this out there in case someone is interested: it would also be nice if the element could support a #bundles property, or even a select list before the autocomplete allowing me to narrow down the available options to autocomplete by individual bundles. Also, does this work with UUIDs?
Comment #37
dawehner@Dave Reid
Yet another thing to discuss about in #2353611: Make it possible to link to an entity by UUID :)
Note: I did some manual testing and it worked exactly as expected out of the box.
Nitpick, afaik we use absolute class (so with namespace)
It would be so great to have a core.routing.yml file, just saying, but totally out of scope of this issue.
Comment #38
amateescu CreditAttribution: amateescu commentedFixed the Request namespace and added an issue to the last @todo remaining in the patch: #2418249: Consider improving the DX of #default_value for the entity_autocomplete form element.
@Dave Reid:
That's already supported. You can provide a 'target_bundles' option to the 'default' selection handler:
@dawehner:
Yep, I tried to do that but it doesn't work. Let's open an issue for it though.
Comment #39
YesCT CreditAttribution: YesCT commentedI looked at the interdiff. should still be rtbc.
Comment #40
jibranI know it is blocking menu work but I'd like to wait for @yched review. Can we please hold RTBC till then?
Comment #41
webchickYeah, I think that's fine. It's only holding up #2418017: Implement autocomplete UI for the link widget and we can review the parts of that patch that are not this one in the meantime.
Notes from my (non-exhaustive) review:
1) We still need a change record. It needs to note that this new field is now available, and a before/after example on how to use it. From http://privatepaste.com/a6b5659a7f:
2) It seems like core/lib/Drupal/Core/Entity/Element/EntityAutocomplete.php should have this type of documentation and currently does not. I guess #1617948: [policy for now] New standard for documenting form/render elements and properties is still outstanding so we haven't yet agreed on the proper way to do this. Maybe ask jhodgdon/timplunkett their thoughts?
3) This patch itself doesn't contain any conversions, which is a little odd because normally we would do at least one. However, given #2418017: Implement autocomplete UI for the link widget does and hopefully will land within a few days, I think that's fine and we can extrapolate from there:
So the default DX here looks pretty simple. We had discussed on IRC that in a follow-up we should talk about allowing #target_type to optionally accept an array of valid types.
Comment #42
webchickMaking that explicit, though that shouldn't stop anyone else from reviewing too. :)
Comment #43
alexpottEntity is missing a t
inexistent
isnonexistent
Comment #44
yched CreditAttribution: yched commentedWill try to review tonight :-)
Comment #45
Wim LeersI can only find one nit that hasn't already been found. Looking forward to yched's review :)
We could typehint
&$element
and&$complete_form
toarray
here.Comment #46
amateescu CreditAttribution: amateescu commentedRe #43:
Drupal\system\Tests\Entity\EntityReferenceSelection\EntityReferenceSelectionAccessTest
Fixed #45 too :)
@webchick:
Note that there is actually a conversion in the patch, the ER autocomplete widgets are converted to use this new element otherwise they wouldn't work anymore. See this hunk:
Comment #47
jibranOk I have done some manual testing. This testing was done after applying the patch and a fresh Drupal install.
AutocompleteWidget
is working fine.Then I change the term ER field to
AutocompleteTagsWidget
and unlimited cardinalityI created a new node with two tags works fine.
I went to edit the field. It was populated correctly
I removed both tags and added new tag
I previewed the node.
I pressed back to content editing page. The field was still populated by new tag.
I clicked view tab on node
I clicked edit tab and saw new tag instead of original tags.
Comment #48
yched CreditAttribution: yched commentedLooking at the last screenshot in #47 just above:
On edit of a field with pre-existing values, shouldn't we populate #default_value with the disambiguating "(entity_id)" at the end ?
That's what ER autocomplete widget currently does in HEAD.
Comment #49
amateescu CreditAttribution: amateescu commented@yched, I think that's a new tag, so an unsaved entity.
@jibran, can you please try the same scenario in HEAD without the patch applied?
Comment #50
yched CreditAttribution: yched commentedPatch is awesome, beautifully documented and commented, @amateescu+++++++++
A couple questions / nitpicks below, none of them are blocking, except maybe the first one.
Yay for the widgets in Core !
If those move from e_r.module into the large-ish "all field types" bucket in Drupal/Core/Field/Plugin/Field/FieldWidget, we should probably rename the classes to *Entity*Autocomplete, they are not "generic autocomplete" widgets.
Also - does this mean a couple modules can stop depending on e_r.module ?
(actually, wondering what's left in e_r.module now :-p)
#autocreate is now an array of data, would it make sense for '#selection_*' as well ?
Wondered about that, and the ER widgets provide a nice explanation, but that is potentially dangerous.
is there a place we can document the do's and don'ts about that property on the FAPI element ? Like "only set to FALSE if proper validation by the selection handler is performed at another level on the extracted form values" or something.
Maybe at least here in the Element's getInfo(), if nowhere else ?
Similarly, maybe reversing the bool and naming it '#skip_reference_validation' would make it sound a bit scarier ?
Isn't it weird that we Tags::explode() regardless of $element['#tags'] ? What if a non-tag-style autocomplete contains a node title that includes a comma ?
Is that reference still relevant ? Just wondering - ER fields are now just one use case now, other direct consumers of the new FAPI element will need to handle that 'entity' themselves, right ?
Means you're forced to provide an #autocreate['uid'] even for an autocomplete on an entity type that is not an EntityOwnerInterface ?
Maybe we can just default to anon if no #autocreate['uid'] is provided ?
JS leak ? ;-)
And a lot others : yay, those made little sense on the non-tag widget :-)
Uber-nitpick, feel free to ignore :-)
In the context of the "EntityAutoCompleteController", we could be less verbose on the var and property names, "matcher" would work fine IMO.
@group needs updating ?
Also, not sure what's the split between that test being moved around from entity_ref.module, and the newly added EntityAutocompleteElementFormTest, don't they both test the generic 'entity_autocomplete' element now ?
The Return of Uber-nitpick: property name mismatch ? If the interface is SelectionPluginManager, the property could be selectionManager ? Not sure where we stand on naming around selection plugins :-)
Comment #51
amateescu CreditAttribution: amateescu commented@yched, I knew we could count on you to point out every possible nitpick :D
Sorry if this comment looks a bit rushed, the previous version was much longer but d.o decided to not post it..
Drupal\Core\Render\Element\PathElement
is doing with its#validate_path
property. But until we can document it properly on api.d.o, I included your comment there.Tags::encode()
on every label inEntityAutocompleteMatcher
:)EntityAutocomplete::processEntityAutocomplete()
.Comment #52
amateescu CreditAttribution: amateescu commentedWhaaaaat, d.o ate my comment :((
Edit: oh well, I wrote it again.
Comment #53
yched CreditAttribution: yched commentedThanks for the replies @amateescu.
Works for me, pending the possible issue in #48 / #49 (sorry, can't test myself, my local install seems broken atm)
Comment #54
jibranThis is the bug in HEAD :(. I'll try to create a test-only patch for this bug in a follow up bug report.
That is correct.
We still need a follow up for this .
Thank you @webchick for holding the RTBC. Thank you @yched for the review. And thank you @amateescu for awesome work on the patch. I have created an issue #2411981: Fixes after generic 'entity_autocomplete' Form API element for DER to cope with these core changes please help us find the correct solution there. Thank you all for reviews.
RTBC +1.
Comment #55
yched CreditAttribution: yched commented@jibran :
Not sure we're clear here.
The referenced entity was "new" when you typed its name in the ER widget in the containing node and submitted the form. Then it was created and saved during the node save.
Next time you edit the containing node, the referenced entity is not "new" anymore, it's a regular case of "existing node references existing entity", and it should appear as "Title (id)" in the widget #default_value.
That's what happens in HEAD currently (tested it yesterday night), but the last screenshot in your #47 seems to indicate it's not the case with the patch ?
(again, sorry, can't test it myself right now, I will tonight)
Comment #56
jibranYeah that is bug.
Steps to reproduce:
Comment #57
amateescu CreditAttribution: amateescu commentedThanks, it's much easier to follow the steps presented like this without the distracting images. I can confirm the bug in HEAD, so it's not related to this patch.
It also happens with the taxonomy reference field in HEAD, so this is actually a general problem with the node preview functionality. I'm guessing that we're not clearing whatever is in temp store when we come back from preview to the edit form.
Comment #58
Wim LeersI found one more problem: this autocomplete unfortunately autocompletes even nodes that are not accessible by the current user. This will violate the information disclosure policy we currently have for the link widget in HEAD, where we carefully made sure to not ever expose whether a path exists or not, and definitely never tell the user that a certain entity exists, let alone disclose its title.
Perhaps that's a pre-existing problem in ER autocomplete in HEAD, but I think it's worth un-RTBC'ing this for — I find that very sad too btw :( — because we should at least have a discussion about this.
Comment #59
Wim LeersMeant to un-RTBC.
And looked at the patch:
This is removed, but not added. So it's a newly introduced bug. And it means we have no test coverage for it.
No such access checking in here.
Comment #60
amateescu CreditAttribution: amateescu commentedI signaled the same thing in #23 and I agree it needs to be solved somehow.
But are you sure about autocompleting nodes that are not accessible to the current user? Selection handlers should already take care of that.
I can take a look in a few hours :)
Comment #61
Wim LeersAbsolutely certain, I'm afraid.
I created article node 1. Then created user 2 who couldn't access nodes (removed the
access content
permission from the "authenticated user" role). Verified by doingvar_dump(Node::load(1)->access('view'))
, which printed TRUE for user 1, FALSE for user 2. Yet user 2 did get it in the autocomplete. Also after adrush cr
.Yay! :)
Comment #62
amateescu CreditAttribution: amateescu commentedI looked into it and the problem found in #58 has nothing to do with #59/#23, so I opened a separate issue: #2419923: Port SA-CONTRIB-2013-096 to D8
Comment #63
Wim LeersAlright, that addresses my concern. Thank you! Back to RTBC! :)
Comment #64
Wim LeersActually, more than that: this patch (#51) is included in the patch at #2418017: Implement autocomplete UI for the link widget (because that issue is blocked on this one), and it's been working splendidly. Zero complaints.
Comment #66
amateescu CreditAttribution: amateescu commentedRerolled.
Comment #67
webchickI already looked at this the other day and it looks like it only got more awesome since then. :) Change record looks good.
Committed and pushed to 8.0.x. Thanks!
Comment #69
yched CreditAttribution: yched commentedCongrats @amateescu !
We still need a followup for #56 / #57 ?
Comment #70
jibranSee #2421263: Potential data loss: concurrent (i.e. by different users) node edits leak through preview for #56.
Comment #71
amateescu CreditAttribution: amateescu commented@jibran, I don't see how that issue is related. The only similarity is that both bugs are related to the node preview functionality.
I opened #2421581: Node preview causes stale values to be kept indefinitely for exisiting nodes to fix #56.
Comment #72
jibranThanks @amateescu.
Comment #73
amateescu CreditAttribution: amateescu commentedStarted working on converting stuff to this new form element, the first issue is here: #2428881: Remove TermAutocompleteController::autocompletePerVid()
Comment #74
amateescu CreditAttribution: amateescu commentedNext one: #2428941: Update the Node views wizard to use 'entity_autocomplete' for the "tagged_with" field
Comment #75
amateescu CreditAttribution: amateescu commentedAnd the last: #2434697: Remove UserAutocompleteController
Edit: This one also fixes #50.4. The fact that core was doing it that way doesn't mean that we shouldn't improve it :)