Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUGFIX] Fix indexing of access protected pages #3811

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Build/Test/phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,5 @@ parameters:
- '#^Variable \$_EXTKEY might not be defined\.#'
- '#^Method .*\\QueryBuilder::buildSuggestQuery\(\) should return .*\\SuggestQuery but returns .*\\Search\\Query\\Query\|null.#'
- '#^Method .*\\QueryBuilder::use.*FromTypoScript\(\) should return .*\\QueryBuilder but returns .*\\AbstractQueryBuilder.#'
- '#^Access to protected property .*\\PageRepository::\$where_groupAccess.#'
- '#^Unreachable statement - code above always terminates.#'
- '#^Parameter \#1 \$queryAlternative of method .*\\DisMax::setQueryAlternative\(\) expects string, null given.#'
11 changes: 9 additions & 2 deletions Classes/EventListener/PageIndexer/FrontendGroupsModifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,13 @@ class FrontendGroupsModifier
public function __invoke(ModifyResolvedFrontendGroupsEvent $event): void
{
$pageIndexerRequest = $event->getRequest()->getAttribute('solr.pageIndexingInstructions');
if (!$pageIndexerRequest instanceof PageIndexerRequest) {
if (!$pageIndexerRequest instanceof PageIndexerRequest
|| ((int)$pageIndexerRequest->getParameter('userGroup') === 0
&& (int)$pageIndexerRequest->getParameter('pageUserGroup') < 1)
) {
return;
}

if (!$pageIndexerRequest->isAuthenticated()) {
$logger = GeneralUtility::makeInstance(SolrLogManager::class, self::class);
$logger->error(
Expand All @@ -58,7 +62,7 @@ public function __invoke(ModifyResolvedFrontendGroupsEvent $event): void
'error' => [
'code' => 403,
'message' => 'Invalid Index Queue Request.',
],
],
],
403
),
Expand All @@ -67,6 +71,9 @@ public function __invoke(ModifyResolvedFrontendGroupsEvent $event): void
}

$groups = $this->resolveFrontendUserGroups($pageIndexerRequest);
if ((int)$pageIndexerRequest->getParameter('pageUserGroup') > 0) {
$groups[] = (int)$pageIndexerRequest->getParameter('pageUserGroup');
}
$groupData = [];
foreach ($groups as $groupUid) {
if (in_array($groupUid, [-2, -1])) {
Expand Down
35 changes: 27 additions & 8 deletions Classes/IndexQueue/FrontendHelper/PageIndexer.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@
*/
class PageIndexer implements FrontendHelper, SingletonInterface
{
protected bool $activated = false;

/**
* This frontend helper's executed action.
*/
Expand Down Expand Up @@ -92,6 +94,7 @@ class PageIndexer implements FrontendHelper, SingletonInterface
public function activate(): void
{
$this->logger = GeneralUtility::makeInstance(SolrLogManager::class, __CLASS__);
$this->activated = true;
}

/**
Expand Down Expand Up @@ -141,7 +144,8 @@ protected function generatePageUrl(TypoScriptFrontendController $controller): st
public function __invoke(AfterCacheableContentIsGeneratedEvent $event): void
{
$this->request = $event->getRequest()->getAttribute('solr.pageIndexingInstructions');
if (!$this->request) {

if (!$this->request || $this->activated === false) {
return;
}
$this->setupConfiguration();
Expand Down Expand Up @@ -188,9 +192,9 @@ public function __invoke(AfterCacheableContentIsGeneratedEvent $event): void
}

/**
* @internal currently only public for tests
* Index item
*/
public function index(Item $indexQueueItem, TypoScriptFrontendController $tsfe): void
protected function index(Item $indexQueueItem, TypoScriptFrontendController $tsfe): void
{
$this->solrConnection = $this->getSolrConnection($indexQueueItem, $tsfe->getLanguage(), $this->configuration->getLoggingExceptions());

Expand Down Expand Up @@ -287,7 +291,7 @@ protected function getPageDocument(TypoScriptFrontendController $tsfe, string $u
*
* @return bool TRUE after successfully indexing the page, FALSE on error
*/
public function indexPage(
protected function indexPage(
Document $pageDocument,
Item $indexQueueItem,
TypoScriptFrontendController $tsfe,
Expand Down Expand Up @@ -362,11 +366,13 @@ protected function addDocumentsToSolrIndex(array $documents): bool
}

/**
* @internal only used for tests
* Initialize PageIndexer
*
* As the Solr configuration initialization might affect the request
* we cannot initialize the configuration directly on activation
*/
public function setupConfiguration(): void
protected function setupConfiguration(): void
{
// currently needed for tests, will be separated.
$this->logger = new SolrLogManager(__CLASS__, GeneralUtility::makeInstance(DebugWriter::class));
$this->configuration = Util::getSolrConfiguration();
}
Expand All @@ -381,6 +387,19 @@ protected function getEventDispatcher(): EventDispatcherInterface
*/
public function deactivate(PageIndexerResponse $response): void
{
$response->addActionResult($this->action, $this->responseData);
if ($this->activated) {
if (!isset($this->responseData['pageIndexed'])) {
$this->responseData['pageIndexed'] = false;
}
$response->addActionResult($this->action, $this->responseData);

$this->setupConfiguration();
if ($this->configuration->getLoggingExceptions()) {
$this->logger->error(
'Unknown exception while trying to index page',
);
}
}
$this->activated = false;
}
}
13 changes: 6 additions & 7 deletions Classes/IndexQueue/FrontendHelper/UserGroupDetector.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,17 +124,13 @@ public function deactivateTcaFrontendGroupEnableFields(
* @param int $uid The page ID
* @param bool $disableGroupAccessCheck If set, the check for group access is disabled. VERY rarely used
* @param PageRepository $parentObject parent \TYPO3\CMS\Core\Domain\Repository\PageRepository object
*
* @noinspection PhpMissingReturnTypeInspection
*/
public function getPage_preProcess(
&$uid,
&$disableGroupAccessCheck,
PageRepository $parentObject
) {
): void {
$disableGroupAccessCheck = true;
// @todo: Check if reset "where_groupAccess" really wanted. Most probably the core aspect 'frontend.user' must be used instead.
$parentObject->where_groupAccess = ''; // just to be on the safe side
}

/**
Expand Down Expand Up @@ -190,7 +186,7 @@ protected function findFrontendGroups(array $record, string $table): void
if (isset($this->originalTca[$table]['ctrl']['enablecolumns']['fe_group'])) {
$frontendGroups = $record[$this->originalTca[$table]['ctrl']['enablecolumns']['fe_group']] ?? null;

if (empty($frontendGroups)) {
if (empty($frontendGroups) || $frontendGroups === '-1') {
// default = public access
$frontendGroups = 0;
} elseif ($this->request->getParameter('loggingEnabled')) {
Expand Down Expand Up @@ -222,7 +218,10 @@ protected function getFrontendGroups(): array

// clean up: filter double groups
$frontendGroups = array_unique($frontendGroups);
$frontendGroups = array_values($frontendGroups);
$frontendGroups = array_filter(
array_values($frontendGroups),
static fn (int $val): bool => ($val !== -1)
);

if (empty($frontendGroups)) {
// most likely an empty page with no content elements => public
Expand Down
18 changes: 8 additions & 10 deletions Classes/IndexQueue/PageIndexer.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,16 +59,9 @@ public function index(Item $item): bool
return false;
}

$solrConnections = $this->getSolrConnectionsByItem($item);
foreach ($solrConnections as $systemLanguageUid => $solrConnection) {
$systemLanguageUids = array_keys($this->getSolrConnectionsByItem($item));
foreach ($systemLanguageUids as $systemLanguageUid) {
$contentAccessGroups = $this->getAccessGroupsFromContent($item, $systemLanguageUid);

if (empty($contentAccessGroups)) {
// might be an empty page w/no content elements or some TYPO3 error / bug
// FIXME logging needed
continue;
}

foreach ($contentAccessGroups as $userGroup) {
$this->indexPage($item, $systemLanguageUid, $userGroup);
}
Expand Down Expand Up @@ -299,6 +292,12 @@ protected function indexPage(Item $item, ?int $language = 0, ?int $userGroup = 0
$request->setIndexQueueItem($item);
$request->addAction('indexPage');
$request->setParameter('accessRootline', $accessRootline);
$request->setParameter('userGroup', $userGroup);

$feGroupColumn = $GLOBALS['TCA']['pages']['ctrl']['enablecolumns']['fe_group'] ?? '';
if (!empty($feGroupColumn)) {
$request->setParameter('pageUserGroup', $item->getRecord()[$feGroupColumn]);
}

$indexRequestUrl = $this->getDataUrl($item, $language);
$response = $request->send($indexRequestUrl);
Expand Down Expand Up @@ -329,7 +328,6 @@ protected function indexPage(Item $item, ?int $language = 0, ?int $userGroup = 0

if (empty($indexActionResult['pageIndexed'])) {
$message = 'Failed indexing page Index Queue item: ' . $item->getIndexQueueUid() . ' url: ' . $indexRequestUrl;

throw new \RuntimeException($message, 1331837081);
}

Expand Down
2 changes: 1 addition & 1 deletion Configuration/RequestMiddlewares.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
$requestMiddlewares = [
'apache-solr-for-typo3/page-indexer-initialization' => [
'target' => \ApacheSolrForTypo3\Solr\Middleware\PageIndexerInitialization::class,
'before' => ['typo3/cms-frontend/tsfe'],
'before' => ['typo3/cms-frontend/tsfe', 'typo3/cms-frontend/authentication'],
'after' => ['typo3/cms-core/normalized-params-attribute'],
],
];
Expand Down
8 changes: 8 additions & 0 deletions Documentation/Releases/solr-release-12-0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,14 @@ If you've used this class or the SolrConnection directly, you have to adapt your

Note: With dropping the Node implementation we also dropped the backwards compatibility that allows to define the Solr path segment "/solr" within "solr_path_read" or "solr_path_write". Be sure your configuration doesn't contain this path segment!

!!! Changed visibility of ApacheSolrForTypo3\Solr\IndexQueue\FrontendHelper\PageIndexer methods
-----------------------------------------------------------------------------------------------

For testing purposes some methods of the PageIndexer were defined as public, these methods are now protected. The tests are adapted accordingly, so that there is no need to declare the methods as public.
If you have used one of this methods, you have to adapt your code. Affected methods:
- setupConfiguration
- index
- indexPage

!!! Solr route enhancer disabled by default
-------------------------------------------
Expand Down
56 changes: 6 additions & 50 deletions Tests/Integration/Fixtures/Search/can_search.csv
Original file line number Diff line number Diff line change
@@ -1,50 +1,6 @@
"pages",,,,,,
,"uid","is_siteroot","doktype","title","slug","hidden"
,1,1,1,"Hello Search Test","/",0
"sys_template",,,,,,
,"uid","pid","root","clear","sorting","config",
,1,1,1,3,100,"
page = PAGE
page.typeNum = 0

plugin.tx_solr {

enabled = 1

index {
fieldProcessingInstructions {
changed = timestampToIsoDate
created = timestampToIsoDate
endtime = timestampToUtcIsoDate
rootline = pageUidToHierarchy
}

queue {

// mapping tableName.fields.SolrFieldName => TableFieldName (+ cObj processing)

pages = 1
pages {
initialization = ApacheSolrForTypo3\Solr\IndexQueue\Initializer\Page

// allowed page types (doktype) when indexing pages
allowedPageTypes = 1,7

indexingPriority = 0

indexer = ApacheSolrForTypo3\Solr\IndexQueue\PageIndexer
indexer {
// add options for the indexer here
}

// Only index standard pages and mount points that are not overlayed.
additionalWhereClause = (doktype = 1 OR (doktype=7 AND mount_pid_ol=0)) AND no_search = 0

fields {
sortSubTitle_stringS = subtitle
}
}

}
}
}"
"pages",
,"uid","pid","is_siteroot","doktype","slug","title","subtitle","crdate","tstamp"
,2,1,1,1,"/hello_solr","Hello Search Test","the subtitle",1449151778,1449151778
"tx_solr_indexqueue_item",
,"uid","root","item_type","item_uid","indexing_configuration","changed","indexed","has_indexing_properties","indexing_priority","indexed","errors"
,2,1,"pages",2,"pages",1449151778,0,0,0,0,0
94 changes: 32 additions & 62 deletions Tests/Integration/Fixtures/Search/phrase_search.csv
Original file line number Diff line number Diff line change
@@ -1,64 +1,34 @@
"pages",,,,,,,
,"uid","pid","is_siteroot","doktype","hidden","slug","title"
,1,0,1,1,0,"/","World Hello Search Test"
,2,1,0,1,0,"/improve","Hello you can improve the precision by using phrase configuration World"
,3,1,0,1,0,"/hello-phrase-search-world","Hello phrase search World"
,4,1,0,1,0,"/hello-test-wonderful-world","Hello Test wonderful World"
,5,1,0,1,0,"/hello-wonderful-test-world","Hello wonderful Test World"
,6,1,0,1,0,"/bigram-phrases","Bigraming phrases strip down the sentence to the two-word combinations."
,7,1,0,1,0,"/trigram-phrases","Trigraming phrases strip down the sentence to triplets phrases"
,8,1,0,1,0,"/difference-to-bi-is-tri","Difference to bi is tri, which means building of triplets phrases."
,9,1,0,1,0,"/hello-solr-wolrd","Hello Solr Wolrd"
,10,1,0,1,0,"/hello-test-wolrd","Hello Test Wolrd"
,11,1,0,1,0,"/test-hello-solr-world","Test Hello Solr World"
,12,1,0,1,0,"/test-hello-search-world","Test Hello Search World"
,13,1,0,1,0,"/hello-the-test-search-world","Hello the Test Search World"
,14,1,0,1,0,"/hello-world-for-phrase-searching","Hello World for phrase searching"
,15,1,0,1,0,"/about","Solr is blazing-fast and open source enterprise search platform built on Apache Lucene"
"sys_template",,,,,,,
,"uid","pid","root","clear","sorting","constants","config",
,1,1,1,3,100,"","
page = PAGE
page.typeNum = 0

plugin.tx_solr {
search.query.phrase = 1
enabled = 1

index {
fieldProcessingInstructions {
changed = timestampToIsoDate
created = timestampToIsoDate
endtime = timestampToUtcIsoDate
rootline = pageUidToHierarchy
}

queue {

// mapping tableName.fields.SolrFieldName => TableFieldName (+ cObj processing)

pages = 1
pages {
initialization = ApacheSolrForTypo3\Solr\IndexQueue\Initializer\Page

// allowed page types (doktype) when indexing pages
allowedPageTypes = 1,7

indexingPriority = 0

indexer = ApacheSolrForTypo3\Solr\IndexQueue\PageIndexer
indexer {
// add options for the indexer here
}

// Only index standard pages and mount points that are not overlayed.
additionalWhereClause = (doktype = 1 OR (doktype=7 AND mount_pid_ol=0)) AND no_search = 0

fields {
sortSubTitle_stringS = subtitle
}
}

}
}
}",
,2,1,1,1,0,"/","World Hello Search Test"
,3,1,0,1,0,"/improve","Hello you can improve the precision by using phrase configuration World"
,4,1,0,1,0,"/hello-phrase-search-world","Hello phrase search World"
,5,1,0,1,0,"/hello-test-wonderful-world","Hello Test wonderful World"
,6,1,0,1,0,"/hello-wonderful-test-world","Hello wonderful Test World"
,7,1,0,1,0,"/bigram-phrases","Bigraming phrases strip down the sentence to the two-word combinations."
,8,1,0,1,0,"/trigram-phrases","Trigraming phrases strip down the sentence to triplets phrases"
,9,1,0,1,0,"/difference-to-bi-is-tri","Difference to bi is tri, which means building of triplets phrases."
,10,1,0,1,0,"/hello-solr-wolrd","Hello Solr Wolrd"
,11,1,0,1,0,"/hello-test-wolrd","Hello Test Wolrd"
,12,1,0,1,0,"/test-hello-solr-world","Test Hello Solr World"
,13,1,0,1,0,"/test-hello-search-world","Test Hello Search World"
,14,1,0,1,0,"/hello-the-test-search-world","Hello the Test Search World"
,15,1,0,1,0,"/hello-world-for-phrase-searching","Hello World for phrase searching"
,16,1,0,1,0,"/about","Solr is blazing-fast and open source enterprise search platform built on Apache Lucene"
"tx_solr_indexqueue_item",
,"uid","root","item_type","item_uid","indexing_configuration","changed","indexed","has_indexing_properties","indexing_priority","indexed","errors"
,2,1,"pages",2,"pages",1449151778,0,0,0,0,0
,3,1,"pages",3,"pages",1449151778,0,0,0,0,0
,4,1,"pages",4,"pages",1449151778,0,0,0,0,0
,5,1,"pages",5,"pages",1449151778,0,0,0,0,0
,6,1,"pages",6,"pages",1449151778,0,0,0,0,0
,7,1,"pages",7,"pages",1449151778,0,0,0,0,0
,8,1,"pages",8,"pages",1449151778,0,0,0,0,0
,9,1,"pages",9,"pages",1449151778,0,0,0,0,0
,10,1,"pages",10,"pages",1449151778,0,0,0,0,0
,11,1,"pages",11,"pages",1449151778,0,0,0,0,0
,12,1,"pages",12,"pages",1449151778,0,0,0,0,0
,13,1,"pages",13,"pages",1449151778,0,0,0,0,0
,14,1,"pages",14,"pages",1449151778,0,0,0,0,0
,15,1,"pages",15,"pages",1449151778,0,0,0,0,0
,16,1,"pages",16,"pages",1449151778,0,0,0,0,0
Loading