From 2f86eecc95e07f8bd085a7c22a065d1774782e7d Mon Sep 17 00:00:00 2001 From: vcg-development Date: Mon, 14 Oct 2024 09:13:56 +0200 Subject: [PATCH 1/2] Add isDescendantOfNodetype Condition --- .../Node/Doctrine/ConditionGenerator.php | 12 +++++++++ .../Privilege/Node/NodePrivilegeContext.php | 27 +++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/Neos.ContentRepository/Classes/Security/Authorization/Privilege/Node/Doctrine/ConditionGenerator.php b/Neos.ContentRepository/Classes/Security/Authorization/Privilege/Node/Doctrine/ConditionGenerator.php index ac708a5247f..3a09d5733bd 100644 --- a/Neos.ContentRepository/Classes/Security/Authorization/Privilege/Node/Doctrine/ConditionGenerator.php +++ b/Neos.ContentRepository/Classes/Security/Authorization/Privilege/Node/Doctrine/ConditionGenerator.php @@ -18,6 +18,7 @@ use Neos\Flow\Security\Authorization\Privilege\Entity\Doctrine\ConditionGenerator as EntityConditionGenerator; use Neos\Flow\Security\Authorization\Privilege\Entity\Doctrine\DisjunctionGenerator; use Neos\Flow\Security\Authorization\Privilege\Entity\Doctrine\PropertyConditionGenerator; +use Neos\Flow\Security\Authorization\Privilege\Entity\Doctrine\DecendantOfNodetypeConditionGenerator; use Neos\Flow\Security\Exception\InvalidPrivilegeException; use Neos\ContentRepository\Domain\Model\NodeData; use Neos\ContentRepository\Domain\Model\NodeInterface; @@ -86,6 +87,17 @@ public function isDescendantNodeOf($nodePathOrIdentifier) return new DisjunctionGenerator([$propertyConditionGenerator1->like($nodePath . '/%'), $propertyConditionGenerator2->equals($nodePath)]); } + /** + * @param array $nodeTypes + * @return PropertyConditionGenerator + */ + public function isDescendantOfNodetype($nodeTypes) + { + $propertyConditionGenerator1 = new DecendantOfNodetypeConditionGenerator($nodeTypes); + + return $propertyConditionGenerator1; + } + /** * @param string|array $nodeTypes * @return PropertyConditionGenerator diff --git a/Neos.ContentRepository/Classes/Security/Authorization/Privilege/Node/NodePrivilegeContext.php b/Neos.ContentRepository/Classes/Security/Authorization/Privilege/Node/NodePrivilegeContext.php index aba4e98892c..3fa95a7dea9 100644 --- a/Neos.ContentRepository/Classes/Security/Authorization/Privilege/Node/NodePrivilegeContext.php +++ b/Neos.ContentRepository/Classes/Security/Authorization/Privilege/Node/NodePrivilegeContext.php @@ -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 @@ -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 isDescendantOfNodetype($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 * From 94e6956bce89e254efdc4045f66b0a3dbb4ac6d3 Mon Sep 17 00:00:00 2001 From: vcg-development Date: Wed, 16 Oct 2024 14:31:11 +0200 Subject: [PATCH 2/2] Add isDescendantOfNodetype Tests --- .../Security/EditNodePrivilege.feature | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/Neos.ContentRepository/Tests/Behavior/Features/Security/EditNodePrivilege.feature b/Neos.ContentRepository/Tests/Behavior/Features/Security/EditNodePrivilege.feature index 230ac3de6f4..8ffce17ce56 100644 --- a/Neos.ContentRepository/Tests/Behavior/Features/Security/EditNodePrivilege.feature +++ b/Neos.ContentRepository/Tests/Behavior/Features/Security/EditNodePrivilege.feature @@ -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: 'isDescendantOfNodetype("Neos.ContentRepository.Testing:ContentCollection")' + roles: 'Neos.Flow:Everybody': privileges: [] @@ -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: @@ -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 ContenCollection 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 ContenCollection 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