diff --git a/Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/FakeAuthProviderFactory.php b/Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/TestingAuthProviderFactory.php similarity index 63% rename from Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/FakeAuthProviderFactory.php rename to Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/TestingAuthProviderFactory.php index f239fb410d7..0fb820d5f03 100644 --- a/Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/FakeAuthProviderFactory.php +++ b/Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/TestingAuthProviderFactory.php @@ -4,16 +4,15 @@ namespace Neos\ContentRepository\BehavioralTests\TestSuite\Behavior; -use Neos\ContentRepository\Core\Feature\Security\AuthProviderInterface; use Neos\ContentRepository\Core\Projection\ContentGraph\ContentGraphReadModelInterface; use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId; -use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\Helpers\FakeAuthProvider; +use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\Helpers\TestingAuthProvider; use Neos\ContentRepositoryRegistry\Factory\AuthProvider\AuthProviderFactoryInterface; -final class FakeAuthProviderFactory implements AuthProviderFactoryInterface +final class TestingAuthProviderFactory implements AuthProviderFactoryInterface { - public function build(ContentRepositoryId $contentRepositoryId, ContentGraphReadModelInterface $contentGraphReadModel): AuthProviderInterface + public function build(ContentRepositoryId $contentRepositoryId, ContentGraphReadModelInterface $contentGraphReadModel): TestingAuthProvider { - return new FakeAuthProvider(); + return new TestingAuthProvider(); } } diff --git a/Neos.ContentRepository.BehavioralTests/Configuration/Testing/Behat/Settings.ContentRepositoryRegistry.yaml b/Neos.ContentRepository.BehavioralTests/Configuration/Testing/Behat/Settings.ContentRepositoryRegistry.yaml index 74387df65ff..c7bd8303a73 100644 --- a/Neos.ContentRepository.BehavioralTests/Configuration/Testing/Behat/Settings.ContentRepositoryRegistry.yaml +++ b/Neos.ContentRepository.BehavioralTests/Configuration/Testing/Behat/Settings.ContentRepositoryRegistry.yaml @@ -3,7 +3,7 @@ Neos: presets: default: authProvider: - factoryObjectName: 'Neos\ContentRepository\BehavioralTests\TestSuite\Behavior\FakeAuthProviderFactory' + factoryObjectName: 'Neos\ContentRepository\BehavioralTests\TestSuite\Behavior\TestingAuthProviderFactory' clock: factoryObjectName: 'Neos\ContentRepository\BehavioralTests\TestSuite\Behavior\FakeClockFactory' nodeTypeManager: diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/CRTestSuiteRuntimeVariables.php b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/CRTestSuiteRuntimeVariables.php index b6ca95a29b6..d8ff69457b2 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/CRTestSuiteRuntimeVariables.php +++ b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/CRTestSuiteRuntimeVariables.php @@ -26,7 +26,7 @@ use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; -use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\Helpers\FakeAuthProvider; +use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\Helpers\TestingAuthProvider; use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\Helpers\FakeClock; /** @@ -73,7 +73,7 @@ abstract protected function getContentRepository(ContentRepositoryId $id): Conte */ public function iAmUserIdentifiedBy(string $userId): void { - FakeAuthProvider::setUserId(UserId::fromString($userId)); + TestingAuthProvider::setDefaultUserId(UserId::fromString($userId)); } /** diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Helpers/FakeAuthProvider.php b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Helpers/FakeAuthProvider.php deleted file mode 100644 index 916e98ffee3..00000000000 --- a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Helpers/FakeAuthProvider.php +++ /dev/null @@ -1,42 +0,0 @@ -getAuthenticatedUserId(); + } + return self::$userId ?? null; + } + + public function getVisibilityConstraints(WorkspaceName $workspaceName): VisibilityConstraints + { + if (self::$contentRepositoryAuthProvider !== null) { + return self::$contentRepositoryAuthProvider->getVisibilityConstraints($workspaceName); + } + return VisibilityConstraints::withoutRestrictions(); + } + + public function canReadNodesFromWorkspace(WorkspaceName $workspaceName): Privilege + { + if (self::$contentRepositoryAuthProvider !== null) { + return self::$contentRepositoryAuthProvider->canReadNodesFromWorkspace($workspaceName); + } + return Privilege::granted(self::class . ' always grants privileges'); + } + + public function canExecuteCommand(CommandInterface $command): Privilege + { + if (self::$contentRepositoryAuthProvider !== null) { + return self::$contentRepositoryAuthProvider->canExecuteCommand($command); + } + return Privilege::granted(self::class . ' always grants privileges'); + } +} diff --git a/Neos.Neos/Tests/Behavior/Features/Bootstrap/ContentRepositorySecurityTrait.php b/Neos.Neos/Tests/Behavior/Features/Bootstrap/ContentRepositorySecurityTrait.php new file mode 100644 index 00000000000..6d950404a80 --- /dev/null +++ b/Neos.Neos/Tests/Behavior/Features/Bootstrap/ContentRepositorySecurityTrait.php @@ -0,0 +1,206 @@ + $className + * @return T + */ + abstract private function getObject(string $className): object; + + #[BeforeScenario] + public function resetContentRepositorySecurity(): void + { + TestingAuthProvider::resetAuthProvider(); + $this->contentRepositorySecurityEnabled = false; + } + + #[BeforeFeature] + #[AfterFeature] + public static function resetPolicies(): void + { + if (self::$testingPolicyPathAndFilename !== null && file_exists(self::$testingPolicyPathAndFilename)) { + unlink(self::$testingPolicyPathAndFilename); + } + } + + private function enableFlowSecurity(): void + { + if ($this->flowSecurityEnabled === true) { + return; + } + $this->getObject(PrivilegeManagerInterface::class)->reset(); + + $tokenAndProviderFactory = $this->getObject(TokenAndProviderFactoryInterface::class); + + $this->testingProvider = $tokenAndProviderFactory->getProviders()['TestingProvider']; + + $securityContext = $this->getObject(SecurityContext::class); + $securityContext->clearContext(); + $httpRequest = $this->getObject(ServerRequestFactoryInterface::class)->createServerRequest('GET', 'http://localhost/'); + $this->mockActionRequest = ActionRequest::fromHttpRequest($httpRequest); + $securityContext->setRequest($this->mockActionRequest); + $this->flowSecurityEnabled = true; + } + + private function enableContentRepositorySecurity(): void + { + if ($this->contentRepositorySecurityEnabled === true) { + return; + } + $contentRepositoryAuthProviderFactory = $this->getObject(ContentRepositoryAuthProviderFactory::class); + $contentGraphProjection = $this->getContentRepositoryService(new class implements ContentRepositoryServiceFactoryInterface { + public function build(ContentRepositoryServiceFactoryDependencies $serviceFactoryDependencies): ContentRepositoryServiceInterface + { + $contentGraphProjection = $serviceFactoryDependencies->projectionsAndCatchUpHooks->contentGraphProjection; + return new class ($contentGraphProjection) implements ContentRepositoryServiceInterface { + public function __construct( + public ContentGraphProjectionInterface $contentGraphProjection, + ) { + } + }; + } + })->contentGraphProjection; + $contentRepositoryAuthProvider = $contentRepositoryAuthProviderFactory->build($this->currentContentRepository->id, $contentGraphProjection->getState()); + + TestingAuthProvider::replaceAuthProvider($contentRepositoryAuthProvider); + $this->contentRepositorySecurityEnabled = true; + } + + private function authenticateAccount(Account $account): void + { + $this->enableFlowSecurity(); + $this->testingProvider->setAuthenticationStatus(TokenInterface::AUTHENTICATION_SUCCESSFUL); + $this->testingProvider->setAccount($account); + + $securityContext = $this->getObject(SecurityContext::class); + $securityContext->clearContext(); + $securityContext->setRequest($this->mockActionRequest); + $this->getObject(AuthenticationProviderManager::class)->authenticate(); + } + + /** + * @Given content repository security is enabled + */ + public function contentRepositorySecurityIsEnabled(): void + { + $this->enableContentRepositorySecurity(); + } + + + /** + * @Given The following additional policies are configured: + */ + public function theFollowingAdditionalPoliciesAreConfigured(PyStringNode $policies): void + { + $policyService = $this->getObject(PolicyService::class); + $policyService->getRoles(); // force initialization + $policyConfiguration = ObjectAccess::getProperty($policyService, 'policyConfiguration', true); + $mergedPolicyConfiguration = Arrays::arrayMergeRecursiveOverrule($policyConfiguration, Yaml::parse($policies->getRaw())); + + self::$testingPolicyPathAndFilename = $this->getObject(Environment::class)->getPathToTemporaryDirectory() . 'Policy.yaml'; + file_put_contents(self::$testingPolicyPathAndFilename, Yaml::dump($mergedPolicyConfiguration)); + + ObjectAccess::setProperty($policyService, 'initialized', false, true); + $this->getObject(ConfigurationManager::class)->flushConfigurationCache(); + } + + /** + * @When the user :username accesses the content graph for workspace :workspaceName + */ + public function theUserAccessesTheContentGraphForWorkspace(string $username, string $workspaceName): void + { + $this->enableContentRepositorySecurity(); + $user = $this->getObject(UserService::class)->getUser($username); + $this->authenticateAccount($user->getAccounts()->first()); + $this->tryCatchingExceptions(fn () => $this->currentContentRepository->getContentGraph(WorkspaceName::fromString($workspaceName))); + } + + /** + * @Then The user :username should not be able to read node :nodeAggregateId + */ + public function theUserShouldNotBeAbleToReadNode(string $username, string $nodeAggregateId): void + { + $user = $this->getObject(UserService::class)->getUser($username); + $this->authenticateAccount($user->getAccounts()->first()); + $node = $this->currentContentRepository->getContentSubgraph($this->currentWorkspaceName, $this->currentDimensionSpacePoint)->findNodeById(NodeAggregateId::fromString($nodeAggregateId)); + if ($node !== null) { + Assert::fail(sprintf('Expected node "%s" to be inaccessible to user "%s" but it was loaded', $nodeAggregateId, $username)); + } + } + + /** + * @Then The user :username should be able to read node :nodeAggregateId + */ + public function theUserShouldBeAbleToReadNode(string $username, string $nodeAggregateId): void + { + $user = $this->getObject(UserService::class)->getUser($username); + $this->authenticateAccount($user->getAccounts()->first()); + $node = $this->currentContentRepository->getContentSubgraph($this->currentWorkspaceName, $this->currentDimensionSpacePoint)->findNodeById(NodeAggregateId::fromString($nodeAggregateId)); + if ($node === null) { + Assert::fail(sprintf('Expected node "%s" to be accessible to user "%s" but it could not be loaded', $nodeAggregateId, $username)); + } + } +} diff --git a/Neos.Neos/Tests/Behavior/Features/Bootstrap/ExceptionsTrait.php b/Neos.Neos/Tests/Behavior/Features/Bootstrap/ExceptionsTrait.php index fabfcd12608..228d4594bdc 100644 --- a/Neos.Neos/Tests/Behavior/Features/Bootstrap/ExceptionsTrait.php +++ b/Neos.Neos/Tests/Behavior/Features/Bootstrap/ExceptionsTrait.php @@ -46,6 +46,15 @@ public function anExceptionShouldBeThrown(string $exceptionMessage): void $this->lastCaughtException = null; } + /** + * @Then no exception should be thrown + */ + public function noExceptionShouldBeThrown(): void + { + Assert::assertNull($this->lastCaughtException, 'Expected no exception but one was thrown'); + $this->lastCaughtException = null; + } + /** * @BeforeScenario * @AfterScenario diff --git a/Neos.Neos/Tests/Behavior/Features/Bootstrap/FeatureContext.php b/Neos.Neos/Tests/Behavior/Features/Bootstrap/FeatureContext.php index 9d06ce491eb..a522afdd352 100644 --- a/Neos.Neos/Tests/Behavior/Features/Bootstrap/FeatureContext.php +++ b/Neos.Neos/Tests/Behavior/Features/Bootstrap/FeatureContext.php @@ -46,6 +46,7 @@ class FeatureContext implements BehatContext use AssetTrait; use WorkspaceServiceTrait; + use ContentRepositorySecurityTrait; use UserServiceTrait; protected Environment $environment; diff --git a/Neos.Neos/Tests/Behavior/Features/Bootstrap/UserServiceTrait.php b/Neos.Neos/Tests/Behavior/Features/Bootstrap/UserServiceTrait.php index 4d8d153f64e..4c4118f8f57 100644 --- a/Neos.Neos/Tests/Behavior/Features/Bootstrap/UserServiceTrait.php +++ b/Neos.Neos/Tests/Behavior/Features/Bootstrap/UserServiceTrait.php @@ -16,8 +16,10 @@ use Neos\Flow\Persistence\PersistenceManagerInterface; use Neos\Flow\Security\AccountFactory; use Neos\Flow\Security\Cryptography\HashService; +use Neos\Flow\Security\Policy\PolicyService; use Neos\Neos\Domain\Model\User; use Neos\Neos\Domain\Service\UserService; +use Neos\Neos\Security\Authorization\Privilege\ReadNodePrivilege; use Neos\Party\Domain\Model\PersonName; use Neos\Utility\ObjectAccess; diff --git a/Neos.Neos/Tests/Behavior/Features/ContentRepository/Security.feature b/Neos.Neos/Tests/Behavior/Features/ContentRepository/Security.feature new file mode 100644 index 00000000000..9b4e721c733 --- /dev/null +++ b/Neos.Neos/Tests/Behavior/Features/ContentRepository/Security.feature @@ -0,0 +1,75 @@ +@flowEntities +Feature: TODO + + Background: + Given The following additional policies are configured: + """ + privilegeTargets: + 'Neos\Neos\Security\Authorization\Privilege\ReadNodePrivilege': + 'Neos.Neos:ReadBlog': + matcher: 'blog' + roles: + + 'Neos.Neos:Administrator': + privileges: + - privilegeTarget: 'Neos.Neos:ReadBlog' + permission: GRANT + """ + And using no content dimensions + And using the following node types: + """yaml + 'Neos.ContentRepository.Testing:Document': {} + """ + And using identifier "default", I define a content repository + And I am in content repository "default" + And I am user identified by "initiating-user-identifier" + And the command CreateRootWorkspace is executed with payload: + | Key | Value | + | workspaceName | "live" | + | newContentStreamId | "cs-identifier" | + And I am in workspace "live" and dimension space point {} + And the command CreateRootNodeAggregateWithNode is executed with payload: + | Key | Value | + | nodeAggregateId | "root" | + | nodeTypeName | "Neos.ContentRepository:Root" | + And the following CreateNodeAggregateWithNode commands are executed: + | nodeAggregateId | nodeTypeName | parentNodeAggregateId | nodeName | + | a | Neos.ContentRepository.Testing:Document | root | a | + | a1 | Neos.ContentRepository.Testing:Document | a | a1 | + | a1a | Neos.ContentRepository.Testing:Document | a1 | a1a | + | a1a1 | Neos.ContentRepository.Testing:Document | a1a | a1a1 | + | a1a1a | Neos.ContentRepository.Testing:Document | a1a1 | a1a1a | + | a1a1b | Neos.ContentRepository.Testing:Document | a1a1 | a1a1b | + | a1a2 | Neos.ContentRepository.Testing:Document | a1a | a1a2 | + | a1b | Neos.ContentRepository.Testing:Document | a1 | a1b | + | a2 | Neos.ContentRepository.Testing:Document | a | a2 | + | b | Neos.ContentRepository.Testing:Document | root | b | + | b1 | Neos.ContentRepository.Testing:Document | b | b1 | + And the following Neos users exist: + | Id | Username | First name | Last name | Roles | + | janedoe | jane.doe | Jane | Doe | Neos.Neos:Administrator | + | johndoe | john.doe | John | Doe | Neos.Neos:RestrictedEditor,Neos.Neos:UserManager | + | editor | editor | Edward | Editor | Neos.Neos:Editor | + + Scenario: Access content graph for root workspace without role assignments + Given I am in workspace "live" + And the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "a" | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "blog" | + And the role VIEWER is assigned to workspace "live" for group "Neos.Flow:Everybody" + When content repository security is enabled + Then The user "john.doe" should not be able to read node "a1" + Then The user "jane.doe" should be able to read node "a1" + + Scenario: TODO + When content repository security is enabled + And the user "jane.doe" accesses the content graph for workspace "live" + Then an exception 'Read access denied for workspace "live": Account "jane.doe" is a Neos Administrator without explicit role for workspace "live"' should be thrown + + Scenario: TODO + Given the role MANAGER is assigned to workspace "live" for user "janedoe" + When content repository security is enabled + And the user "jane.doe" accesses the content graph for workspace "live" + Then no exception should be thrown diff --git a/Neos.Neos/Tests/Behavior/Features/Security/NodeTreePrivilege.__feature b/Neos.Neos/Tests/Behavior/Features/Security/NodeTreePrivilege.__feature deleted file mode 100644 index 2fa92e93581..00000000000 --- a/Neos.Neos/Tests/Behavior/Features/Security/NodeTreePrivilege.__feature +++ /dev/null @@ -1,148 +0,0 @@ -# TODO rewrite test after https://github.com/neos/neos-development-collection/issues/3732 - -Feature: Privilege to restrict nodes shown in the node tree - - Background: - Given I have the following policies: - """ - privilegeTargets: - - 'Neos\Neos\Security\Authorization\Privilege\NodeTreePrivilege': - 'Neos.ContentRepository:CompanySubtree': - matcher: 'isDescendantNodeOf("/sites/content-repository/company")' - 'Neos.ContentRepository:ServiceSubtree': - matcher: 'isDescendantNodeOf("/sites/content-repository/service")' - - 'Neos.ContentRepository:NeosSite': - matcher: 'isDescendantNodeOf("/sites/neos")' - 'Neos.ContentRepository:NeosTeams': - matcher: 'isAncestorOrDescendantNodeOf("/sites/neos/community/teams")' - - 'Neos\ContentRepository\Security\Authorization\Privilege\Node\EditNodePrivilege': - 'Neos.ContentRepository:EditNeosTeamsPath': - matcher: 'isAncestorNodeOf("/sites/neos/community/teams")' - - roles: - 'Neos.Flow:Everybody': - privileges: [] - - 'Neos.Flow:Anonymous': - privileges: [] - - 'Neos.Flow:AuthenticatedUser': - privileges: [] - - 'Neos.Neos:Editor': - privileges: - - - privilegeTarget: 'Neos.ContentRepository:CompanySubtree' - permission: GRANT - - 'Neos.Neos:Administrator': - parentRoles: ['Neos.Neos:Editor'] - privileges: - - - privilegeTarget: 'Neos.ContentRepository:ServiceSubtree' - permission: GRANT - - - privilegeTarget: 'Neos.ContentRepository:NeosTeams' - permission: GRANT - - - privilegeTarget: 'Neos.ContentRepository:EditNeosTeamsPath' - permission: DENY - - """ - - And I have the following nodes: - | Identifier | Path | Node Type | Properties | Workspace | - | ecf40ad1-3119-0a43-d02e-55f8b5aa3c70 | /sites | unstructured | | live | - | fd5ba6e1-4313-b145-1004-dad2f1173a35 | /sites/content-repository | Neos.ContentRepository.Testing:Document | {"title": "Home"} | live | - | 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 | - | 3223481d-e11c-4db7-95de-b371411a2431 | /sites/content-repository/service/newsletter | Neos.ContentRepository.Testing:Document | {"title": "Newsletter"} | live | - | 544e14a3-b21d-429a-9fdd-cbeccc8d2b0f | /sites/content-repository/about-us | Neos.ContentRepository.Testing:Document | {"title": "About us"} | live | - | 56217c92-07e9-4554-ac35-03f86d278870 | /sites/neos | Neos.ContentRepository.Testing:Document | {"title": "Neos"} | live | - | 4be072fe-0738-4892-8a27-342a6ac96075 | /sites/neos/community | Neos.ContentRepository.Testing:Document | {"title": "Community"} | live | - | c56d66e7-9c55-4eef-a2b1-c263b3261996 | /sites/neos/community/teams | Neos.ContentRepository.Testing:Document | {"title": "Teams"} | live | - | 07902b2e-61d9-4ce4-9b90-1cf338830d2f | /sites/neos/community/teams/member| Neos.ContentRepository.Testing:Document | {"title": "Johannes"} | live | - - @Isolated @fixtures - Scenario: Editors are granted to set properties on company node - Given I am authenticated with role "Neos.Neos:Editor" - And I get a node by path "/sites/content-repository/company" with the following context: - | Workspace | - | user-admin | - Then I should be granted to set the "title" property to "The company" - And I should get true when asking the node authorization service if editing this node is granted - - @Isolated @fixtures - Scenario: Editors are not granted to set properties on service node - Given I am authenticated with role "Neos.Neos:Editor" - And I get a node by path "/sites/content-repository/service" with the following context: - | Workspace | - | user-admin | - Then I should not be granted to set the "title" property to "Our services" - And I should get false when asking the node authorization service if editing this node is granted - - @Isolated @fixtures - Scenario: Editors are not granted to set properties on service sub node - Given I am authenticated with role "Neos.Neos:Editor" - And I get a node by path "/sites/content-repository/service/newsletter" with the following context: - | Workspace | - | user-admin | - Then I should not be granted to set the "title" property to "Our newsletter" - And I should get false when asking the node authorization service if editing this node is granted - - @Isolated @fixtures - Scenario: Administrators are granted to set properties on company node - Given I am authenticated with role "Neos.Neos:Administrator" - And I get a node by path "/sites/content-repository/company" with the following context: - | Workspace | - | user-admin | - Then I should be granted to set the "title" property to "The company" - And I should get true when asking the node authorization service if editing this node is granted - - @Isolated @fixtures - Scenario: Administrators are granted to set properties on service node - Given I am authenticated with role "Neos.Neos:Administrator" - And I get a node by path "/sites/content-repository/service" with the following context: - | Workspace | - | user-admin | - Then I should be granted to set the "title" property to "Our services" - And I should get true when asking the node authorization service if editing this node is granted - - @Isolated @fixtures - Scenario: Administrators are granted to set properties on service sub node - Given I am authenticated with role "Neos.Neos:Administrator" - And I get a node by path "/sites/content-repository/service/newsletter" with the following context: - | Workspace | - | user-admin | - Then I should be granted to set the "title" property to "Our newsletter" - And I should get true when asking the node authorization service if editing this node is granted - - @Isolated @fixtures - Scenario: Editors are not granted to set properties on a neos sub node - Given I am authenticated with role "Neos.Neos:Editor" - And I get a node by path "/sites/neos/community/teams" with the following context: - | Workspace | - | user-admin | - Then I should not be granted to set the "title" property to "The Teams" - And I should get false when asking the node authorization service if editing this node is granted - - @Isolated @fixtures - Scenario: Administrators are granted to set properties on a neos sub node - Given I am authenticated with role "Neos.Neos:Administrator" - And I get a node by path "/sites/neos/community/teams/member" with the following context: - | Workspace | - | user-admin | - Then I should be granted to set the "title" property to "Basti" - And I should get true when asking the node authorization service if editing this node is granted - - @Isolated @fixtures - Scenario: Administrators are not granted to set properties on an ancestor node of teams - Given I am authenticated with role "Neos.Neos:Administrator" - And I get a node by path "/sites/neos/community" with the following context: - | Workspace | - | user-admin | - Then I should not be granted to set the "title" property to "The Community" - And I should get false when asking the node authorization service if editing this node is granted