diff --git a/Neos.Neos/Classes/Command/WorkspaceCommandController.php b/Neos.Neos/Classes/Command/WorkspaceCommandController.php
index fa834b4258..4dd8a0acd8 100644
--- a/Neos.Neos/Classes/Command/WorkspaceCommandController.php
+++ b/Neos.Neos/Classes/Command/WorkspaceCommandController.php
@@ -30,6 +30,7 @@
use Neos\Neos\Domain\Model\WorkspaceDescription;
use Neos\Neos\Domain\Model\WorkspaceRole;
use Neos\Neos\Domain\Model\WorkspaceRoleAssignment;
+use Neos\Neos\Domain\Model\WorkspaceRoleAssignments;
use Neos\Neos\Domain\Model\WorkspaceRoleSubject;
use Neos\Neos\Domain\Model\WorkspaceRoleSubjectType;
use Neos\Neos\Domain\Model\WorkspaceTitle;
@@ -205,6 +206,7 @@ public function createSharedCommand(string $workspace, string $baseWorkspace = '
WorkspaceTitle::fromString($title ?? $workspaceName->value),
WorkspaceDescription::fromString($description ?? ''),
WorkspaceName::fromString($baseWorkspace),
+ WorkspaceRoleAssignments::createEmpty()
);
$this->outputLine('Created shared workspace "%s"', [$workspaceName->value]);
}
diff --git a/Neos.Neos/Classes/Domain/Model/WorkspaceRoleAssignments.php b/Neos.Neos/Classes/Domain/Model/WorkspaceRoleAssignments.php
index ef9af39059..28d8aec212 100644
--- a/Neos.Neos/Classes/Domain/Model/WorkspaceRoleAssignments.php
+++ b/Neos.Neos/Classes/Domain/Model/WorkspaceRoleAssignments.php
@@ -25,6 +25,16 @@ private function __construct(WorkspaceRoleAssignment ...$assignments)
$this->assignments = $assignments;
}
+ public static function createEmpty(): self
+ {
+ return new self();
+ }
+
+ public static function create(WorkspaceRoleAssignment ...$assignments): self
+ {
+ return new self(...$assignments);
+ }
+
/**
* @param array $assignments
*/
diff --git a/Neos.Neos/Classes/Domain/Service/WorkspaceService.php b/Neos.Neos/Classes/Domain/Service/WorkspaceService.php
index a15c2b583c..7dfebc3c93 100644
--- a/Neos.Neos/Classes/Domain/Service/WorkspaceService.php
+++ b/Neos.Neos/Classes/Domain/Service/WorkspaceService.php
@@ -154,10 +154,15 @@ public function createPersonalWorkspace(ContentRepositoryId $contentRepositoryId
/**
* Create a new, potentially shared, workspace
+ *
+ * NOTE: By default - if no role assignments are specified - only administrators can manage workspaces without role assignments.
*/
- public function createSharedWorkspace(ContentRepositoryId $contentRepositoryId, WorkspaceName $workspaceName, WorkspaceTitle $title, WorkspaceDescription $description, WorkspaceName $baseWorkspaceName): void
+ public function createSharedWorkspace(ContentRepositoryId $contentRepositoryId, WorkspaceName $workspaceName, WorkspaceTitle $title, WorkspaceDescription $description, WorkspaceName $baseWorkspaceName, WorkspaceRoleAssignments $workspaceRoleAssignments): void
{
$this->createWorkspace($contentRepositoryId, $workspaceName, $title, $description, $baseWorkspaceName, null, WorkspaceClassification::SHARED);
+ foreach ($workspaceRoleAssignments as $assignment) {
+ $this->metadataAndRoleRepository->assignWorkspaceRole($contentRepositoryId, $workspaceName, $assignment);
+ }
}
/**
diff --git a/Neos.Neos/Classes/Security/Authorization/ContentRepositoryAuthorizationService.php b/Neos.Neos/Classes/Security/Authorization/ContentRepositoryAuthorizationService.php
index 6de599cbd7..b187e63f7a 100644
--- a/Neos.Neos/Classes/Security/Authorization/ContentRepositoryAuthorizationService.php
+++ b/Neos.Neos/Classes/Security/Authorization/ContentRepositoryAuthorizationService.php
@@ -59,6 +59,10 @@ public function getWorkspacePermissions(ContentRepositoryId $contentRepositoryId
if ($userId !== null) {
$subjects[] = WorkspaceRoleSubject::createForUser($userId);
}
+ /**
+ * We hardcode the check against administrators to always grant manage permissions. This is done to allow administrators to fix permissions of all workspaces.
+ * We don't allow all rights like read and write. Admins should be able to grant themselves permissions to write to other personal workspaces, but they should not have this permission automagically.
+ */
$userIsAdministrator = in_array(self::ROLE_NEOS_ADMINISTRATOR, $roleIdentifiers, true);
$userWorkspaceRole = $this->metadataAndRoleRepository->getMostPrivilegedWorkspaceRoleForSubjects($contentRepositoryId, $workspaceName, WorkspaceRoleSubjects::fromArray($subjects));
if ($userWorkspaceRole === null) {
diff --git a/Neos.Neos/Tests/Behavior/Features/Bootstrap/WorkspaceServiceTrait.php b/Neos.Neos/Tests/Behavior/Features/Bootstrap/WorkspaceServiceTrait.php
index deee0129a5..1910727fe2 100644
--- a/Neos.Neos/Tests/Behavior/Features/Bootstrap/WorkspaceServiceTrait.php
+++ b/Neos.Neos/Tests/Behavior/Features/Bootstrap/WorkspaceServiceTrait.php
@@ -22,7 +22,9 @@
use Neos\Neos\Domain\Model\WorkspaceDescription;
use Neos\Neos\Domain\Model\WorkspaceRole;
use Neos\Neos\Domain\Model\WorkspaceRoleAssignment;
+use Neos\Neos\Domain\Model\WorkspaceRoleAssignments;
use Neos\Neos\Domain\Model\WorkspaceRoleSubject;
+use Neos\Neos\Domain\Model\WorkspaceRoleSubjectType;
use Neos\Neos\Domain\Model\WorkspaceTitle;
use Neos\Neos\Domain\Service\UserService;
use Neos\Neos\Domain\Service\WorkspaceService;
@@ -112,15 +114,28 @@ public function aPersonalWorkspaceForUserIsCreated(string $username): void
/**
* @When the shared workspace :workspaceName is created with the target workspace :targetWorkspace
+ * @When the shared workspace :workspaceName is created with the target workspace :targetWorkspace and role assignments:
*/
- public function theSharedWorkspaceIsCreatedWithTheTargetWorkspace(string $workspaceName, string $targetWorkspace): void
+ public function theSharedWorkspaceIsCreatedWithTheTargetWorkspace(string $workspaceName, string $targetWorkspace, ?TableNode $rawRoleAssignments = null): void
{
+ $workspaceRoleAssignments = [];
+ foreach ($rawRoleAssignments?->getHash() ?? [] as $row) {
+ $workspaceRoleAssignments[] = WorkspaceRoleAssignment::create(
+ WorkspaceRoleSubject::create(
+ WorkspaceRoleSubjectType::from($row['Type']),
+ $row['Value']
+ ),
+ WorkspaceRole::from($row['Role'])
+ );
+ }
+
$this->tryCatchingExceptions(fn () => $this->getObject(WorkspaceService::class)->createSharedWorkspace(
$this->currentContentRepository->id,
WorkspaceName::fromString($workspaceName),
WorkspaceTitle::fromString($workspaceName),
WorkspaceDescription::fromString(''),
WorkspaceName::fromString($targetWorkspace),
+ WorkspaceRoleAssignments::fromArray($workspaceRoleAssignments)
));
}
diff --git a/Neos.Neos/Tests/Behavior/Features/ContentRepository/Security/WorkspacePermissions.feature b/Neos.Neos/Tests/Behavior/Features/ContentRepository/Security/WorkspacePermissions.feature
index 800d45c8bc..3fc1101b7d 100644
--- a/Neos.Neos/Tests/Behavior/Features/ContentRepository/Security/WorkspacePermissions.feature
+++ b/Neos.Neos/Tests/Behavior/Features/ContentRepository/Security/WorkspacePermissions.feature
@@ -51,15 +51,16 @@ Feature: Workspace permission related features
# neos user with out any editing roles
| simple_user | Neos.Neos:UserManager |
- And the shared workspace "shared-workspace" is created with the target workspace "live"
- And the role COLLABORATOR is assigned to workspace "shared-workspace" for group "Neos.Neos:AbstractEditor"
+ When content repository security is enabled
+ And the shared workspace "shared-workspace" is created with the target workspace "live" and role assignments:
+ | Role | Type | Value |
+ | COLLABORATOR | GROUP | Neos.Neos:AbstractEditor |
+ Given I am authenticated as owner
And the personal workspace "workspace" is created with the target workspace "live" for user "owner"
And the role MANAGER is assigned to workspace "workspace" for user "manager"
And the role COLLABORATOR is assigned to workspace "workspace" for user "collaborator"
- When content repository security is enabled
-
Scenario Outline: Creating a root workspace
Given I am authenticated as
When the command CreateRootWorkspace is executed with payload '{"workspaceName":"new-ws","newContentStreamId":"new-cs"}' and exceptions are caught
diff --git a/Neos.Workspace.Ui/Classes/Controller/WorkspaceController.php b/Neos.Workspace.Ui/Classes/Controller/WorkspaceController.php
index e8f02988ac..99971e52e1 100644
--- a/Neos.Workspace.Ui/Classes/Controller/WorkspaceController.php
+++ b/Neos.Workspace.Ui/Classes/Controller/WorkspaceController.php
@@ -55,6 +55,7 @@
use Neos\Neos\Domain\Model\WorkspaceDescription;
use Neos\Neos\Domain\Model\WorkspaceRole;
use Neos\Neos\Domain\Model\WorkspaceRoleAssignment;
+use Neos\Neos\Domain\Model\WorkspaceRoleAssignments;
use Neos\Neos\Domain\Model\WorkspaceTitle;
use Neos\Neos\Domain\Repository\SiteRepository;
use Neos\Neos\Domain\Service\NodeTypeNameFactory;
@@ -222,6 +223,16 @@ public function createAction(
$title,
$description,
$baseWorkspace,
+ WorkspaceRoleAssignments::create(
+ WorkspaceRoleAssignment::createForUser(
+ $currentUser->getId(),
+ WorkspaceRole::MANAGER,
+ ),
+ WorkspaceRoleAssignment::createForGroup(
+ 'Neos.Neos:AbstractEditor',
+ WorkspaceRole::COLLABORATOR,
+ )
+ )
);
} catch (WorkspaceAlreadyExists $exception) {
$this->addFlashMessage(
@@ -231,22 +242,6 @@ public function createAction(
);
$this->redirect('new');
}
- $this->workspaceService->assignWorkspaceRole(
- $contentRepositoryId,
- $workspaceName,
- WorkspaceRoleAssignment::createForUser(
- $currentUser->getId(),
- WorkspaceRole::MANAGER,
- )
- );
- $this->workspaceService->assignWorkspaceRole(
- $contentRepositoryId,
- $workspaceName,
- WorkspaceRoleAssignment::createForGroup(
- 'Neos.Neos:AbstractEditor',
- WorkspaceRole::COLLABORATOR,
- )
- );
$this->addFlashMessage($this->getModuleLabel('workspaces.workspaceHasBeenCreated', [$title->value]));
$this->redirect('index');
}
@@ -1029,7 +1024,7 @@ protected function prepareBaseWorkspaceOptions(
continue;
}
$permissions = $this->contentRepositoryAuthorizationService->getWorkspacePermissions($contentRepository->id, $workspace->workspaceName, $this->securityContext->getRoles(), $currentUser?->getId());
- if (!$permissions->manage) {
+ if (!$permissions->read) {
continue;
}
$baseWorkspaceOptions[$workspace->workspaceName->value] = $workspaceMetadata->title->value;