[FEATURE] Add Frontend User access query for secure search on elastic index

This commit is contained in:
Benjamin Serfhos 2018-10-22 17:28:17 +02:00
parent 404f49aad2
commit 7566bf93d5
11 changed files with 134 additions and 47 deletions

View file

@ -63,7 +63,6 @@ class IndexCommandController extends CommandController
$this->outputLine('No indexer found for: ' . $value);
}
}
}
/**

View file

@ -27,5 +27,4 @@ use TYPO3\CMS\Core\TypoScript\TypoScriptService as CoreTypoScriptService;
*/
class TypoScriptService extends CoreTypoScriptService implements TypoScriptServiceInterface
{
}

View file

@ -27,5 +27,4 @@ use TYPO3\CMS\Extbase\Service\TypoScriptService as CoreTypoScriptService;
*/
class TypoScriptService76 extends CoreTypoScriptService implements TypoScriptServiceInterface
{
}

View file

@ -26,7 +26,6 @@ use Codappix\SearchCore\Domain\Search\QueryFactory;
use Elastica\Query;
use TYPO3\CMS\Core\SingletonInterface as Singleton;
use TYPO3\CMS\Extbase\Object\ObjectManagerInterface;
use TYPO3\CMS\Extbase\Utility\DebuggerUtility;
/**
* Outer wrapper to elasticsearch.

View file

@ -178,7 +178,7 @@ class TcaTableService implements TcaTableServiceInterface
true
);
// Always fallback on public visibility when configured
$record[$this->tca['ctrl']['enablecolumns']['fe_group']] = !empty($groups) ? $groups : [0];
$record['search_access'] = !empty($groups) ? $groups : [0];
}
if (!isset($record['search_page_typolink'])) {

View file

@ -5,7 +5,6 @@ namespace Codappix\SearchCore\Domain\Search;
use Codappix\SearchCore\Connection\SearchRequestInterface;
use Codappix\SearchCore\Connection\SearchResultInterface;
use TYPO3\CMS\Core\SingletonInterface;
use TYPO3\CMS\Extbase\Utility\DebuggerUtility;
/**
* Service: Cached Search
@ -13,7 +12,11 @@ use TYPO3\CMS\Extbase\Utility\DebuggerUtility;
*/
class CachedSearchService implements SingletonInterface
{
/**
* @var array
*/
protected $results = [];
/**
* @var SearchService
*/
@ -51,5 +54,4 @@ class CachedSearchService implements SingletonInterface
}
return sha1(serialize($searchRequest));
}
}

View file

@ -0,0 +1,6 @@
<?php
namespace Codappix\SearchCore\Domain\Search;
class MissingAttributeException extends \InvalidArgumentException
{
}

View file

@ -84,7 +84,7 @@ class QueryFactory
$this->addSize($searchRequest, $query);
$this->addSearch($searchRequest, $query);
$this->addBoosts($searchRequest, $query);
$this->addFilter($searchRequest, $query);
$this->addFilters($searchRequest, $query);
$this->addFacets($searchRequest, $query);
$this->addFields($searchRequest, $query);
$this->addSort($searchRequest, $query);
@ -249,67 +249,76 @@ class QueryFactory
* @param array $query
* @return void
*/
protected function addFilter(SearchRequestInterface $searchRequest, array &$query)
protected function addFilters(SearchRequestInterface $searchRequest, array &$query)
{
if (!$searchRequest->hasFilter()) {
return;
}
$filter = [];
foreach ($searchRequest->getFilter() as $name => $value) {
$filter[] = $this->buildFilter(
$this->addFilter(
$name,
$value,
$this->configuration->getIfExists('searching.mapping.filter.' . $name) ?: []
$this->configuration->getIfExists('searching.mapping.filter.' . $name) ?: [],
$query
);
}
ArrayUtility::mergeRecursiveWithOverrule($query, [
'query' => [
'bool' => [
'filter' => $filter,
],
],
]);
}
/**
* @param string $name
* @param $value
* @param string $value
* @param array $config
* @param array $query
* @return array
*/
protected function buildFilter(string $name, $value, array $config): array
protected function addFilter(string $name, $value, array $config, array &$query): array
{
if ($config === []) {
return [
'term' => [
$name => $value,
],
];
}
if (!empty($config)) {
if ($config['type'] && $config['type'] === 'user') {
if (!isset($config['userFunc'])) {
throw new MissingAttributeException('No userFunc configured for filter type: user', 1539876182018);
}
$filter = [];
$parameters = [
'config' => $config,
'value' => $value,
'query' => &$query,
];
GeneralUtility::callUserFunction($config['userFunc'], $parameters, $this);
} else {
$filter = [];
if (isset($config['fields'])) {
foreach ($config['fields'] as $elasticField => $inputField) {
$filter[$elasticField] = $value[$inputField];
}
}
if (isset($config['fields'])) {
foreach ($config['fields'] as $elasticField => $inputField) {
$filter[$elasticField] = $value[$inputField];
if (isset($config['raw'])) {
$filter = array_merge($config['raw'], $filter);
}
if ($config['type'] === 'range') {
$query['query']['bool']['filter'][] = [
'range' => [
$config['field'] => $filter
]
];
} else {
$query['query']['bool']['filter'][] = [
$config['field'] => $filter
];
}
}
}
if (isset($config['raw'])) {
$filter = array_merge($config['raw'], $filter);
}
if ($config['type'] === 'range') {
return [
'range' => [
$config['field'] => $filter,
],
} else {
$query['query']['bool']['filter'][] = [
'term' => [
$name => $value
]
];
}
return [$config['field'] => $filter];
return $query;
}
/**

View file

@ -0,0 +1,63 @@
<?php
namespace Codappix\SearchCore\Hook\Filter;
use TYPO3\CMS\Frontend\Authentication\FrontendUserAuthentication;
/**
* Filter: FrontendUserAccess
* @package Codappix\SearchCore\Hook\Filter
*/
class FrontendUserAccessFilter
{
/**
* @param array $parameters
* @return void
*/
public function generate($parameters)
{
$this->appendQueryWithAccessFilter($parameters['query'], $parameters['value']);
}
/**
* @param array $query
* @param string $field
*/
protected function appendQueryWithAccessFilter(array &$query, string $field)
{
$query['query']['bool']['must'][] = [
'terms' => [$field => $this->getUserGroups()]
];
}
/**
* @return array
*/
protected function getUserGroups(): array
{
$feUser = $this->getFrontendUserAuthentication();
if ($feUser !== null) {
// If groups is not yet rendered, make sure the group data are fetched
if (!isset($feUser->groupData['uid'])) {
$feUser->fetchGroupData();
}
$values = $feUser->groupData['uid'];
if (!empty($values)) {
// Add public content with values
return array_merge([0], $values);
}
}
// Fallback on public content
return [0];
}
/**
* @return FrontendUserAuthentication
*/
protected function getFrontendUserAuthentication()
{
return $GLOBALS['TSFE']->fe_user ?? null;
}
}

View file

@ -3,7 +3,6 @@
use TYPO3\CMS\Extbase\Utility\ExtensionUtility;
call_user_func(function ($extension, $table) {
$plugin = ExtensionUtility::registerPlugin(
'Codappix.' . $extension,
'Results',
@ -21,5 +20,4 @@ call_user_func(function ($extension, $table) {
) ?? 'searchcore_form';
$GLOBALS['TCA'][$table]['types']['list']['subtypes_excludelist'][$plugin] = 'recursive,pages';
}, 'search_core', 'tt_content');

View file

@ -39,6 +39,19 @@ plugin.tx_searchcore {
# Default query fields (leave empty for all)
query =
}
filter {
frontendUserAccess = search_access
}
mapping {
filter {
frontendUserAccess {
type = user
userFunc = Codappix\SearchCore\Hook\Filter\FrontendUserAccessFilter->generate
}
}
}
}
}
}