hey! i came across this same behavior this weekend, it delayed the launch of a website as my views depended on this great module.
Has anyone found out what is causing this? it is strange to have a not required check box that worked only as admin... unless i am missing something. I've tried filtering out the empty references but still only display as admin.
thanks.
It looks like content access module is the culprit. once i disable the module, everything works fine. I now uninstall the module and looking for a access control module that works well with this great module.
- 🇫🇷France Damien Tournoud
Entity Reference and Views both respect access control now. Check your access control configuration.
- 🇺🇸United States that0n3guy
I'm having this issue, but only when using content access module. I am using entity relationship 7.x-1.x-dev and views 3.0, content access dev.
I have a topic type and alert type. Alert types reference topic types. The exported view below shows topic content types and uses the "Entity Reference: Referencing entity" so I can get a count of alerts referencing the topic.
When a non-user1 user looks at this view: http://pastebin.com/1BBBeg6j , the user does NOT see all the topics he should. He only see's topics that have alerts referencing them. If the topic doesn't have alerts, it should still show (as it does when using user1) but with a blank in the number of alerts column, but instead that topic just isn't shown.
If I remove the relationship from the view. It will show all the topics to non-user1 users.
- 🇩🇰Denmark Morten Najbjerg
Anyone found a solution? I'm not using the Content Access module but am experiencing the same problem using OG-7.x-.2.x
- 🇫🇷France jygastaud
You can try in your view -> advanced setting -> query settings - to check to box “Disable SQL rewriting“.
I have the same problem here when using Domain Access. The 'Disable SQL rewriting' option gave me the desired results.
- 🇪🇸Spain aleix
What about if I want a view in a organic group context and the group content visibility ( public | private ) to be respected? It's not if sql rewrite option is marked (as it's adviced) ... I think it's working forever as "require this relationship".
- 🇦🇺Australia Alan D.
Actually, AFAICK, this is a bug report. However, if it is for this module, views or every module that implements the access control is another matter.
An optional relationship should have
(X IS NULL OR X IN (a,b,c))
.'Disable SQL rewriting' is not a solution.
It is interesting to note that the core Term references (basic forward relationships) does not use a views relationship and the access control is not triggered.
- 🇺🇸United States xjm
I've just confirmed this bug. Steps to reproduce:
- Install D7.14 with the standard profile.
- Install ctools, views, views_ui, entity, entityreference.
- Add an entityreference field to the article node type that references nodes, page bundle, with other settings as defaults.
- Create a page node.
- Create two article nodes, one that references the the page node, and the other with the reference field blank.
- Create a view of article nodes with a page display.
- Add a relationship for
Entityreference: Referenced entity
. Do not check "require this relationship". No need to add any fields using the relationship.- Visit the page display as uid 1. Both articles are listed. Query:
/* DEBUG VIEW QUERY */ SELECT node.title AS node_title, node.nid AS nid, node.created AS node_created FROM node node LEFT JOIN field_data_field_page field_data_field_page ON node.nid = field_data_field_page.entity_id AND (field_data_field_page.entity_type = :views_join_condition_0 AND field_data_field_page.deleted = :views_join_condition_1) LEFT JOIN node node_field_data_field_page ON field_data_field_page.field_page_target_id = node_field_data_field_page.nid WHERE (( (node.status = :db_condition_placeholder_2) AND (node.type IN (:db_condition_placeholder_3)) )) ORDER BY node_created DESC LIMIT 10 OFFSET 0
- Visit the page display as an anonymous user. Both articles are listed. Query:
/* DEBUG VIEW QUERY */ SELECT node.title AS node_title, node.nid AS nid, node.created AS node_created FROM node node LEFT JOIN field_data_field_page field_data_field_page ON node.nid = field_data_field_page.entity_id AND (field_data_field_page.entity_type = :views_join_condition_0 AND field_data_field_page.deleted = :views_join_condition_1) LEFT JOIN node node_field_data_field_page ON field_data_field_page.field_page_target_id = node_field_data_field_page.nid WHERE (( (node.status = :db_condition_placeholder_2) AND (node.type IN (:db_condition_placeholder_3)) )) ORDER BY node_created DESC LIMIT 10 OFFSET 0
- Visit the page display as uid 1. Both articles are listed. Query:
- Install any node access module, e.g. TAC, and rebuild permissions. No need to configure it; just allow full access to everything.
- Visit the page display as uid 1. Both articles are listed. Query:
/* DEBUG VIEW QUERY */ SELECT node.title AS node_title, node.nid AS nid, node.created AS node_created FROM node node LEFT JOIN field_data_field_page field_data_field_page ON node.nid = field_data_field_page.entity_id AND (field_data_field_page.entity_type = :views_join_condition_0 AND field_data_field_page.deleted = :views_join_condition_1) LEFT JOIN node node_field_data_field_page ON field_data_field_page.field_page_target_id = node_field_data_field_page.nid WHERE (( (node.status = :db_condition_placeholder_2) AND (node.type IN (:db_condition_placeholder_3)) )) ORDER BY node_created DESC LIMIT 10 OFFSET 0
- Visit the page display as an anonymous user. The article with an empty reference field has disappeared. Query:
/* DEBUG VIEW QUERY */ SELECT node.title AS node_title, node.nid AS nid, node.created AS node_created FROM node node LEFT JOIN field_data_field_page field_data_field_page ON node.nid = field_data_field_page.entity_id AND (field_data_field_page.entity_type = :views_join_condition_0 AND field_data_field_page.deleted = :views_join_condition_1) LEFT JOIN node node_field_data_field_page ON field_data_field_page.field_page_target_id = node_field_data_field_page.nid WHERE (( (node.status = :db_condition_placeholder_2) AND (node.type IN (:db_condition_placeholder_3)) ))AND ( EXISTS (SELECT na.nid AS nid FROM node_access na WHERE (( (na.gid = :db_condition_placeholder_4) AND (na.realm = :db_condition_placeholder_5) )OR( (na.gid = :db_condition_placeholder_6) AND (na.realm = :db_condition_placeholder_7) ))AND (na.grant_view >= :db_condition_placeholder_8) AND (node.nid = na.nid) )) AND ( EXISTS (SELECT na.nid AS nid FROM node_access na WHERE (( (na.gid = :db_condition_placeholder_9) AND (na.realm = :db_condition_placeholder_10) )OR( (na.gid = :db_condition_placeholder_11) AND (na.realm = :db_condition_placeholder_12) ))AND (na.grant_view >= :db_condition_placeholder_13) AND (node_field_data_field_page.nid = na.nid) )) ORDER BY node_created DESC LIMIT 10 OFFSET 0
- Visit the page display as uid 1. Both articles are listed. Query:
- Edit the view and remove the relationship.
- Visit the page display as uid 1. Both articles are listed. Query:
/* DEBUG VIEW QUERY */ SELECT node.title AS node_title, node.nid AS nid, node.created AS node_created FROM node node WHERE (( (node.status = :db_condition_placeholder_0) AND (node.type IN (:db_condition_placeholder_1)) )) ORDER BY node_created DESC LIMIT 10 OFFSET 0
- Visit the page display as an anonymous user. Both articles are listed. Query:
/* DEBUG VIEW QUERY */ SELECT node.title AS node_title, node.nid AS nid, node.created AS node_created FROM node node WHERE (( (node.status = :db_condition_placeholder_0) AND (node.type IN (:db_condition_placeholder_1)) ))AND ( EXISTS (SELECT na.nid AS nid FROM node_access na WHERE (( (na.gid = :db_condition_placeholder_2) AND (na.realm = :db_condition_placeholder_3) )OR( (na.gid = :db_condition_placeholder_4) AND (na.realm = :db_condition_placeholder_5) ))AND (na.grant_view >= :db_condition_placeholder_6) AND (node.nid = na.nid) )) ORDER BY node_created DESC LIMIT 10 OFFSET 0
- Visit the page display as uid 1. Both articles are listed. Query:
- 🇺🇸United States antiorario
Might be a bug in Views. I'm using the References module, not Entity reference, and I have the same problem. I'm also using Node Access User Reference and Node Access Node Reference for access control.
- 🇺🇸United States freelock Seattle
We've hit this bug, too. Twice in two weeks, actually -- and the first time was in Drupal 6/Views 2! I just confirmed through debugging that it's a result of any node access module getting enabled -- the views query gets altered to look in the node_access table for the base table and the table of any relationship.
I think Alan D has the correct solution -- Disable SQL rewriting is a poor workaround that might open up other problems, the real answer is to make the node access query use an OR X IS NULL query when checking node access on optional relationship tables.
And here's where it's getting mis-applied (Drupal 7.14):
node.module, in function _node_query_node_access_alter($query, $type) (definition starts at line 3183).
Line 3311 seems to be where we need to fix:
$subquery->where("$nalias.$field = na.nid"); $query->exists($subquery);
At that point, $tableinfo['join type'] is set to 'LEFT' whereas the base table has that set to null. I'm not familiar with the EXISTS SQL statement -- I think this needs to get rewritten to not use exists and add an or condition where ("$nalias.$field" IS NULL).
- 🇺🇸United States xjm
- 🇺🇸United States xjm
Oh, and I am not considering this a security issue because we are displaying less data than we should, not more data than we should.
- 🇺🇸United States xjm
And maybe this is a duplicate of the never-dying #1222324: Fix query access control on relationships (comments) → .
- 🇺🇸United States freelock Seattle
@xjm I believe this is a core bug, not a views bug -- Views just happens to trigger it. Moving issue to Drupal core.
The problem is that _node_query_node_access_alter in node.module does not properly apply node access permissions to related tables, when the join type is set to LEFT -- it should allow null values as well as values in the node_access table.
Views is properly setting the join type.
- 🇺🇸United States rbruhn
I've ran into this issue as well and the only access control module I'm using is OG.
Logging MySql queries I receive the following:SELECT node.title AS node_title, node.nid AS nid, node.created AS node_created FROM drupal_node node LEFT JOIN drupal_field_data_standard_image field_data_standard_image ON node.nid = field_data_standard_image.entity_id AND (field_data_standard_image.entity_type = 'node' AND field_data_standard_image.deleted = '0') LEFT JOIN drupal_node node_field_data_standard_image ON field_data_standard_image.standard_image_target_id = node_field_data_standard_image.nid WHERE (( (node.nid = '2343' ) )AND(( (node.status = '1') AND (node.type IN ('bir_album')) )))AND ( EXISTS (SELECT na.nid AS nid FROM drupal_node_access na WHERE (( (na.gid = '0') AND (na.realm = 'all') ))AND (na.grant_view >= '1') AND (node.nid = na.nid) )) AND ( EXISTS (SELECT na.nid AS nid FROM drupal_node_access na WHERE (( (na.gid = '0') AND (na.realm = 'all') ))AND (na.grant_view >= '1') AND (node_field_data_standard_image.nid = na.nid) )) ORDER BY node_created DESC
This is a simple view using node Album with Entity Reference (standard_image) to an Image node. As can be seen, the node access checks the permissions for the standard_image node. The problem is, there are times the standard_image is non-existent for a given Album. The only way to make it work in my case would be to make the standard_image field required. As soon as I add a standard_image, it works fine.
- 🇺🇸United States xjm
The problem is that _node_query_node_access_alter in node.module does not properly apply node access permissions to related tables, when the join type is set to LEFT -- it should allow null values as well as values in the node_access table.
This sounds quite dangerous to me; a little voice in the back of my head is muttering "access bypass". I'm not convinced that is a correct solution. The query is tagged and views can alter it as needed.
If it's a core bug, let's get a test case demonstrating a non-views path to reproduce this.
- 🇺🇸United States freelock Seattle
@rbruhn your query illustrates the problem, right here:
EXISTS (SELECT na.nid AS nid FROM drupal_node_access na WHERE (( (na.gid = '0') AND (na.realm = 'all') ))AND (na.grant_view >= '1') AND (node_field_data_standard_image.nid = na.nid) )
If there are no image nodes returned in the main query, node_field_data_standard_image.nid will be null, and this subquery won't return any rows. This will filter out the album row.
The query object passed into the _node_query_node_access_alter has a join type set to LEFT for that table, but that's ignored and the access check basically makes it so the relationship is not optional.
- 🇺🇸United States freelock Seattle
@xjm fixing this shouldn't lead to an access bypass -- as you stated earlier, the current behavior is to filter too much out, and addressing this in the node access system should make it work correctly.
The node access query should only be changed for subqueries with a join type of LEFT -- the base table has a null join type, and for that case you would expect a row in the node_access table.
Building a test case for this looks like involves creating a PDO query with a left joined table, and tagging it for node_access, which will invoke the hook_query_TAG_alter for core node_access, node_query_node_access_alter.
- 🇺🇸United States xjm
@agentrickard pointed me at #1422040: Use leftJoin when base table uses a leftJoin → also.
- 🇺🇸United States agentrickard Georgia (US)
I'm not sure how core can be expected to adapt to this kind of complex, dynamic query. Looking at the MySQL JOIN documentation, I think the burden here is in the JOIN condition, not the WHERE clause behavior:
The conditional_expr used with ON is any conditional expression of the form that can be used in a WHERE clause. Generally, you should use the ON clause for conditions that specify how to join tables, and the WHERE clause to restrict which rows you want in the result set.
See: https://dev.mysql.com/doc/refman/5.0/en/join.html
By that logic, the proper fix here is to have Views add an ON condition when using a relationship:
/* DEBUG VIEW QUERY */ SELECT node.title AS node_title, node.nid AS nid, node.created AS node_created FROM node node LEFT JOIN field_data_field_page field_data_field_page ON node.nid = field_data_field_page.entity_id AND (field_data_field_page.entity_type = :views_join_condition_0 AND field_data_field_page.deleted = :views_join_condition_1) LEFT JOIN node node_field_data_field_page ON (field_data_field_page.field_page_target_id = node_field_data_field_page.nid OR field_data_field_page.field_page_target_id IS NULL) WHERE (( (node.status = :db_condition_placeholder_2) AND (node.type IN (:db_condition_placeholder_3)) ))AND ( EXISTS (SELECT na.nid AS nid FROM node_access na WHERE (( (na.gid = :db_condition_placeholder_4) AND (na.realm = :db_condition_placeholder_5) )OR( (na.gid = :db_condition_placeholder_6) AND (na.realm = :db_condition_placeholder_7) ))AND (na.grant_view >= :db_condition_placeholder_8) AND (node.nid = na.nid) )) AND ( EXISTS (SELECT na.nid AS nid FROM node_access na WHERE (( (na.gid = :db_condition_placeholder_9) AND (na.realm = :db_condition_placeholder_10) )OR( (na.gid = :db_condition_placeholder_11) AND (na.realm = :db_condition_placeholder_12) ))AND (na.grant_view >= :db_condition_placeholder_13) AND (node_field_data_field_page.nid = na.nid) )) ORDER BY node_created DESC LIMIT 10 OFFSET 0
And given that this query is built largely by Views, it would be exceedingly onerous for core to try to unpack the query structure in order to insert the proper ON conditional.
- 🇺🇸United States agentrickard Georgia (US)
That said, the above query may still return zero rows.
- 🇺🇸United States agentrickard Georgia (US)
And we have debunked that approach in IRC. The problem is that both NID references are being run against node access, and one of them is returning NULL from the LEFT JOIN.
- 🇺🇸United States rbruhn
@agentrickard - You maybe right in that it can't be handled.
A relationship that is not required in Views creates a left join. If the value does not exist, and some node_access check is done, the row will not be returned due to the where clause. If the check on node_access is a left join, it's not really going to give you anything worthwhile. Meaning, it's not restricting anything even if there is a value existing in the relationship.
I imagine if someone creates an entity relationship, and that value exists, of course they would want to know if the user viewing has access to it. I'm not sure if there is a way in a where clause to say, "do not return this row if a user does not have access base on that left join... but oh ya... if the value in the left join is null go ahead and show the row."
- 🇺🇸United States agentrickard Georgia (US)
Here's the only query variant that I could make work. I am replicating xjm's test, using Domain Access.
* 2 Article nodes
* 1 node is referenced to a Page nodeWe want 2 rows to be returned.
Initial query from Views: returns zero rows
SELECT node.created AS node_created, node.nid AS nid, node_field_data_field_reference.nid AS field FROM node node LEFT JOIN field_data_field_reference field_data_field_reference ON node.nid = field_data_field_reference.entity_id AND (field_data_field_reference.entity_type = 'node' AND field_data_field_reference.deleted = '0') LEFT JOIN node node_field_data_field_reference ON field_data_field_reference.field_reference_target_id = node_field_data_field_reference.nid WHERE ( ( (node.status = '1') AND (node.type IN ('article')) )) AND ( EXISTS (SELECT na.nid AS nid FROM node_access na WHERE (( (na.gid = '0') AND (na.realm = 'all') )OR( (na.gid = '0') AND (na.realm = 'domain_site') )OR( (na.gid = '1') AND (na.realm = 'domain_id') ))AND (na.grant_view >= '1') AND (node.nid = na.nid) )) AND ( EXISTS (SELECT na.nid AS nid FROM node_access na WHERE (( (na.gid = '0') AND (na.realm = 'all') )OR( (na.gid = '0') AND (na.realm = 'domain_site') )OR( (na.gid = '1') AND (na.realm = 'domain_id') ))AND (na.grant_view >= '1') AND (node_field_data_field_reference.nid = na.nid) )) ORDER BY node_created DESC LIMIT 10 OFFSET 0
Working query: returns 2 rows
SELECT node.created AS node_created, node.nid AS nid, node_field_data_field_reference.nid AS field FROM node node LEFT JOIN field_data_field_reference field_data_field_reference ON node.nid = field_data_field_reference.entity_id AND (field_data_field_reference.entity_type = 'node' AND field_data_field_reference.deleted = '0') LEFT JOIN node node_field_data_field_reference ON field_data_field_reference.field_reference_target_id = node_field_data_field_reference.nid WHERE ( ( (node.status = '1') AND (node.type IN ('article')) )) AND ( EXISTS (SELECT na.nid AS nid FROM node_access na WHERE (( (na.gid = '0') AND (na.realm = 'all') )OR( (na.gid = '0') AND (na.realm = 'domain_site') )OR( (na.gid = '1') AND (na.realm = 'domain_id') ))AND (na.grant_view >= '1') AND (node.nid = na.nid) )) AND ( EXISTS (SELECT na.nid AS nid FROM node_access na LEFT JOIN field_data_field_reference ON na.nid = field_data_field_reference.entity_id WHERE field_data_field_reference.entity_id IS NULL OR (( (na.gid = '0') AND (na.realm = 'all') )OR( (na.gid = '0') AND (na.realm = 'domain_site') )OR( (na.gid = '1') AND (na.realm = 'domain_id') ))AND (na.grant_view >= '1') AND (node_field_data_field_reference.nid = na.nid) )) ORDER BY node_created DESC LIMIT 10 OFFSET 0
This suggests that any {node_access} subquery has to be LEFT JOINed any related table, so that we can check IS NULL.
- 🇺🇸United States agentrickard Georgia (US)
And the problem with that approach is that query_alter has no knowledge of how to JOIN the table to the node_access table.
- 🇺🇸United States agentrickard Georgia (US)
Brief chat with @freelock and it turns out my query was failing because the _referenced node_ was not visible to the current user. So this query "works" now that it is:
SELECT node.created AS node_created, node.nid AS nid, node_field_data_field_reference.nid AS field FROM node node LEFT JOIN field_data_field_reference field_data_field_reference ON node.nid = field_data_field_reference.entity_id AND (field_data_field_reference.entity_type = 'node' AND field_data_field_reference.deleted = '0') LEFT JOIN node node_field_data_field_reference ON field_data_field_reference.field_reference_target_id = node_field_data_field_reference.nid WHERE ( ( (node.status = '1') AND (node.type IN ('article')) )) AND ( EXISTS (SELECT na.nid AS nid FROM node_access na WHERE (( (na.gid = '0') AND (na.realm = 'all') )OR( (na.gid = '0') AND (na.realm = 'domain_site') )OR( (na.gid = '1') AND (na.realm = 'domain_id') ))AND (na.grant_view >= '1') AND (node.nid = na.nid) )) AND (node_field_data_field_reference.nid IS NULL OR ( EXISTS (SELECT na.nid AS nid FROM node_access na WHERE (( (na.gid = '0') AND (na.realm = 'all') )OR( (na.gid = '0') AND (na.realm = 'domain_site') )OR( (na.gid = '1') AND (na.realm = 'domain_id') ))AND (na.grant_view >= '1') AND (node_field_data_field_reference.nid = na.nid) ))) ORDER BY node_created DESC LIMIT 10 OFFSET 0
- 🇺🇸United States agentrickard Georgia (US)
However, I see no valid reason why we should be checking the node access status of the referenced entity when building a list of nodes.
- 🇺🇸United States freelock Seattle
Ok, as discussed on IRC, the test case in #32 is not working quite as expected, because the page node being referenced did not have an entry in the node_access table. So the expected result should be 1 row returned -- the row with no referenced page.
This illustrates a corner case that I'm not sure we want to solve, because we don't have enough information in the query object to do a join any other way.
So let me restate a couple different test case scenarios:
Case A:
* 2 article nodes, nid 9 and 12
* 1 page node, nid 13, related to nid 12
* User has access (entries in node_access table) for all 3 nodes
* Expected result: 2 rows, the row for nid 9 having null values for the referenced fields
* Actual result, currently: 1 row, row 12 with the related fields from node 13Case B: (AgentRickard's original results)
* 2 article nodes, nid 9 and 12
* 1 page node, nid 13, related to nid 12
* User only has access to article nodes, but does not have access to node 13
* Expected result: ? (I would expect 2 rows with null columns for both rows, but don't see how we can get there without entirely rewriting the parent query).
* Actual result: 0 rows (row with optional relationship blocked by null value, row with denied page relationship blocked by node access)
* Proposed result: 1 row (node 9, with null values for the referenced fields -- if we allow the row with node 12 to come through, it would be an access bypass vulnerability exposing data from the blocked node 13)I think this query will achieve the proposed result, and address the issues in case A:
SELECT node.created AS node_created, node.nid AS nid, node_field_data_field_reference.nid AS field FROM node node LEFT JOIN field_data_field_reference field_data_field_reference ON node.nid = field_data_field_reference.entity_id AND (field_data_field_reference.entity_type = 'node' AND field_data_field_reference.deleted = '0') LEFT JOIN node node_field_data_field_reference ON field_data_field_reference.field_reference_target_id = node_field_data_field_reference.nid WHERE ( ( (node.status = '1') AND (node.type IN ('article')) )) AND ( EXISTS (SELECT na.nid AS nid FROM node_access na WHERE (( (na.gid = '0') AND (na.realm = 'all') )OR( (na.gid = '0') AND (na.realm = 'domain_site') )OR( (na.gid = '1') AND (na.realm = 'domain_id') ))AND (na.grant_view >= '1') AND (node.nid = na.nid) )) AND ( EXISTS (SELECT na.nid AS nid FROM node_access na WHERE (( (na.gid = '0') AND (na.realm = 'all') )OR( (na.gid = '0') AND (na.realm = 'domain_site') )OR( (na.gid = '1') AND (na.realm = 'domain_id') ))AND (na.grant_view >= '1') AND (node_field_data_field_reference.nid = na.nid) ) OR field_data_field_reference.entity_id IS NULL) ORDER BY node_created DESC LIMIT 10 OFFSET 0
That last OR clause should only be added if the join type of the table in the query is LEFT.
- 🇺🇸United States freelock Seattle
@agentrickard in #35, I think it's reasonable in a node_access rewrite to block any access to a node a user does not have permission to view -- here's a use case:
Project management tool
* Project A
** Case AA <- Client can see this
** Case AB <- Private case hidden from client* Project B
(no cases)* Project C
** Case CA <- private caseIn this case, a view of all open cases across projects, that uses projects as the base type and cases as a relationship, this access check would filter Case AB out of the result set when clients view it.
Before a patch, the client would see only Case AA under Project A, and would not see Project B or C.
After correcting the node access as proposed, the client would see Case AA under Project A and Project B with no cases. They would not see project C until a case was added to it that the client could access, or the private case removed.
- 🇺🇸United States agentrickard Georgia (US)
Well, here's a version that eliminates the secondary access query on the related node. Possibly not the final approach.
Also attached is a screen cap of the data passed to the alter query for each table, which shows we have two tables identified as $base_table, which I think is wrong. We should only be checking the node access status of the parent node. The fact that you can attached child nodes and see their fields in Views is not, perhaps, a core issue.
- 🇺🇸United States freelock Seattle
Ok, patch against 7.14, still haven't tested, not sure this is correct syntax for chaining together the conditions.
- 🇺🇸United States agentrickard Georgia (US)
$table['join type'] needs to be $tableinfo['join type']. If it is, I get this query (and one record):
SELECT node.title AS node_title, node.nid AS nid, node.language AS node_language, node_field_data_field_reference.title AS node_field_data_field_reference_title, node_field_data_field_reference.nid AS node_field_data_field_reference_nid, node_field_data_field_reference.language AS node_field_data_field_reference_language, node.created AS node_created FROM node node LEFT JOIN field_data_field_reference field_data_field_reference ON node.nid = field_data_field_reference.entity_id AND (field_data_field_reference.entity_type = 'node' AND field_data_field_reference.deleted = '0') LEFT JOIN node node_field_data_field_reference ON field_data_field_reference.field_reference_target_id = node_field_data_field_reference.nid WHERE (( (node.status = '1') AND (node.type IN ('article')) ))AND ( EXISTS (SELECT na.nid AS nid FROM node_access na WHERE (( (na.gid = '0') AND (na.realm = 'all') )OR( (na.gid = '0') AND (na.realm = 'domain_site') )OR( (na.gid = '1') AND (na.realm = 'domain_id') ))AND (na.grant_view >= '1') AND (node.nid = na.nid) )) AND( (node_field_data_field_reference.nid IS NULL ) OR ( EXISTS (SELECT na.nid AS nid FROM node_access na WHERE (( (na.gid = '0') AND (na.realm = 'all') )OR( (na.gid = '0') AND (na.realm = 'domain_site') )OR( (na.gid = '1') AND (na.realm = 'domain_id') ))AND (na.grant_view >= '1') AND (node_field_data_field_reference.nid = na.nid) )) ) ORDER BY node_created DESC LIMIT 10 OFFSET 0
- 🇺🇸United States agentrickard Georgia (US)
Here is @freelock's patch for D8.
- 🇺🇸United States agentrickard Georgia (US)
Re-roll of @freelock's patch against HEAD.
- 🇺🇸United States agentrickard Georgia (US)
Re-Roll of my patch against d8 HEAD.
- 🇺🇸United States rbruhn
#41 with the $tableinfo fix from #42 works in my particular circumstance.
- 🇺🇸United States xjm
Oopsie, 8.x HEAD is still broken, so we need to wait for #1445224: Add new HTML5 FAPI element: color → to be fixed (again).
- 🇺🇸United States agentrickard Georgia (US)
#46: 1349080-d8-do-not-double-join.patch queued for re-testing.
- 🇺🇸United States agentrickard Georgia (US)
@rbruhn "works" is a pretty subjective statement here and needs more detail.
The problem with the patch in 41/42/45 is that if you cannot access the attached node, it will deny access to the main node. I think that behavior is wrong.
- 🇺🇸United States rbruhn
@agentrickard - I was referring to the problem I saw and posted about earlier in the discussion. In that, when a relationship points to a non-existent node, the null value stops any results being returned. The patch fixed that.
In regards to still showing a result even if the user does not have access to the related node, I agree with you in that is the behavior desired. I've been playing around with queries to see what I can figure out.
- 🇺🇸United States freelock Seattle
@agentrickard, rbruhn, note that the query does not block access to the parent node entirely.
It only blocks access to the parent node iff all child nodes have blocked access. If there is another child node the user can access, the parent node will show up.
- 🇺🇸United States agentrickard Georgia (US)
@freelock That is an interesting distinction, but we have to consider the implications before changing core.
- 🇺🇸United States freelock Seattle
@agentrickard in my view this is fixing a bug, core node access is not working the way it's intended. And the corner case this does not address is easily understandable from a database point of view...
- 🇺🇸United States agentrickard Georgia (US)
That's where we disagree. I don't think core node access was ever intended to check the condition of two separate nodes in order to return a single node record. That's what the multiple $base_table invocations does.
The fact that not running the second check allows a JOIN to attach unrestricted data is, perhaps, a Views problem.
[EDIT: additional]
I would also say that if this were any module other than Views, my answer would be "Of course this fails. The queries are wrong. You can't check access to both the parent node and its child data in one query. You have to load the child data on separately."
In fact, if you use a 'content' display mode and not a 'field' display mode, this is what Views does, and it works correctly when using the "only allow a single node access JOIN" rule. The problem here is that Views is rather blindly adding field data to a query that is really asking "show me a list of nodes of condition X." It should not be asking "show me a list of nodes of condition X where an attached child node also meets condition X."
- 🇺🇸United States freelock Seattle
Well I would say that Views here is acting as a query builder, nothing more.
If you're developing with a database-oriented view, rather than an object oriented view, it's inane that a LEFT JOIN is not properly handled. Especially when it's specified in the query object passed in.
Looking at: http://api.drupal.org/api/drupal/includes%21database%21select.inc/functi... ... the database API explicitly supports doing LEFT OUTER queries. (Though I notice that Views is specifying this as LEFT, not LEFT OUTER).
It's perfectly valid sql to join a table multiple times, even as a self-join (though with Drupal's schema in practice there's nearly always an intervening table). In many cases you might want to explicitly look for a null value in the return of such a query.
The alternative here that you're asking module developers to do, is to do extra queries in code, most likely inside a loop.
If we're talking about something as small as 100 rows of parent objects, joined to 1,000 rows of child objects, without having a proper left join syntax, you're turning what could be done in a single query to now doing 101 queries. And if you have a thousand parents and 100 children, now you would have to do 1001 queries to get the same results as could be done in a single query for a left join. Because if this node_access function only handles the parents, you would need to do an additional query on each parent object to find the children your user can access.
Having node_access properly rewrite sql to block access to a node whenever it sees the node table seems like the entire purpose of this function.
If we only do that SOME of the time, then you're putting the burden on less-experienced contrib module developers to know that this function does not fully protect them, even if they tag their query with node_access. And so not only are you making it much easier to have a whole slew of access bypass issues, you are also forcing module developers to do multiple queries inside a loop to properly protect from that, making Drupal a horrible framework for doing basic fundamental database work. When the fix is 4 lines of code that puts the heavy lifting in the database where it belongs, this seems like a no-brainer to me.
- 🇺🇸United States freelock Seattle
It should not be asking "show me a list of nodes of condition X where an attached child node also meets condition X."
Why not?
That seems like a perfectly legitimate thing to do. And that case works perfectly well, right now.
The case that's broken is:
"show me a list of nodes of condition X where an attached child node also meets condition X OR there is no attached child node."
- 🇺🇸United States agentrickard Georgia (US)
And that's where we disagree, and rather strongly. The node access restriction should be applied to the question:
* Show me a list of nodes I can view. (e.g. All "article" nodes of access group "foo").
Not the question:
* Show me a list of nodes I can view that might also contain attached data from nodes that I can view. (e.g. All "article" nodes of access group "foo" that either have no attached data "bar" or whose "bar" is also in access group "foo".)
The second condition breaks the logic of generating the list. That is the core problem here, not JOIN syntax. The original query breaks because it tries to apply node access conditions twice, which is invalid because the logic is not trustworthy.
In security terms, we should never grant access to a node that does not have a record in the {node_access} table. The fact that the secondary condition adds this possibility means that the query logic is malformed, because it either a) routes around proper node access to attach data or b) improperly restricts valid access based on a secondary (and irrelevant) condition.
Check my last note which indicates this is only a problem with Views that rip Field data out of context. If you use a proper node_load() / entity_load() structure, yes, you get extra queries, but you get proper access controls. Extra queries are a side-effect of having granular access control rules; and a side-effect we've been comfortable with for a long time.
But I fear we're just arguing past each other at this point. We need to get more opinions here.
- 🇺🇸United States agentrickard Georgia (US)
For reference, look at
entityreference_field_formatter_prepare_view()
and how it checks access to an entity before attaching it to a standard node view. Views bypasses this step when using field output (but not when using content output.) - 🇺🇸United States tim.plunkett Philadelphia
The node access restriction should be applied to the question:
* Show me a list of nodes I can view. (e.g. All "article" nodes of access group "foo").
Not the question:
* Show me a list of nodes I can view that might also contain attached data from nodes that I can view. (e.g. All "article" nodes of access group "foo" that either have no attached data "bar" or whose "bar" is also in access group "foo".)
Yes, this. I agree 100%.
- 🇺🇸United States freelock Seattle
Eww. Really? entity_load the entire set and entity_access on each loaded entity inside a loop? No wonder Drupal is getting slower...
In security terms, we should never grant access to a node that does not have a record in the {node_access} table. The fact that the secondary condition adds this possibility means that the query logic is malformed, because it either a) routes around proper node access to attach data or b) improperly restricts valid access based on a secondary (and irrelevant) condition.
Hmm. Your fix causes a. My fix causes b. The status quo is an even more extreme version of b). And eliminating b entirely would entail a lot more query mangling than I think is reasonable to do.
Can you provide an example of how my fix would result in broken logic, aside from the known corner condition?
By my reading, this function is providing a valid sql clause that should properly restrict rows containing node data I cannot view.
Your fix would return rows with data I am not supposed to view -- if we're talking about security, your solution clearly reveals more information, returns more rows than mine does.
The current function additionally blocks rows with no child objects, even when they have no restricted data -- that's what my patch fixes.
Hmm. I wonder if there's enough data in the query object to move that access clause to the join? If that's in the query, it should be possible to apply the base node access clause to the entire query, and the secondary node access clause to the join clause, and solve both a and b.
The real world case I'm hitting does not seem uncommon -- organic groups, where generally people with access to the parent have access to all the children -- and a desire for some aggregate reports on hierarchical data. You don't want leaves of the hierarchy just disappearing on you, and generally the access rules are the same for the entire tree.
This function already does a good job of only allowing access to node data you can view. Why can't we fix the case where it goes too far? Why burden module developers with having to load entities and run them through access checks when this function is entirely capable of doing it for them, far more reliably?
- 🇺🇸United States freelock Seattle
Hmm. I wonder if there's enough data in the query object to move that access clause to the join? If that's in the query, it should be possible to apply the base node access clause to the entire query, and the secondary node access clause to the join clause, and solve both a and b.
At first glance, this appears to work, and address @agentrickard's a and b scenarios in #62. Needs more checks to make sure we're adding to an existing condition, possibly, and also to the entity section... this against 7.14:
diff --git a/modules/node/node.module b/modules/node/node.module index 57133c6..3c49380 100644 --- a/modules/node/node.module +++ b/modules/node/node.module @@ -3309,7 +3309,11 @@ function _node_query_node_access_alter($query, $type) { $field = 'entity_id'; } $subquery->where("$nalias.$field = na.nid"); - $query->exists($subquery); + if (empty($tableinfo['join type'])) { + $query->exists($subquery); + } else { + $tables[$nalias]['condition'] .= ' AND ' . (string)$subquery; + } } }
I have not yet examined the generated sql, just dropped it into my current project and it's returning desired results.
- 🇺🇸United States freelock Seattle
I'm sure that needs a bit of polishing, but it should make this function now:
* Show me a list of nodes I can view. If there are any attached nodes I can view, show additional data from those nodes.
Parent node should no longer be dependent on child node.
- 🇺🇸United States agentrickard Georgia (US)
The condition you are outlining is something Views has to fix. Not core.
- 🇦🇺Australia rcross
there is a string of issues (some reaching back several years/versions) that finally seem to lead to this one being the root cause.
Can you elaborate on why this is not something that should be fixed in core?
- 🇦🇺Australia rcross
Also, just wanted to point out where this is being tracked from a views perspective #1222324: Fix query access control on relationships (comments) →
- 🇺🇸United States merlinofchaos
I support the method in #66. Ken points out there is still a potential false deny but the rarity of that denial is sufficiently low that I believe we can document that possibility and provide a workaround for it. It is better than allowing unfiltered data that is more difficult to remove.
The kind of joins that we are doing in Views is one of the key features that the transition from Views 1 to 2 allowed us and it is not something that could be removed or done differently.
In theory Views could add more access control to entity field rendering, however, but that is a very big job and not one that could be undertaken lightly.
- 🇺🇸United States agentrickard Georgia (US)
@merlinofchaos and I just walked through the two possible solutions here at DrupalCamp NYC. I'm ok with the approach in #66 now, given that it is the "least bad" option.
We would need to document (for Views users, primarily) the workaround for handling advanced use-cases as described in #62.
- 🇦🇺Australia rcross
do we need a patch from #66 to move this forward?
Also, any pointers on how to resolve this in D7?
- 🇨🇦Canada joel_osc
FYI - the code in #66 is againt 7.14 and I have tested it and it seems to work great! Thanks @freelock.
- 🇺🇸United States agentrickard Georgia (US)
I have copies of a D8 and D7 patch lying around that I will post shortly. The big step is tests.
- 🇺🇸United States agentrickard Georgia (US)
The patch in #77 is ready for tests.
- 🇺🇸United States freelock Seattle
Glad to see some progress here! Had on my list to create some tests around this, but don't currently have a test environment set up, will do later this week if somebody doesn't beat me to it.
@merlinofchaos in #71, curious what condition would trigger a false deny?
There was a false deny in my initial algorithm, in #36 - #45 above. In that query, I was adding an "OR (aliased table.id is null)" clause. This would cause a false deny if all rows in the joined table were denied by the node_access subquery. In #66, I'm adding as an AND clause to the join condition. This would fail with an SQL error if there is no previous join condition... otherwise if the join type is an outer join, the joined table would return null values if there was no value as well as no valid access in the node_access table, and the base table should still return its results.
What am I overlooking?
- 🇺🇸United States freelock Seattle
Oh, just read the patches... @agentrickard, those are the original patches. Need to rewrite with the join condition instead of isNull.
- 🇺🇸United States freelock Seattle
D8 Patch.
Note: I have not gone through the code block that follows this patch -- if the object type is an entity, it looks like this might add an or condition for particular fields. This section probably also needs a patch, but since I'm not sure offhand when it applies, I'm not sure how to patch that section.
- 🇺🇸United States freelock Seattle
Ok, try again... Looks like my local git clone of drupal wasn't getting fresh updates from HEAD... This update assumes the query object structure and api hasn't changed drastically since 7, haven't yet spun up a copy of 8 to make sure this is functional...
- 🇺🇸United States merlinofchaos
Ah putting the check in the join should remove the false deny so that is a win. It might be worth testing any potential false deny scenarios that we can think of.
- 🇺🇸United States freelock Seattle
Ok, looks like D8 has changed enough that the query isn't necessarily the same structure, at least in the book and search tests.
- 🇨🇦Canada emorency
I've rewritten the patch from comment #77 in order to be able to apply it to the latest version, 7.15.
- 🇺🇸United States tim.plunkett Philadelphia
Please see http://drupal.org/node/767608
- 🇲🇽Mexico zatarain21 Guadalajara
Hello I don't know is someone find a solution.
I test Drupal 7.15 and Views 7x 3.5.
Now with the administration account you can get reverse reference with no cases
Father_Node 1
- Child_Reference_Node 1
- Child_Reference_Node 2Father_Node 2
- No childs nodes have been created.And if you seleted that the reverse reference is requiered you only get.
Father_Node 1
- Child_Reference_Node 1
- Child_Reference_Node 2That is correct!! ; )
But other users only get.
Father_Node 1
- Child_Reference_Node 1
- Child_Reference_Node 2No mather if the relationship is requiered or not. : (
Thanks for your help
- 🇲🇽Mexico zatarain21 Guadalajara
I tried with the patch in post 89 and it WORKS for me!!!!
Thanks emorency - 🇦🇺Australia rcross
@Tim - views is not in core yet, so lets address this in contrib space while we can.
- 🇺🇸United States tim.plunkett Philadelphia
This is filed against Drupal Core, not Views. Either way, the backport policy still applies.
- 🇺🇸United States JonMcL Brooklyn, NY
So if I'm reading things correctly, this cannot be fixed in D7 until it is fixed in D8? (since it is a core patch and there is the backport policy)
So where does D8 patch at #85 stand? Is this still an issue in D8?
It would be great if this can be put into D7 for a future release. Some of us forget to re-apply core patches after we install security upgrades to core :)
Any suggestions for getting to to move forward with D7 or do we have to wait for the D8 fix no matter what?
- 🇺🇸United States xjm
Yes, it will be fixed in D8 and then in D7. The fastest way to get it fixed in D7 is to help it get fixed in D8. :)
- 🇺🇸United States freelock Seattle
Hi,
I'm part way through creating a test case for this. Finally got a chance to set up a test environment, find what's changed in D8, learn what needs to happen to set up the failing case, etc.
I was trying to leverage the node_access_test module to assign these permissions, but I'm not getting them invoked correctly in my test case -- hoping to get another chance to get the test working correctly in 8, and then update the patch.
Attached is what I've done so far. Right now the test does not appear to invoke the node access hooks in node_access_test -- if somebody could point out what I'm doing wrong, I'd appreciate it -- if not I think I'll whip up another test support module with a simpler node_access invocation...
- 🇺🇸United States freelock Seattle
Ok. I have a working test that fails because of this bug. Still needs to be run through coder, but I think this tests for the correct behavior.
Can somebody please review?
- 🇺🇸United States freelock Seattle
I still have too much on my plate, but I believe the last test above is testing for this issue correctly. However, my last patch fails the test.
What I'm trying to do is add additional conditions to the JOIN clause on the query object. However, by the time it gets to the node_access function, the condition on the join clause is already converted to a string -- and what I'm trying to append is still an object. I'm basically looking for a SQL fragment for this clause to append to the existing join condition string -- if I cast the object to a string, I get a full-blown SELECT query when all I want is the WHERE condition.
I can continue digging on this when I get time, but if somebody who knows SelectQuery objects well can give me a pointer, I'm sure I can get this working much quicker...
- 🇺🇸United States freelock Seattle
At long last, I have a test and a patch.
This patch does work -- it returns rows where there are no matches in the subquery, and it prevents information disclosure/access bypass, blocking access to rows the user does not have access to.
However, I am getting one slightly unexpected result -- when a subquery matches two rows, but the user only has access to one, there are two rows returned, with the blocked one returning null values for the right hand table columns. I've commented out a test for the expected number of rows (lines 192-3 in the test file). I'm not quite following why -- I would expect this case to return a single row, with the subquery values for the node the user has access to.
Can somebody please review?
Thanks!
- 🇺🇸United States freelock Seattle
Ok. At long last, I finally have a working patch!
Definitely need some feedback on this, whether this will break anything. Using query->nextPlaceholder() to increment the placeholder values here seems a bit hackish, but is working pretty well.
The challenge I had to overcome in this is when the base node table is joined to the query, I wanted to add the condition to the join clause. Since join conditions are strings, there does not seem to be a proper way to do this -- I had to generate the proper query conditions, and add the compiled version of that along with the appropriate arguments.
When the main query already had arguments, this made it so there was a name collision on the arguments.
And after incrementing the query->placeholder value appropriately to avoid these collisions, I hit another case where there were placeholder collisions -- when the PagerSelectExtender (or presumably any SelectExtender) is used.
So this might actually fix another set of bugs related to placeholder naming collisions. I think this is a safe way to fix the issue. And short of having a better way in the API to alter table join collisions, this seems like the best way to fix...
Feedback?
- 🇩🇪Germany dawehner
Thank you for working on this issue!
+++ b/core/lib/Drupal/Core/Database/Query/SelectExtender.phpundefined @@ -55,6 +55,7 @@ public function uniqueIdentifier() { + $this->query->nextPlaceholder();
Couldn't we just return $this->query->nextPlaceholder(), just wondering.
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeAccessSubqueryTest.phpundefined @@ -0,0 +1,229 @@ + * ¶ ... + ¶ ... + ¶
Some trailing whitespace is left.
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeAccessSubqueryTest.phpundefined @@ -0,0 +1,229 @@ + // Test #1349080
We could instead of this set a // @see http://drupal.org/node/1349080
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeAccessSubqueryTest.phpundefined @@ -0,0 +1,229 @@ + // Join on $join_table ... + // Now add subquery join
A trailing dot should be added here.
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeAccessSubqueryTest.phpundefined @@ -0,0 +1,229 @@ + // test as admin_user.
Uppercase T please.
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeAccessSubqueryTest.phpundefined @@ -0,0 +1,229 @@ + "Admin user should get $expected_admin_count rows returned after initial load. Actual: ".count($untagged)); + $this->verbose('Admin query result: '. + theme('table',array('header'=>array('nid','title','subquery_nid','subquery title'), + 'rows'=>$untagged) + ) + ); + $this->verbose('Db Query used: '.print_r($result->queryString,1));
If we have something with a dynamic number we can use format_string() for the message.
In general this needs some small changes for codestyle.
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeAccessSubqueryTest.phpundefined @@ -0,0 +1,229 @@ + $this->assertEqual(count($tagged), $expected_user_count, + "Regular user should get $expected_user_count rows returned after initial load. Actual: ".count($tagged)); + $this->verbose('Regular user query result: ' . + theme('table',array('header'=>array('nid','title','subquery_nid','subquery title'), + 'rows'=>$tagged) + ) + ); + $this->verbose('Db Result: '.print_r($result->queryString,1));
I guess we can remove the verbose as it's just used for testing?
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeAccessSubqueryTest.phpundefined @@ -0,0 +1,229 @@ + * @return null + * + * Assertions are made from this function, so no return value necessary.
We probably don't have to document that.
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeAccessSubqueryTest.phpundefined @@ -0,0 +1,229 @@ + $this->fail('User was able to access a node in the returned result, in the parent query.'); ... + $this->fail('User was able to access a node in the returned result, in the subquery.');
I guess it would be also helpful to include somehow the actual values so it can be tracked down more easy once this breaks.
+++ b/core/modules/node/node.moduleundefined @@ -3092,8 +3092,22 @@ function node_query_node_access_alter(AlterableInterface $query) { + } else {
The codestyle says: Add a new line for an else{}
+++ b/core/modules/node/node.moduleundefined @@ -3092,8 +3092,22 @@ function node_query_node_access_alter(AlterableInterface $query) { + // Increment the placeholder count on the main query until it matches the placeholders + // used by the subquery. + $cond_count = $subquery->nextPlaceholder(); + while ($cond_count--) { + $query->nextPlaceholder();
This seems to be really hacky, can't we request a new placeholder and use that?
- 🇺🇸United States freelock Seattle
@dawehner, thanks for the review! I'll clean up the style issue and repost the patch in the next couple days. I do think the two code comments bear more widespread review:
+++ b/core/lib/Drupal/Core/Database/Query/SelectExtender.phpundefined @@ -55,6 +55,7 @@ public function uniqueIdentifier() { + $this->query->nextPlaceholder();
Couldn't we just return $this->query->nextPlaceholder(), just wondering.
I don't know this API thoroughly, but I would think that's an improvement. I see no reason to keep two placeholder values in the same query object -- just confuses things and leads to bugs.
+++ b/core/modules/node/node.moduleundefined @@ -3092,8 +3092,22 @@ function node_query_node_access_alter(AlterableInterface $query) { + // Increment the placeholder count on the main query until it matches the placeholders + // used by the subquery. + $cond_count = $subquery->nextPlaceholder(); + while ($cond_count--) { + $query->nextPlaceholder();
This seems to be really hacky, can't we request a new placeholder and use that?
I agree, this seems hacky, but it's the only method I could find to access the protected member placeholder property. I was thinking a different placeholder name (before the incrementing value) might be appropriate, but that's set in the ->compile method.
So unless I'm missing something, this is the only way to avoid argument naming collisions when assembling a query object with multiple subqueries compiled at different times. A shortcoming in the API?
I think the best, less hacky solution would be to support using a Condition object as a $table['condition']. Then this alter could move an existing table join condition into a query object, and the whole thing would get compiled at the same time, avoiding name collisions. It looks like the $condition argument of all the join methods expect a string, and only do %alias expansions if it is a string. And while I'm not seeing an explicit prohibition on using condition objects here (I thought I had seen it specified as a string earlier, but can't find that documented), it's certainly not working if I change the patch to replace the string with a condition object.
The other less hacky approach might be to check for any existing placeholder arguments recursively through the query at compile or string casting time. I do see it explicitly documented that a placeholder can only be used once within a given query. If this is checked when converting conditions to argument placeholders, that would be a better solution, and likely catch other corner cases that currently fail.
I'm thinking specifically in Condtion::compile(), where the :db_condition_placeholder label is applied -- perhaps move that text into the Query::nextPlaceholder() function, change that function's return value to a string, and have it check against the current Query arguments() for a collision.
Obviously both of those involve much bigger API changes... and it seems a bit late in the release cycle for that...
Any other thoughts?
- 🇩🇪Germany manuelBS
It seams to me that 7.x patch http://drupal.org/node/1349080#comment-6384002 #89 has a security problem because when I show entities in a view that reference other entities and I check "require this relationship", i see the entities even if i don't have access to the referenced entities.
- 🇺🇸United States tim.plunkett Philadelphia
Views is not in Core in Drupal 7.
- 🇩🇪Germany dawehner
Thank you manuel for the feedback, I guess the following line is problematic.
Instead of checking for an empty join type we should probably check for an INNER join type, as then we want to handle it the strict way.
if (empty($tableinfo['join type'])) {
In order to get this into Drupal the process is to first get it into Drupal8 and then backport which is pretty straighforward once there is a good test coverage.
- 🇺🇸United States freelock Seattle
@dawehner I don't think this matters. If there is any join, we can add the conditions to the join condition (inner join or outer join). If there is no join, or if it's an inner join, we can add to the main where condition. When it's an inner join, the net effect should be the same whether the condition is on the join or on the where condition. It's an outer join we need to specifically add to the join condition.
@manuelBS, the patch has not yet been updated for D7, and the earlier test failures did find a logic flaw. So I'm not surprised you were able to find a test case that breaks in D7. It would be very useful to create an automated test to replicate the scenario you outlined.
@tim.plunkett this is not a patch for views, it's a patch for node access (and also the DB abstraction layer, SelectExtender interface). Views just depends upon this behavior working correctly.
- 🇺🇸United States xjm
@tim.plunkett this is not a patch for views, it's a patch for node access (and also the DB abstraction layer, SelectExtender interface). Views just depends upon this behavior working correctly.
Core patches also need to go into D8 first. :)
- 🇩🇪Germany dawehner
@freelock
Would it be possible to fix at least the code-style issues, maybe this will trigger people with knowledge to node access to review it.
- 🇺🇸United States freelock Seattle
Ok! Here's an updated patch, fixing the code style issues identified. No coder for d8 yet!
- 🇬🇧United Kingdom Alice Heaton
I can confirm #89 works for my D7 test case (node reference from a term view) - thanks :)
- 🇺🇸United States freelock Seattle
@Alice, the patch for D7 is incomplete, and can trigger SQL errors in certain conditions -- I haven't yet backported the corrected patch from D8.
Can someone provide a good review of the patch from #119?
- 🇩🇪Germany manuelBS
Now I tried to backport the patch from #119 to D7. But there still seams to be a problem whit entities in a view in the fallowing use case. Before I create a test case, I want to make sure that the problem is related to this issue:
I have a "self made" entity that references a node just be putting the nodes nid into the entity tabel (no reference field). Then I added this relationship in hook_views_data.
In my view I show the "self made" entities and I added the relation to the referenced node, the relation is required.
I make sure that I dont have access to all referenced nodes. If I apply the patch, I see all the "self made" entities in the view. If I don't apply the patch, these entities that reference a node where I don't have access to, are not shown in the view (but of course then the initial issue occurs again). But as I understand, the query should check access to related nodes if "the relationship" is required. - 🇩🇪Germany manuelBS
Instead of checking for an empty join type we should probably check for an INNER join type, as then we want to handle it the strict way.
as @dawehner wrote works form me. And in my opinion this makes sence to check
if (empty($tableinfo['join type']) || $tableinfo['join type'] == 'INNER') {
cause in case of an inner join (when for axample a relationship is required) we need to have access check with
$query->exists($subquery);
To ensure that the user has access to the referenced nodes.
I added tha patch to this comment - 🇩🇪Germany Raumfisch
#126: d7_move_access_to_join_condition-1349080.patch queued for re-testing.
- 🇺🇸United States freelock Seattle
@manuelBS the patch is failing to apply because you need to create the entire patch, not a patch of my patch ;-)
But I am not understanding the case you're hitting -- when I spent time analyzing this problem, adding the condition to the join clause if there was one seemed like a total wash if it was an inner join.
Can you provide the SQL that is failing with my patch? Maybe we can come up with a clear test for that case?
Thanks!
- 🇩🇪Germany manuelBS
Sorry bad fault ;-) Here is the patch again. I hope it works now @freelock thanks for your help.
Does http://drupal.org/node/1349080#comment-7141442 not explain my thoughts or do you think these thought are not always right and open other issues? - 🇺🇸United States freelock Seattle
@manuelBS, I think your addition is unnecessary -- your statement in #126 that you need to have an access check when there's an inner join implies that there isn't one. But there is -- it is just moved to the join condition rather than being in a subselect in the where clause. When there is an inner join clause in the SQL, adding the condition to the join clause should return exactly the same set of rows as adding the condition as an exists subquery in the main where clause. But I could be missing something.
That's why I'm asking for some SQL that my patch is generating -- to prove me wrong.
If you can provide a very specific test case that breaks with my patch, then let's see if your version works (in my debugging on this, the "join type" values have been very inconsistent -- I've seen INNER, INNER JOIN, LEFT, LEFT JOIN, LEFT OUTER JOIN iirc, so at a minimum we would need to check more carefully the contents to cover all cases). If you can post some SQL and a pretty clear step-by-step of how you generated that SQL, I can write the test case which we need anyway for each patch.
If your backport is failing in D7, I do notice your patch is missing a couple key things -- the reference to the tables returned from the query object, and the fix to the pager query to prevent name collisions of the database placeholders...
- 🇺🇸United States freelock Seattle
Didn't realize this had gone back to Needs Work -- the patch for D8 is complete as far as I know, and needs review before backporting to D7.
Can we get this reviewed and committed? :-)
Reposting patch from #119.
- 🇺🇸United States freelock Seattle
Update test for changes to NodeTestBase::drupalCreateNode, which now adds the language code and breaks if one is used.
- 🇩🇪Germany Alexander Hadj Hassine
Why this patch isn't in Drupal 7.22 ? I have on 7.22 still the same problem. Or is there a other way to fix that?
- 🇺🇸United States freelock Seattle
Hi,
I can probably find some time this week to backport the patch to D7. But how do I post this for the testbot? And is there anyone who can review the D8 patch further?
I don't think the patch in #89 is correct -- it can trigger some name collisions that can result in failed SQL queries.
Cheers,
John - 🇺🇸United States dobe
Agree with John, #89 is not a fix. It would be great to backport to D7. Have not had a chance to look into the D8 patch but if it is acceptable it would be great to move forward with these issues.
- 🇧🇷Brazil gilsbert
Hi.
I would like to know if the patch for D7 will be released.
Regards,
Gilsberty - 🇳🇴Norway steinmb
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeAccessSubqueryTest.php @@ -0,0 +1,204 @@ + $this->field = field_create_field( + array( + 'field_name' => $this->field_name, + 'type' => 'number_integer', + 'cardinality' => FIELD_CARDINALITY_UNLIMITED + ) + );
Testbot failed on this with a Call to undefined function Drupal\node\Tests\field_create_field()
- 🇩🇰Denmark RunePhilosof
HEAD had a lot of new things, I have updated a good deal of the test, but I didn't have time to make it work completely.
The sql inbase_query
needs to be updated. - 🇩🇰Denmark RunePhilosof
I managed to finish a working backport to D7, including the test.
- 🇧🇷Brazil gilsbert
Hi.
I tested patch #149 without success.
That doesn't mean the patch is not correct but perhaps it is not the correct solution for the issues: https://drupal.org/node/2012250 and https://drupal.org/node/2113919.
Do you think that two issues are directly related with this one?
Regards,
Gilsberty - 🇮🇹Italy olivo.marco
Same issue here. I tested patch #149 partly successfully: what I now can see is the proper list of objects in a view even if there is no relationship on those rows, but what is missing is the pager: if I have multiple results, I do not see them unless I manually change the URL to show the next page.
Do you have any clue on what we should look into? Maybe the views module?
Thank you,
Marco - 🇺🇸United States freelock Seattle
Hi, Gilsbert,
After a quick review of #2012250: entity reference in profile field permissions → and [2113919] I suspect this issue is the underlying cause of both of them. And so if you're not getting the expected result, the patch is incomplete.
What triggers this issue is having some sort of node_access module enabled -- when a query gets tagged with node_access, the query gets rewritten incorrectly. What we need is a test case to replicate the failure.
I have not yet reviewed RunePhilisof's patches, will take a look over our holiday weekend. But if they are failing for you, you've probably hit some case where this patch is incomplete. Can you provide more details? e.g. which node access module, what configurations are still failing with the patch?
@olivo.marco I would think if you're getting correct results back but having pager trouble, this sounds like a pager issue -- are you using grouping?
- 🇳🇴Norway steinmb
One site I work on showed something similar, that site uses https://drupal.org/project/view_unpublished. Have not verified that this might be the cause of this but it fiddles with node access.
- 🇮🇹Italy olivo.marco
What I am using as a content access module is tac_lite. But no grouping is involved: the pager has just disappeared when there is a relationship (non-required), but "manual paging" via URL-modification works.
- 🇺🇸United States freelock Seattle
@olivo Hmm. That suggests that the count query is not getting altered correctly. That does suggest a new test case we'll need to build for this.
- 🇧🇷Brazil gilsbert
I'm sorry for taking two days for my answer.
Yes I will make a detailed test.
Working on it right now. - 🇧🇷Brazil gilsbert
Version of drupal core and extra modules
Drupal Core - 7.24
Chaos Tools - 7.x-1.3
Entity API - 7.x-1.2
Entity Reference - 7.x-1.1
Views & Views UI - 7.x-3.7With this setup the issue doesn't happen as freelock commented at #152 (no node_access module enabled).
The following modules were turned on individually and the issue happened on each of them.
views unpublished - 7.x-1.1
content access - 7.x-1.2-BETA2+0-devI didn't test others because I know/use only those two.
The issue is happening even after applying the patch #149.
Steps to reproduce the issue
1 - create a new content type "parent a" (fields title and body are enough)
2 - create a new content type "parent b" (fields title and body are enough)
3 - create a new content type "children" with fields
a) title and body
b) field_parent_a: entity reference to "parent a", cardinality unlimited
c) field_parent_b: entity reference to "parent b", cardinality unlimitedCreate the contents as following:
- parent a: "a1" and "a2"
- parent b: "b1" and "b2"
- children: "c" and point for field_parent_a the nodes "a2" and "a1" and for field_parent_b the node "b1"Now create a view with the objective to list all nodes of type "parent a" or "parent b" following the order gave by the node of type "children", listing first parent a then parent b and finally the rest of the nodes by the update date.
That way you would get a list like this:
a2
a1
b2
b1This view works perfectly for superuser but not for anonymous user!
(P.S.: please remember to turn on at least one of the node_access modules)Below there is the exported view and following it the SQL generated by the view.
View
====$view = new view();
$view->name = 'v1';
$view->description = '';
$view->tag = 'default';
$view->base_table = 'node';
$view->human_name = 'v1';
$view->core = 7;
$view->api_version = '3.0';
$view->disabled = FALSE; /* Edit this to true to make a default view disabled initially *//* Display: Master */
$handler = $view->new_display('default', 'Master', 'default');
$handler->display->display_options['title'] = 'v1';
$handler->display->display_options['use_more_always'] = FALSE;
$handler->display->display_options['access']['type'] = 'perm';
$handler->display->display_options['cache']['type'] = 'none';
$handler->display->display_options['query']['type'] = 'views_query';
$handler->display->display_options['exposed_form']['type'] = 'basic';
$handler->display->display_options['exposed_form']['options']['reset_button_label'] = 'Reiniciar';
$handler->display->display_options['pager']['type'] = 'full';
$handler->display->display_options['pager']['options']['items_per_page'] = '10';
$handler->display->display_options['pager']['options']['tags']['first'] = '« início';
$handler->display->display_options['pager']['options']['tags']['previous'] = '‹ anterior';
$handler->display->display_options['pager']['options']['tags']['next'] = 'próximo ›';
$handler->display->display_options['pager']['options']['tags']['last'] = 'fim »';
$handler->display->display_options['style_plugin'] = 'default';
$handler->display->display_options['row_plugin'] = 'fields';
/* Relationship: Entity Reference: Referencing entity */
$handler->display->display_options['relationships']['reverse_field_parent_a_node']['id'] = 'reverse_field_parent_a_node';
$handler->display->display_options['relationships']['reverse_field_parent_a_node']['table'] = 'node';
$handler->display->display_options['relationships']['reverse_field_parent_a_node']['field'] = 'reverse_field_parent_a_node';
/* Relationship: Entity Reference: Referencing entity */
$handler->display->display_options['relationships']['reverse_field_parent_b_node']['id'] = 'reverse_field_parent_b_node';
$handler->display->display_options['relationships']['reverse_field_parent_b_node']['table'] = 'node';
$handler->display->display_options['relationships']['reverse_field_parent_b_node']['field'] = 'reverse_field_parent_b_node';
/* Campo: Conteúdo: Título */
$handler->display->display_options['fields']['title']['id'] = 'title';
$handler->display->display_options['fields']['title']['table'] = 'node';
$handler->display->display_options['fields']['title']['field'] = 'title';
$handler->display->display_options['fields']['title']['label'] = 'title';
/* Campo: Conteúdo: Body */
$handler->display->display_options['fields']['body']['id'] = 'body';
$handler->display->display_options['fields']['body']['table'] = 'field_data_body';
$handler->display->display_options['fields']['body']['field'] = 'body';
$handler->display->display_options['fields']['body']['label'] = 'body';
/* Sort criterion: Conteúdo: parent_a (field_parent_a:delta) */
$handler->display->display_options['sorts']['delta']['id'] = 'delta';
$handler->display->display_options['sorts']['delta']['table'] = 'field_data_field_parent_a';
$handler->display->display_options['sorts']['delta']['field'] = 'delta';
/* Sort criterion: Conteúdo: parent_b (field_parent_b:delta) */
$handler->display->display_options['sorts']['delta_1']['id'] = 'delta_1';
$handler->display->display_options['sorts']['delta_1']['table'] = 'field_data_field_parent_b';
$handler->display->display_options['sorts']['delta_1']['field'] = 'delta';
/* Sort criterion: Conteúdo: Updated date */
$handler->display->display_options['sorts']['changed']['id'] = 'changed';
$handler->display->display_options['sorts']['changed']['table'] = 'node';
$handler->display->display_options['sorts']['changed']['field'] = 'changed';
$handler->display->display_options['sorts']['changed']['order'] = 'DESC';
/* Filter criterion: Conteúdo: Publicado */
$handler->display->display_options['filters']['status']['id'] = 'status';
$handler->display->display_options['filters']['status']['table'] = 'node';
$handler->display->display_options['filters']['status']['field'] = 'status';
$handler->display->display_options['filters']['status']['value'] = 1;
$handler->display->display_options['filters']['status']['group'] = 1;
$handler->display->display_options['filters']['status']['expose']['operator'] = FALSE;
/* Filter criterion: Conteúdo: Tipo */
$handler->display->display_options['filters']['type']['id'] = 'type';
$handler->display->display_options['filters']['type']['table'] = 'node';
$handler->display->display_options['filters']['type']['field'] = 'type';
$handler->display->display_options['filters']['type']['value'] = array(
'parent_a' => 'parent_a',
'parent_b' => 'parent_b',
);/* Display: Page */
$handler = $view->new_display('page', 'Page', 'page');
$handler->display->display_options['path'] = 'v1';
$translatables['v1'] = array(
t('Master'),
t('v1'),
t('more'),
t('Apply'),
t('Reiniciar'),
t('Sort by'),
t('Asc'),
t('Desc'),
t('Items per page'),
t('- All -'),
t('Offset'),
t('« início'),
t('‹ anterior'),
t('próximo ›'),
t('fim »'),
t('Conteúdo referencing Conteúdo from field_parent_a'),
t('Conteúdo referencing Conteúdo from field_parent_b'),
t('title'),
t('body'),
t('Page'),
);SQL
===SELECT node.title AS node_title, node.nid AS nid, field_data_field_parent_a.delta AS field_data_field_parent_a_delta, field_data_field_parent_b.delta AS field_data_field_parent_b_delta, node.changed AS node_changed, 'node' AS field_data_body_node_entity_type
FROM
{node} node
LEFT JOIN {field_data_field_parent_a} field_data_field_parent_a ON node.nid = field_data_field_parent_a.field_parent_a_target_id AND (field_data_field_parent_a.entity_type = 'node' AND field_data_field_parent_a.deleted = '0')
LEFT JOIN {node} field_parent_a_node ON field_data_field_parent_a.entity_id = field_parent_a_node.nid
LEFT JOIN {field_data_field_parent_b} field_data_field_parent_b ON node.nid = field_data_field_parent_b.field_parent_b_target_id AND (field_data_field_parent_b.entity_type = 'node' AND field_data_field_parent_b.deleted = '0')
LEFT JOIN {node} field_parent_b_node ON field_data_field_parent_b.entity_id = field_parent_b_node.nid
WHERE (( (node.status = '1') AND (node.type IN ('parent_a', 'parent_b')) ))
ORDER BY field_data_field_parent_a_delta ASC, field_data_field_parent_b_delta ASC, node_changed DESC
LIMIT 10 OFFSET 0 - 🇧🇷Brazil gilsbert
If you need more information please let me know!
Regards,
Gilsberty - 🇺🇸United States freelock Seattle
Hi,
@gilsbert, I spun up a pretty vanilla test install of D7, following your instructions and importing your view. I confirmed that with no access modules enabled, it worked for anonymous users, but with either content_access or view_unpublished it failed for anonymous users.
However, after applying the patch in #149, I got the expected behavior with the same nodes available for anonymous users as user 1. So this patch appears to be working, here...
I've left both view_unpublished and content_access set up. Are you sure you applied the patch correctly? If so, there's something missing from your recipe. I'll leave this install up for a week or so if you want to see if you can break the node access again ;-) http://d7.dotest.freelock.net , admin/admin and test/test accounts set up.
@olivo would be great if you could set up some test data illustrating your pager issue on this instance...
- 🇧🇷Brazil gilsbert
Hi @freelock.
Thank you very much for allowing me to help you with this issue.
Unfortunately I confirm that the patch #149 doesn't worked for me.
But I got more details that might help us find why this is happening.
In a summary I believe the patch is OK but we might have found another bug (related or not with this one) restricted to postgresql database.So before I continue let me explain: I use postgresql on my Drupal installation and that would not be the first time I face an issue restricted to it.
Is the site posted by you using mysql or postgresql?
Now let me explain why I'm having this conclusion.
1 - I turned on "devel" information for anonymous user on both sites (mine and yours).
--> You can access my site by http://www.ifch.unicamp.br/beto/v1
--> Yours is at http://d7.dotest.freelock.net//v12 - In the list of queries located in the footer of each page I found in your site the following 3 queries:
a) - node_access_view_all_nodes
SELECT COUNT(*) AS expression FROM node_access node_access WHERE (nid = '0') AND (grant_view >= '1') AND(( (gid = '0') AND (realm = 'all') )OR( (gid = '0') AND (realm = 'content_access_author') )OR( (gid = '1') AND (realm = 'content_access_rid') ))b) - views_plugin_pager::execute_count_query
* I didn't paste the SQL here because I believe it is not relevant.c) - views_plugin_query_default::execute
SELECT node.title AS node_title, node.nid AS nid, field_data_field_parent_a.delta AS field_data_field_parent_a_delta, field_data_field_parent_b.delta AS field_data_field_parent_b_delta, node.changed AS node_changed, 'node' AS field_data_body_node_entity_type FROM node node LEFT JOIN field_data_field_parent_a field_data_field_parent_a ON node.nid = field_data_field_parent_a.field_parent_a_target_id AND (field_data_field_parent_a.entity_type = 'node' AND field_data_field_parent_a.deleted = '0') LEFT JOIN node field_parent_a_node ON field_data_field_parent_a.entity_id = field_parent_a_node.nid AND EXISTS(SELECT na.nid AS nid FROM node_access na WHERE (( (na.gid = '0') AND (na.realm = 'all') )OR( (na.gid = '0') AND (na.realm = 'content_access_author') )OR( (na.gid = '1') AND (na.realm = 'content_access_rid') ))AND (na.grant_view >= '1') AND (field_parent_a_node.nid = na.nid) ) LEFT JOIN field_data_field_parent_b field_data_field_parent_b ON node.nid = field_data_field_parent_b.field_parent_b_target_id AND (field_data_field_parent_b.entity_type = 'node' AND field_data_field_parent_b.deleted = '0') LEFT JOIN node field_parent_b_node ON field_data_field_parent_b.entity_id = field_parent_b_node.nid AND EXISTS(SELECT na.nid AS nid FROM node_access na WHERE (( (na.gid = '0') AND (na.realm = 'all') )OR( (na.gid = '0') AND (na.realm = 'content_access_author') )OR( (na.gid = '1') AND (na.realm = 'content_access_rid') ))AND (na.grant_view >= '1') AND (field_parent_b_node.nid = na.nid) ) WHERE (( (node.status = '1') AND (node.type IN ('parent_a', 'parent_b')) ))AND ( EXISTS (SELECT na.nid AS nid FROM node_access na WHERE (( (na.gid = '0') AND (na.realm = 'all') )OR( (na.gid = '0') AND (na.realm = 'content_access_author') )OR( (na.gid = '1') AND (na.realm = 'content_access_rid') ))AND (na.grant_view >= '1') AND (node.nid = na.nid) )) ORDER BY field_data_field_parent_a_delta ASC, field_data_field_parent_b_delta ASC, node_changed DESC LIMIT 10 OFFSET 03 - In the list of queries on my site I found only:
a) - node_access_view_all_nodes
* Same querie as yours.The queries (b) and (c) are not being executed on my site.
There are not any warning/error messages so I can't explain why they are not being executed.
But I can confirm those informations:- the query (a) is returning zero as the result for "count(*)" on my site (is that correct? is the same result for you?)
- the query (c) is correctly returning the rows that we need to show in the view when I paste it and execute it directly on my database (thats why I believe the patch #149 is OK)
So there is something happening after the query (a) that is not allowing the queries (b) and (c) to be executed on my site. What it could be? Where/how can I look deeper?
Regards,
GilsbertyP.S.: me and @drunken_monkey found an issue with complex queries and postgresql database related here: https://drupal.org/node/2142107 . Do you think the problem with "v1" view on my site might be related with the issue #2142107?
- 🇺🇸United States freelock Seattle
Hi, @gilsbert,
Thanks for the follow-up! Yes, it does seem quite likely that you're hitting the same issue as #2142107: Complex cloned query dependent on __toString() call → -- the change with the patch does involve casting a subquery object to a string, so if the Postgres driver has trouble in certain cases doing that, it could very well be the source of this bug.
I do get a count of 0 when running query (a) as shown, so that's not the issue.
I would say the next step is going through the code in a debugger, and finding out exactly where it's failing. Do you have a debugger/IDE set up?
I've got a pretty full plate this week, but I'll see if I can carve out a couple hours to step through this on postgres in a few days...
P.S. We need to see if this is an issue in D8, too. And yes, this server is using MySQL -- well, MariaDB, actually.
- 🇧🇷Brazil gilsbert
Hi @freelock.
I dont have a debugger/IDE on my site :-(
I would also need first to debugg it in a site where the workflow is working to compare with mine.I can edit the module files and manually debugg using "echo". I would just need a hint where to start.
I guess I should start in views module or in a workflow control module that calls views and check why it is not being called.Regards,
Gilsberty - 🇨🇦Canada kiwad
In my specific case
A calendar show nodes where some have a reference and some don't, #149 worked great - 🇩🇪Germany manuelBS
I tested the patch at #149 and it also worked great for me. Thanks!
- 🇧🇷Brazil gilsbert
Hi @freelock.
May we try to solve the postgresql issue?
Regards,
Gilsberty - 🇺🇸United States freelock Seattle
Hi, @gilsbert,
Been slammed around here. I did swap out the dotest.freelock.net instance with a postgres database, but haven't had a chance to replay your steps to reproduce. I did run the automated node access tests, and they passed on Postgres, so we definitely do not have test coverage that identifies your issue.
Can you go ahead and get the scenario you described up and running on that instance? User admin/pw admin should get you in as user 1, and the add-on modules for content access, etc should be available to enable. I do have xdebug installed on this server, but have not (yet) configured it -- once we have a test case I can probably get that configured and then step through it with a debugger and find the problem...
Thanks,
John - 🇧🇷Brazil gilsbert
Hi John.
The view "v1" is avaliable in your site.
http://d7.dotest.freelock.net/v1It works for superuser and doesn't work for anonymous.
I gave to anonymous and authenticated users permission to see published content and to see devel information.
I tested the permission to see contents visiting the page http://d7.dotest.freelock.net/content/c .Going back to the view the behavior is equal what I reported at #160.
The queries "views_plugin_pager::execute_count_query" and "views_plugin_query_default::execute" are not being executed.So I believe we reproduced the full scenario with sucess.
Let me know if I can help further.
Regards,
Gilsberty - 🇺🇸United States freelock Seattle
Ok, I've confirmed that this is an issue, and ran out of steam before getting to the bottom of it.
One thing I've found is that subselect handling of placeholders is still broken -- what's different about this scenario is that there are two subqueries getting added to the query -- the node table appears in this query 3 times, and the second two use joins with subqueries. Both of these end up with the same db_placeholder keys. I think this works in MySQL because they are exactly the same in both subqueries, and so the replacement happens to work anyway. Something in Postgres must be interfering with this token replacement.
It could be related to #886970: DB API putting wrong db placeholders in complex queries → , specifically @Crell's comment #9, item 2.
If this is the case, we might be able to get around it by calling $subquery->get_arguments() before casting the subquery to a string.
Also, getting back into this again, I think this patch is incomplete, as it does not cover when node_access is called with a type of "entity". I don't know of any examples where that is used, or a good way to build a test case for it -- I would suggest we deal with that in a separate issue.
I'll come back to this later, but I need to run for now...
- 🇨🇦Canada yang_yi_cn
I also tested #149,
My view has a pager. After applying the patch the result for anonymous users changed from nothing to show the first page, but the pager disappeared. In the meaning time, Root user can see the pager with no problem though.
- 🇩🇪Germany manuelBS
As patch #149 works for my use cases perfectly in D7 on mysql but cannot be applied to the latest 7.25 release, here is the patch rerolled if anybody else needs it.
- 🇨🇴Colombia vramiguez
#174 worked for me! I'm using D7 latest version and after clearing cache, the views that were not displaying to the anonymous user are now showing up. Thanks a lot!
- 🇧🇾Belarus spleshka UAE
I've also tested patch in #174 and confirm that is works like a charm! Thank you.
- 🇧🇾Belarus spleshka UAE
Change branch to 7.x, since patch in #174 is for 7.x and needs to be tested by a testbot.
- 🇦🇺Australia rcross
I think for this to be tested by testbot for d7, this needs to be an issue in the views contrib project.
- 🇩🇪Germany manuelBS
@rcross but why in the view project? This is really related to core.
- 🇧🇷Brazil gilsbert
Hello friends.
After a deserved vacation I'm back.
Patch #174 doesn't work on postgresql environment.
After testing it I got the same results reported at #160.But it might be related with the postgresql driver...
I hope to get an answer at https://drupal.org/node/2142107 and then I will retest this patch.
Regards,
Gilsberty - 🇦🇺Australia rcross
@manuelBS I thought this was related to the views project. Views is only in core for D8.
- 🇨🇦Canada mgifford Ottawa, Ontario
The bot didn't run so re-attaching the same patch.
It applies nicely to my local install.
- 🇷🇺Russia maximpodorov
Testbot, where are you?
The patch applies and solves the problem. - 🇷🇺Russia maximpodorov
Reattaching the same file with the name which asks the bot to test the patch.
- 🇷🇺Russia maximpodorov
185: 1349080-174-d7-move-access-to-join-condition-update-please-test.patch queued for re-testing.
- 🇨🇦Canada mgifford Ottawa, Ontario
I can't see why that patch fails with this test:
/** * Tests that search returns results with punctuation in the search phrase. */ function testPhraseSearchPunctuation() { $node = $this->drupalCreateNode(array('body' => array(LANGUAGE_NONE => array(array('value' => "The bunny's ears were fuzzy."))))); // Update the search index. module_invoke_all('update_index'); search_update_totals(); // Refresh variables after the treatment. $this->refreshVariables(); // Submit a phrase wrapped in double quotes to include the punctuation. $edit = array('keys' => '"bunny\'s"'); $this->drupalPost('search/node', $edit, t('Search')); $this->assertText($node->title); }
trying to replicate it here, it seems to work - http://s4daf11e38186177.s3.simplytest.me/search/node/bunny%27s
- 🇷🇺Russia maximpodorov
The patch deals with placeholders incorrectly. The resulting query has multiple placeholders having the same name.
- 🇫🇷France andypost
1) there's a same issue in 8.x - so should be fixed first
2) #115 is not addressed! but test is written for outer join
3) the approach is fragile because assumes that the order of placeholders and joins would be the same-
+++ b/modules/node/node.module @@ -3402,6 +3402,13 @@ function _node_query_node_access_alter($query, $type) { + $np = count($query->getArguments()); + while ($np--) {
please use more readable $placeholer_count
-
+++ b/modules/node/node.module @@ -3434,7 +3441,22 @@ function _node_query_node_access_alter($query, $type) { + $tables[$nalias]['condition'] .= ' AND EXISTS(' . (string)$subquery . ')'; + $tables[$nalias]['arguments'] += $subquery->arguments();
not sure that $subquery will always get right placeholders
-
- 🇳🇱Netherlands alexanderpas
1. https://drupal.org/node/767608
2. Any time the version is changed back to D7, you're delaying the patch for both D7 and D8.
3. A patch for D7 will be made when the D8 patch is committed to Core. - 🇨🇦Canada mgifford Ottawa, Ontario
@maximpodorov - yes.
At the moment you can only pick one version for each issue, but they often go back/forth as needed.
If you want it tested, then you can switch it back to D7, run the bot, then when that's passed or failed, switch it back to D8.
- 🇺🇸United States freelock Seattle
@andypost in #198, thank you for a clear summary here of what still needs to happen.
Really your item #3 is the big concern here.
I think #2, the issue in #115, is not an issue -- if there is any kind of join, moving the conditions to the join results in the desired result. So it does not matter if it is an inner or an outer join -- if it's an outer join, the conditions MUST be on the join, whereas if it's an inner join, you get the same result regardless of whether the conditions are on the join or in the where clause.
But the placeholder brittleness is a big concern -- I'm not quite sure how to get a test case to illustrate this, or a better approach for this problem. Do you (or anyone else) have any suggestions for that? The test cases we have (and even the previous placeholder hackery) arose from conflicts running other modules that resulted in placeholder name collisions -- the solutions have worked for me, but I'm not confident they work everywhere.
Also, there is one other issue, raised by @gilsbert -- a specific scenario built up that fails in Postgres but passes in MySQL. Would like to get a test written for that. I don't understand what that problem is.
- 🇧🇷Brazil gilsbert
Hi @freelock.
I will try to give more information about the postgresql's scenario.
I found an error message in the database log that explain why statements (b) and (c) reported at #160 were not being executed in postgresql database when the site was visited by an anonymous user (for superuser everything was working).
FIRST TRY (after applying the patch #174)
The following SQL was the (b) statement for an anonymous user:
SELECT COUNT(*) AS expression
FROM
(SELECT 1 AS expression
FROM
node node
LEFT JOIN field_data_field_parent_a field_data_field_parent_a ON node.nid = field_data_field_parent_a.field_parent_a_target_id AND (field_data_field_parent_a.entity_type = 'node' AND field_data_field_parent_a.deleted = '0')
LEFT JOIN node field_parent_a_node ON field_data_field_parent_a.entity_id = field_parent_a_node.nid AND EXISTS(SELECT na.nid AS nid
FROM
node_access na
WHERE (( (na.gid = '1') AND (na.realm = 'parent_a') )OR( (na.gid = 'parent_b') AND (na.realm = '0') )OR( (na.gid = 'all') AND (na.realm = '0') ))AND (na.grant_view >= 'content_access_author') AND (field_parent_a_node.nid = na.nid) )
LEFT JOIN field_data_field_parent_b field_data_field_parent_b ON node.nid = field_data_field_parent_b.field_parent_b_target_id AND (field_data_field_parent_b.entity_type = 'node' AND field_data_field_parent_b.deleted = '0')
LEFT JOIN node field_parent_b_node ON field_data_field_parent_b.entity_id = field_parent_b_node.nid AND EXISTS(SELECT na.nid AS nid
FROM
node_access na
WHERE (( (na.gid = '1') AND (na.realm = 'parent_a') )OR( (na.gid = 'parent_b') AND (na.realm = '0') )OR( (na.gid = 'all') AND (na.realm = '0') ))AND (na.grant_view >= 'content_access_author') AND (field_parent_b_node.nid = na.nid) )
WHERE (( (node.status = '1') AND (node.type IN ('parent_a', 'parent_b')) ))AND ( EXISTS (SELECT na.nid AS nid
FROM
node_access na
WHERE (( (na.gid = '0') AND (na.realm = 'all') )OR( (na.gid = '0') AND (na.realm = 'content_access_author') )OR( (na.gid = '1') AND (na.realm = 'content_access_rid') ))AND (na.grant_view >= '1') AND (node.nid = na.nid) )) ) subqueryYou will find comparations with field "gid" in table "node_access" using a string value ('parent_b' and 'all').
This will not work on postgres because the gid field is a bigint and the database can't convert the strings into an integer value!In mysql it might be working and returning "false" as result on those comparations.
In postgresql it generates an error and the statement fails.SECOND TRY (after applying the patch #195)
EUREKA!
The patch did the work and fixed the issue!
The view is working and correctly showing the nodes for superuser and anonymous!The following SQL is the new statement (b):
SELECT COUNT(*) AS expression FROM (SELECT 1 AS expression FROM node node LEFT JOIN field_data_field_parent_a field_data_field_parent_a ON node.nid = field_data_field_parent_a.field_parent_a_target_id AND (field_data_field_parent_a.entity_type = 'node' AND field_data_field_parent_a.deleted = '0') LEFT JOIN node field_parent_a_node ON field_data_field_parent_a.entity_id = field_parent_a_node.nid AND EXISTS(SELECT na.nid AS nid FROM node_access na WHERE (( (na.gid = '0') AND (na.realm = 'all') )OR( (na.gid = '0') AND (na.realm = 'content_access_author') )OR( (na.gid = '1') AND (na.realm = 'content_access_rid') ))AND (na.grant_view >= '1') AND (field_parent_a_node.nid = na.nid) ) LEFT JOIN field_data_field_parent_b field_data_field_parent_b ON node.nid = field_data_field_parent_b.field_parent_b_target_id AND (field_data_field_parent_b.entity_type = 'node' AND field_data_field_parent_b.deleted = '0') LEFT JOIN node field_parent_b_node ON field_data_field_parent_b.entity_id = field_parent_b_node.nid AND EXISTS(SELECT na.nid AS nid FROM node_access na WHERE (( (na.gid = '0') AND (na.realm = 'all') )OR( (na.gid = '0') AND (na.realm = 'content_access_author') )OR( (na.gid = '1') AND (na.realm = 'content_access_rid') ))AND (na.grant_view >= '1') AND (field_parent_b_node.nid = na.nid) ) WHERE (( (node.status = '1') AND (node.type IN ('parent_a', 'parent_b')) ))AND ( EXISTS (SELECT na.nid AS nid FROM node_access na WHERE (( (na.gid = '0') AND (na.realm = 'all') )OR( (na.gid = '0') AND (na.realm = 'content_access_author') )OR( (na.gid = '1') AND (na.realm = 'content_access_rid') ))AND (na.grant_view >= '1') AND (node.nid = na.nid) )) ) subquery
The field gid is now only compared with integer values!
Everything working perfectly.Thank you very much.
Will this change be commited to Drupal or is there more work to do?
Regards,
GilsbertyP.S.: I believe this issue is not related with https://drupal.org/node/2142107 since the patch #195 fixed the issue!
- 🇧🇷Brazil gilsbert
Hi.
I believe the patch #195 introduced a new issue with the testing module (file node.test).
After applying the patch the "simpletest" stops to work.
PHP's log shows the message: PHP Fatal error: Cannot redeclare class NodeAccessSubqueryTest in /srv/www/drupal/versao-atual/modules/node/node.test on line 3153.
May we fix this?
Regards,
Gilsberty - 🇫🇷France steveoriol Grenoble 🇫🇷
Hello,
For me, after apply the patch #195,
all my views with a "Filter criteria" like "Domain Access: Available on current domain (True)" disappear, on anonymous acces, superuser is ok.
:-( - 🇺🇸United States capellic Austin, Texas
I too have a View with an Entity Reference in the Relationships area. All was fine until I started using the Views Unpublished module which caused the View to disappear for those users who didn't have the rights to see unpublished nodes that appeared in that View. Applying the patch in #195 works for me. Thank you all for your work on this, sticking with it, and getting us here.
- 🇨🇦Canada Renee S
This patch worked for me!
My use-case: I had a View that was supposed to use a non-required relationship-provided field as a filter, ORed with some other filter conditions on fields that didn't share the relationship. Nothing that wasn't in the relationship was showing up.
Patch fixed it, and no side-effects that I can tell. Thanks!
It sounds like the postgre SQL problem is fixed, and there are quite a few reviews of the patch here saying it worked. What else do we need to get this committed to the next release? Is there an error in the test but not the patch?
- 🇧🇷Brazil gilsbert
Hi @Renee S.
Yes. There is a small problem with the test as I reported at #206.
Regards,
Gilsberty - 🇪🇸Spain bmunslow
#195 worked great for me too.
Similar context: View with an non-required entityreference field relationship to access additional field from the referenced entity.
Anonymous users did'n't get the rows with an empty referenced entity.
Patched fixed the issue, thanks, no side-effects for the moment.
- 🇦🇺Australia Alan D.
As alexanderpas said in comment #199, setting back to D7 slows the process down.
Re-rolled D7 is great, just upload the D7 patch ending in "do-not-test.patch" and leave the version alone ;)
- 🇪🇸Spain bmunslow
WARNING: #195 solves the issue, yet it does cause another issue.
After applying patch #195, anonymous users can't search any contents on the site using drupal's default search.
Patch needs more work!
- 🇳🇱Netherlands MLZR Zutphen
# 195 works for me, untill now without side effects.
- 🇺🇸United States dobe
#195 (with or without) Doesn't work for me for this query:
I have to turn Disable SQL rewriting on for Anonymous to get any view.
SELECT file_managed_field_data_field_image.fid AS file_managed_field_data_field_image_fid, commerce_product_field_data_commerce_product.product_id AS commerce_product_field_data_commerce_product_product_id, 'commerce_product' AS field_data_field_image_commerce_product_entity_type FROM {commerce_product} commerce_product LEFT JOIN {field_data_field_product} field_data_field_product ON commerce_product.product_id = field_data_field_product.field_product_product_id LEFT JOIN {node} field_product_commerce_product ON field_data_field_product.entity_id = field_product_commerce_product.nid LEFT JOIN {field_data_field_cards} field_data_field_cards ON commerce_product.product_id = field_data_field_cards.entity_id AND (field_data_field_cards.entity_type = 'commerce_product' AND field_data_field_cards.deleted = '0') LEFT JOIN {commerce_line_item} commerce_line_item_field_data_field_cards ON field_data_field_cards.field_cards_line_item_id = commerce_line_item_field_data_field_cards.line_item_id LEFT JOIN {field_data_commerce_product} commerce_line_item_field_data_field_cards__field_data_commerce_product ON commerce_line_item_field_data_field_cards.line_item_id = commerce_line_item_field_data_field_cards__field_data_commerce_product.entity_id AND (commerce_line_item_field_data_field_cards__field_data_commerce_product.entity_type = 'commerce_line_item' AND commerce_line_item_field_data_field_cards__field_data_commerce_product.deleted = '0') LEFT JOIN {commerce_product} commerce_product_field_data_commerce_product ON commerce_line_item_field_data_field_cards__field_data_commerce_product.commerce_product_product_id = commerce_product_field_data_commerce_product.product_id LEFT JOIN {field_data_field_image} commerce_product_field_data_commerce_product__field_data_field_image ON commerce_product_field_data_commerce_product.product_id = commerce_product_field_data_commerce_product__field_data_field_image.entity_id AND (commerce_product_field_data_commerce_product__field_data_field_image.entity_type = 'commerce_product' AND commerce_product_field_data_commerce_product__field_data_field_image.deleted = '0') LEFT JOIN {file_managed} file_managed_field_data_field_image ON commerce_product_field_data_commerce_product__field_data_field_image.field_image_fid = file_managed_field_data_field_image.fid WHERE (( (field_product_commerce_product.nid = '2412' ) )AND(( (commerce_product.type IN ('card_package')) )))
- 🇪🇸Spain espurnes
I have this problem after enabling View Unpublished module.
The rows of the views with a node entity_reference empty are not visible for any user. Just user-1 can see them.
Disabling this module it works for all the users with privileges.I applied the patch #195 . With the patch applied the rows are shown for all the users with privileges, but all the other views (without node entity_reference) shows no results.
Any suggestion?
- 🇬🇧United Kingdom leewillis77
Hi @dobe,
Can you turn SQL rewriting back on, and post a copy of the generated SQL *without* the patch in #195 and also *with* the patch in #195?
- 🇩🇪Germany fuerst
The patch from #195 prevents Views to substitute (at least) the ***CURRENT_TIME*** placeholder (see
views_views_query_substitutions()
andviews_query_views_alter()
). I tracked that down to the call to $query->getArguments() which in turn calls $this->compile(). There it somehow will use the query conditions before Views can substitute them using itshook_query_TAG_alter()
.This can be reproduced by creating a simple node based View with default settings. Add the filter criteria Content: Has new content. As soon as Node Access kicks in the problem occurs. I triggered it using the Content Access modul (default settings) and accessing the Views path as standard authorized user. The resulting SQL code was:
SELECT node.title AS node_title, node.nid AS nid, node.created AS node_created FROM node node LEFT JOIN history history ON node.nid = history.nid AND history.uid = '3' INNER JOIN node_comment_statistics node_comment_statistics ON node.nid = node_comment_statistics.nid WHERE (( (node.status = '1') AND ((history.timestamp IS NULL AND (node.changed > (***CURRENT_TIME*** - 2592000) OR node_comment_statistics.last_comment_timestamp > (***CURRENT_TIME*** - 2592000))) OR history.timestamp < node.changed OR history.timestamp < node_comment_statistics.last_comment_timestamp) ))AND ( EXISTS (SELECT na.nid AS nid FROM node_access na WHERE (( (na.gid = '0') AND (na.realm = 'all') )OR( (na.gid = '3') AND (na.realm = 'content_access_author') )OR( (na.gid = '2') AND (na.realm = 'content_access_rid') ))AND (na.grant_view >= '1') AND (node.nid = na.nid) )) ORDER BY node_creat
Query without patch looks like this:
SELECT node.title AS node_title, node.nid AS nid, node.created AS node_created FROM node node LEFT JOIN history history ON node.nid = history.nid AND history.uid = '3' INNER JOIN node_comment_statistics node_comment_statistics ON node.nid = node_comment_statistics.nid WHERE (( (node.status = '1') AND ((history.timestamp IS NULL AND (node.changed > (1412939965 - 2592000) OR node_comment_statistics.last_comment_timestamp > (1412939965 - 2592000))) OR history.timestamp < node.changed OR history.timestamp < node_comment_statistics.last_comment_timestamp) ))AND ( EXISTS (SELECT na.nid AS nid FROM node_access na WHERE (( (na.gid = '0') AND (na.realm = 'all') )OR( (na.gid = '3') AND (na.realm = 'content_access_author') )OR( (na.gid = '2') AND (na.realm = 'content_access_rid') ))AND (na.grant_view >= '1') AND (node.nid = na.nid) )) ORDER BY node_created DESC LIMIT 10 OFFSET 0
- 🇩🇪Germany fuerst
SelectQuery::getArguments()
callsSelectQuery::arguments()
so usingarguments()
instead ofgetArguments()
does fix the problem described in #224. Modified patch from #195 for Drupal 7.31 is attached.Problems mentioned in #198 remaining, of course.
- 🇪🇸Spain GoddamnNoise
I think I have the same problem here with Drupal 7.31 (running over MySQL), Search By Page 7.x-1.3 and Profile 2 7.x-1.3 modules. If you create a profile for a user wich contains the word X and a create a node with the same word and then index all the content on the site, if you search for the word X with uid=1, then you get two search results (the node and the user profile), but if you search for the word X as anonymous user, then you get only one result (the node).
The problem here is that the Search By Page module tags the query with the node_access tag, so Drupal core rewrites the query to check for node access permissions. This works ok with nodes, but not when searching for users because the node_access table shouldn't be checked for users. This is the SQL query once Drupal core has rewritten it:
SELECT i.type AS type, i.sid AS sid, SUM((11.1543620469 * i.score * t.count)) AS calculated_score FROM search_index i INNER JOIN sbp_path sp ON i.sid = sp.pid LEFT OUTER JOIN node sbpn_n ON sbpn_n.nid = sp.modid LEFT OUTER JOIN db_temporary_0 sbpp_p ON sbpp_p.pid = sp.modid LEFT OUTER JOIN users sbpu_u ON sbpu_u.uid = sp.modid INNER JOIN search_total t ON i.word = t.word INNER JOIN search_dataset d ON i.sid = d.sid AND i.type = d.type WHERE (sp.environment = :db_condition_placeholder_0) AND (sp.language = :db_condition_placeholder_1) AND( (0=1) OR( (sbpn_n.status = :db_condition_placeholder_2) AND (sp.from_module = :db_condition_placeholder_3) )OR( (sp.from_module = :db_condition_placeholder_4) )OR( (sbpu_u.status = :db_condition_placeholder_5) AND (sp.from_module = :db_condition_placeholder_6) ))AND( (i.word = :db_condition_placeholder_7) )AND (i.type = :db_condition_placeholder_8) AND ( EXISTS (SELECT na.nid AS nid FROM node_access na WHERE (( (na.gid = :db_condition_placeholder_9) AND (na.realm = :db_condition_placeholder_10) ))AND (na.grant_view >= :db_condition_placeholder_11) AND (sbpn_n.nid = na.nid) )) AND( (d.data LIKE :db_condition_placeholder_12 ESCAPE '\\') ) GROUP BY i.type, i.sid HAVING (COUNT(*) >= :matches) ORDER BY calculated_score DESC LIMIT 10 OFFSET 0
As you can see, the problem is in the " EXISTS (SELECT na.nid AS nid..." subquery when the "LEFT OUTER JOIN users" is present.
Hope this helps to catch this annoying bug in Drupal Core.
GoddamnNoise, have you tried to apply patch from this issue?
- 🇪🇸Spain GoddamnNoise
Yes, i've tried to apply the patch in #225 with no success.
- 🇮🇹Italy TBarina
I have a couple of views that didn't work with standard core node.module (Drupal v. 7.32).
The first view is a query that has a node table appearing twice with a left join. Patch #174 fixed the issue.
Then I built another view (a completely different one) with an Entity Reference in the Relationship area. The view has an exposed filter based on a field belonging to the referenced Entity.
Patch #174 caused a problem since the pager of the view disappeared each time I filled in the filter field even though there were more rows matching the specified criteria than those displayed in the first page.After applying patch #195 the issue is fixed. The SQL code generated by the view is the same both under patch #174 and #195. But now the pager works correctly. I noticed that under patch #195 the internal "count_query" (see code in function execute() in module views_plugin_query_default.inc) now returns the correct number of total rows and thus the pager is properly displayed.
#195 did a great job for me for both views. Thanks a lot.
- 🇨🇦Canada bisonbleu
Similar issue. Drove me crazy for while. Applied patch in #195 → to Drupal 7.32 and I'm happy to report that it works!
Thanks @AndreyMaximov and thank you all!
- 🇩🇪Germany christianadamski Berlin, Germany
We use #195 in our project, to make entity references and views and "view_unpublished" modules work together.
However: search stopped working, after adding the "search_config" module.
Problem: view_unpublised and search_config both alter query_node_access. The above patch tries to handle several of these, by counting and increasing "query->nextPlaceholder()". The idea being, that the separate subqueries use :db_condition_placeholder_XX and the "XX" part counting up through the subqueries.
That does not work.
The internal counter for subqueries is increased, but it seems to me it's also ignored or reset. Instead it seems the arguments are just counted, which causes each subquery to start at the same value and causes collisions between the subquery placeholders.
So instead, I altered #195 (and #225) to not use $query->condition at all, but ->where() instead, which allows me to name the placeholders myself.
I also removed the placeholder counting part added by above patches. - 🇨🇦Canada mgifford Ottawa, Ontario
What is the latest D8 version of this patch? Lots of recent focus on D7, but we need it fixed in Drupal 8. What's the last D8 patch?
- 🇮🇹Italy sylvaticus
Issue #2213729 → has been marked as duplicate of this issue (and patch in #231 solved the problem).
- 🇺🇸United States jastraat
Patch #231 works for me. Is this a confirmed bug in D8? It's been a number of years since this was first reported, and it seems like a number of folks have reviewed this for D7.
- 🇨🇦Canada Renee S
Confirmed #231 for D7.36 (I had been using the prior patch; this one also works.)
- 🇦🇺Australia SegementOfAnOrange
Patch in #231 with 7.35 worked like a charm.
- 🇫🇷France yonailo Paris
yes it works, when will this patch go into the official release ?, it is marked as Major and I think it is important enough to make it into the next 7.36 release...
- 🇫🇮Finland jgullstr
Added related issue #2213729: Items with empty entity reference field not shown in view when entity-reference based relationship is included →
Also, #231 works for 7.37
- 🇨🇦Canada balleyne
Just tried #231 on Drupal 7.38 and it appears to have fixed a longstanding bug on a View on one of our websites... fix would be nice in 7.x core...
- 🇦🇹Austria alexh
Also just tried #231 on Drupal 7.38 and it solves a bug with dissappering rows I had with a View using a not required relationship. Hope this goes into core asap.
Patched Drupal 7.38 with #231 and I can confirm that this fixed the missing nodes on views under non-administrators.
Had a non-required node reference relation in a view. Wasn't working for non-administrators.
Patch #231 on 7.38 fixed the issue.- 🇮🇹Italy apetro
Patch #231 works! My setup is Drupal 7.38 - Views 7.x-3.11 - Taxonomy Access Control Lite 7.x-1.2.
- 🇮🇪Ireland andrew@oscailte.org
Patch #231 worked for me on Drupal 7.38 with Entity Reference 7.x-1.1 and Views 7.x-3.11
- 🇮🇹Italy apetro
When will patch #231 join next Drupal core release and fix this blocking bug? I have no idea how does it work.
- 🇺🇸United States Christopher Riley
Even with patch 231 I am still running into an issue where $subquery is not being generated. What are the odds that we could get a wrapper in place that tests to see if it exists before running the:
if ($type == 'entity' && count($subquery->conditions())) at the end f the function.
Where I am butting my head against it is a add another date field to a drupal commerce item.
Thanks in advance.
- 🇺🇸United States Morasta
Patch #231 solved my issue with this in Drupal 7.39. Would be nice to see it rolled in...it's unclear why this isn't in it yet and there hasn't been much discussion beyond the patch working for various versions.
- 🇨🇦Canada Renee S
I've flipped this to RTBC, because, I believe it is. (Yes, it works for me under 7.39 also)
- 🇨🇦Canada Renee S
I've added a needs-maintainer-reply tag to this, hopefully a core maintainer can take a look and advise, since this is so helpful and has been around for so long and was passing tests, and needs a helping hand...
- 🇺🇸United States les lim
There are a couple things that need work on this issue:
1) Patch Drupal 8. If the problem does not exist in Drupal 8, update the issue summary to explain why this does not need to be fixed for D8.
2) The reason why the patches pass tests is because no tests exist to catch the original bug. Any patch that would be a candidate for committing to D7 will need to include a test that verifies that the bug exists and that the patch fixes it.
- 🇩🇪Germany christianadamski Berlin, Germany
I'll try to do this by early next week.
1.) Provide a D7 Test
2.) Check D8 for this and include a patch if necessary. - 🇩🇪Germany christianadamski Berlin, Germany
Ok, I added a simplified version of the test from the earlier patches here.
It works in that a non patched version will fail for not retrieving the correct amount of nodes.I have to point out though, that I am pretty sure, that this does not fix the underlying issue.
The placeholders in queries or more specifically subqueries, get mixed up. Two or more subqueries with conditions that require a variable to be included in the condition, will cause collisions, because variables from the later subqueries are replacing the ones from the earlier subquery. This is in turn is a somewhat correct behavior, because the naming of the placeholders is incorrect. The database-engine expects each placeholder to be unique through the entire query, but within the subqueries, you get duplicates.
This points to issues in the actual database engine.The earlier patches (#195, #225) not working any more might (just might) be related to Drupalgeddon and the changes of the replacement-pattern handling there.
- 🇺🇸United States michelle Wisconsin, USA
@ChristianAdamski: Looking at the diff between #231 and #269 I see that, in addition to the added test, this part was removed. Was that intentional?
- $tables = $query->getTables(); + $tables = &$query->getTables();
Changing the version/status to test that last patch.
- 🇩🇪Germany christianadamski Berlin, Germany
@Michelle: I honestly do not know anymore. But we are altering $tables. And that pass by reference variant "$tables = &$query->getTables();" is used at at least one other occasion in that file. So I think I actually removed that "&" from the patch by accident...
Maybe add another patch to test that? Sadly don't know when I get around to check that. I'll try though.
- 🇺🇸United States michelle Wisconsin, USA
I have been trying to use some of my contrib time to test this patch but I can't reproduce the problem. I don't know why the patch was on the client site so I can't test it there and I can't reproduce this in a fresh D7 install. I've tried both the repro steps and also following along with the original report and both times all the nodes show up whether I am logged in or not.
Hopefully someone who is having this problem can confirm your patch works. All I can confirm is that it didn't cause any visible problems on the client site when I tested it there.
- 🇺🇸United States toddejohnson
This is affecting my current project. Applied the patch from #269 and all the nodes re-appeared in the view.
- 🇩🇪Germany cherabomb
Patch 231 fixed the following problem on our site, currently running Drupal 7.41. Steps to reproduce problem:
- Create node type Article with Taxonomy field "Target user group". Create node type Employee and use the Entity Reference module to add an "Author" field on the Article type that references the Employee entity. The "Author" field is *not* required.
- Create a couple articles, some linked to a "All users including guests" group and some linked to a "Registered users" group. Make sure one article linked to the "Registered users" group does not have a value for the Author field.
- Use Taxonomy Access Lite Control to restrict access to nodes linked to the "Registered users" taxonomy term to authenticated users.
- Now create a view of Articles including their Authors. Make sure the Author relationship is not required.
- As an administrator, it will appear the view is working correctly. As an anonymous user, it will appear the view is working correctly. Log in as a standard registered user and you will be unable to see the Article without an Author.... until you apply path 231 ;)
- 🇩🇪Germany christianadamski Berlin, Germany
Just to state what I am aware is still missing here:
- Review of the patch and especially the test by smarter people than me.
- Addition of another test following #272++. Copied from earlier patch versions here, my latest patch version also adds the node-access-check for joined tables. But as pointed out in #272, I accidentally disabled that, by not passing by reference the $tables variable. What I do not really get, is what scenario exactly is prevented by this. I guess a joined table could be restricted and therefor should be checked, but I don't know, why this should happen here. So this leaves us with 3 options:
-- Remove the addition of the node access check for joined tables here. It's not working anyway right now.
-- Restore the missing pass-by-reference line and assume this is doing a good thing.
-- Wait for somebody who can describe a scenario where those checks are actually needed and build a test based on that. - 🇬🇧United Kingdom tresti88 Manchester
Patch 231 worked for me Drupal version 7.39
- 🇺🇸United States Nephele
Patch 269 does NOT work for me -- because I need the node_access check on joined tables. And therefore the deleted '&' discussed in #272 and #274 needs to be re-inserted.
Re: #279. Disabling node_access checks for joined tables is not what the OP requested -- plus it would disable checks for inner joins that are currently functional and therefore presumably being used. So, if a scenario and test are needed to make it happen, here goes.
A variant of #277 provides a scenario:
- Create node type Article with Taxonomy field "Target user group". Create node type Employee and use the Entity Reference module to add an "Author" field on the Article type that references the Employee entity. The "Author" field is *not* required.
- Create a couple articles, some linked to a "All users including guests" group and some linked to a "Registered users" group. Assign different authors to each article.
- Use Taxonomy Access Lite Control to restrict access to nodes linked to the "Registered users" taxonomy term to authenticated users.
- Now create a view listing the Employee nodes. Add a non-required relationship to Articles. Add the Article node title as another column in the viewed table.
- The resulting table should list all employees, for all users. The node access check should only affect the article-title column, ensuring that only titles visible to the current user are displayed. The bug in the original code is that employees with non-visible articles were removed from the table completely instead of being restricted. The bug in patch 269 is that restricted titles are visible to all users.
Finally, the patch I'm uploading reinserts the '&', plus expands the test -- the test now fails in all identified situations.
- 🇺🇸United States David_Rothstein
(I moved it back to Drupal 8 since the Drupal 7 testbot run is finished - we still need to get an up-to-date Drupal 8 patch here so it can be fixed there first.)
- 🇷🇴Romania tic2000
I just saw this and I think it's related to #1969208: Query node access alter filtering out accesible nodes → which also has a D8 patch waiting for review in #1969208-83: Query node access alter filtering out accesible nodes →
- 🇷🇴Romania tic2000
I marked #1969208: Query node access alter filtering out accesible nodes → as a duplicate of this one.
The patch is a little bit different from the one provided here. I would need steps to reproduce why the count is required for gids to see if it affects D8 or not. Note that in D8 the code is different for that part.
From the duplicate issue steps to reproduce this on D8
Reproduction and testing steps
- Install module attached in #1349080-286: node_access filters out accessible nodes when node is left joined →
- Create 2 regular users (user1 and user2)
- Give authenticated users the permission to create articles
- Attach a "field_private" field of type "List (integer)" to the article content type which allows only one value. The allowed values for it should be:
0|Public 1|Private
- Attach an entity reference to the page content type named field_related_article. It should allow node of type article
- Login with "user1". Create 2 articles. Leave one as default and the second one make it private by selecting the private value in the field_private select box
- Login with the admin and create 3 pages
- One with no related article
- one using the public article as reference
- one using the private article
- Login with "user1" and go to /test/access page.
- Expected result: a table with 3 rows, one for each page
- Actual result: a table with 2 rows, missing the page with no related article referenced
- Login with "user2" and go to /test/access page.
- Expected result: a table with 2 rows, one for each page
- Actual result: a table with 1 row, missing the page with no related article referenced
- Login with an admin and enable the "View private content" permission for authenticated users
- Login with "user2" and go to /test/access page.
- Expected result: a table with 3 rows, one for each page
- Actual result: a table with 2 rows, missing the page with no related article referenced
- Login with an admin and disable the "View private content" permission for authenticated users
- Apply the patch you wish to test
- Repeat steps 8 - 11 and now the actual result should mach the expected results
- 🇺🇸United States lokapujya Boston
+++ b/core/modules/node/src/Tests/NodeAccessJoinTest.php @@ -0,0 +1,179 @@ + $node = $this->drupalCreateNode($edit);
variable $node does not get used anywhere.
Also, since this is a new file and we are using the shorthand array style in some places, we might as well use it consistently.
- 🇷🇴Romania tic2000
Also, since this is a new file and we are using the shorthand array style in some places, we might as well use it consistently.
Were exactly do we use that? I looked at NodeAccessBaseTableTest, NodeAccessFieldTest, NodeTestBase and WebTestBase and I don't see that.
Actually that's the first time I see that in Drupal.
The use of PHP 5.4+ short array syntax for Drupal 8.x is being discussed and is used in some patches already. When used, try to apply it consistently to at least a whole method or function. Short array syntax should not be used in Drupal 7.x or 6.x core or contributed modules
So that's only discussed.
- 🇺🇸United States lokapujya Boston
+++ b/core/modules/node/src/Tests/NodeAccessJoinTest.php @@ -0,0 +1,179 @@ + $this->regularUser = $this->drupalCreateUser(['access content']);
For example, It was used here within the new file. So we might as well use it in all places.
We could remove some of the unneeded settings in the view to make it simpler, but since that is what the configuration system exported, maybe we should just leave it that way?
+++ b/core/modules/node/tests/modules/node_test_views/test_views/views.view.test_node_access_join.yml @@ -0,0 +1,264 @@ + fields: + title: + id: title + table: node_field_data + field: title + entity_type: node + entity_field: title + alter: + alter_text: false + make_link: false + absolute: false + trim: false + word_boundary: false + ellipsis: false + strip_tags: false + html: false + hide_empty: false + empty_zero: false
so many settings...
- 🇺🇸United States lokapujya Boston
Also, it's interesting the last D8 patch (#148 maybe) in this issue did not use a view just a db_select(). But I think I like the view better because it provides more test coverage.
- 🇷🇴Romania tic2000
The array stuff is OK.
In the module I created and uploaded I don't use a view. But since for D8 we do use views we should use that.
When porting to D7 we will need a custom page.
- 🇺🇸United States lokapujya Boston
From the duplicate issue, Credit should also be attributed to: benjifisher, TechNikh, Ericmaster
- 🇺🇸United States Nephele
(Deleting tag from #266 -- effectively answered by #267)
- 🇺🇸United States Nephele
After reading/digesting this entire issue, I've realized that the coding approach used in the patch is somewhat more contentious than I had thought. Adopting the patch from #1969208: Query node access alter filtering out accesible nodes → effectively reverses an earlier decision, and therefore I think the change needs to be justified.
The two coding approaches under consideration are:
- Add an is-null-check (as in #289, and in much older patches such as #41)
- Move the node-access conditions into the join conditions (first proposed in #65, most recently used in #282, e.g. the latest d7 patch).
The original change from approach #1 to approach #2 was made following a lot of discussion (e.g., #36, #62, #65, #132), and approach #2 was endorsed by multiple contributors (see #71, #72).
In short, my vote is for approach #1 -- but only if it's possible to prove through tests that it can correctly handle various problems identified in earlier discussions. (At which point the d7 patch would need to be revised).
To explain more fully, I believe that approach #2 is perhaps the more elegant solution. However, implementing approach #2 cleanly isn't possible (at least not in d7 -- I don't know d8 well enough yet), so it ends up requiring some hacky and fragile coding. The issue being that DatabaseCondition objects (such as $subquery) can not be used as join conditions. Rather, the join condition has to be a string, and any placeholders need to be manually created and added to the join arguments. In other words the subquery can't be moved using simple code like:
$tables[$nalias]['condition'][] = $subquery;
Instead the code has to be:
$tables[$nalias]['condition'] .= ' AND EXISTS(' . (string)$subquery . ')'; $tables[$nalias]['arguments'] += $subquery->arguments();
Which involves casting $subquery into a string, as well as manually naming the placeholders used in the arguments. (See #111). This has caused numerous problems: postgresql fails when casting $subquery into a string (#161); generating unique placeholder names is not straightforward (#190). Which leads me to conclude that approach #1 is more robust and therefore preferable.
However, concerns have been raised about whether approach #1 works correctly in all situations. I've been able to identify two primary concerns that motivated the switch away from approach #1:- Is access granted to nodes that have no entries in the node_access table (see #36, #62)?
- Is access granted to nodes that have multiple entries in the node_access table, when all of the entries deny access (see #80)?
The earlier discussions imply that adding an is-null-check will incorrectly grant access in these two cases. While that would be true if the patch added
isNull("node_access.nid")
, all of the submitted patches instead addisNull("$nalias.$nfield")
-- testing the variable in the base table, not the joined table. In other words, the code change allows entries where the value of an entity reference field is null; it is impossible for such an entry to match any node, therefore it's impossible for it to grant access to any nodes.Nevertheless, if we are going to switch away from an endorsed approach, I think tests have to be added to explicitly address all previously-raised concerns, and confirm that the patch behaves correctly in all identified scenarios. Which means I think at least three more tests are needed:
- Test missing node_access entries: After creating a node and referencing it (e.g., adding it as a related_article), manually delete all entries for it in the node_access table. Confirm that the reference is hidden from all non-admin users.
- Test multiple node_access entries: For example, need to have a list of permitted users for each private article, and create a node with at least two permitted users. Confirm that a reference to the node is hidden to non-permitted users.
- Test multiple joins (see #160): For example, the related_articles need to also have related_articles. And/or there needs to be a second field, e.g. second_article. The view then needs to have three columns, to show all the related articles.
I may be able to put together some d7 code implementing these tests (or at least more clearly demonstrating them), but I haven't worked in d8 yet.
- 🇷🇴Romania tic2000
The D8 test can be changed to test for point and 3. I think that 2 is already covered by the test.
I also did a manual test and after deleting the entries for a private article I can't see the listing of the page in the table. Note that deleting directly from table should not happen and when I delete the node from the UI it also deletes it's reference from the page that was referencing it.
- 🇷🇴Romania tic2000
I also tested point 3 by adding another reference field to a page and it shows the results as expected. If I don't have access to any of the references I don't see the entry. If I have no access to one and the second is empty I don't see the entry. If I have access to one and the other is empty I see the entry.
- 🇷🇴Romania tic2000
I modified the test with the following:
1. Changed article to also allow the related article reference.
2. Change the view to display a 3rd column with the reference attached to the article.
3. In the test I create articles for both a selected user (author) and anonymous user with combination of private and public references.
4. I create pages with more combination, private, public, references both by the "author" and by the anonymous user.
5. I calculate the total of rows each user should see.
6. Some more text based check to be sure users don't see rows they shouldn't see. Regular should not see the word "private" at all, while "author" can not see "- private" which denotes a private article he is not author of. This test are to be sure the totals check are not just a fluke.
7. Check for the total number of rows each should see.I attach screenshots with how the tables look for each user and let me know what other text checks I should include.
- 🇷🇴Romania tic2000
One more patch. The previous didn't have 2 cases:
- page > private article > author private
- page > author private article > private
I added code to create those 2 situations and also I change the
assertTrue()
used for row count check to useassertEqual()
- 🇨🇦Canada chx
I complete agree and really, really like applying There Is No Kill Like Overkill to testing security related aspects of Drupal core.
- 🇺🇸United States Nephele
Thanks for putting in the extra tests. I agree that the patch seems to have a pretty comprehensive set of tests now.
Re: #297. Yes, upon examining the node_access_test module more closely I confirmed that point 2 is already covered by the tests, i.e., private nodes already have 2-3 entries each in the node_access table. And given that you manually confirmed point 1, i.e., that the case with 0 node_access entries behaves properly, that seems like enough (since the basic node_access tests don't even check this case, and technically it should never occur).
- 🇺🇸United States Nephele
My apologies, but somehow I messed up in my initial evaluation of whether an is-null check is equivalent to moving the condition into the join. I suppose the good news is that the tests in patch #302 (which I started to port into d7) do demonstrate the differences between the two approaches.
When I run the tests from #302 against the d7 code from #282 (where the node-access condition is moved into the join), all users see a table with 15 rows -- because all of the 'page' nodes are public. What changes is the contents of the 'Article' and 'Article 1' columns -- all inaccessible 'article' nodes are hidden, based on the current user's permissions.
And that's what a left join should do. Adding a left join to a query shouldn't make any of the original rows (e.g., the page nodes) disappear; it should just add extra information whenever it is available. The node-access condition places more limits upon whether the extra information is indeed available, but if it also makes the original rows disappear, then it's behaving like an inner join.
So unfortunately I think the patch needs to be rewritten.
- 🇺🇸United States Nephele
And more bad news is that d8 still does not have a clean way of moving the node_access subquery into the join -- there's just a feature request at #2275519: Unable to use Condition objects with joins → .
- 🇷🇴Romania tic2000
From the IS:
When two node tables are left joined then access checks prevent access to the node when nothing is matched in the table on the right-hand side of the join.
Access should be granted when nothing is matched in the right-hand side (and the node on the left-hand side is permitted).Exactly that is what the patch solves.
You want to change the last phrase to
Access should be granted when nothing is matched in the right-hand side (and the node on the left-hand side is permitted), but in case something is matched on right side check access on right side and show the left side while hiding the right side if access to right side is not permitted.
That I think is for another issue which can be opened after the issue here is fixed.
I move this back to RTBC. If the maintainers think we should expand the scope of this they can move it back to needs work.
- 🇺🇸United States Nephele
I do not agree that this issue is anywhere near RTBC.
For four years all the development in this queue was on a patch where the condition was moved into the join. That is the approach that was endorsed by multiple early contributors (#71, #72), who spent a lot of time debating the merits of the different approaches. The dozens of different contributors to this issue over the last four years who have said that a patch works for them were all using a patch in which the condition was moved into the join.
The change in approach dates back only 2 weeks, and was reviewed primarily in another issue ( #1969208: Query node access alter filtering out accesible nodes → ), where alternatives were never discussed. The is-null-test approach was explicitly criticized by the early contributors to this issue.
In terms of the desired behaviour, the behaviour I'm advocating was requested by multiple contributors: For example #54:
The problem with the patch in 41/42/45 is that if you cannot access the attached node, it will deny access to the main node. I think that behavior is wrong.
#55:
In regards to still showing a result even if the user does not have access to the related node, I agree with you in that is the behavior desired.
#66:
Show me a list of nodes I can view. If there are any attached nodes I can view, show additional data from those nodes.
The summary that you quote was added in #143, after all of the previous comments had been incorporated into the patch design. So my interpretation is that the summary is incorrect. I'm willing to take a stab at revising the summary, but preferably only after we reach a consensus on what the summary should say.
- 🇺🇸United States lokapujya Boston
Changing to Needs Work because The description in the comment of the test needs some re-working anyway. For example:
-
+++ b/core/modules/node/src/Tests/NodeAccessJoinTest.php @@ -0,0 +1,322 @@ + * - Create user with "access content" and "create article" permissions which + * will be author having access to some private articles but not others.
be an author having
-
+++ b/core/modules/node/src/Tests/NodeAccessJoinTest.php @@ -0,0 +1,322 @@ + * - Create pages with articles as reference for any combination of article
??
-
+++ b/core/modules/node/src/Tests/NodeAccessJoinTest.php @@ -0,0 +1,322 @@ + * he is not the author of.
he => the user
-
- 🇺🇸United States lokapujya Boston
The problem with the patch in 41/42/45 is that if you cannot access the attached node, it will deny access to the main node. I think that behavior is wrong.
I don't think we should fix this. That sounds like a feature request.
What might be helpful is if we could publicize the test case in the issue descriptions in simplest form possible so that we agree on how it should work. This would eventually become part of the documentation.
For example:Left Right Role Access Public Public normal granted Public [NULL] normal granted Public Private normal ??
- 🇺🇸United States Nephele
Admittedly, the problem on my site that led me here involves null-values. Which is why adding an is-null-check on my site appeared to work, and I didn't notice the differences between the two approaches initially.
My primary concern is that I don't want previous discussions / consensus /decisions in this issue to be overlooked, and especially not if it's based on my mistakes parsing those discussions.
The fact that the tests in #302 fail when used with the previously-accepted patch (#286) is objective evidence that the various symptoms are part of a single bug. I doubt tests should be added to core when there's disagreement about the expected results of the test.
Furthermore, reading through those discussions and examining the differing results has led me to conclude that the behaviour when the condition is moved into the join is correct. I think dropping null-value entries is the most visible symptom of this node_access bug -- because it will even affect views involving only public content, and most content on most sites is public. But hiding a public node because it is left-joined to a restricted node is another symptom of the same line of code, just one that affects fewer views and fewer users. Restricted content should only hide rows when it is required (i.e., inner-joined), not when it is optional (i.e., left-joined). And tagging a query with node_access should only remove restricted nodes, not public nodes.
In fact, I now know that my site has views where this an issue. My site has some complex views with multiple layers of left-joined nodes where access restrictions are critical. But missing data on those views had not been brought to my attention because it only affects a small subset of users, and those users didn't realize a handful of valid rows were missing. So just as with the tests, I can't support a patch now that I know it doesn't fix all the issues.
- 🇺🇸United States lokapujya Boston
So we need to go with:
Show me a list of nodes I can view. If there are any attached nodes I can view, show additional data from those nodes.
which is the #282 fix? The tests will probably need to be updated. Are there any scenarios where this doesn't work and someone would intend the view to work the like the #302 fix? But first, we need an issue summary update because that's not what the issue summary reads.
- 🇺🇸United States Nephele
I've made some revisions to the title/summary to bring it up-to-date, and I also tried to pull in some wording from #1969208: Query node access alter filtering out accesible nodes → .
- 🇺🇸United States Nephele
To help facilitate a comparison, I'm uploading a patch that should basically be a d8 port of #282.
It's not identical to #282 -- I've pulled in a patch from #2275519: Unable to use Condition objects with joins → because it allows cleaner code. For now I'm uploading it without the new tests, because I know those will fail.
- 🇺🇸United States Nephele
Apologies, I'm writing d8 code blindly because my about-to-be-replaced test machine can't run php 5.5.
The last submitted patch, 317: node_access_for_left_joins_d8-1349080-317-without_tests.patch, failed testing.
- 🇫🇷France andypost
+++ b/core/modules/node/src/NodeGrantDatabaseStorageInterface.php @@ -50,7 +50,7 @@ public function checkAll(AccountInterface $account); - public function alterQuery($query, array $tables, $op, AccountInterface $account, $base_table); + public function alterQuery($query, array &$tables, $op, AccountInterface $account, $base_table);
this is API change so needs change record
- 🇺🇸United States Nephele
Re: API change. This is actually a slightly odd situation; in some ways my edit is more like a documentation fix than an API change. The edit isn't changing the capabilities of the alterQuery function; it's just making the function definition provide correct information about whether arguments may change.
In the original code, alterQuery already has the ability to make changes to $tables. This is because $tables is actually a redundant argument -- it's just a reference to an array stored within $query (i.e., the object provided as the first function argument). alterQuery can make any changes it wants to $query, and therefore it can make any changes it wants to $tables. To demonstrate, I'm uploading a new version of the patch which has the exact same functionality, but does it without an API change.
Personally, I think the code in #318 is better, but I realize that in the context of a large project, a stable API may be more important than good code. Does anyone have any feedback on which one is preferable?
- 🇺🇸United States Nephele
I've now added tests to this version of the code. The tests are derived from the tests in #302, but I ended up doing a fair bit of refactoring. Plus of course changing the details so that the approach I've been using passes the tests.
There are a few commented-out bits of code that can be enabled to make the tests more similar to those in #302 and #299 -- they're not intended to be part of the final code, but I left them in place in case anyone else is trying to make more direct comparisons with the previous tests.
[Also added a link to #106721: Optimize node access query building → -- which is making edits to the same function. Earlier patches had overlap issues, but the approaches used in #302 and #321 are overlap-free (even if/when a D7 backport is created).]
- 🇺🇸United States Nephele
The only difference between 321 and 326 is that tests were added. Nevertheless, I'm uploading an interdiff.
- 🇺🇸United States Nephele
To help visualize the tests in #326 I'm uploading screenshots of the views generated by the tests. Note that the displayed node titles are of the format "Node_type node_status - linked_node_status" -- so whether a user can access a node is based solely on the information before the dash (-).
Three of the screenshots are the views generated by #326. For comparison I've also provided one screenshot if the code from #302 is substituted in, and two screenshots for non-patched code.
- 🇺🇸United States Nephele
In the absence of any other feedback, I've been trying on my own to find ways to resolve the question of whether patch#326 → or patch#302 → is the better solution. For anyone starting at the end, both cover the minimum requirements (all node_access-restrictions are enforced; null-entry rows are not hidden), but patch#302 hides entire rows instead of just cells when there is restricted content.
I've created a new d7 patch derived line-for-line from (d8) patch#326, including all the tests. I need the patch for my own website; hopefully there are others who will also find it easier to use and provide feedback given a d7 patch.
Using these d7 tests, I've been able to evaluate many of the patches previously uploaded to this issue. The results were:
- Unpatched code fails the tests, i.e., the tests detect the original problem
- All other patches I checked (e.g.,
#149 →
,
#195 →
,
#269 →
, etc.) failed testing (either in the tests I've added, or in search tests, see
#206 →
). So the various problems reported for those interim patches are all detected by tests.
- Even the failing patches still generate views that restore all the incorrectly-hidden rows (failures are triggered by details such as cell contents). This behavior is notably different from the alternative d8 patch#302, in which more rows are kept hidden.
My conclusion is that patch#326 is what comments #1-#281 were working to achieve; the alternative patch#302 is not. By my count, that includes 17 different users reporting that patch#231 worked for them, all of whom should get identical results with patch#326 (or the d7 version added here).
Finally, the tie-breaker for me is that patch#326 can satisfy everyone's needs, but patch#302 cannot. If patch#302 is adopted, it is impossible for a query to generate results comparable to patch#326 -- patch#302 forcibly excludes entire rows, even though the rows contain publicly visible information. On the other hand, patch#326 will work for users who prefer patch#302, e.g., users who want to exclude public nodes because those nodes have non-visible links to private nodes. Those users can just add appropriate filters/conditions to their query (e.g., "where field_related_article.target_id is not null and related_article.id is null").
- 🇺🇸United States burnsjeremy
I'm still running into this issue myself, I haven't actually tested the D8 patches (the only D8 sites that I have are pretty simple, therefore this issue hasn't came up) but I did test out both of the current D7 patches but I ended up choosing #231 because it changed the least amount of code. I know that's not necessarily the best route or that just b/c it changed the least code it is the best but it was less convoluted considering the length of this thread and the problem that we were facing with what was getting filtered out in our views on a project that we are currently working on. The patch worked and fixed our current problem but we plan on re-visiting this issue soon to either contribute another patch if needed or at least pitch in to get this issue worked out. Thanks all who have worked on this thread, it is definitely a pain point at this time and hopefully all of the hard work will pay off soon. Also commenting to subscribe to future updates since I now have a vested interest in the work being done in this thread.
- 🇺🇸United States Nephele
@burnsjeremy: Patch #231 is functionally equivalent to #332 (and passes all the tests). Theoretically, however, #231 is less robust than #332 -- meaning that #231 is less likely to work on excessively complex queries.
Re: D7 patch testing in #332. I wanted to test the patch against other databases (given earlier problems reported for PostgreSQL), so I queued up some extra tests. But the alternate database tests all use PHP5.5 instead of PHP5.3. As far as I can tell, the test failures are not caused by the patch. Instead, I think core D7 can't pass tests under PHP5.5.
I'm also revising the issue summary based on my comments in #330; I think the summary now more accurately reflects the issue's status.
Drupal 8.0.6 → was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 → is now available and sites should prepare to update to 8.1.0.
Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule → and the Allowed changes during the Drupal 8 release cycle → .
- 🇬🇧United Kingdom catch
We discussed this on a call with both core committers and entity API maintainers and agreed this is definitely major. Tagging as such.
- 🇺🇸United States cydharttha
Thanks for the work everyone. I applied #195 for now, it resolved various issues we had with Entity References and Views + Content Access module.
The last submitted patch, 339: 1349080-339.patch, failed testing.
- 🇩🇪Germany jelhan
#332 fixed the Content Access + Entity Reference + Views issue for my.
Drupal 7
PHP 5.4
mySQL 5.5 - 🇳🇱Netherlands daffie
#2275519: Unable to use Condition objects with joins → is in. Rerolled the current patch and removed the changes for the files core/lib/Drupal/Core/Database/Query/Select.php and core/tests/Drupal/KernelTests/Core/Database/SelectComplexTest.php.
The last submitted patch, 342: 1349080-342.patch, failed testing.
Drupal 8.1.9 → was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 → is now available and sites should prepare to upgrade to 8.2.0.
Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule → and the Allowed changes during the Drupal 8 release cycle → .
Tried applying patches 195 and 332. No errors, but neither one worked. Is a PHP 5.5 workaround still in the works? I just updated to 7.51 with PHP 5.5.24.
- 🇮🇹Italy apetro
I have not updated from 7.43 with patch #231. It is essential for my website that patch works.
I agree with burnsjeremy (#333): patch #231 changes less code and, for production site, I think is more prudential to use. I'm worried about changes in 7.51: is it compatible with patch #231? - 🇸🇪Sweden twod Sweden
We are using #332 in production (on PHP 5.6 and MySQL). Picked it for the reasons outlined in #330. Basically, it's a very useful API addition, it's backwards compatible, it comes with tests, and it feels like something which D8 should handle in the same way.
Had no issues applying #332 to 7.51, other than a couple of extra whitespaces. Verified it still works for our test cases.
Our test case includes a user which should be able to see certain nodes in a View, which may optionally refer to another node of the same type (its "parent"). Which node(s) the user has access to is determined using node access records/grants and they normally get access to both the "parent" and the "child" nodes.
Without the patch in #332, our user is not able to see any of the top level nodes which do not have a parent. Applying the patch immediately makes the top level nodes appear in the View, with the "parent" left empty, as they should.
@TwoD (#347) - can you specify which files had the extra whitespaces in them? I'm wondering if I missed them, and they might be the reason I'm not seeing results.
- 🇸🇪Sweden twod Sweden
@tonka67 The only output I got from git was
<stdin>:455: trailing whitespace. // Non-empty nodes are wrapped in <a> solely for sake of xpath counting -- <stdin>:465: trailing whitespace. } Warning: 2 rows add whitespace errors
The patch still applies cleanly, it's just that git doesn't like the whitespaces it adds after a comment and the closing curly bracket. It's in node_access_test.module so wouldn't affect the normal functionality.
EDIT: Removed extra output from the curl call I piped into git...
@TwoD Thanks, that helps. I'll keep tweaking it. Meanwhile, I've had some success by-passing the problem altogether by re-architecting my entityreferences.
- 🇩🇪Germany bzrudi71
No need for PostgreSQL issue tag as it's not PostgreSQL specific - removing.
- 🇺🇸United States ExTexan
I just applied patch #332 to a D7.51 installation and started getting this error repeatedly...
Recoverable fatal error: Method DatabaseCondition::__toString() must return a string value in SelectQuery->__toString() (line 1565 of /path/to/root/includes/database/select.inc).
.
Line 1565 of that file is...
if (!empty($table['condition'])) { $query .= ' ON ' . (string) $table['condition']; <= Line 1565 }
.
When I reverted the two patched files, the errors stopped.
I know that, early in this thread, it was speculated that this issue might be related to the content access module, but I don't have that module installed. I am, however, using the Domain module (and domain_access).
- 🇺🇸United States lokapujya Boston
The detailed examples in the issue summary become documentation. This issue might never get resolved, unless it's first agreed how it should work. Where is the discussion from #337?
- 🇺🇸United States freelock Seattle
As one of the early people in this discussion who outlined the approach the patches have taken, and wrote the first few iterations of the patch, it really has nothing to do specifically with content_access -- it has to do with all access modules that make use of the node_access api.
I wasn't involved in the core committers call, but it's certainly been a major issue for many major releases now. I'd really be curious as to what's holding it up...
- 🇬🇷Greece cirrus3d
@ExTexan, what version of Views do you have, and could you tell us your PHP/MySQL specs?
- 🇺🇸United States ExTexan
@cirrus3d, sorry for the late reply. I was trying to find time to get back in and apply the patch again so I could answer the question from TwoD (#353). By the time I saw his question, I couldn't remember exactly where/when the error appeared.
But as for your questions:
Views 7.x-3.14
PHP 5.6.10
MySQL 5.5.52
(running in MAMP Pro) - 🇪🇸Spain plopesc Valladolid
Attaching new patch for D7 version after updating to 7.52
- 🇪🇨Ecuador jwilson3
The above patch fixes the error message noted in #352 with the following additional hunk change:
@@ -3467,7 +3467,7 @@ function _node_query_node_access_alter($query, $type) { $join_cond->where($tables[$nalias]['condition'], $tables[$nalias]['arguments']); $tables[$nalias]['arguments'] = array(); } - $tables[$nalias]['condition'] = $join_cond; + $tables[$nalias]['condition'] = $join_cond->__toString(); } } }
- 🇬🇧United Kingdom P2790
I tried #358, patches successfully but doesn't fix the original problem. Only disabling sql rewriting in the views > advanced works for me.
- 🇺🇸United States jastraat
#332 works for us, and we've been using it in production for roughly 9 months. It still applies to 7.53 (with a 15 line offset) and fixes our issue with left joins.
Note that to generate the original issue described by this ticket, a content access module is not necessarily required. Just an optional relationship in a view using an entityreference field.
- 🇺🇸United States Sinan Erdem
I have tried the patch on #332 for Drupal 7 and my issues with Content Access and Views modules are resolved.
Drupal 8.2.6 → was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. ( Drupal 8.3.0-alpha1 → is available for testing.)
Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule → and the Allowed changes during the Drupal 8 release cycle → .
- 🇸🇪Sweden twod Sweden
The D7 patch in #358 DOES NOT work. It created massive problems for us by removing all ON - conditions in joins to aliases of
{node}
. Views which relied on node access show random nodes when the join condition is cast to a string (the only real difference since #322).#332 is still the way to go. We've been using it since 7.52 and confirmed it still does the same thing on 7.54 without issues.
- 🇳🇱Netherlands HansKuiters
Patch #332 works for me. 7.54 + Views (using relations and aggregation) + Organic Groups.
- 🇺🇸United States lokapujya Boston
It would be even more helpful, in general for any issue, if folks can say how they tested a patch rather than just saying "works for me".
- 🇺🇸United States lokapujya Boston
#326 no longer applies, neither does #342
The last submitted patch, 370: 1349080-370.patch, failed testing.
- 🇫🇷France thib France
Hi,
Is this the same issue : Views 'comment count' field doesn't display on referenced node with 0 comment thru relationships → ? (Don't use any control access module) - 🇪🇬Egypt Sherif Darwish
#332 is tested and worked for drupal version 7.54, my setup includes views with optional relationship, content access module.
- 🇺🇸United States Fool2
Have applied #332 to a dev site on 7.56 successfully. Fixed the immediate problem with my view that led me here (simple optional entity reference use case)
For future reference (and google-foo) the way I originally noticed this issue was that I was testing a view on two different browsers-- one logged in as admin and the other as a less privileged user, and suddenly the less privileged user was missing rows in the view when I added the reference. This is likely because admin user skips node access checks altogether.
The worst part about this bug is that I think I have run into it before and thought I was doing something wrong, causing me to abandon/change my approach to what I was working on. As others have stated it is hard to detect and non-intuitive. I am wondering if there is anything we can do to make this more likely to be committed to D7 core. If it cannot be committed to core, it might be worthwhile adding warnings/language or making mandatory the "require this relationship" checkbox when the conditions are right for this bug's behavior to emerge.
- 🇺🇸United States ryan.gibson
Alright, #342 applied cleanly to 8.2 and solved the issue (which took forever to diagnose, btw—glad to see this was being worked on).
My issue was an admin view in which a table listing listed content type A as well as content from referenced content type B. A relationship was added (not required). The issue only occurred when that reference field was empty—when it was, only admin users could see the content. It was filtered out for all other roles. I applied this patch cleanly, cleared caches, refreshed, and now all content shows up, even if the referenced relationship field is empty (as expected).
I won't change the status, but for 8.2, this is working great.
- 🇧🇷Brazil gilsbert
Hi.
#332 worked perfectly!
Drupal 7.56 + content_access
database: postgresql
->view with an optional relationship was empty for anonymous users before the patch
->after patch and a cache clear everything is working fine!
For D7 I would recommned RTBC for #332!
Thank you all for the great work!
I hope this will be commited soon to D7!
- 🇳🇿New Zealand dangreenman
Patch #332 confirmed working with:
Drupal 7.56, Mysql, (OG) Organic groups 7.x-2.9Thank you all for your fine work.
- 🇷🇺Russia kalistos
Thanks a lot for #370!
But small issue: it contains row
if ($tables_ref[$nalias]['condition'] instanceof ConditionInterface) {
And ConditionInterface class is not defined as it is out of uses classes at the top of file. - 🇨🇦Canada circuscowboy
If I am not mistaken the process is that drupal 8 will be patched and then the patch will get back ported to D7 and all can be done in the same issue. That is what I have seen in the past.
I have been bringing this patch along for months so it would be good to get committed. (D7 - haven't used on D8 so can't review)
- 🇳🇿New Zealand john pitcairn
Oops, the issue version was still 8.3.x but the test passes against 8.4.x - so resetting the issue version to that and hoping it can get into 8.4-rc as a bugfix, since the priority is major.
- 🇷🇺Russia kalistos
I updated #370 with adding class ConditionInterface to use statements and fixed automating testing error.
- 🇳🇱Netherlands HansKuiters
I first said that #332 works for me, I now have the error message as in #352. For that I added the addition of #359. No errors for now. I have OG, not any other access module.
PHP 5.6
Drupal 7.56
Views 7.x-3.18 (using relations and aggregation)
Organic Groups 7.x-2.9 - 🇵🇹Portugal jrochate
Yet another +1 report:
PHP7.1
Drupal 7.56
Views 7.x-3.18
TAC 7.x-1.0
Workbench Access 7.x-1.5#332 fix entity relation optional (left join)
Thanks. This should be on next stable 7.x release.
- 🇺🇸United States jennyOlsen
#332 works for me! I had a view with a required content relationship and optional entity reference relationship. Before the patch it only worked for admins, after the patch it works for all users with the correct permissions. Thanks for the work on this!
PHP 5.6
Drupal 7.56
Views 7.x-3.18 Drupal 8.5.0-alpha1 will be released the week of January 17, 2018, which means new developments and disruptive changes should now be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule → and the Allowed changes during the Drupal 8 release cycle → .
- 🇺🇸United States nwoodland
Patch from #379 works great in Drupal 8.4. Thanks!
- 🇮🇱Israel Amir Simantov
Hi guys. For D7 - why fix is not yet in core? Thanks.
- 🇳🇱Netherlands dmsmidt Amsterdam 🇳🇱🇪🇺
Since this is a bug on the current stable release, setting this back to 8.4.x.
Here is a test only patch with a kernel test that shows the problem using a Dynamic Query, to prove this is not only a views issue.
- 🇳🇱Netherlands dmsmidt Amsterdam 🇳🇱🇪🇺
Here is the last patch with the extra test and some cleanup.
The original test case should probably be rewritten since Drupal\node\Tests\NodeTestBase is deprecated.
The last submitted patch, 393: drupal-node_access_for_left_joins-1349080-393-NEW-TEST-ONLY.patch, failed testing. View results →
- 🇳🇱Netherlands Lendude Amsterdam
Thanks everybody who has worked on this, great to see all the test coverage. Haven't really looked at the 'is this the right fix' thing, just a quick scan of the contents. This needs some more clean up.
-
+++ b/core/modules/node/src/NodeGrantDatabaseStorage.php @@ -152,46 +153,75 @@ public function alterQuery($query, array $tables, $op, AccountInterface $account $grants = node_access_grants($op, $account); + foreach ($tables as $nalias => $tableinfo) {
Unrelated whitespace change, lets prevent bloating this as much as possible.
-
+++ b/core/modules/node/src/NodeGrantDatabaseStorage.php @@ -152,46 +153,75 @@ public function alterQuery($query, array $tables, $op, AccountInterface $account + if ($table instanceof SelectInterface|| $table != $base_table) {
Needs a space before ||
-
+++ b/core/modules/node/src/Tests/NodeAccessJoinTest.php @@ -0,0 +1,358 @@ + +/** + * @file + * Contains \Drupal\node\Tests\NodeAccessJoinTest. + */ +
This can be removed
-
+++ b/core/modules/node/src/Tests/NodeAccessJoinTest.php @@ -0,0 +1,358 @@ +namespace Drupal\node\Tests; ... +class NodeAccessJoinTest extends NodeTestBase {
per #394 this needs to be rewritten as a BrowserTestBase test and moved to the right dir and namespace for that
-
+++ b/core/modules/node/src/Tests/NodeAccessJoinTest.php @@ -0,0 +1,358 @@ + /** + * Modules to enable. + * + * @var array + */
This can just be {@inheritdoc}
-
+++ b/core/modules/node/src/Tests/NodeAccessJoinTest.php @@ -0,0 +1,358 @@ + protected function setUp() {
This needs a docblock, can just be {@inheritdoc}
-
+++ b/core/modules/node/src/Tests/NodeAccessJoinTest.php @@ -0,0 +1,358 @@ + // User to add articles and test author access. + $this->authorUser = $this->drupalCreateUser(['access content', 'create article content']); + // Another user to add articles (whose private articles can not be accessed + // by authorUser). + $this->otherUser = $this->drupalCreateUser(array('access content', 'create article content')); + + // Create the articles. ... + // Generate a view listing all the pages, and check the view's content for + // users with three different access levels. + + ViewTestData::createTestViews(get_class($this), ['node_test_views']);
Everything between and including these lines feel like something that should be in setUp(), because its setting stuff up...
-
+++ b/core/modules/node/src/Tests/NodeAccessJoinTest.php @@ -0,0 +1,358 @@ +// // Enable this check to simulate tests in patch#299 +// if ($reference2 != 'no_reference' && ((substr($article, 0, 6) == 'author') != (substr($reference2, 0, 6) == 'author'))) { +// continue; +// } +// // Enable this check to simulate tests in patch#302 +// if ($reference2 != 'no_reference' && ((substr($article, 0, 6) == 'author') != (substr($reference2, 0, 6) == 'author')) && !(substr($article, -7) == 'private' && substr($reference2, -7) == 'private')) { +// continue; +// }
This is commented code, use it or lose it.
-
+++ b/core/modules/node/src/Tests/NodeAccessJoinTest.php @@ -0,0 +1,358 @@ + // The naming system ensures that the text 'Article $article' will only appear + // in the view if an article with that access type is displayed in the view. (The text + // '$article' alone will appear in the titles of other nodes that reference
> 80 characters
-
+++ b/core/modules/node/src/Tests/NodeAccessJoinTest.php @@ -0,0 +1,358 @@ + $total = 0; + $count_s_total = $count_s2_total = 0; + $count_s_public = $count_s2_public = 0; + $count_s_author = $count_s2_author = 0; + $total_public = $total_author = 0;
Why are we running all this code to calculate these numbers? They are just static within the parameters of this test right? This is just making this harder to read and review.
-
+++ b/core/modules/node/src/Tests/NodeAccessJoinTest.php @@ -0,0 +1,358 @@ + // Create page nodes referencing each article, as well as a page with no reference.
> 80 characters
-
+++ b/core/modules/node/src/Tests/NodeAccessJoinTest.php @@ -0,0 +1,358 @@ + // Following test is no longer relevant. + //$this->assertNoText('- private', 'Author should not see pages related to others\' private articles.'); ... + // Following test is no longer relevant. + //$this->assertNoText('private', 'Public user should not see pages related to any private articles.');
Not relevant apparently, so we can take that out.
-
+++ b/core/modules/node/tests/modules/node_test_views/test_views/views.view.test_node_access_join.yml @@ -0,0 +1,339 @@ +uuid: 0a62a0f4-8322-49c3-964d-770997ac5ac0
uuid needs to be taken out
-
- 🇩🇪Germany nghai
I have also tested the 1349080-397-D8.patch with Drupal core 8.5.3 and it worked.
- 🇮🇹Italy finex
I also tested #394 with Drupal 8.5.4 and it fixed the bug. Thanks!
- 🇳🇱Netherlands spokje
For what it's worth: #397 Applied cleanly and works on Drupal 8.3.9 (and yes, it's patched for all Drupalgeddons)
- 🇨🇭Switzerland ayalon
Will this ever be applied to Drupal Core? I'm porting this patch since 4 minor versions.
- 🇺🇸United States jadhavdevendra
Can someone review the simpler solution that I have posted for D7 here #2994870: Empty node reference permission issue in Views →
- 🇺🇸United States jadhavdevendra
After reading near about 300 odd comments for D7 patch from #332 works perfectly!
The details about the problem that I faced is reported here #2994870: Empty node reference permission issue in Views → - 🇬🇧United Kingdom jofitz
The last submitted patch, 407: 1349080-407.patch, failed testing. View results →
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.- 🇬🇧United Kingdom jofitz
My local test system is not working, but I think this should resolve that test failure.
Also corrected the 3 coding standards errors.
The last submitted patch, 409: 1349080-409.patch, failed testing. View results →
- 🇮🇷Iran garamani
#332 Patched and works.
PHP 5.4.16
Drupal 7.59
Views: 7.x-3.18 (Relationships: "user: some_fields" and User: Content authored), Ajax enabled
Organic Groups: 7.x-2.10 - 🇮🇹Italy finex
Hi, I've just patched 8.6.5 using #411 and it works perfectly :-)
- 🇩🇪Germany markdc Hamburg
I just applied #411 in 8.6.7 and can also confirm it solves the issue.
- 🇺🇸United States ashrafabed
Also applied #411 and it solved the issue for me. Thank you.
- 🇬🇧United Kingdom rachelf
Applied #411 in 8.6.10 which solved issue for me.
- 🇺🇸United States Chris Charlton Los Angeles
So far, that's five votes for RTBC. :)
Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule → and the Allowed changes during the Drupal 8 release cycle → .
- 🇭🇺Hungary tamasd
Applied #411 on Drupal 8.6.13 (PHP 7.3.3) and solved the issue for me.
- 🇺🇸United States nwoodland
Patch from #411 on Drupal 8.6.13 and PHP 7.2.15 works great. Thanks!
- 🇺🇸United States jcory
Hi, I only encountered this problem recently, but only because I wasn't expecting it since admin worked OK. I am working with Drupal 7.65, OG 2.1, all other modules up to date. I had stumbled on a fix some time ago by chance, using Views Field View module, though at the time I did not know it was a fix. I don't like patching Core since unintended consequences could occur. Until a final core release for 7.x comes out, I am rewriting any views that use Entity Reference as chains of views implemented with Views Field View.
- 🇬🇧United Kingdom alexpott 🇪🇺🌍
This patch doesn't apply to 8.8.x as there are changes to a kernel test there and it needs an update due to
FILE: ...ev/core/modules/node/tests/src/Functional/NodeAccessJoinTest.php ---------------------------------------------------------------------- FOUND 1 ERROR AFFECTING 1 LINE ---------------------------------------------------------------------- 230 | ERROR | Unnecessarily gendered language in a comment ----------------------------------------------------------------------
2x: entity_get_display() is deprecated in drupal:8.8.0. It will be removed before drupal:9.0.0. Use \Drupal::service('entity_display.repository')->getViewDisplay() instead. See https://www.drupal.org/node/2835616 2x in NodeAccessJoinTest::testNodeAccessJoin from Drupal\Tests\node\Functional 2x: entity_get_form_display() is deprecated in drupal:8.8.0. It will be removed before drupal:9.0.0. Use \Drupal::service('entity_display.repository')->getFormDisplay() instead. See https://www.drupal.org/node/2835616 2x in NodeAccessJoinTest::testNodeAccessJoin from Drupal\Tests\node\Functional
Also need to fix this ^^
I've tried to review the code changes. Complex stuff. The test coverage of views integration looks good. It would be great to get a +1 from one of the node access maintainers.
- 🇺🇸United States pookmish
The patch in #411 works technically. However it more than tripled the view render time necessary to display results. I know the following scenario is not ideal, but it valuable to think about. When displaying about 230 nodes and displaying 10 fields i see an no increase in the main query build or execution times. But I see an increase from 10002.92ms to 31705.65ms after applying the patch. I'm curious if there might be a solution that solves the problem but doesn't add another issue.
- 🇺🇸United States freelock Seattle
@pookmish I'm not clear about the scenario you're seeing this performance regression. Can you share the query that was actually in use?
The gist here is that unpatched, node_access queries are simply incorrect, and will not allow users to access certain content in views that use the same base table more than once. After patching, this should have no effect on views that don't do this -- if your view doesn't use a relationship, I would expect no performance impact. If your view uses an entityreference relationship to pull in related entities of the same entitytype, then without this patch, that view might be broken if you have an access modules that limits access to some entities -- some results will be missing.
You can work around this now by disabling sql rewriting on the view, and providing your own access control (e.g. using a permission on the view, a filter, etc). If having this patch causes a performance regression on a particular view, you could do the same -- disable query rewriting and handle permissions yourself. Or do some query analysis, possibly find an index you can add to the database to improve things.
But without this patch, your view is likely not working correctly -- so you're pointing out a choice between performance and correct results.
Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule → and the Allowed changes during the Drupal 8 and 9 release cycles → .
- 🇳🇱Netherlands Lendude Amsterdam
Addressed #423, lets see if we can get some numbers on Views query times with vs without
- 🇧🇪Belgium ducktape
Rerolled against 8.9. Fixed some minor conflicts in NodeGrantDatabaseStorage.php.
The last submitted patch, 428: 1349080-428.patch, failed testing. View results →
- 🇮🇳India rensingh99
Hi,
I have tried to reproduce this bug with 8.9x to test the patch. But I have not gotten this issue.
Below are my steps.
1 I have added the entity reference field of the "article" type in the "basic page" type.
2 I have post three nodes in the "basic page" content type and I have entered related articles in only one node.
3 I have made the view of basic content type and I have added the relationship of referenced field(field_related_article) to show the title of the related article.
Below is an output screenshot of view as an admin user.
Below is an output screenshot of view as an anonymous user.
The view result is the same for both admin and anonymous.
Am I doing anything wrong? Or is it resolved in the latest version?
Thanks,
Ren - 🇺🇸United States freelock Seattle
@rensingh99 the bug is in the node access system, so it only takes effect if you have a module that is implementing node access rules.
I'm not exactly sure what module in core uses this system -- content moderation possibly? You can definitely trigger with contrib modules such as OG, Group, Domain Access, etc.
The last submitted patch, 434: 1349080-374.patch, failed testing. View results →
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.- 🇺🇸United States byrond
#430 works for us on 8.8.2 and also passes tests for 8.9, whereas #434 is currently failing.
- 🇺🇦Ukraine aleevas
This patch should fix the latest patch failure.
Also was fixed coding standard issues - 🇬🇧United Kingdom danharper
Hi,
I have tested the patch and it works but using views_data_export attached view it creates duplicates, not sure if that's a views data export issue or something this patch is creating.
Cheers Dan
Drupal 8.9.0-beta1 → was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule → and the Allowed changes during the Drupal 8 and 9 release cycles → .
- 🇨🇭Switzerland boromino
#439 works on 8.8.6, no duplicates with views data export.
- 🇳🇱Netherlands Lendude Amsterdam
This is using methods that have been removed in D9, so this needs a reroll/rework to get to work on D9. Other than that, it looks great.
I've tried to get numbers on the with/without patch query times, but haven't seen anything major, but yeah, any additional join will have a performance impact. Looking at the given times in #424, "10002.92ms to 31705.65m" that is one massively underperforming query to begin with, so I can totally see that adding an extra join to that would make it even worse. But I have to agree with #425, its a matter of performance VS getting the correct result, so the correct result should win here.
- 🇳🇱Netherlands Lendude Amsterdam
Thanks @aleevas for the quick reroll. Some things I still see:
+++ b/core/modules/node/src/NodeGrantDatabaseStorage.php @@ -210,7 +241,16 @@ public function write(NodeInterface $node, array $grants, $realm = NULL, $delete - $query = $this->database->insert('node_access')->fields(['nid', 'langcode', 'fallback', 'realm', 'gid', 'grant_view', 'grant_update', 'grant_delete']); + $query = $this->database->insert('node_access')->fields([ + 'nid', + 'langcode', + 'fallback', + 'realm', + 'gid', + 'grant_view', + 'grant_update', + 'grant_delete', + ]); @@ -257,13 +297,13 @@ public function delete() { ->fields([ - 'nid' => 0, - 'realm' => 'all', - 'gid' => 0, - 'grant_view' => 1, - 'grant_update' => 0, - 'grant_delete' => 0, - ]) + 'nid' => 0, + 'realm' => 'all', + 'gid' => 0, + 'grant_view' => 1, + 'grant_update' => 0, + 'grant_delete' => 0, + ])
These changes are unrelated to the patch, can we take them out please? This is hard enough to review as it is :)
-
+++ b/core/modules/node/src/NodeGrantDatabaseStorage.php --- /dev/null +++ b/core/modules/node/src/Tests/NodeAccessJoinTest.php +++ b/core/modules/node/src/Tests/NodeAccessJoinTest.php @@ -0,0 +1,357 @@ +namespace Drupal\node\Tests;
This is in the old simpletest path and namespace. It needs to be moved to node/tests/src/Functional and the namespace to match
-
+++ b/core/modules/node/src/Tests/NodeAccessJoinTest.php @@ -0,0 +1,357 @@ +/** + * @file + * Contains \Drupal\node\Tests\NodeAccessJoinTest. + */
We don't do this anymore, can be taken out
-
- 🇳🇱Netherlands Lendude Amsterdam
- 🇧🇯Benin delacosta456
hi
you people save my life after hours of debugging.... #332 worked for me on D7.Many thanks
- 🇳🇿New Zealand quietone
There was a call for a reroll in #bugsmash, so here is my attempt. Adding tag
I started with the patch in #439 because the reroll in #444 had some out of scope changes. Also, as per #446, added back the test, NodeAccessTest::testQueryWithBaseTableJoin, from #393 that got lost along the way.
- 🇳🇿New Zealand quietone
There were one or two things that made the code hard for me to read, so I changed them. If not wanted, I'll remove it. I also updated the comments to align better to 80 columns, removed '--', and other minor things that I thought were improvements. I still think the comments need improving, particular removing the references to '$parameter' name. But then I don't know this area.
- 🇳🇿New Zealand quietone
Oops, wasn't working on HEAD and I didn't notice the patch sized changed.
- 🇳🇱Netherlands Lendude Amsterdam
@quietone thanks for improving the comments, this is complicated stuff so anything that helps make this easier to read is a big plus.
Updated the IS a bit, took another look at this and it all seems good to me. All feedback has been addressed.
Since this messes with queries, I've queued up all databases to make sure we don't break anything on them either.
- 🇺🇸United States freelock Seattle
Woo! So gratifying to see this FINALLY RTBC!
We've been applying this patch to most of our complex Drupal sites for the better part of a decade... I still recall spending what felt like weeks in a debugger to identify the cause and arguing with @agentrickard over the correct solution... Thank you to everyone keeping it current and getting it across the finish line!
- 🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10
-
+++ b/core/modules/node/tests/src/Functional/NodeAccessJoinTest.php @@ -0,0 +1,348 @@ + public static $modules = ['node_access_test', 'node_test_views', 'views'];
this needs to be protected now
-
+++ b/core/modules/node/tests/src/Functional/NodeAccessJoinTest.php @@ -0,0 +1,348 @@ + protected $profile = 'standard';
this is going to be costly. Do we absolutely have to use standard here?
This test is very difficult to read because there's a fair bit going on. I'll come back and look at it again with fresh eyes.
-
- 🇳🇿New Zealand quietone
1. Fixed
2. Let's see what happens if it is changed to minimal and added stark theme.Due to changes to the test I made a fail patch as well.
The last submitted patch, 456: 1349080-456-fail.patch, failed testing. View results →
- 🇳🇱Netherlands Lendude Amsterdam
+++ b/core/modules/node/tests/modules/node_test_views/test_views/views.view.test_node_access_join.yml @@ -0,0 +1,338 @@ +uuid: 0a62a0f4-8322-49c3-964d-770997ac5ac0
We need to take the uuid out of the View, sorry for missing that before, other then that it looks great
- 🇳🇱Netherlands Lendude Amsterdam
All feedback has been addressed, back to RTBC
The last submitted patch, 459: 1349080-459.patch, failed testing. View results →
- 🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10
Given the IS references installing the entity reference module this needs an IS update
The last submitted patch, 459: 1349080-459.patch, failed testing. View results →
- 🇬🇧United Kingdom mustanggb Coventry, United Kingdom
Opened 🐛 [D7] node_access filters out accessible nodes when node is left joined Postponed to track the D7 backport.
Drupal 9.1.0-alpha1 → will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule → and the Allowed changes during the Drupal 9 release cycle → .
- 🇳🇿New Zealand quietone
In #463 an Issue Summary was requested by larowlan. Setting back to NW.
- 🇳🇿New Zealand quietone
Arg! I don't know what happened there! Restoring the tag and setting to NW.
- 🇩🇪Germany Elin Yordanov
The patch at #439 works very well on Drupal 8.8.11.
- 🇳🇿New Zealand quietone
Sorry, I missed that there was an issue summary update in #464. I've removed the tag.
- 🇬🇧United Kingdom thetwentyseven
I could not apply the patch for Drupal 7.77 with #332 patch. I had only to change escapeTable to escapeAlias.
- 🇬🇧United Kingdom mustanggb Coventry, United Kingdom
Hey thetwentyseven, please see 🐛 [D7] node_access filters out accessible nodes when node is left joined Postponed for the D7 backport.
- 🇳🇿New Zealand quietone
Re-uploading the patch from #459 so that it is testing against 9.2.x
- 🇬🇧United Kingdom alexpott 🇪🇺🌍
+++ b/core/modules/node/tests/modules/node_access_test/node_access_test.module @@ -79,7 +79,7 @@ function node_access_test_node_grants($account, $op) { - if (!\Drupal::state()->get('node_access_test.private') || $node->private->value) { + if (!\Drupal::state()->get('node_access_test.private') || (isset($node->private) && $node->private->value)) {
How come? Testing shows why - \Drupal\Tests\node\Functional\NodeAccessJoinTest has node types with and without the private field. So +1
-
+++ b/core/modules/node/src/NodeGrantDatabaseStorage.php @@ -151,16 +152,29 @@ public function alterQuery($query, array $tables, $op, AccountInterface $account + // $tables_ref should effectively be the same as $tables, except it is a + // reference to the original copy of the data, within the $query object. + // Edits made to $tables_ref are retained within the $query object. + // $tables_ref would not be necessary if the version of $tables in the + // alterQuery arguments was passed by reference but that would technically + // be an API change. + $tables_ref = &$query->getTables();
This documentation feels a bit awkward. I think this could be simpler if we don't have the whole $tables_ref thing. And do
if (empty($tableinfo['join type'])) { $query->exists($subquery); } else { // If this is a join, add the node access check to the join condition. // This requires using $query->getTables() to alter the table // information. $join_cond = $query ->andConditionGroup() ->exists($subquery); // Add the existing join conditions into the Condition object. if ($tableinfo['condition'] instanceof ConditionInterface) { $join_cond->condition($tableinfo['condition']); } else { $join_cond->where($tableinfo['condition'], $tableinfo[$nalias]['arguments']); $query->getTables()[$nalias]['arguments'] = []; } $query->getTables()[$nalias]['condition'] = $join_cond; }
Then there is one source of truth about table info and we don't have to do things like
if (empty($tableinfo['join type']) || empty($tables_ref[$nalias]['join type'])) {
and ponder how and why these could ever be different. -
+++ b/core/modules/node/src/NodeGrantDatabaseStorage.php @@ -151,16 +152,29 @@ public function alterQuery($query, array $tables, $op, AccountInterface $account + // The main loop is using $tables instead of $tables_ref, if for any reason + // the two arrays differ, technically this function has been told to operate + // on the entries listed in $tables.
If we don't have $tables_ref we could do away with this awkwardness.
-
+++ b/core/modules/node/src/NodeGrantDatabaseStorage.php @@ -191,7 +205,26 @@ public function alterQuery($query, array $tables, $op, AccountInterface $account + // Add the existing join conditions into the Condition object. + if ($tables_ref[$nalias]['condition'] instanceof ConditionInterface) { + $join_cond->condition($tables_ref[$nalias]['condition']); + } + else { + $join_cond->where($tables_ref[$nalias]['condition'], $tables_ref[$nalias]['arguments']); + $tables_ref[$nalias]['arguments'] = []; + } +++ b/core/modules/node/tests/modules/node_access_test/node_access_test.module @@ -79,7 +79,7 @@ function node_access_test_node_grants($account, $op) { + if (!\Drupal::state()->get('node_access_test.private') || (isset($node->private) && $node->private->value)) { +++ b/core/modules/node/tests/src/Functional/NodeAccessJoinTest.php --- a/core/modules/node/tests/src/Kernel/NodeAccessTest.php +++ b/core/modules/node/tests/src/Kernel/NodeAccessTest.php
Do we have test coverage of both sides of this if? I comment out
$join_cond->condition($tables_ref[$nalias]['condition']);
Both core/modules/node/tests/src/Kernel/NodeAccessTest.php and core/modules/node/tests/src/Functional/NodeAccessJoinTest.php pass.
-
- 🇩🇪Germany Ronino
I cannot confirm #473. For me #332 applies fine on both 7.77 and 7.78 (apart from some offsets).
- 🇬🇧United Kingdom mustanggb Coventry, United Kingdom
@Ronino
For D7 please comment in 🐛 [D7] node_access filters out accessible nodes when node is left joined Postponed and perhaps the maintainers will see it, also there is a more recent re-roll. - 🇳🇱Netherlands spokje
Let's start with a reroll of patch #477 🐛 node_access filters out accessible nodes when node is left joined Needs work
- 🇳🇱Netherlands spokje
Addressed #480 🐛 node_access filters out accessible nodes when node is left joined Needs work #1 and #2.
Looking into #3 now.
- 🇳🇱Netherlands spokje
(Hopefully correctly) Addressed #480 🐛 node_access filters out accessible nodes when node is left joined Needs work #1 and #2.
Looking into #3 now.
- 🇳🇱Netherlands spokje
Forgot to add
NodeAccessJoinTest
and its resources...
:/ - 🇳🇱Netherlands spokje
On #480 🐛 node_access filters out accessible nodes when node is left joined Needs work #3:
+++ b/core/modules/node/src/NodeGrantDatabaseStorage.php @@ -191,7 +205,26 @@ public function alterQuery($query, array $tables, $op, AccountInterface $account + // Add the existing join conditions into the Condition object. + if ($tableinfo['condition'] instanceof ConditionInterface) { + $join_cond->condition($tableinfo['condition']); + } + else { + $join_cond->where($tableinfo['condition'], $query->getTables()[$nalias]['arguments']); + $query->getTables()[$nalias]['arguments'] = []; + } + $query->getTables()[$nalias]['condition'] = $join_cond; + }
There is indeed no test coverage of the
if
part of the above.Looking through the codebase I couldn't find any way to trigger this in a functional test.
- 🇳🇱Netherlands spokje
@jordan.jamous: You probably changed the version of this issue, because you want your 9.1 re-roll tested against
9.1.x-dev
. You can achieve just that by ticking the checkboxCustom parameters
on the "Add test/retest" page. Doing that allows you to select a Drupal Core, PHP and database version. - 🇦🇺Australia jordan.jamous
@Spokje yeah thanks mate, I did that by mistake and reverted it. Apologies.
- 🇳🇱Netherlands spokje
@jordan.jamous: No worries, the important part here is:
I did that by mistake and reverted it.
Thanks for that :)
Drupal 9.2.0-alpha1 → will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule → and the Allowed changes during the Drupal core release cycle → .
- 🇳🇿New Zealand quietone
This needs tests for #480-3 🐛 node_access filters out accessible nodes when node is left joined Needs work which Spokje replied to in #489 🐛 node_access filters out accessible nodes when node is left joined Needs work .
Adding tag.
Since there is a dedicated Drupal 7 issue, removing backport tag.
- 🇺🇸United States danflanagan8 St. Louis, US
Updated the IS to reflect that writing tests is not complete, as described in #497.
- 🇮🇹Italy sylvaticus
[OT] Happy 10 years bug report ! I don't work on web dev anymore, but it really makes you think to see a **10 years** bug that continue to move on patch A provided, there is some problem with patch A, patch B.... It must be frustrating for many. Ok, sorry for the troll, but it really makes you think....[/OT]
- 🇳🇱Netherlands spokje
Rerolled against
9.4.x-dev
and minimally altered the patch. - 🇳🇱Netherlands Lendude Amsterdam
In the rerolls the changes that @Spokje did in #483-#488 were lost, and those cleaned it up a lot and addressed the feedback by @alexpott, so I've gone back to that version.
Added test coverage for using a Condition object in the join, but that still means we can do without the
if
, as far as I can tell the$join_cond->where($tables_ref[$nalias]['condition'], $tables_ref[$nalias]['arguments']);
handles the Condition object just fine.I think this should cover the remaining feedback.
- 🇳🇱Netherlands spokje
Fixed PHPCS error in #501 🐛 node_access filters out accessible nodes when node is left joined Needs work patch and reverted back to strong type-checking in
NodeAccessJoinTest
I've checked it and it works. Looks good to me. Changed status to RTBC.
I've checked it and it works. Looks good to me. Changed status to RTBC.
- 🇬🇧United Kingdom alexpott 🇪🇺🌍
+++ b/core/modules/node/tests/src/Functional/NodeAccessJoinTest.php @@ -0,0 +1,361 @@ + /** + * The installation profile to use with this test. + * + * @var string + */ + protected $profile = 'minimal';
This is not necessary. It's better if this test is using the testing profile is used. Can be set directly back to RTBC once that is removed. The test passes fine without it.
- 🇳🇱Netherlands spokje
Can be set directly back to RTBC once that is removed.
The last submitted patch, 506: 1349080-506.patch, failed testing. View results →
- 🇳🇱Netherlands spokje
The test passes fine without it.
Well, That Could Have Gone Better:
Unsilenced deprecation notices (3) 1x: stripos(): Passing null to parameter #1 ($haystack) of type string is deprecated 1x in NodeAccessTest::testQueryWithBaseTableJoin from Drupal\Tests\node\Kernel 1x: strpbrk(): Passing null to parameter #1 ($string) of type string is deprecated 1x in NodeAccessTest::testQueryWithBaseTableJoin from Drupal\Tests\node\Kernel 1x: strtoupper(): Passing null to parameter #1 ($string) of type string is deprecated 1x in NodeAccessTest::testQueryWithBaseTableJoin from Drupal\Tests\node\Kernel
- 🇭🇺Hungary mxr576 Hungary
The output on the CI is truncated (probably that should be fixed). The full context for the first deprecation warning is
[28-Apr-2022 16:17:52 Australia/Sydney] PHP Deprecated: a:5:{s:11:"deprecation";s:80:"stripos(): Passing null to parameter #1 ($haystack) of type string is deprecated";s:5:"class";s:39:"Drupal\Tests\node\Kernel\NodeAccessTest";s:6:"method";s:26:"testQueryWithBaseTableJoin";s:15:"triggering_file";s:78:"/mnt/files/local_mount/build/core/lib/Drupal/Core/Database/Query/Condition.php";s:11:"files_stack";a:12:{i:0;s:78:"/mnt/files/local_mount/build/core/lib/Drupal/Core/Database/Query/Condition.php";i:1;s:75:"/mnt/files/local_mount/build/core/lib/Drupal/Core/Database/Query/Select.php";i:2;s:75:"/mnt/files/local_mount/build/core/lib/Drupal/Core/Database/Query/Select.php";i:3;s:75:"/mnt/files/local_mount/build/core/lib/Drupal/Core/Database/Query/Select.php";i:4;s:75:"/mnt/files/local_mount/build/core/lib/Drupal/Core/Database/Query/Select.php";i:5;s:82:"/mnt/files/local_mount/build/core/modules/node/tests/src/Kernel/NodeAccessTest.php";i:6;s:58:"/mnt/files/local_mount/build/sites/simpletest/TestCase.php";i:7;s:58:"/mnt/files/local_mount/build/sites/simpletest/TestCase.php";i:8;s:80:"/mnt/files/local_mount/build/vendor/phpunit/phpunit/src/Framework/TestResult.php";i:9;s:58:"/mnt/files/local_mount/build/sites/simpletest/TestCase.php";i:10;s:19:"Standard input code";i:11;s:19:"Standard input code";}} in /mnt/files/local_mount/build/vendor/symfony/phpunit-bridge/Legacy/SymfonyTestsListenerTrait.php on line 289
"triggering_file";s:78:"/mnt/files/local_mount/build/core/lib/Drupal/Core/Database/Query/Condition.php";s
And the rest is also pointing at the same file.
Based on this, the deprecation warning is unrelated to this issue; therefore back to RTBC.
Update: opened https://www.drupal.org/project/drupal/issues/3277602 → as a follow up.
- 🇳🇱Netherlands Lendude Amsterdam
@mxr576 I like the idea, but that would mean we would break the tests in HEAD if this gets committed, which will not happen.
So, dug a bit, and unfortunately this reveals a bug in
\Drupal\Core\Database\Query\Condition
.When adding a condition through
\Drupal\Core\Database\Query\Condition::where
(like this test does), the operator is set to NULL, but theif
that checks for anything added by this method usesisset()
, so that leaves the operator on NULL which then gets passed to all these string functions.I hope we can drag this into scope because we add test coverage for this here too (if somewhat implicit).
- 🇭🇺Hungary mxr576 Hungary
@Lendude yes, my primary goal was not to increase the scope of this ooooold issue, although I could not resist opening xDebug and figuring out what is happening after my previous comment. In the end, while you worked on this change, have committed a different fix in #3277602 → .
Maybe we should join our efforts there and fix this problem before this fix can get merged ;S
- 🇳🇱Netherlands Lendude Amsterdam
@mxr576 you got it right, I got it wrong :)
Took your fix from #3277602: Handle better when $condition['field'] is a ConditionInterface → and added it here. Interdiff is from 506 which is the relevant previous version of this patch.
If dragging it in here is not acceptable to committers then we should fix it in your spin off issue.
The last submitted patch, 510: 1349080-510.patch, failed testing. View results →
- 🇭🇺Hungary mxr576 Hungary
> If dragging it in here is not acceptable to committers then we should fix it in your spin off issue.
+1But I have a random (?) JS failure in the spin-off... https://www.drupal.org/pift-ci-job/2370115 →
Drupal 9.4.0-alpha1 → was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule → and the Allowed changes during the Drupal core release cycle → .
- 🇺🇸United States neclimdul Houston, TX
As noted in my reviews of #3277602: Handle better when $condition['field'] is a ConditionInterface → this deprecation gets triggered when you miss use Condition::where by passing a Condition. Doing this is technically a violation of the ConditionInterface::where signature which only accepts a string, not a Condition. Views is already violating it today so maybe we expand the type but probably also it means we might want to take a closer look at this line and make sure its correct:
+++ b/core/modules/node/src/NodeGrantDatabaseStorage.php @@ -191,7 +193,20 @@ public function alterQuery($query, array $tables, $op, AccountInterface $account + $join_cond->where($tableinfo['condition'], $query->getTables()[$nalias]['arguments']);
- 🇳🇱Netherlands daffie
Postponing this issue until the fix for the Database API is in ( #3277602: Handle better when $condition['field'] is a ConditionInterface → );
Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened → , as Drupal.org infrastructure cannot currently fully support a branch named
main
. New developments and disruptive changes should now be targeted for the11.x
branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule → and the Allowed changes during the Drupal core release cycle → .Drupal 9.5.0-beta2 → and Drupal 10.0.0-beta2 → were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule → and the Allowed changes during the Drupal core release cycle → .
- last update
over 1 year ago 29,453 pass - 🇳🇱Netherlands Lendude Amsterdam
Back down the rabbit hole!
This is based on #506, none of the database layer stuff in here.
Fresh look makes me think we can just fix this by updating the test that caused to deprecations. None of the functional tests was causing problems, so Views when used through the UI is fine. It was the kernel test that was causing deprecations. Thanks to the discussion on #3277602: Handle better when $condition['field'] is a ConditionInterface → I finally wrapped my head around this (thanks people in that issue!!).
This just makes sure we are passing in a string and not a Condition and that makes the deprecations go away. Also removed the testing theme setting since that is now the default.
I think this is good to go again, I think @alexpott was ready to commit in #505 so lets see if we can get this in! (and hope this goes green on the bot ;))
- Status changed to RTBC
over 1 year ago 4:36pm 15 June 2023 - 🇺🇸United States smustgrave
Tried replicating following the issue summary but after talking to @lendude sounds like it requires a contrib for testing.
So instead I'm going to rely on the tests to show that there is an issue. Running both without the fix I get the following
NodeAccessJoinTest
Author should see 21 rows. Actual: 9 Failed asserting that 21 matches expected 9. Expected :9 Actual :21
NodeAccessTest
Failed asserting that '0' matches expected 2. Expected :2 Actual :0
Reviewing the fix change and it appears to be pretty small (but mighty). The documentation seems good too.
Reviewing the last few comments and agree it seemed this was super close.
With almost 500 comments ticket may have performance issues soon. So hopefully this good for committing.
- last update
over 1 year ago 29,502 pass - Open on Drupal.org →Environment: PHP 8.2 & MySQL 8last update
over 1 year ago Waiting for branch to pass - 🇺🇸United States xjm
We (I) should probably look at this before it goes in and confirm the behavior change is what we want.
It also needs a CR and a release note.
Thanks everyone for your perseverance on this issue! My first comment on this issue was almost 11 years ago. 😭
- last update
over 1 year ago 29,511 pass - last update
over 1 year ago 29,556 pass - last update
over 1 year ago 29,556 pass - last update
over 1 year ago 29,562 pass - last update
over 1 year ago 29,570 pass - last update
over 1 year ago 29,574 pass - last update
over 1 year ago 29,804 pass - last update
over 1 year ago 29,804 pass - last update
over 1 year ago 29,805 pass - last update
over 1 year ago 29,807 pass - last update
over 1 year ago 29,814 pass - last update
over 1 year ago 29,817 pass - last update
over 1 year ago 29,818 pass - last update
over 1 year ago 29,818 pass 16:04 32:52 Running45:13 43:29 Running- last update
over 1 year ago 29,868 pass, 2 fail The last submitted patch, 521: 1349080-521.patch, failed testing. View results →
- last update
over 1 year ago 29,880 pass - 🇫🇮Finland lauriii Finland
A known random fail: 🐛 Random test fail in Drupal\Tests\Component\Utility\RandomTest::testRandomMachineNamesUniqueness Needs work .
- last update
over 1 year ago 29,882 pass - last update
over 1 year ago 29,889 pass - last update
over 1 year ago 29,911 pass - last update
over 1 year ago 29,949 pass - last update
over 1 year ago 29,949 pass - last update
over 1 year ago 29,956 pass - last update
over 1 year ago 29,956 pass - last update
over 1 year ago 29,961 pass 1:03 56:13 Running- last update
over 1 year ago 29,961 pass - last update
about 1 year ago 29,962 pass - last update
about 1 year ago 30,047 pass - last update
about 1 year ago 30,052 pass - last update
about 1 year ago 30,059 pass - last update
about 1 year ago 30,060 pass - Status changed to Needs work
about 1 year ago 11:15pm 24 August 2023 - 🇳🇿New Zealand quietone
I'm triaging RTBC issues → .
I skimmed the issue summary and then skimmed the last few comments. I see that this is tagged for a CR and a release note snippet. I added the heading for the release note to the Issue Summary. I am also setting back to NW for the change record. I will ping about this in #contribute.
- Status changed to Needs review
about 1 year ago 6:28am 25 August 2023 - 🇳🇱Netherlands Lendude Amsterdam
Took a stab at a CR https://www.drupal.org/node/3383274 → , back to "Needs review" for the snippet and the CR
- Status changed to RTBC
about 1 year ago 6:39am 25 August 2023 - last update
about 1 year ago 30,063 pass - last update
about 1 year ago 30,063 pass - last update
about 1 year ago 30,101 pass - last update
about 1 year ago 30,137 pass - last update
about 1 year ago 30,138 pass - last update
about 1 year ago 30,139 pass - last update
about 1 year ago 30,139 pass - last update
about 1 year ago 29,474 pass - last update
about 1 year ago 30,149 pass - last update
about 1 year ago 30,151 pass - last update
about 1 year ago 30,153 pass - last update
about 1 year ago 30,161 pass - last update
about 1 year ago 30,164 pass - last update
about 1 year ago 30,171 pass - last update
about 1 year ago 30,171 pass - last update
about 1 year ago 30,208 pass - last update
about 1 year ago 30,362 pass, 2 fail The last submitted patch, 521: 1349080-521.patch, failed testing. View results →
- Status changed to Needs work
about 1 year ago 9:42am 26 September 2023 - 🇸🇰Slovakia coaston
Guys,
Patch #521 fixed issues in views in my cases for D10.1.3, however my editor says there is an issue as described on picture below :
in NodeAccessJoinTest.php
is that okey? - Status changed to RTBC
about 1 year ago 1:50pm 26 September 2023 - 🇳🇱Netherlands Lendude Amsterdam
Unrelated fail, so back to RTBC
@coaston could it be that your editor is checking against an old version of PHP that doesn't support type hinting?
- 🇸🇰Slovakia coaston
You are right, when I used a different one the syntax error disappeared.
31:02 27:30 Running- last update
about 1 year ago 30,363 pass - last update
about 1 year ago 30,363 pass - last update
about 1 year ago 30,374 pass - last update
about 1 year ago 30,380 pass - last update
about 1 year ago 30,385 pass - last update
about 1 year ago 30,387 pass - last update
about 1 year ago 30,397 pass - last update
about 1 year ago 30,400 pass - last update
about 1 year ago 30,414 pass - last update
about 1 year ago 30,420 pass - last update
about 1 year ago 30,423 pass - last update
about 1 year ago Patch Failed to Apply - 🇳🇿New Zealand quietone
I have worked to update credit. I got down to 'catch' in the list and ran out of steam.
- last update
about 1 year ago Patch Failed to Apply - last update
about 1 year ago Patch Failed to Apply - last update
about 1 year ago Patch Failed to Apply - last update
about 1 year ago Patch Failed to Apply - last update
about 1 year ago Patch Failed to Apply - last update
about 1 year ago Patch Failed to Apply - last update
about 1 year ago Patch Failed to Apply - last update
about 1 year ago Patch Failed to Apply - last update
about 1 year ago Patch Failed to Apply - Status changed to Needs work
about 1 year ago 11:43pm 10 November 2023 The Needs Review Queue Bot → tested this issue.
While you are making the above changes, we recommend that you convert this patch to a merge request → . Merge requests are preferred over patches. Be sure to hide the old patch files as well. (Converting an issue to a merge request without other contributions to the issue will not receive credit.)
- Status changed to RTBC
12 months ago 11:22am 27 November 2023 - last update
12 months ago Patch Failed to Apply - last update
12 months ago Custom Commands Failed - last update
12 months ago Patch Failed to Apply - last update
12 months ago Custom Commands Failed - last update
12 months ago Custom Commands Failed - last update
12 months ago Custom Commands Failed - last update
11 months ago Custom Commands Failed - last update
11 months ago Custom Commands Failed - Status changed to Needs work
11 months ago 5:49am 8 December 2023 The Needs Review Queue Bot → tested this issue. It fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".
This does not mean that the patch needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide → to find step-by-step guides for working with issues.
- Status changed to Needs review
11 months ago 7:56am 11 December 2023 - 🇳🇱Netherlands Lendude Amsterdam
#537 wasn't enough, also needed to update a changed variable name, updated it and moved to using MRs so hiding all the files
- Status changed to RTBC
11 months ago 6:13pm 11 December 2023 - 🇺🇸United States smustgrave
Restoring status and will ping #security-discussion channel to see if anyone can take a look.
- last update
11 months ago Patch Failed to Apply - 🇳🇿New Zealand quietone
Completed update of credit which I find challenging for an issue with so many people involved. One the other hand, I do like progress of the old issues.
I also read the change record. It has the detail, which is great. And I like the explanation of what will happen for Editors and Site builds. I did make some changes for plain English and formatting. It is worth another read. I also think the title should mention that this change is about views. At least for me, from the title alone I had no idea what it was about. I am adding a review of the CR to the remaining tasks. (Oh, there is no remaining tasks - I will add it)
Similarly, the release note snippet could be simpler as it will link to the Change record. Sorry, I don't have a suggestion for that right now.
I did not review the MR.
- 🇪🇨Ecuador jwilson3
Reviewed the changes https://www.drupal.org/node/3383274/revisions/view/13235090/13361832 →
They make sense but there was a grammatical error that I fixed here, presuming you meant to write "And" instead of "An".
https://www.drupal.org/node/3383274/revisions/view/13361832/13364203 →
It is worth another read. I also think the title should mention that this change is about views
I re-read the CR → and ...
Queries with the node_access tag get access information joined to the correct table. This means that when joining the node table this data is added to the correct join.
I think the wording of the first two sentences is still quite confusing to someone coming at this with fresh eyes and no context. I also agree that it should mention Views earlier, if not in the title, then at least in the first or second sentence. IMO, it makes little sense to require devs and site builders (to whom I guess this change record is written for) have to dig into this issue summary here to figure out that issue of disappearing rows typically happens when you add an optional relationship to a view. I'm not sure how to rephrase this more simply.
For Site builders, this means that complex Views with multiple relationships to the Node table will show the correct results
Are "complex Views" and "multiple relationships" on the View an actual requirement to trigger this bug? The steps to reproduce on this issue summary do not really indicate this.
- Status changed to Fixed
10 months ago 12:18am 5 January 2024 -
alexpott →
committed c271adbb on 11.x
Issue #1349080 by Nephele, freelock, Spokje, quietone, Lendude,...
-
alexpott →
committed c271adbb on 11.x
- 🇺🇸United States freelock Seattle
Super stoked to see this committed!
@quietone @jwilson3 this issue is not strictly related to Views, though views is the easiest place to reproduce the issue.
It requires a query (or view) with a relationship to another table/entity where entity access of some kind is used to filter out rows. I've hit it most often with OG or Group module. In this scenario, the query filters out the wrong items -- usually hiding rows the user should be able to see.
Has anyone actually benchmarked performance regressions with this change? I'm not sure why that belongs in the change record -- using a node access module implies slower performance, but we use this on sites with tens of thousands of affected entities without anything being noticeably slow... I think the change record should focus on it returning correct results.
I've needed to add this patch to dozens of sites over the years...
- last update
10 months ago Custom Commands Failed Automatically closed - issue fixed for 2 weeks with no activity.
- 🇧🇾Belarus beloglazov91
The patch uploaded in https://www.drupal.org/project/drupal/issues/1349080#comment-15334980 🐛 node_access filters out accessible nodes when node is left joined Needs work had a little bug. I've fixed it.
- 🇧🇾Belarus beloglazov91
The patch uploaded in https://www.drupal.org/project/drupal/issues/1349080#comment-15334980 🐛 node_access filters out accessible nodes when node is left joined Needs work had a little bug. I've fixed it.
- 🇦🇺Australia jordan.jamous
@beloglazov91 this issue is fixed/closed, please don't upload patches to this issue.
if you have other concerns, you may want to create a new issue, reference this ticket, then add your details and fixes. - 🇺🇸United States nicxvan
@jordan.jamous in general I think you're correct, however this is an edge case I think where the previous patch for 10.1 does not work for 10.2 and the update was not backported. So until 10.3 comes out there would be no fix for this issue for 10.2 sites.
I think in this case a backported patch is ok, though it should be numbered properly.