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

BUGFIX: WorkspaceService adjust to real world use cases #5334

Merged
merged 25 commits into from
Dec 12, 2024

Conversation

mhsdesign
Copy link
Member

@mhsdesign mhsdesign commented Oct 31, 2024

The adjustments which are needed for the new workspace UI #5132

Fix up for #5146 (original introduction of mighty WorkspaceService), and #5298 (partial refactoring yet again towards authentication provider)

As separate PR to have the bugfixes tested and also better discussed.

Todo:

  • write test for workspace delete
  • test for workspace low level pruning? -> should be tested as part of site:pruneAll
  • test for live publisher (via "normal" editor)
  • test to change base workspace
  • cleanup old policy yaml, and explain "special" magic features (like live publisher is added as role on creation for live)
  • Discuss deletion should also work from core command? Maybe catchup hook or delete dangling workspace metadata on creation of new identical

Upgrade instructions

Review instructions

Checklist

Neos.Neos/Classes/Domain/Service/WorkspaceService.php Outdated Show resolved Hide resolved
@mhsdesign
Copy link
Member Author

Also im not sure why these changes are needed but they were made originally in 916e510:

diff --git a/Neos.Neos/Classes/Domain/Service/WorkspaceService.php b/Neos.Neos/Classes/Domain/Service/WorkspaceService.php
index 8d7e11d2e4f..d515a0205cc 100644
--- a/Neos.Neos/Classes/Domain/Service/WorkspaceService.php
+++ b/Neos.Neos/Classes/Domain/Service/WorkspaceService.php
@@ -302,19 +302,30 @@ public function getWorkspacePermissionsForUser(ContentRepositoryId $contentRepos
         } catch (NoSuchRoleException $e) {
             throw new \RuntimeException(sprintf('Failed to determine roles for user "%s", check your package dependencies: %s', $user->getId()->value, $e->getMessage()), 1727084881, $e);
         }
+
+        $userIsAdministrator = in_array('Neos.Neos:Administrator', $userRoles, true);
+
+        if ($userIsAdministrator) {
+            return WorkspacePermissions::all();
+        }
+
         $workspaceMetadata = $this->loadWorkspaceMetadata($contentRepositoryId, $workspaceName);
-        if ($workspaceMetadata !== null && $workspaceMetadata->ownerUserId !== null && $workspaceMetadata->ownerUserId->equals($user->getId())) {
+        $userIsOwner = $workspaceMetadata !== null && $workspaceMetadata->ownerUserId !== null && $workspaceMetadata->ownerUserId->equals($user->getId());
+
+        if ($userIsOwner) {
             return WorkspacePermissions::all();
         }
+
         $userWorkspaceRole = $this->loadWorkspaceRoleOfUser($contentRepositoryId, $workspaceName, $user->getId(), $userRoles);
-        $userIsAdministrator = in_array('Neos.Neos:Administrator', $userRoles, true);
+
         if ($userWorkspaceRole === null) {
-            return WorkspacePermissions::create(false, false, $userIsAdministrator);
+            return WorkspacePermissions::none();
         }
+
         return WorkspacePermissions::create(
             read: $userWorkspaceRole->isAtLeast(WorkspaceRole::COLLABORATOR),
             write: $userWorkspaceRole->isAtLeast(WorkspaceRole::COLLABORATOR),
-            manage: $userIsAdministrator || $userWorkspaceRole->isAtLeast(WorkspaceRole::MANAGER),
+            manage: $userWorkspaceRole->isAtLeast(WorkspaceRole::MANAGER),
         );
     }

a lot of test fail with this change and im not sure what the reason for this was.

@mhsdesign mhsdesign force-pushed the bugfix/workspace-service-adjustments branch from 0e00dfa to a7d887f Compare December 6, 2024 10:19
@mhsdesign
Copy link
Member Author

Also it seems, that if we allow to create workspaces only with read permission this test does not pass because EVERY Neos user is EVERYBODY and they are VIEWER

Scenario Outline: Creating a workspace without READ permissions (on live)
  Given I am authenticated as <user>
  And the shared workspace "some-shared-workspace" is created with the target workspace "live"
  Then an exception of type "AccessDenied" should be thrown with code 1729086686

  And the personal workspace "some-other-personal-workspace" is created with the target workspace "live" for user <user>
  Then an exception of type "AccessDenied" should be thrown with code 1729086686

  Examples:
    | user              |
    | restricted_editor |
    | simple_user       |

Technically - if would test this which we dont - this meand that even an unauthenticated request could just create workspaces? - we definitely need test for the not authenticated case as well imo, especially since the default => grant would be dangerous no? ->

Comment on lines 103 to 120
Scenario: Creating a workspace without Neos User but READ permissions on live
Given I am not authenticated
And the shared workspace "some-shared-workspace" is created with the target workspace "live"

Scenario Outline: Creating a workspace with READ permissions (on live)
Given I am authenticated as <user>
And the shared workspace "some-shared-workspace" is created with the target workspace "live"

And the personal workspace "some-other-personal-workspace" is created with the target workspace "live" for user <user>

Examples:
| user |
| admin |
| owner |
| collaborator |
| uninvolved_editor |
| restricted_editor |
| simple_user |
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

basically theses test means that EVERYBODY can create a new workspace based on live, not even a neos user is required - im not sure if this is correct, but in 8.3 i also could find no restriction for new Workspace or adding that to the repository.

@bwaidelich
Copy link
Member

@mhsdesign thanks for extracting this PR!

im not sure why these changes are needed

They make me suspicious, too. IMO an admin should be able to grant themselves permissions to write to other personal workspaces, but they should not have this permission automagically.

we definitely need test for the not authenticated case as well imo [...]

Yes, absolutely. I'm not sure, who is supposed to be able to create workspaces – maybe we need an explicit role/privilege for that

[...] especially since the default => grant would be dangerous no?

The default of grant just matches commands that don't exist yet (because other cases should be covered). That is potentially dangerous ofc (I tried to create an "allowlist"-test but it's not easily possible to get all instances of the CommandInterface without our Flow ReflectionService). But AFAIS that is not related to the unauthenticated case

@mhsdesign
Copy link
Member Author

regarding that not authenticated users can create workspaces based on live (see 28b98c5)

maybe that is okay as in 8.3 that was only restricted via the endpoint and Neos.Neos:Backend.CreateWorkspaces now in 9.0 renamed to Neos.Workspace.Ui:Backend.CreateWorkspaces:

https://github.com/neos/neos-development-collection/blob/67c9ec4d2c1a198786b18a3da194edeca2bce5da/Neos.Workspace.Ui/Configuration/Policy.yaml#L9C6-L11

So the privilege still exists and covers the default endpoint and usecase. Still having a custom controller could contain code creating a workspace which is then not restricted by the cr. As long as this is the same behaviour as in 8.3 that might be just valid.


But AFAIS that is not related to the unauthenticated case

it is imo, because then we never ensure that the roles contain Authenticated or that a user exists...

…ew shared workspace

... otherwise authentication fails and the workspace roles cannot be assigned because management is not granted (yet) - only admins would be able to do that.
@mhsdesign
Copy link
Member Author

mhsdesign commented Dec 9, 2024

Fixed a conceptional bug to allow to specify WorkspaceRoleAssignments when creating a new shared workspace

otherwise authorisation fails when trying to issue assignWorkspaceRole: the workspace roles cannot be assigned because management is not granted (yet) - only admins would be able to do that.

I fixed that nicely by allowing to specify the WorkspaceRoleAssignments at creation:

$this->workspaceService->createSharedWorkspace(
    $contentRepositoryId,
    $workspaceName,
    $title,
    $description,
    $baseWorkspace,
    WorkspaceRoleAssignments::create(
        WorkspaceRoleAssignment::createForUser(
            $currentUser->getId(),
            WorkspaceRole::MANAGER,
        ),
        WorkspaceRoleAssignment::createForGroup(
            'Neos.Neos:AbstractEditor',
            WorkspaceRole::COLLABORATOR,
        )
    )
);

Edit i introduced static factories for that istead:

$this->workspaceService->createSharedWorkspace(
    ...,
    WorkspaceRoleAssignments::createForSharedWorkspace(
        $currentUser->getId()
    )
);
$this->workspaceService->createRootWorkspace(
    $this->contentRepository->id,
    WorkspaceName::forLive(),
    WorkspaceTitle::fromString('Public live workspace'),
    WorkspaceDescription::empty(),
    WorkspaceRoleAssignments::createForLiveWorkspace()
);
/**
 * Default role assignment to be specified at creation via {@see WorkspaceService::createRootWorkspace()}
 *
 * Users with the role "Neos.Neos:LivePublisher" are collaborators and everybody can read.
 */
public static function createForLiveWorkspace(): self
{
    return new self(
        WorkspaceRoleAssignment::createForGroup(
            'Neos.Neos:LivePublisher',
            WorkspaceRole::COLLABORATOR
        ),
        WorkspaceRoleAssignment::createForGroup(
            'Neos.Flow:Everybody',
            WorkspaceRole::VIEWER
        )
    );
}

/**
 * Default role assignment to be specified at creation via {@see WorkspaceService::createSharedWorkspace()}
 *
 * Users with the role "Neos.Neos:AbstractEditor" are collaborators and the specified user is manager
 */
public static function createForSharedWorkspace(UserId $userId): self
{
    return new self(
        WorkspaceRoleAssignment::createForUser(
            $userId,
            WorkspaceRole::MANAGER,
        ),
        WorkspaceRoleAssignment::createForGroup(
            'Neos.Neos:AbstractEditor',
            WorkspaceRole::COLLABORATOR,
        )
    );
}

and replace `createLiveWorkspaceIfMissing`

The `WorkspaceRoleAssignments` have two static factories for sane defaults for the live workspace and share one so that information is not spread out too much over the packages
… a user

the order by was just introduced to make this case explicit, the new test pass without.
@mhsdesign mhsdesign changed the title BUGFIX: Workspace service adjustments BUGFIX: WorkspaceService adjust to real world use cases Dec 9, 2024
Comment on lines 112 to 117
Scenario: For multiple personal workspaces only one workspace is returned
When the root workspace "some-root-workspace" is created
And the personal workspace "b-user-workspace" is created with the target workspace "some-root-workspace" for user "jane.doe"
And the personal workspace "a-user-workspace" is created with the target workspace "some-root-workspace" for user "jane.doe"
And the personal workspace "c-user-workspace" is created with the target workspace "some-root-workspace" for user "jane.doe"
Then the personal workspace for user "jane.doe" is "a-user-workspace"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe for the 9.0 release we should disallow having two personal workspaces per user? Not really via sql index but at least via php api? That would allow us to reduce some insanity like seen here 😅 We can always relax that constraint later.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Edit: with 31473fb i introduced a constraint to not allow that 😅

…paces for one user

we might change the concepts later and add a mapping to the "current" users workspace in their session but for now we dont need the complexity
Copy link
Contributor

@dlubitz dlubitz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me, once the tests have been fixed.

Copy link
Member

@bwaidelich bwaidelich left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great, thanks a lot!
I just left some (partly nitpicky) comments for now, but in general it's a +1 from me

We still try to catch the error beforehand via php constraint (so that the `CreateWorkspace` is not handled), but in a race condition this will be thrown at last:

> Integrity constraint violation: 1062 Duplicate entry 'default-janedoe' for key 'owner''
@mhsdesign mhsdesign merged commit adb6713 into neos:9.0 Dec 12, 2024
9 checks passed
@mhsdesign mhsdesign deleted the bugfix/workspace-service-adjustments branch December 12, 2024 09:47
mhsdesign added a commit that referenced this pull request Dec 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

3 participants