Using highlight processor causes theme to think user is anonymous

Created on 2 February 2020, about 5 years ago
Updated 22 June 2023, almost 2 years ago

I've discovered a bug that happens only when I enable the "Highlight" processor in my search index. I would like to use this so I can have a clean highlighted excerpt on my main search results page.

If I enable the "Highlight" processor, when any views that use this Search API index are rendered, all of the theme hooks for that page think $vars['logged_in'] is FALSE. This only happens on the first page load for a user after I clear the caches. All users, authenticated and anonymous, see anonymous renderings of everything.

This happens even if the view isn't using the excerpt at all (e.g., if I use Rendered Entity mode).

I've traced the cause back to this code in \Drupal\search_api\Plugin\search_api\processor\RenderedItem::addFieldValues:

$this->getAccountSwitcher()->switchTo(new UserSession(['roles' => $configuration['roles']]));

If I disable this line of code (and the corresponding switchBack() call), the unexpected behavior goes away.

For what it's worth, user_template_preprocess_default_variables_alter() is where the 'logged_in' var is being set for all of the theme hooks. This is called shortly after addFieldValues() executes.

I have tried setting up my "rendered_item" field in the index to use "Anonymous" and (separately and together) "Authenticated" roles.
This had no effect. If I disable the "Create excerpt" setting in the highlight settings it still breaks and the page thinks the user is not authenticated. I'm using the "Search Index" view mode for each of the content types I'm indexing.

As soon as I turn off the "Highlight" processor, everything works fine.

I intend to test on a stock Drupal 8 site to see if it's something specific to my site.

🐛 Bug report
Status

Needs review

Version

1.10

Component

General code

Created by

🇺🇸United States agileadam Maine, USA

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • Open in Jenkins → Open on Drupal.org →
    Core: 9.5.x + Environment: PHP 8.1 & sqlite-3.27
    last update almost 2 years ago
    544 pass
  • 🇩🇪Germany sunlix Wesel

    #5 respectivly #12 fixes the issue.

  • 🇨🇦Canada gwvoigt London, ON 🇨🇦

    +1 for #12, fixed my issue.

  • Status changed to RTBC over 1 year ago
  • Status changed to Needs work over 1 year ago
  • 🇦🇹Austria drunken monkey Vienna, Austria

    Thanks for reporting this issue.
    As the elaborate code in RenderedItem::addFieldValues() suggests, temporarily switching themes or users is unfortunately far from trivial in Drupal, and also far from safe. There is never a guarantee that, while user or theme are switched, some code somewhere doesn’t statically cache this information, causing problems later in the request when the user/theme has already been switched back.
    We also just fixed 🐛 RenderedItem::addFieldValues() may not switch back to the correct session Fixed there, which meant that the account wasn’t switched back correctly in some cases. Would be great if everyone having this problem could first test with the latest dev version, to see if that fixes the problem.

    Anyways, before committing a solution like #5/#12, which looks like it could lead to security issues in some setups (privilege escalation when some part of the system thinks the current user really has those roles, since the UIDs now match), it would be important to know the real root cause of this problem. Maybe fixing the problem somewhere else, or in some other way, would make much more sense? I also think it’s very likely that the root cause is actually different for different people.

    In any case, what this issue definitely needs before I can commit anything is a regression test.
    Furthermore, regarding the currently proposed fix, maybe it would be safer, but also solve the problem, if we used a non-existent UID for the user? Please test.

  • 🇩🇪Germany sunlix Wesel

    I have tested version 1.30 of search_api where the mentioned fix is in.
    The error still occurs.

    What I have tested:

    • Restrict 'main navigation' block to authenticated role.
    • Enabled highlight processor
    • Search without any search term: all fine
    • Search with search term and results: main navigation disapears (Logged in as administrator)
  • 🇦🇹Austria drunken monkey Vienna, Austria

    Does #16 also resolve the problem for you?

  • 🇩🇪Germany sunlix Wesel

    Yes, your patch works pretty fine. :-)
    The restricted main navigation stays displayed!

  • 🇦🇹Austria drunken monkey Vienna, Austria

    Can anyone else confirm that #16 works for them? I guess if enough people confirm we can also skip the regression test. Though I’d still be very grateful if someone could write one.

  • Status changed to Needs review over 1 year ago
  • Open in Jenkins → Open on Drupal.org →
    Core: 9.5.x + Environment: PHP 8.1 & sqlite-3.27
    last update over 1 year ago
    545 pass
  • 🇦🇹Austria drunken monkey Vienna, Austria
  • 🇺🇸United States danflanagan8 St. Louis, US

    Hey, @drunken_monkey. The patch in #16 fixed the bugs for me when using search_api 8.x-1.34. That release has the fix from the related issue.

    I had a very similar experience to @sunlix. I had a menu block with a visibility condition restricting it to authenticated users. From time to time (I couldn't figure out a real pattern!) the menu would not be visible when loading a search_api View page as an authenticated user. Concurrently, a couple places that were leveraging the `logged_in` twig variable rendered as if the user was logged out. After applying the patch, the intermittent bugginess was resolved. Though, being intermittent, it's hard to say with 100% confidence...

    I wonder what kind of test coverage we could cook up for this. I couldn't figure out a consistent set of steps to coax the bug out.

  • Status changed to Needs work 10 months ago
  • 🇺🇸United States danflanagan8 St. Louis, US

    Darn. We just ran into a problem with the patch in #16. There was an error that was triggered while in the context of the huge uid and that resulted in an error when logging to the db:

    Drupal\Core\Database\DatabaseExceptionWrapper: SQLSTATE[22003]: Numeric value out of range: 1264 Out of range value for column 'uid' at row 1: INSERT INTO "watchdog" ("uid", "type", "message", "variables", "severity", "link", "location", "referer", "hostname", "timestamp") VALUES (:db_insert_placeholder_0, :db_insert_placeholder_1, :db_insert_placeholder_2, :db_insert_placeholder_3, :db_insert_placeholder_4, :db_insert_placeholder_5, :db_insert_placeholder_6, :db_insert_placeholder_7, :db_insert_placeholder_8, :db_insert_placeholder_9); Array
    (
    [:db_insert_placeholder_0] => 9223372036854775807
    [:db_insert_placeholder_1] => php
    [:db_insert_placeholder_2] => %type: @message in %function (line %line of %file).
    [:db_insert_placeholder_3] => a:6:{s:5:"%type";s:45:"Drupal\Core\Database\DatabaseExceptionWrapper";s:8:"@message";s:15217:"SQLSTATE[22003]: Numeric value out of range: 1264 Out of range value for column 'uid' at row 1: INSERT INTO "watchdog" 
    ...
    

    So PHP_MAX_INT may be too big. We may need to pick a uid that would be legal in the watchdog table. It looks like that's an unsigned int, but I don't know if that has different meaning for different database backends.

  • Status changed to Needs review 10 months ago
  • 🇦🇹Austria drunken monkey Vienna, Austria

    Ah, that makes sense. It’s of course not ideal that this dummy UID ends up in the database, but I’d say that’s not critical in case of the watchdog table – just choosing a smaller dummy value should be fine.
    I converted the patch to an MR, please test/review!
    (I picked 2147483647 as the new value, which is the maximum value for that column in both MySQL and Postgres. SQLite doesn’t seem to have any restriction.)

  • First commit to issue fork.
  • 🇺🇸United States edwardsay

    I discovered a new issue related to the RenderedItem processor and access caching.

    It's a unique situation: I have nodes with a paragraphs field and the Paragraphs Role Visibility module enabled, so different roles see different sets of paragraphs. Additionally, I have rendered_item fields in my search index, each configured to render a full node for a specific role.

    However, due to access caching in EntityAccessControlHandler, all rendered_item index fields are populated with the same value during reindexing. This happens because, even though the set of roles differs for each index field, the User ID is the same (specifically, it defaults to 0 if a patch for this issue isn't applied). EntityAccessControlHandler::getCache() uses only the User ID and doesn’t distinguish between caches for different roles.

    I resolved this issue by setting a random UID for the dummy user in the RenderedItem processor.

    I've created a new merge request to address this issue: https://git.drupalcode.org/project/search_api/-/merge_requests/188

  • Pipeline finished with Success
    5 months ago
    Total: 415s
    #332466
  • 🇦🇹Austria drunken monkey Vienna, Austria

    How about instead decreasing the used UID value at each run?
    Using a random value seems like it would lead to rare but all the more confusing bugs.

    Still NW for the tests.

Production build 0.71.5 2024