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

FEATURE: isDescendantOfNodetype matcher #5291

Open
wants to merge 11 commits into
base: 8.4
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,15 @@ public function isDescendantNodeOf($nodePathOrIdentifier)
return new DisjunctionGenerator([$propertyConditionGenerator1->like($nodePath . '/%'), $propertyConditionGenerator2->equals($nodePath)]);
}

/**
vcg-development marked this conversation as resolved.
Show resolved Hide resolved
* @param array $nodeTypes
* @return PropertyConditionGenerator
*/
public function isDescendantOfType($nodeTypes)
{
return new DecendantOfTypeConditionGenerator($nodeTypes);
}

/**
* @param string|array $nodeTypes
* @return PropertyConditionGenerator
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php
namespace Neos\ContentRepository\Security\Authorization\Privilege\Node\Doctrine;

/*
* This file is part of the Neos.Flow package.
vcg-development marked this conversation as resolved.
Show resolved Hide resolved
*
* (c) Contributors of the Neos Project - www.neos.io
*
* This package is Open Source Software. For the full copyright and license
* information, please view the LICENSE file which was distributed with this
* source code.
*/

use Doctrine\Persistence\Mapping\ClassMetadata;
use Doctrine\ORM\Query\Filter\SQLFilter as DoctrineSqlFilter;
use Neos\Flow\Annotations as Flow;

/**
* A SQL generator to create a condition matching anything.
vcg-development marked this conversation as resolved.
Show resolved Hide resolved
*/
class DecendantOfTypeConditionGenerator implements SqlGeneratorInterface
vcg-development marked this conversation as resolved.
Show resolved Hide resolved
{
private array $nodetypes;

/**
* @param array $nodetypes
*/
public function __construct(array $nodetypes)
{
$this->nodetypes = $nodetypes;
}

/**
* Returns an SQL query part that is basically a no-op in order to match any entity
vcg-development marked this conversation as resolved.
Show resolved Hide resolved
*
* @param DoctrineSqlFilter $sqlFilter
* @param ClassMetadata $targetEntity
* @param string $targetTableAlias
* @return string
*/
public function getSql(DoctrineSqlFilter $sqlFilter, ClassMetadata $targetEntity, $targetTableAlias)
{
$nodetypeList = implode("','", $this->nodetypes);

return "select * from public.neos_contentrepository_domain_model_nodedata n1
JOIN public.neos_contentrepository_domain_model_nodedata n2 ON n1.path LIKE CONCAT('%', n2.path, '%')
vcg-development marked this conversation as resolved.
Show resolved Hide resolved
WHERE n2.nodetype in ('" . $nodetypeList . "')";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use Neos\ContentRepository\Domain\Model\NodeInterface;
use Neos\ContentRepository\Domain\Service\ContentDimensionPresetSourceInterface;
use Neos\ContentRepository\Domain\Service\ContextFactory;
use Neos\Eel\FlowQuery\FlowQuery;

/**
* An Eel context matching expression for the node privileges
Expand Down Expand Up @@ -104,6 +105,32 @@ public function isDescendantNodeOf($nodePathOrIdentifier)
return substr($this->node->getPath() . '/', 0, strlen($nodePath)) === $nodePath;
}

/**
*
* @param string|array $nodeTypes A single or an array of fully qualified NodeType name(s), e.g. "Neos.Neos:Document"
* @return boolean true if the given node matches otherwise false
*/
public function isDescendantOfType($nodeTypes)
{
if ($this->node === null) {
return true;
}
if (!is_array($nodeTypes)) {
$nodeTypes = [$nodeTypes];
}

foreach ($nodeTypes as $nodeType) {
$fq = new FlowQuery([$this->node]);

$counted = $fq->closest('[instanceof ' . $nodeType . ']')->count();

if ($counted > 0) {
return true;
}
}
return false;
}

/**
* Matches if the selected node is a *descendant* or *ancestor* of the given node specified by $nodePathOrIdentifier
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ Feature: Privilege to restrict editing of nodes
'Neos.ContentRepository:EditEventNodes':
matcher: 'isDescendantNodeOf("11d3aded-fb1a-70e7-1412-0b465b11fcd8")'

'Neos.ContentRepository:EditCollectionType':
matcher: 'isDescendantOfType("Neos.ContentRepository.Testing:ContentCollection")'

roles:
'Neos.Flow:Everybody':
privileges: []
Expand All @@ -31,6 +34,9 @@ Feature: Privilege to restrict editing of nodes
-
privilegeTarget: 'Neos.ContentRepository:EditEventNodes'
permission: GRANT
-
privilegeTarget: 'Neos.ContentRepository:EditCollectionType'
permission: GRANT
"""

And I have the following nodes:
Expand All @@ -40,6 +46,26 @@ Feature: Privilege to restrict editing of nodes
| 68ca0dcd-2afb-ef0e-1106-a5301e65b8a0 | /sites/content-repository/company | Neos.ContentRepository.Testing:Document | {"title": "Company"} | live |
| 52540602-b417-11e3-9358-14109fd7a2dd | /sites/content-repository/service | Neos.ContentRepository.Testing:Document | {"title": "Service"} | live |
| 11d3aded-fb1a-70e7-1412-0b465b11fcd8 | /sites/content-repository/events | Neos.ContentRepository.Testing:Document | {"title": "Events", "description": "Some cool event"} | live |
| d09c4e76-79c6-45d9-a12a-c1a06450329c | /sites/content-repository/service/collection | Neos.ContentRepository.Testing:ContentCollection | {} | live |
| 4f7230ba-36b2-4dc3-96fa-b4159371cd3b | /sites/content-repository/service/collection/text | Neos.ContentRepository.Testing:Text | {"text": "Cool text"} | live |

@Isolated @fixtures
Scenario: Anonymous users are not granted to edit childnodes on ContentCollection nodetypes
Given I am not authenticated
And I get a node by path "/sites/content-repository/service/collection/text" with the following context:
| Workspace |
| user-admin |
Then I should not be granted to set the "text" property to "Even cooler text"
And I should get false when asking the node authorization service if editing this node is granted

@Isolated @fixtures
Scenario: Administrators are granted to edit childnodes on ContentCollection nodetypes
Given I am authenticated with role "Neos.ContentRepository:Administrator"
And I get a node by path "/sites/content-repository/service/collection/text" with the following context:
| Workspace |
| user-admin |
Then I should be granted to set the "text" property to "Even cooler text"
And I should get true when asking the node authorization service if editing this node is granted

@Isolated @fixtures
Scenario: Anonymous users are granted to set properties on company node
Expand Down
Loading