diff --git a/services/graph/pkg/identity/cache.go b/services/graph/pkg/identity/cache/cache.go similarity index 85% rename from services/graph/pkg/identity/cache.go rename to services/graph/pkg/identity/cache/cache.go index e1e158d7f..3bd13bf44 100644 --- a/services/graph/pkg/identity/cache.go +++ b/services/graph/pkg/identity/cache/cache.go @@ -1,4 +1,4 @@ -package identity +package cache import ( "context" @@ -12,6 +12,7 @@ import ( "github.com/jellydator/ttlcache/v3" libregraph "github.com/opencloud-eu/libre-graph-api-go" "github.com/opencloud-eu/opencloud/services/graph/pkg/errorcode" + "github.com/opencloud-eu/opencloud/services/graph/pkg/identity" "github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool" revautils "github.com/opencloud-eu/reva/v2/pkg/utils" ) @@ -85,33 +86,38 @@ func NewIdentityCache(opts ...IdentityCacheOption) IdentityCache { } // GetUser looks up a user by id, if the user is not cached, yet it will do a lookup via the CS3 API -func (cache IdentityCache) GetUser(ctx context.Context, userid string) (libregraph.User, error) { - u, err := cache.GetCS3User(ctx, userid) +func (cache IdentityCache) GetUser(ctx context.Context, tenantId, userid string) (libregraph.User, error) { + // can we get the tenant from the context or do we have to pass it? + u, err := cache.GetCS3User(ctx, tenantId, userid) if err != nil { return libregraph.User{}, err } - return *CreateUserModelFromCS3(u), nil + if tenantId != u.GetId().GetTenantId() { + return libregraph.User{}, identity.ErrNotFound + } + return *identity.CreateUserModelFromCS3(u), nil } -func (cache IdentityCache) GetCS3User(ctx context.Context, userid string) (*cs3User.User, error) { +func (cache IdentityCache) GetCS3User(ctx context.Context, tenantId, userid string) (*cs3User.User, error) { var user *cs3User.User - if item := cache.users.Get(userid); item == nil { + if item := cache.users.Get(tenantId + "|" + userid); item == nil { gatewayClient, err := cache.gatewaySelector.Next() if err != nil { return nil, errorcode.New(errorcode.GeneralException, err.Error()) } cs3UserID := &cs3User.UserId{ OpaqueId: userid, + TenantId: tenantId, } user, err = revautils.GetUserNoGroups(ctx, cs3UserID, gatewayClient) if err != nil { if revautils.IsErrNotFound(err) { - return nil, ErrNotFound + return nil, identity.ErrNotFound } return nil, errorcode.New(errorcode.GeneralException, err.Error()) } - cache.users.Set(userid, user, ttlcache.DefaultTTL) + cache.users.Set(tenantId+"|"+userid, user, ttlcache.DefaultTTL) } else { user = item.Value() } @@ -124,7 +130,7 @@ func (cache IdentityCache) GetAcceptedUser(ctx context.Context, userid string) ( if err != nil { return libregraph.User{}, err } - return *CreateUserModelFromCS3(u), nil + return *identity.CreateUserModelFromCS3(u), nil } func (cache IdentityCache) GetAcceptedCS3User(ctx context.Context, userid string) (*cs3User.User, error) { @@ -140,7 +146,7 @@ func (cache IdentityCache) GetAcceptedCS3User(ctx context.Context, userid string user, err = revautils.GetAcceptedUserWithContext(ctx, cs3UserID, gatewayClient) if err != nil { if revautils.IsErrNotFound(err) { - return nil, ErrNotFound + return nil, identity.ErrNotFound } return nil, errorcode.New(errorcode.GeneralException, err.Error()) } @@ -173,10 +179,10 @@ func (cache IdentityCache) GetGroup(ctx context.Context, groupID string) (libreg switch res.Status.Code { case rpc.Code_CODE_OK: g := res.GetGroup() - group = *CreateGroupModelFromCS3(g) + group = *identity.CreateGroupModelFromCS3(g) cache.groups.Set(groupID, group, ttlcache.DefaultTTL) case rpc.Code_CODE_NOT_FOUND: - return group, ErrNotFound + return group, identity.ErrNotFound default: return group, errorcode.New(errorcode.GeneralException, res.Status.Message) } diff --git a/services/graph/pkg/identity/cache/cache_suite_test.go b/services/graph/pkg/identity/cache/cache_suite_test.go new file mode 100644 index 000000000..f9503ab20 --- /dev/null +++ b/services/graph/pkg/identity/cache/cache_suite_test.go @@ -0,0 +1,13 @@ +package cache_test + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func TestCache(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Cache Suite") +} diff --git a/services/graph/pkg/identity/cache/cache_test.go b/services/graph/pkg/identity/cache/cache_test.go new file mode 100644 index 000000000..c35f41cd2 --- /dev/null +++ b/services/graph/pkg/identity/cache/cache_test.go @@ -0,0 +1,106 @@ +package cache + +import ( + "context" + "time" + + gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1" + cs3User "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool" +) + +// mockGatewaySelector is a mock implementation of pool.Selectable[gateway.GatewayAPIClient] +type mockGatewaySelector struct { + client gateway.GatewayAPIClient +} + +func (m *mockGatewaySelector) Next(opts ...pool.Option) (gateway.GatewayAPIClient, error) { + return m.client, nil +} + +var _ = Describe("Cache", func() { + var ( + ctx context.Context + idc IdentityCache + mockGwSelector pool.Selectable[gateway.GatewayAPIClient] + ) + + BeforeEach(func() { + // Create a mock gateway selector (client can be nil for cached tests) + mockGwSelector = &mockGatewaySelector{ + client: nil, + } + + idc = NewIdentityCache( + IdentityCacheWithGatewaySelector(mockGwSelector), + ) + ctx = context.Background() + }) + + Describe("GetUser", func() { + It("should return no error", func() { + alan := &cs3User.User{ + Id: &cs3User.UserId{ + OpaqueId: "alan", + TenantId: "", + }, + DisplayName: "Alan", + } + // Persist the user to the cache for 1 hour + idc.users.Set(alan.GetId().GetTenantId()+"|"+alan.GetId().GetOpaqueId(), alan, time.Hour) + + // getting the cache item in cache.go line 103 does not work + ru, err := idc.GetUser(ctx, "", "alan") + Expect(err).To(BeNil()) + Expect(ru).ToNot(BeNil()) + Expect(ru.GetId()).To(Equal(alan.GetId().GetOpaqueId())) + Expect(ru.GetDisplayName()).To(Equal(alan.GetDisplayName())) + }) + + It("should return the correct user if two users with the same uid and different tennant ids exist", func() { + alan1 := &cs3User.User{ + Id: &cs3User.UserId{ + OpaqueId: "alan", + TenantId: "1234", + }, + DisplayName: "Alan1", + } + + alan2 := &cs3User.User{ + Id: &cs3User.UserId{ + OpaqueId: "alan", + TenantId: "5678", + }, + DisplayName: "Alan2", + } + // Persist the user to the cache for 1 hour + idc.users.Set(alan1.GetId().GetTenantId()+"|"+alan1.GetId().GetOpaqueId(), alan1, time.Hour) + idc.users.Set(alan2.GetId().GetTenantId()+"|"+alan2.GetId().GetOpaqueId(), alan2, time.Hour) + ru, err := idc.GetUser(ctx, "5678", "alan") + Expect(err).To(BeNil()) + Expect(ru.GetDisplayName()).To(Equal(alan2.GetDisplayName())) + ru, err = idc.GetUser(ctx, "1234", "alan") + Expect(err).To(BeNil()) + Expect(ru.GetDisplayName()).To(Equal(alan1.GetDisplayName())) + }) + + It("should not return an error, if the tenant id does match", func() { + alan := &cs3User.User{ + Id: &cs3User.UserId{ + OpaqueId: "alan", + TenantId: "1234", + }, + DisplayName: "Alan", + } + // Persist the user to the cache for 1 hour + cu := idc.users.Set(alan.GetId().GetTenantId()+"|"+alan.GetId().GetOpaqueId(), alan, time.Hour) + // Test if element has been persisted in the cache + Expect(cu.Value().GetId().GetOpaqueId()).To(Equal(alan.GetId().GetOpaqueId())) + ru, err := idc.GetUser(ctx, "1234", "alan") + Expect(err).To(BeNil()) + Expect(ru.GetDisplayName()).To(Equal(alan.GetDisplayName())) + }) + }) +}) diff --git a/services/graph/pkg/service/v0/api_driveitem_permissions.go b/services/graph/pkg/service/v0/api_driveitem_permissions.go index c7ccb0530..aa68e8d0f 100644 --- a/services/graph/pkg/service/v0/api_driveitem_permissions.go +++ b/services/graph/pkg/service/v0/api_driveitem_permissions.go @@ -38,6 +38,7 @@ import ( "github.com/opencloud-eu/opencloud/services/graph/pkg/config" "github.com/opencloud-eu/opencloud/services/graph/pkg/errorcode" "github.com/opencloud-eu/opencloud/services/graph/pkg/identity" + "github.com/opencloud-eu/opencloud/services/graph/pkg/identity/cache" "github.com/opencloud-eu/opencloud/services/graph/pkg/unifiedrole" "github.com/opencloud-eu/opencloud/services/graph/pkg/validate" ) @@ -89,7 +90,7 @@ type ListPermissionsQueryOptions struct { } // NewDriveItemPermissionsService creates a new DriveItemPermissionsService -func NewDriveItemPermissionsService(logger log.Logger, gatewaySelector pool.Selectable[gateway.GatewayAPIClient], identityCache identity.IdentityCache, config *config.Config) (DriveItemPermissionsService, error) { +func NewDriveItemPermissionsService(logger log.Logger, gatewaySelector pool.Selectable[gateway.GatewayAPIClient], identityCache cache.IdentityCache, config *config.Config) (DriveItemPermissionsService, error) { return DriveItemPermissionsService{ BaseGraphService: BaseGraphService{ logger: &log.Logger{Logger: logger.With().Str("graph api", "DrivesDriveItemService").Logger()}, @@ -103,6 +104,7 @@ func NewDriveItemPermissionsService(logger log.Logger, gatewaySelector pool.Sele // Invite invites a user to a drive item. func (s DriveItemPermissionsService) Invite(ctx context.Context, resourceId *storageprovider.ResourceId, invite libregraph.DriveItemInvite) (libregraph.Permission, error) { + tenantId := revactx.ContextMustGetUser(ctx).GetId().GetTenantId() gatewayClient, err := s.gatewaySelector.Next() if err != nil { return libregraph.Permission{}, err @@ -184,7 +186,7 @@ func (s DriveItemPermissionsService) Invite(ctx context.Context, resourceId *sto cTime = createShareResponse.GetShare().GetCtime() expiration = createShareResponse.GetShare().GetExpiration() default: - user, err := s.identityCache.GetCS3User(ctx, objectID) + user, err := s.identityCache.GetCS3User(ctx, tenantId, objectID) if errors.Is(err, identity.ErrNotFound) && s.config.IncludeOCMSharees { user, err = s.identityCache.GetAcceptedCS3User(ctx, objectID) if err == nil && IsSpaceRoot(statResponse.GetInfo().GetId()) { @@ -259,14 +261,14 @@ func (s DriveItemPermissionsService) Invite(ctx context.Context, resourceId *sto } if user, ok := revactx.ContextGetUser(ctx); ok { - identity, err := userIdToIdentity(ctx, s.identityCache, user.GetId().GetOpaqueId()) + userIdentity, err := userIdToIdentity(ctx, s.identityCache, tenantId, user.GetId().GetOpaqueId()) if err != nil { s.logger.Error().Err(err).Msg("identity lookup failed") return libregraph.Permission{}, errorcode.New(errorcode.InvalidRequest, err.Error()) } permission.SetInvitation(libregraph.SharingInvitation{ InvitedBy: &libregraph.IdentitySet{ - User: &identity, + User: &userIdentity, }, }) } diff --git a/services/graph/pkg/service/v0/api_driveitem_permissions_links_test.go b/services/graph/pkg/service/v0/api_driveitem_permissions_links_test.go index be7432d02..47124eef0 100644 --- a/services/graph/pkg/service/v0/api_driveitem_permissions_links_test.go +++ b/services/graph/pkg/service/v0/api_driveitem_permissions_links_test.go @@ -11,18 +11,18 @@ import ( provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + libregraph "github.com/opencloud-eu/libre-graph-api-go" "github.com/opencloud-eu/opencloud/pkg/log" "github.com/opencloud-eu/opencloud/services/graph/mocks" "github.com/opencloud-eu/opencloud/services/graph/pkg/config/defaults" "github.com/opencloud-eu/opencloud/services/graph/pkg/errorcode" - "github.com/opencloud-eu/opencloud/services/graph/pkg/identity" + "github.com/opencloud-eu/opencloud/services/graph/pkg/identity/cache" "github.com/opencloud-eu/opencloud/services/graph/pkg/linktype" service "github.com/opencloud-eu/opencloud/services/graph/pkg/service/v0" revactx "github.com/opencloud-eu/reva/v2/pkg/ctx" "github.com/opencloud-eu/reva/v2/pkg/rgrpc/status" "github.com/opencloud-eu/reva/v2/pkg/utils" cs3mocks "github.com/opencloud-eu/reva/v2/tests/cs3mocks/mocks" - libregraph "github.com/opencloud-eu/libre-graph-api-go" "github.com/stretchr/testify/mock" ) @@ -51,7 +51,7 @@ var _ = Describe("createLinkTests", func() { gatewaySelector = mocks.NewSelectable[gateway.GatewayAPIClient](GinkgoT()) gatewaySelector.On("Next").Return(gatewayClient, nil) - cache := identity.NewIdentityCache(identity.IdentityCacheWithGatewaySelector(gatewaySelector)) + cache := cache.NewIdentityCache(cache.IdentityCacheWithGatewaySelector(gatewaySelector)) cfg := defaults.FullDefaultConfig() svc, err = service.NewDriveItemPermissionsService(logger, gatewaySelector, cache, cfg) diff --git a/services/graph/pkg/service/v0/api_driveitem_permissions_test.go b/services/graph/pkg/service/v0/api_driveitem_permissions_test.go index 81e2e297f..3adb5b2dc 100644 --- a/services/graph/pkg/service/v0/api_driveitem_permissions_test.go +++ b/services/graph/pkg/service/v0/api_driveitem_permissions_test.go @@ -37,7 +37,7 @@ import ( "github.com/opencloud-eu/opencloud/services/graph/mocks" "github.com/opencloud-eu/opencloud/services/graph/pkg/config/defaults" "github.com/opencloud-eu/opencloud/services/graph/pkg/errorcode" - "github.com/opencloud-eu/opencloud/services/graph/pkg/identity" + identitycache "github.com/opencloud-eu/opencloud/services/graph/pkg/identity/cache" "github.com/opencloud-eu/opencloud/services/graph/pkg/linktype" svc "github.com/opencloud-eu/opencloud/services/graph/pkg/service/v0" "github.com/opencloud-eu/opencloud/services/graph/pkg/unifiedrole" @@ -56,7 +56,7 @@ var _ = Describe("DriveItemPermissionsService", func() { OpaqueId: "user", }, } - cache identity.IdentityCache + cache identitycache.IdentityCache statResponse *provider.StatResponse driveItemId *provider.ResourceId ctx context.Context @@ -70,7 +70,7 @@ var _ = Describe("DriveItemPermissionsService", func() { gatewaySelector = mocks.NewSelectable[gateway.GatewayAPIClient](GinkgoT()) gatewaySelector.On("Next").Return(gatewayClient, nil) - cache = identity.NewIdentityCache(identity.IdentityCacheWithGatewaySelector(gatewaySelector)) + cache = identitycache.NewIdentityCache(identitycache.IdentityCacheWithGatewaySelector(gatewaySelector)) cfg = defaults.FullDefaultConfig() service, err := svc.NewDriveItemPermissionsService(logger, gatewaySelector, cache, cfg) @@ -139,7 +139,7 @@ var _ = Describe("DriveItemPermissionsService", func() { Expiration: utils.TimeToTS(*driveItemInvite.ExpirationDateTime), } - permission, err := driveItemPermissionsService.Invite(context.Background(), driveItemId, driveItemInvite) + permission, err := driveItemPermissionsService.Invite(ctx, driveItemId, driveItemInvite) Expect(err).ToNot(HaveOccurred()) Expect(permission.GetId()).To(Equal("123")) Expect(permission.GetExpirationDateTime().Equal(*driveItemInvite.ExpirationDateTime)).To(BeTrue()) @@ -149,6 +149,7 @@ var _ = Describe("DriveItemPermissionsService", func() { It("creates group shares as expected (happy path)", func() { gatewayClient.On("GetGroup", mock.Anything, mock.Anything).Return(getGroupResponse, nil) + gatewayClient.On("GetUser", mock.Anything, mock.Anything).Return(getUserResponse, nil) gatewayClient.On("CreateShare", mock.Anything, mock.Anything).Return(createShareResponse, nil) driveItemInvite.Recipients = []libregraph.DriveRecipient{ {ObjectId: libregraph.PtrString("2"), LibreGraphRecipientType: libregraph.PtrString("group")}, @@ -159,7 +160,7 @@ var _ = Describe("DriveItemPermissionsService", func() { Expiration: utils.TimeToTS(*driveItemInvite.ExpirationDateTime), } - permission, err := driveItemPermissionsService.Invite(context.Background(), driveItemId, driveItemInvite) + permission, err := driveItemPermissionsService.Invite(ctx, driveItemId, driveItemInvite) Expect(err).ToNot(HaveOccurred()) Expect(permission.GetId()).To(Equal("123")) Expect(permission.GetExpirationDateTime().Equal(*driveItemInvite.ExpirationDateTime)).To(BeTrue()) @@ -175,7 +176,7 @@ var _ = Describe("DriveItemPermissionsService", func() { } driveItemInvite.Roles = []string{unifiedrole.UnifiedRoleViewerID} - permission, err := driveItemPermissionsService.Invite(context.Background(), driveItemId, driveItemInvite) + permission, err := driveItemPermissionsService.Invite(ctx, driveItemId, driveItemInvite) Expect(err).ToNot(HaveOccurred()) Expect(permission.GetRoles()).To(HaveLen(1)) @@ -191,7 +192,7 @@ var _ = Describe("DriveItemPermissionsService", func() { } driveItemInvite.Roles = []string{unifiedrole.UnifiedRoleEditorID} - permission, err := driveItemPermissionsService.Invite(context.Background(), driveItemId, driveItemInvite) + permission, err := driveItemPermissionsService.Invite(ctx, driveItemId, driveItemInvite) Expect(err).ToNot(HaveOccurred()) Expect(permission.GetRoles()).To(HaveLen(1)) @@ -203,7 +204,7 @@ var _ = Describe("DriveItemPermissionsService", func() { {ObjectId: libregraph.PtrString("1"), LibreGraphRecipientType: libregraph.PtrString("user")}, } driveItemInvite.Roles = []string{unifiedrole.UnifiedRoleManagerID} - permission, err := driveItemPermissionsService.Invite(context.Background(), driveItemId, driveItemInvite) + permission, err := driveItemPermissionsService.Invite(ctx, driveItemId, driveItemInvite) Expect(err).To(MatchError(errorcode.New(errorcode.InvalidRequest, "role not applicable to this resource"))) Expect(permission).To(BeZero()) @@ -214,7 +215,7 @@ var _ = Describe("DriveItemPermissionsService", func() { {ObjectId: libregraph.PtrString("1"), LibreGraphRecipientType: libregraph.PtrString("user")}, } driveItemInvite.Roles = []string{unifiedrole.UnifiedRoleEditorID} - permission, err := driveItemPermissionsService.Invite(context.Background(), driveItemId, driveItemInvite) + permission, err := driveItemPermissionsService.Invite(ctx, driveItemId, driveItemInvite) Expect(err).To(MatchError(errorcode.New(errorcode.InvalidRequest, "role not applicable to this resource"))) Expect(permission).To(BeZero()) @@ -226,7 +227,7 @@ var _ = Describe("DriveItemPermissionsService", func() { {ObjectId: libregraph.PtrString("1"), LibreGraphRecipientType: libregraph.PtrString("user")}, } driveItemInvite.Roles = []string{unifiedrole.UnifiedRoleFileEditorID} - permission, err := driveItemPermissionsService.Invite(context.Background(), driveItemId, driveItemInvite) + permission, err := driveItemPermissionsService.Invite(ctx, driveItemId, driveItemInvite) Expect(err).To(MatchError(errorcode.New(errorcode.InvalidRequest, "role not applicable to this resource"))) Expect(permission).To(BeZero()) @@ -241,7 +242,7 @@ var _ = Describe("DriveItemPermissionsService", func() { driveItemInvite.Roles = nil driveItemInvite.LibreGraphPermissionsActions = []string{unifiedrole.DriveItemContentRead} - permission, err := driveItemPermissionsService.Invite(context.Background(), driveItemId, driveItemInvite) + permission, err := driveItemPermissionsService.Invite(ctx, driveItemId, driveItemInvite) Expect(err).ToNot(HaveOccurred()) Expect(permission).NotTo(BeZero()) @@ -252,7 +253,7 @@ var _ = Describe("DriveItemPermissionsService", func() { It("fails with a missing driveritem", func() { statResponse.Status = status.NewNotFound(context.Background(), "not found") - permission, err := driveItemPermissionsService.Invite(context.Background(), driveItemId, driveItemInvite) + permission, err := driveItemPermissionsService.Invite(ctx, driveItemId, driveItemInvite) Expect(err).To(HaveOccurred()) Expect(err).To(MatchError(errorcode.New(errorcode.ItemNotFound, "not found").WithOrigin(errorcode.ErrorOriginCS3))) Expect(permission).To(BeZero()) @@ -268,7 +269,7 @@ var _ = Describe("DriveItemPermissionsService", func() { Expect(err).ToNot(HaveOccurred()) driveItemInvite.Roles = []string{unifiedrole.UnifiedRoleViewerID, unifiedrole.UnifiedRoleSecureViewerID} - _, err = service.Invite(context.Background(), driveItemId, driveItemInvite) + _, err = service.Invite(ctx, driveItemId, driveItemInvite) Expect(err).To(MatchError(unifiedrole.ErrUnknownRole)) }) }) @@ -336,7 +337,7 @@ var _ = Describe("DriveItemPermissionsService", func() { Expiration: utils.TimeToTS(*driveItemInvite.ExpirationDateTime), } - permission, err := driveItemPermissionsService.SpaceRootInvite(context.Background(), driveId, driveItemInvite) + permission, err := driveItemPermissionsService.SpaceRootInvite(ctx, driveId, driveItemInvite) Expect(err).ToNot(HaveOccurred()) Expect(permission.GetId()).To(Equal("123")) Expect(permission.GetExpirationDateTime().Equal(*driveItemInvite.ExpirationDateTime)).To(BeTrue()) @@ -354,7 +355,7 @@ var _ = Describe("DriveItemPermissionsService", func() { Expiration: utils.TimeToTS(*driveItemInvite.ExpirationDateTime), } - permission, err := driveItemPermissionsService.SpaceRootInvite(context.Background(), driveId, driveItemInvite) + permission, err := driveItemPermissionsService.SpaceRootInvite(ctx, driveId, driveItemInvite) Expect(err).To(HaveOccurred()) Expect(err).To(MatchError(errorcode.New(errorcode.InvalidRequest, "unsupported space type"))) Expect(permission).To(BeZero()) @@ -1061,7 +1062,7 @@ var _ = Describe("DriveItemPermissionsService", func() { SpaceId: "2", OpaqueId: "2", } - res, err := driveItemPermissionsService.UpdatePermission(context.Background(), spaceId, "u:userid", driveItemPermission) + res, err := driveItemPermissionsService.UpdatePermission(ctx, spaceId, "u:userid", driveItemPermission) Expect(err).To(MatchError(errorcode.New(errorcode.InvalidRequest, "role not applicable to this resource"))) Expect(res).To(BeZero()) }) diff --git a/services/graph/pkg/service/v0/base.go b/services/graph/pkg/service/v0/base.go index ba07bc9dd..4b2c8edd2 100644 --- a/services/graph/pkg/service/v0/base.go +++ b/services/graph/pkg/service/v0/base.go @@ -17,6 +17,7 @@ import ( storageprovider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1" libregraph "github.com/opencloud-eu/libre-graph-api-go" + revactx "github.com/opencloud-eu/reva/v2/pkg/ctx" "golang.org/x/sync/errgroup" "google.golang.org/protobuf/types/known/fieldmaskpb" @@ -29,6 +30,7 @@ import ( "github.com/opencloud-eu/opencloud/services/graph/pkg/config" "github.com/opencloud-eu/opencloud/services/graph/pkg/errorcode" "github.com/opencloud-eu/opencloud/services/graph/pkg/identity" + "github.com/opencloud-eu/opencloud/services/graph/pkg/identity/cache" "github.com/opencloud-eu/opencloud/services/graph/pkg/linktype" "github.com/opencloud-eu/opencloud/services/graph/pkg/unifiedrole" ) @@ -44,7 +46,7 @@ type BaseGraphProvider interface { type BaseGraphService struct { logger *log.Logger gatewaySelector pool.Selectable[gateway.GatewayAPIClient] - identityCache identity.IdentityCache + identityCache cache.IdentityCache config *config.Config availableRoles []*libregraph.UnifiedRoleDefinition } @@ -170,7 +172,8 @@ func (g BaseGraphService) cs3SpacePermissionsToLibreGraph(ctx context.Context, s } isGroup = true } else { - cs3Identity, err = userIdToIdentity(ctx, g.identityCache, tmp) + tenantId := revactx.ContextMustGetUser(ctx).GetId().GetTenantId() + cs3Identity, err = userIdToIdentity(ctx, g.identityCache, tenantId, tmp) if err != nil { g.logger.Warn().Str("userid", tmp).Msg("User not found by id") } diff --git a/services/graph/pkg/service/v0/service.go b/services/graph/pkg/service/v0/service.go index cee01f698..f130de6dc 100644 --- a/services/graph/pkg/service/v0/service.go +++ b/services/graph/pkg/service/v0/service.go @@ -15,6 +15,7 @@ import ( "github.com/go-chi/chi/v5/middleware" ldapv3 "github.com/go-ldap/ldap/v3" "github.com/jellydator/ttlcache/v3" + "github.com/opencloud-eu/opencloud/services/graph/pkg/identity/cache" "github.com/riandyrn/otelchi" microstore "go-micro.dev/v4/store" @@ -147,10 +148,10 @@ func NewService(opts ...Option) (Graph, error) { //nolint:maintidx ) go spacePropertiesCache.Start() - identityCache := identity.NewIdentityCache( - identity.IdentityCacheWithGatewaySelector(options.GatewaySelector), - identity.IdentityCacheWithUsersTTL(time.Duration(options.Config.Spaces.UsersCacheTTL)), - identity.IdentityCacheWithGroupsTTL(time.Duration(options.Config.Spaces.GroupsCacheTTL)), + identityCache := cache.NewIdentityCache( + cache.IdentityCacheWithGatewaySelector(options.GatewaySelector), + cache.IdentityCacheWithUsersTTL(time.Duration(options.Config.Spaces.UsersCacheTTL)), + cache.IdentityCacheWithGroupsTTL(time.Duration(options.Config.Spaces.GroupsCacheTTL)), ) baseGraphService := BaseGraphService{ diff --git a/services/graph/pkg/service/v0/utils.go b/services/graph/pkg/service/v0/utils.go index 7e85d9dad..86de9919c 100644 --- a/services/graph/pkg/service/v0/utils.go +++ b/services/graph/pkg/service/v0/utils.go @@ -20,7 +20,7 @@ import ( "github.com/opencloud-eu/opencloud/pkg/log" "github.com/opencloud-eu/opencloud/services/graph/pkg/errorcode" - "github.com/opencloud-eu/opencloud/services/graph/pkg/identity" + "github.com/opencloud-eu/opencloud/services/graph/pkg/identity/cache" "github.com/opencloud-eu/opencloud/services/graph/pkg/unifiedrole" ) @@ -92,11 +92,11 @@ func IsShareJail(id *storageprovider.ResourceId) bool { // userIdToIdentity looks the user for the supplied id using the cache and returns it // as a libregraph.Identity -func userIdToIdentity(ctx context.Context, cache identity.IdentityCache, userID string) (libregraph.Identity, error) { +func userIdToIdentity(ctx context.Context, cache cache.IdentityCache, tennantId, userID string) (libregraph.Identity, error) { identity := libregraph.Identity{ Id: libregraph.PtrString(userID), } - user, err := cache.GetUser(ctx, userID) + user, err := cache.GetUser(ctx, tennantId, userID) if err == nil { identity.SetDisplayName(user.GetDisplayName()) identity.SetLibreGraphUserType(user.GetUserType()) @@ -106,7 +106,7 @@ func userIdToIdentity(ctx context.Context, cache identity.IdentityCache, userID // federatedIdToIdentity looks the user for the supplied id using the cache and returns it // as a libregraph.Identity -func federatedIdToIdentity(ctx context.Context, cache identity.IdentityCache, userID string) (libregraph.Identity, error) { +func federatedIdToIdentity(ctx context.Context, cache cache.IdentityCache, userID string) (libregraph.Identity, error) { identity := libregraph.Identity{ Id: libregraph.PtrString(userID), LibreGraphUserType: libregraph.PtrString("Federated"), @@ -121,19 +121,19 @@ func federatedIdToIdentity(ctx context.Context, cache identity.IdentityCache, us // cs3UserIdToIdentity looks up the user for the supplied cs3 userid using the cache and returns it // as a libregraph.Identity. Skips the user lookup if the id type is USER_TYPE_SPACE_OWNER -func cs3UserIdToIdentity(ctx context.Context, cache identity.IdentityCache, cs3UserID *cs3User.UserId) (libregraph.Identity, error) { +func cs3UserIdToIdentity(ctx context.Context, cache cache.IdentityCache, cs3UserID *cs3User.UserId) (libregraph.Identity, error) { if cs3UserID.GetType() == cs3User.UserType_USER_TYPE_FEDERATED { return federatedIdToIdentity(ctx, cache, cs3UserID.GetOpaqueId()) } if cs3UserID.GetType() != cs3User.UserType_USER_TYPE_SPACE_OWNER { - return userIdToIdentity(ctx, cache, cs3UserID.GetOpaqueId()) + return userIdToIdentity(ctx, cache, cs3UserID.GetTenantId(), cs3UserID.GetOpaqueId()) } return libregraph.Identity{Id: libregraph.PtrString(cs3UserID.GetOpaqueId())}, nil } // groupIdToIdentity looks up the group for the supplied cs3 groupid using the cache and returns it // as a libregraph.Identity. -func groupIdToIdentity(ctx context.Context, cache identity.IdentityCache, groupID string) (libregraph.Identity, error) { +func groupIdToIdentity(ctx context.Context, cache cache.IdentityCache, groupID string) (libregraph.Identity, error) { identity := libregraph.Identity{ Id: libregraph.PtrString(groupID), } @@ -162,7 +162,7 @@ func identitySetToSpacePermissionID(identitySet libregraph.SharePointIdentitySet func cs3ReceivedSharesToDriveItems(ctx context.Context, logger *log.Logger, gatewayClient gateway.GatewayAPIClient, - identityCache identity.IdentityCache, + identityCache cache.IdentityCache, receivedShares []*collaboration.ReceivedShare, availableRoles []*libregraph.UnifiedRoleDefinition, ) ([]libregraph.DriveItem, error) { @@ -341,7 +341,7 @@ func cs3ReceivedSharesToDriveItems(ctx context.Context, } func fillDriveItemPropertiesFromReceivedShare(ctx context.Context, logger *log.Logger, - identityCache identity.IdentityCache, receivedShares []*collaboration.ReceivedShare, + identityCache cache.IdentityCache, receivedShares []*collaboration.ReceivedShare, resourceInfo *storageprovider.ResourceInfo, availableRoles []*libregraph.UnifiedRoleDefinition) (*libregraph.DriveItem, error) { driveItem := libregraph.NewDriveItem() @@ -416,7 +416,7 @@ func fillDriveItemPropertiesFromReceivedShare(ctx context.Context, logger *log.L } func cs3ReceivedShareToLibreGraphPermissions(ctx context.Context, logger *log.Logger, - identityCache identity.IdentityCache, receivedShare *collaboration.ReceivedShare, + identityCache cache.IdentityCache, receivedShare *collaboration.ReceivedShare, resourceInfo *storageprovider.ResourceInfo, availableRoles []*libregraph.UnifiedRoleDefinition) (*libregraph.Permission, error) { permission := libregraph.NewPermission() if id := receivedShare.GetShare().GetId().GetOpaqueId(); id != "" { @@ -510,7 +510,7 @@ func ExtractShareIdFromResourceId(rid *storageprovider.ResourceId) *collaboratio func cs3ReceivedOCMSharesToDriveItems(ctx context.Context, logger *log.Logger, gatewayClient gateway.GatewayAPIClient, - identityCache identity.IdentityCache, + identityCache cache.IdentityCache, receivedShares []*ocm.ReceivedShare, availableRoles []*libregraph.UnifiedRoleDefinition) ([]libregraph.DriveItem, error) { group := new(errgroup.Group) @@ -696,7 +696,7 @@ func cs3ReceivedOCMSharesToDriveItems(ctx context.Context, } func fillDriveItemPropertiesFromReceivedOCMShare(ctx context.Context, logger *log.Logger, - identityCache identity.IdentityCache, receivedShares []*ocm.ReceivedShare, + identityCache cache.IdentityCache, receivedShares []*ocm.ReceivedShare, resourceInfo *storageprovider.ResourceInfo, availableRoles []*libregraph.UnifiedRoleDefinition) (*libregraph.DriveItem, error) { driveItem := libregraph.NewDriveItem() @@ -775,7 +775,7 @@ func fillDriveItemPropertiesFromReceivedOCMShare(ctx context.Context, logger *lo } func cs3ReceivedOCMShareToLibreGraphPermissions(ctx context.Context, logger *log.Logger, - identityCache identity.IdentityCache, receivedShare *ocm.ReceivedShare, + identityCache cache.IdentityCache, receivedShare *ocm.ReceivedShare, resourceInfo *storageprovider.ResourceInfo, availableRoles []*libregraph.UnifiedRoleDefinition) (*libregraph.Permission, error) { permission := libregraph.NewPermission() if id := receivedShare.GetId().GetOpaqueId(); id != "" { diff --git a/services/graph/pkg/service/v0/utils_test.go b/services/graph/pkg/service/v0/utils_test.go index d95b88b89..37e1e04bb 100644 --- a/services/graph/pkg/service/v0/utils_test.go +++ b/services/graph/pkg/service/v0/utils_test.go @@ -9,9 +9,9 @@ import ( "github.com/go-chi/chi/v5" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + libregraph "github.com/opencloud-eu/libre-graph-api-go" rConversions "github.com/opencloud-eu/reva/v2/pkg/conversions" "github.com/opencloud-eu/reva/v2/pkg/utils" - libregraph "github.com/opencloud-eu/libre-graph-api-go" provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" "github.com/opencloud-eu/reva/v2/pkg/storagespace" @@ -19,7 +19,7 @@ import ( "github.com/opencloud-eu/opencloud/pkg/conversions" "github.com/opencloud-eu/opencloud/pkg/log" - "github.com/opencloud-eu/opencloud/services/graph/pkg/identity" + "github.com/opencloud-eu/opencloud/services/graph/pkg/identity/cache" service "github.com/opencloud-eu/opencloud/services/graph/pkg/service/v0" "github.com/opencloud-eu/opencloud/services/graph/pkg/unifiedrole" ) @@ -116,7 +116,7 @@ var _ = Describe("Utils", func() { permission, err := service.CS3ReceivedShareToLibreGraphPermissions( context.Background(), nil, - identity.IdentityCache{}, + cache.IdentityCache{}, &collaboration.ReceivedShare{ Share: &collaboration.Share{ Permissions: &collaboration.SharePermissions{