diff --git a/Classes/EventListener/PageIndexer/FrontendGroupsModifier.php b/Classes/EventListener/PageIndexer/FrontendGroupsModifier.php index 5bfa66a7b7..a8baca6d3c 100644 --- a/Classes/EventListener/PageIndexer/FrontendGroupsModifier.php +++ b/Classes/EventListener/PageIndexer/FrontendGroupsModifier.php @@ -86,7 +86,9 @@ public function __invoke(ModifyResolvedFrontendGroupsEvent $event): void ); } - if ((int)$pageIndexerRequest->getParameter('pageUserGroup') > 0) { + if ((int)$pageIndexerRequest->getParameter('userGroup') > 0 + && (int)$pageIndexerRequest->getParameter('pageUserGroup') > 0 + ) { $groups[] = (int)$pageIndexerRequest->getParameter('pageUserGroup'); } $groupData = []; diff --git a/Classes/IndexQueue/PageIndexer.php b/Classes/IndexQueue/PageIndexer.php index 6b042a60ab..0b63235c4a 100644 --- a/Classes/IndexQueue/PageIndexer.php +++ b/Classes/IndexQueue/PageIndexer.php @@ -67,8 +67,23 @@ public function index(Item $item): bool ); } + $feGroupColumn = $GLOBALS['TCA']['pages']['ctrl']['enablecolumns']['fe_group'] ?? ''; + $pageUserGroup = $feGroupColumn !== '' ? (int)($item->getRecord()[$feGroupColumn] ?? 0) : 0; foreach ($systemLanguageUids as $systemLanguageUid) { $contentAccessGroups = $this->getAccessGroupsFromContent($item, $systemLanguageUid); + if ($pageUserGroup > 0) { + // A page with fe_group restriction has no publicly-accessible content variants: + // remove group 0 (which may originate from global template CEs, not page content). + // Ensure the page's own group is in accessGroups so restricted-but-eligible users + // can still find the page in search results. + $contentAccessGroups = array_values(array_filter( + $contentAccessGroups, + static fn(int $group): bool => $group !== 0, + )); + if (!in_array($pageUserGroup, $contentAccessGroups, true)) { + $contentAccessGroups[] = $pageUserGroup; + } + } foreach ($contentAccessGroups as $userGroup) { $this->indexPage($item, $systemLanguageUid, (int)$userGroup); } diff --git a/Documentation/Releases/solr-release-13-1.rst b/Documentation/Releases/solr-release-13-1.rst index c58526d1ab..3bc39f776e 100644 --- a/Documentation/Releases/solr-release-13-1.rst +++ b/Documentation/Releases/solr-release-13-1.rst @@ -6,6 +6,16 @@ Releases 13.1 .. include:: HintAboutOutdatedChangelog.rst.txt +Release 13.1.2 +============== + +This is a bugfix release for TYPO3 13 LTS. + +All Changes +----------- + +* [BUGFIX] Prevent c:0 variant and content leakage on fe_group-restricted pages by @dkd-kaehm in `#4641 `_ + Release 13.1.1 ============== diff --git a/Tests/Integration/IndexQueue/Fixtures/can_index_protected_page_with_public_and_same_group_protected_content.csv b/Tests/Integration/IndexQueue/Fixtures/can_index_protected_page_with_public_and_same_group_protected_content.csv new file mode 100644 index 0000000000..e594ecb560 --- /dev/null +++ b/Tests/Integration/IndexQueue/Fixtures/can_index_protected_page_with_public_and_same_group_protected_content.csv @@ -0,0 +1,53 @@ +"fe_groups", +,"uid","pid","title" +,1,1,"group 1" +"pages", +,"uid","pid","is_siteroot","doktype","slug","title","subtitle","crdate","tstamp","fe_group" +,2,1,0,1,"/protected_page","protected page","",1449151778,1449151778,1 +"tt_content", +,"uid","pid","CType","header","bodytext","fe_group","sorting" +,11,"2","text","protected ce ","protected bodytext ",1,20 +,20,"1","text","footer nav ce ","footer nav bodytext ",0,10 +"sys_template", +,"uid","pid","root","clear","sorting","config" +,100,1,1,3,50," +@import 'EXT:solr/Tests/Integration/Fixtures/sites_setup_and_data_set/Integration.setup.typoscript' + +# Replicate what addSimpleFrontendRenderingToTypoScriptRendering adds in setUp() +page = PAGE +page.typeNum = 0 +config.index_enable = 1 +page.10 = CONTENT +page.10 { + table = tt_content + select.orderBy = sorting + select.where = colPos=0 + renderObj = COA + renderObj { + 10 = TEXT + 10.field = bodytext + } +} +page.10.renderObj.5 = TEXT +page.10.renderObj.5.field = header +page.10.stdWrap.dataWrap = | + +# Simulates global template content (footer/nav) rendered outside TYPO3SEARCH markers. +# In production, such content from other pages causes UserGroupDetector to collect +# their fe_group values (often 0/empty), which triggers the c:0 indexing variant. +page.20 = CONTENT +page.20 { + table = tt_content + select.pidInList = 1 + select.orderBy = sorting + select.where = colPos=0 + renderObj = COA + renderObj { + 10 = TEXT + 10.field = bodytext + } +} +" +"tx_solr_indexqueue_item", +,"uid","root","item_type","item_uid","indexing_configuration","changed","indexed","has_indexing_properties","indexing_priority","indexed","errors" +,4711,1,"pages",2,"pages",1449151778,0,0,0,0,0 diff --git a/Tests/Integration/IndexQueue/PageIndexerTest.php b/Tests/Integration/IndexQueue/PageIndexerTest.php index 48a6090ff4..9f401cb1ba 100644 --- a/Tests/Integration/IndexQueue/PageIndexerTest.php +++ b/Tests/Integration/IndexQueue/PageIndexerTest.php @@ -105,7 +105,7 @@ public function canIndexPageWithAccessProtectedContentIntoSolr( true, ); - self::assertEquals($expectedNumFound, $solrContent['response']['numFound'] ?? 0, 'Could not index documents into Solr'); + self::assertEquals($expectedNumFound, $solrContent['response']['numFound'] ?? 0, 'Unexpected count of documents in Solr index.'); foreach ($expectedAccessFieldValues as $index => $expectedAccessFieldValue) { self::assertEquals( $expectedAccessFieldValue, @@ -143,7 +143,7 @@ public static function canIndexPageWithAccessProtectedContentIntoSolrDataProvide 'fixture' => 'can_index_access_protected_page', 'expectedNumFound' => 1, 'expectedAccessFieldValues' => [ - '2:1/c:0', + '2:1/c:1', ], 'expectedContents' => [ 'public content of protected page', @@ -171,7 +171,7 @@ public static function canIndexPageWithAccessProtectedContentIntoSolrDataProvide 'fixture' => 'can_index_access_protected_page_with_protected_contents', 'expectedNumFound' => 2, 'expectedAccessFieldValues' => [ - '2:1/c:0', + '2:1/c:1', '2:1/c:2', ], 'expectedContents' => [ @@ -187,7 +187,7 @@ public static function canIndexPageWithAccessProtectedContentIntoSolrDataProvide 'fixture' => 'can_index_access_protected_page_with_protected_contents', 'expectedNumFound' => 2, 'expectedAccessFieldValues' => [ - '2:1/c:0', + '2:1/c:1', '2:1/c:2', ], 'expectedContents' => [ @@ -232,6 +232,20 @@ public static function canIndexPageWithAccessProtectedContentIntoSolrDataProvide 'expectedNumFoundLoggedInUser' => 2, ]; + yield 'protected page: c:0 must not contain same-group protected content (isolation bug)' => [ + 'fixture' => 'can_index_protected_page_with_public_and_same_group_protected_content', + 'expectedNumFound' => 1, + 'expectedAccessFieldValues' => [ + '2:1/c:1', + ], + 'expectedContents' => [ + 'protected ce protected bodytext', + ], + 'expectedNumFoundAnonymousUser' => 0, + 'userGroupToCheckAccessFilter' => '0,1', + 'expectedNumFoundLoggedInUser' => 1, + ]; + yield 'page protected by extend to subpages' => [ 'fixture' => 'can_index_sub_page_of_protected_page_with_extend_to_subpage', 'expectedNumFound' => 1,