diff --git a/services/auth-guest/README.md b/services/auth-guest/README.md index 0aae9c3fb2..209465ad45 100644 --- a/services/auth-guest/README.md +++ b/services/auth-guest/README.md @@ -25,8 +25,8 @@ links feature and start the service. ## Overview -- **Consumes** the share lifecycle events `ShareCreated`, `ShareRemoved` and - `ShareExpired`. +- **Consumes** the share lifecycle events `ShareCreated`, `ShareRemoved`, + `ShareExpired`, `SpaceShared`, `SpaceUnshared` and `SpaceMembershipExpired`. - **Publishes** the `GuestTokenCreated` event (initial token) and the `GuestTokenRenewed` event (refresh, carrying the new token and, when authorized by a session, the PIN). diff --git a/services/auth-guest/pkg/command/server.go b/services/auth-guest/pkg/command/server.go index 720a899a87..fcf577a3e3 100644 --- a/services/auth-guest/pkg/command/server.go +++ b/services/auth-guest/pkg/command/server.go @@ -38,6 +38,8 @@ var _registeredEvents = []events.Unmarshaller{ events.ShareRemoved{}, events.ShareExpired{}, events.SpaceShared{}, + events.SpaceUnshared{}, + events.SpaceMembershipExpired{}, } // Server is the entrypoint for the server command. diff --git a/services/auth-guest/pkg/service/events/handlers.go b/services/auth-guest/pkg/service/events/handlers.go index 7edc958e64..c81e661f80 100644 --- a/services/auth-guest/pkg/service/events/handlers.go +++ b/services/auth-guest/pkg/service/events/handlers.go @@ -110,3 +110,43 @@ func (s *EventConsumer) handleSpaceShared(ctx context.Context, ev events.SpaceSh Timestamp: time.Now(), }) } + +// handleSpaceUnshared handles a space unshared event. +func (s *EventConsumer) handleSpaceUnshared(ctx context.Context, ev events.SpaceUnshared) error { + _, span := tracer.Start(ctx, "handleSpaceUnshared") + defer span.End() + + if ev.GranteeUserID == nil || ev.GranteeUserID.GetType() != user.UserType_USER_TYPE_GUEST { + s.log.Debug().Msg("space unshared event is not for a guest, skipping") + return nil + } + + if ev.ShareID.GetOpaqueId() == "" { + s.log.Warn().Msg("space unshared event without share id, skipping") + return nil + } + + s.log.Debug().Interface("event", ev).Msg("space unshared event received") + + return s.authGuest.CleanupShare(ev.ShareID.GetOpaqueId()) +} + +// handleSpaceMembershipExpired handles a space membership expired event. +func (s *EventConsumer) handleSpaceMembershipExpired(ctx context.Context, ev events.SpaceMembershipExpired) error { + _, span := tracer.Start(ctx, "handleSpaceMembershipExpired") + defer span.End() + + if ev.GranteeUserID == nil || ev.GranteeUserID.GetType() != user.UserType_USER_TYPE_GUEST { + s.log.Debug().Msg("space membership expired event is not for a guest, skipping") + return nil + } + + if ev.ShareID.GetOpaqueId() == "" { + s.log.Warn().Msg("space membership expired event without share id, skipping") + return nil + } + + s.log.Debug().Interface("event", ev).Msg("space membership expired event received") + + return s.authGuest.CleanupShare(ev.ShareID.GetOpaqueId()) +} diff --git a/services/auth-guest/pkg/service/events/handlers_test.go b/services/auth-guest/pkg/service/events/handlers_test.go index 85501a7e93..a41172786a 100644 --- a/services/auth-guest/pkg/service/events/handlers_test.go +++ b/services/auth-guest/pkg/service/events/handlers_test.go @@ -210,3 +210,94 @@ func TestHandleSpaceSharedSkipsEmptyShareID(t *testing.T) { svcMock.AssertNotCalled(t, "CreateToken", mock.Anything, mock.Anything) assert.Empty(t, bus.published) } + +func TestHandleSpaceUnshared(t *testing.T) { + svcMock := mocks.NewAuthGuest(t) + svcMock.On("CleanupShare", testShareID).Return(nil) + svc, _ := newConsumer(t, svcMock) + + ev := events.SpaceUnshared{ + ID: &provider.StorageSpaceId{OpaqueId: "storage$space"}, + ShareID: &collaboration.ShareId{OpaqueId: testShareID}, + Executant: &user.UserId{OpaqueId: "executant"}, + GranteeUserID: &user.UserId{OpaqueId: "guest@example.org", Type: user.UserType_USER_TYPE_GUEST}, + } + + require.NoError(t, svc.handleSpaceUnshared(context.Background(), ev)) + + svcMock.AssertCalled(t, "CleanupShare", testShareID) +} + +func TestHandleSpaceUnsharedSkipsNonGuest(t *testing.T) { + svcMock := mocks.NewAuthGuest(t) + svc, _ := newConsumer(t, svcMock) + + ev := events.SpaceUnshared{ + ID: &provider.StorageSpaceId{OpaqueId: "storage$space"}, + ShareID: &collaboration.ShareId{OpaqueId: testShareID}, + GranteeUserID: &user.UserId{OpaqueId: "user", Type: user.UserType_USER_TYPE_PRIMARY}, + } + + require.NoError(t, svc.handleSpaceUnshared(context.Background(), ev)) + + svcMock.AssertNotCalled(t, "CleanupShare", mock.Anything) +} + +func TestHandleSpaceUnsharedSkipsEmptyShareID(t *testing.T) { + svcMock := mocks.NewAuthGuest(t) + svc, _ := newConsumer(t, svcMock) + + ev := events.SpaceUnshared{ + ID: &provider.StorageSpaceId{OpaqueId: "storage$space"}, + GranteeUserID: &user.UserId{OpaqueId: "guest@example.org", Type: user.UserType_USER_TYPE_GUEST}, + } + + require.NoError(t, svc.handleSpaceUnshared(context.Background(), ev)) + + svcMock.AssertNotCalled(t, "CleanupShare", mock.Anything) +} + +func TestHandleSpaceMembershipExpired(t *testing.T) { + svcMock := mocks.NewAuthGuest(t) + svcMock.On("CleanupShare", testShareID).Return(nil) + svc, _ := newConsumer(t, svcMock) + + ev := events.SpaceMembershipExpired{ + ShareID: &collaboration.ShareId{OpaqueId: testShareID}, + SpaceID: &provider.StorageSpaceId{OpaqueId: "storage$space"}, + GranteeUserID: &user.UserId{OpaqueId: "guest@example.org", Type: user.UserType_USER_TYPE_GUEST}, + } + + require.NoError(t, svc.handleSpaceMembershipExpired(context.Background(), ev)) + + svcMock.AssertCalled(t, "CleanupShare", testShareID) +} + +func TestHandleSpaceMembershipExpiredSkipsNonGuest(t *testing.T) { + svcMock := mocks.NewAuthGuest(t) + svc, _ := newConsumer(t, svcMock) + + ev := events.SpaceMembershipExpired{ + ShareID: &collaboration.ShareId{OpaqueId: testShareID}, + SpaceID: &provider.StorageSpaceId{OpaqueId: "storage$space"}, + GranteeUserID: &user.UserId{OpaqueId: "user", Type: user.UserType_USER_TYPE_PRIMARY}, + } + + require.NoError(t, svc.handleSpaceMembershipExpired(context.Background(), ev)) + + svcMock.AssertNotCalled(t, "CleanupShare", mock.Anything) +} + +func TestHandleSpaceMembershipExpiredSkipsEmptyShareID(t *testing.T) { + svcMock := mocks.NewAuthGuest(t) + svc, _ := newConsumer(t, svcMock) + + ev := events.SpaceMembershipExpired{ + SpaceID: &provider.StorageSpaceId{OpaqueId: "storage$space"}, + GranteeUserID: &user.UserId{OpaqueId: "guest@example.org", Type: user.UserType_USER_TYPE_GUEST}, + } + + require.NoError(t, svc.handleSpaceMembershipExpired(context.Background(), ev)) + + svcMock.AssertNotCalled(t, "CleanupShare", mock.Anything) +} diff --git a/services/auth-guest/pkg/service/events/service.go b/services/auth-guest/pkg/service/events/service.go index aa955ceab6..44bec29f42 100644 --- a/services/auth-guest/pkg/service/events/service.go +++ b/services/auth-guest/pkg/service/events/service.go @@ -138,7 +138,10 @@ func (s *EventConsumer) processEvent(e events.Event) error { return s.handleShareExpired(ctx, ev) case events.SpaceShared: return s.handleSpaceShared(ctx, ev) - // Should we handle space share removed/expired events as well? + case events.SpaceUnshared: + return s.handleSpaceUnshared(ctx, ev) + case events.SpaceMembershipExpired: + return s.handleSpaceMembershipExpired(ctx, ev) default: s.log.Warn(). Str("eventtype", e.Type).