Skip to content

Commit

Permalink
BUGFIX: Only allow to publish if the current user can write to the base
Browse files Browse the repository at this point in the history
  • Loading branch information
mhsdesign committed Dec 6, 2024
1 parent d514e61 commit 484c1ab
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
use Neos\ContentRepository\Core\Feature\SubtreeTagging\Command\UntagSubtree;
use Neos\ContentRepository\Core\Feature\WorkspaceCreation\Command\CreateRootWorkspace;
use Neos\ContentRepository\Core\Feature\WorkspaceCreation\Command\CreateWorkspace;
use Neos\ContentRepository\Core\Feature\WorkspaceCreation\Exception\BaseWorkspaceDoesNotExist;
use Neos\ContentRepository\Core\Feature\WorkspaceModification\Command\ChangeBaseWorkspace;
use Neos\ContentRepository\Core\Feature\WorkspaceModification\Command\DeleteWorkspace;
use Neos\ContentRepository\Core\Feature\WorkspacePublication\Command\DiscardIndividualNodesFromWorkspace;
Expand All @@ -36,6 +37,8 @@
use Neos\ContentRepository\Core\Projection\ContentGraph\ContentGraphReadModelInterface;
use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints;
use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId;
use Neos\ContentRepository\Core\SharedModel\Exception\WorkspaceDoesNotExist;
use Neos\ContentRepository\Core\SharedModel\Exception\WorkspaceHasNoBaseWorkspaceName;
use Neos\ContentRepository\Core\SharedModel\Node\NodeAddress;
use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName;
use Neos\Flow\Security\Context as SecurityContext;
Expand Down Expand Up @@ -134,6 +137,28 @@ public function canExecuteCommand(CommandInterface $command): Privilege
}
return Privilege::granted(sprintf('User has "manage" permissions for workspace "%s" and "read" permissions for base workspace "%s"', $command->workspaceName->value, $command->baseWorkspaceName->value));
}
if ($command instanceof PublishWorkspace || $command instanceof PublishIndividualNodesFromWorkspace) {
$workspacePermissions = $this->getWorkspacePermissionsForCurrentUser($command->workspaceName);
if (!$workspacePermissions->write) {
return Privilege::denied(sprintf('Missing "write" permissions for workspace "%s": %s', $command->workspaceName->value, $workspacePermissions->getReason()));
}
$workspace = $this->contentGraphReadModel->findWorkspaceByName($command->workspaceName);
if ($workspace === null) {
throw WorkspaceDoesNotExist::butWasSupposedTo($command->workspaceName);
}
if ($workspace->baseWorkspaceName === null) {
throw WorkspaceHasNoBaseWorkspaceName::butWasSupposedTo($workspace->workspaceName);
}
$baseWorkspace = $this->contentGraphReadModel->findWorkspaceByName($workspace->baseWorkspaceName);
if ($baseWorkspace === null) {
throw BaseWorkspaceDoesNotExist::butWasSupposedTo($workspace->workspaceName);
}
$baseWorkspacePermissions = $this->getWorkspacePermissionsForCurrentUser($baseWorkspace->workspaceName);
if (!$baseWorkspacePermissions->write) {
return Privilege::denied(sprintf('Missing "write" permissions for base workspace "%s": %s', $baseWorkspace->workspaceName->value, $baseWorkspacePermissions->getReason()));
}
return Privilege::granted(sprintf('User has "manage" permissions for workspace "%s" and "write" permissions for base workspace "%s"', $command->workspaceName->value, $baseWorkspace->workspaceName->value));
}
return match ($command::class) {
AddDimensionShineThrough::class,
ChangeNodeAggregateName::class,
Expand All @@ -143,8 +168,6 @@ public function canExecuteCommand(CommandInterface $command): Privilege
UpdateRootNodeAggregateDimensions::class,
DiscardWorkspace::class,
DiscardIndividualNodesFromWorkspace::class,
PublishWorkspace::class,
PublishIndividualNodesFromWorkspace::class,
RebaseWorkspace::class => $this->requireWorkspaceWritePermission($command->workspaceName),
DeleteWorkspace::class => $this->requireWorkspaceManagePermission($command->workspaceName),
default => Privilege::granted('Command not restricted'),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -277,9 +277,59 @@ Feature: Workspace permission related features
| UpdateRootNodeAggregateDimensions | {"nodeAggregateId":"root"} |
| DiscardWorkspace | {} |
| DiscardIndividualNodesFromWorkspace | {"nodesToDiscard":[{"nodeAggregateId":"a1"}]} |
| PublishWorkspace | {} |
| PublishIndividualNodesFromWorkspace | {"nodesToPublish":[{"nodeAggregateId":"a1"}]} |
| RebaseWorkspace | {} |
# note, creating a core workspace will not grant permissions to it to the current user: Missing "read" permissions for base workspace "new-workspace"
| CreateWorkspace | {"workspaceName":"new-workspace","baseWorkspaceName":"workspace","newContentStreamId":"any"} |

Scenario Outline: Publishing a workspace without WRITE permissions to live
# make changes as owner
Given I am authenticated as owner

And the following CreateNodeAggregateWithNode commands are executed:
| nodeAggregateId | nodeTypeName | parentNodeAggregateId | workspaceName | originDimensionSpacePoint |
| shernode-homes | Neos.Neos:Document | a | workspace | {"language":"de"} |
| other-node | Neos.Neos:Document | a | workspace | {"language":"de"} |

# someone else attempts to publish
Given I am authenticated as <user>

And the command PublishIndividualNodesFromWorkspace is executed with payload and exceptions are caught:
| Key | Value |
| workspaceName | "workspace" |
| nodesToPublish | [{"nodeAggregateId":"shernode-homes"}] |
Then the last command should have thrown an exception of type "AccessDenied" with code 1729086686

And the command PublishWorkspace is executed with payload and exceptions are caught:
| Key | Value |
| workspaceName | "workspace" |
Then the last command should have thrown an exception of type "AccessDenied" with code 1729086686

Examples:
| user |
| restricted_editor |
| simple_user |
| uninvolved |
| editor |
| admin |

Scenario Outline: Publishing a workspace with WRITE permissions to live
Given I am authenticated as <user>

And the following CreateNodeAggregateWithNode commands are executed:
| nodeAggregateId | nodeTypeName | parentNodeAggregateId | workspaceName | originDimensionSpacePoint |
| shernode-homes | Neos.Neos:Document | a | workspace | {"language":"de"} |
| other-node | Neos.Neos:Document | a | workspace | {"language":"de"} |

And the command PublishIndividualNodesFromWorkspace is executed with payload:
| Key | Value |
| workspaceName | "workspace" |
| nodesToPublish | [{"nodeAggregateId":"shernode-homes"}] |

And the command PublishWorkspace is executed with payload:
| Key | Value |
| workspaceName | "workspace" |

Examples:
| user |
| owner |
| collaborator |

0 comments on commit 484c1ab

Please sign in to comment.