From 6105bd99e1a5a0838da82a539b2126caab43cdc9 Mon Sep 17 00:00:00 2001 From: Ishank Arora Date: Tue, 9 Mar 2021 12:57:04 +0100 Subject: [PATCH] ocm: add FindAcceptedUsers to Invite API --- cmd/reva/main.go | 1 + cmd/reva/ocm-find-accepted-users.go | 79 +++++++++++++++++++ cmd/reva/ocm-share-create.go | 4 +- go.mod | 15 ++-- go.sum | 6 ++ .../grpc/services/gateway/ocminvitemanager.go | 24 +++++- .../ocminvitemanager/ocminvitemanager.go | 22 +++++- .../services/oidcprovider/oidcprovider.go | 2 +- .../handlers/apps/sharing/shares/remote.go | 2 +- pkg/ocm/invite/invite.go | 7 +- pkg/ocm/invite/manager/json/json.go | 19 ++++- pkg/ocm/invite/manager/memory/memory.go | 25 +++++- 12 files changed, 182 insertions(+), 24 deletions(-) create mode 100644 cmd/reva/ocm-find-accepted-users.go diff --git a/cmd/reva/main.go b/cmd/reva/main.go index 5f851cc490c..e349a09ab7e 100644 --- a/cmd/reva/main.go +++ b/cmd/reva/main.go @@ -55,6 +55,7 @@ var ( rmCommand(), moveCommand(), mkdirCommand(), + ocmFindAcceptedUsersCommand(), ocmShareCreateCommand(), ocmShareListCommand(), ocmShareRemoveCommand(), diff --git a/cmd/reva/ocm-find-accepted-users.go b/cmd/reva/ocm-find-accepted-users.go new file mode 100644 index 00000000000..5445f9f6580 --- /dev/null +++ b/cmd/reva/ocm-find-accepted-users.go @@ -0,0 +1,79 @@ +// Copyright 2018-2021 CERN +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// In applying this license, CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +package main + +import ( + "encoding/gob" + "io" + "os" + + invitepb "github.com/cs3org/go-cs3apis/cs3/ocm/invite/v1beta1" + rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" + "github.com/jedib0t/go-pretty/table" +) + +func ocmFindAcceptedUsersCommand() *command { + cmd := newCommand("ocm-find-accepted-users") + cmd.Description = func() string { return "find remote users who have accepted invite tokens by their attributes" } + cmd.Usage = func() string { return "Usage: ocm-find-accepted-users " } + + cmd.Action = func(w ...io.Writer) error { + var filter string + if cmd.NArg() == 1 { + filter = cmd.Args()[0] + } + + ctx := getAuthContext() + client, err := getClient() + if err != nil { + return err + } + + acceptedUsersRes, err := client.FindAcceptedUsers(ctx, &invitepb.FindAcceptedUsersRequest{ + Filter: filter, + }) + if err != nil { + return err + } + if acceptedUsersRes.Status.Code != rpc.Code_CODE_OK { + return formatError(acceptedUsersRes.Status) + } + + if len(w) == 0 { + t := table.NewWriter() + t.SetOutputMirror(os.Stdout) + t.AppendHeader(table.Row{"OpaqueId", "Idp", "Mail", "DisplayName"}) + + for _, u := range acceptedUsersRes.AcceptedUsers { + t.AppendRows([]table.Row{ + {u.Id.OpaqueId, u.Id.Idp, u.Mail, u.DisplayName}, + }) + } + t.Render() + } else { + enc := gob.NewEncoder(w[0]) + if err := enc.Encode(acceptedUsersRes.AcceptedUsers); err != nil { + return err + } + } + + return nil + } + return cmd +} diff --git a/cmd/reva/ocm-share-create.go b/cmd/reva/ocm-share-create.go index b073eeedbcc..9b74a645a19 100644 --- a/cmd/reva/ocm-share-create.go +++ b/cmd/reva/ocm-share-create.go @@ -39,7 +39,7 @@ import ( func ocmShareCreateCommand() *command { cmd := newCommand("ocm-share-create") cmd.Description = func() string { return "create OCM share to a user or group" } - cmd.Usage = func() string { return "Usage: ocm-share create [-flags] " } + cmd.Usage = func() string { return "Usage: ocm-share-create [-flags] " } grantType := cmd.String("type", "user", "grantee type (user or group)") grantee := cmd.String("grantee", "", "the grantee") idp := cmd.String("idp", "", "the idp of the grantee, default to same idp as the user triggering the action") @@ -78,7 +78,7 @@ func ocmShareCreateCommand() *command { return err } - remoteUserRes, err := client.GetRemoteUser(ctx, &invitepb.GetRemoteUserRequest{ + remoteUserRes, err := client.GetAcceptedUser(ctx, &invitepb.GetAcceptedUserRequest{ RemoteUserId: &userpb.UserId{OpaqueId: *grantee, Idp: *idp}, }) if err != nil { diff --git a/go.mod b/go.mod index 7f9a1b5804c..01f2ca8f0c1 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/Masterminds/sprig v2.22.0+incompatible github.com/ReneKroon/ttlcache/v2 v2.3.0 github.com/aws/aws-sdk-go v1.37.24 - github.com/c-bata/go-prompt v0.2.6 + github.com/c-bata/go-prompt v0.2.5 github.com/cheggaaa/pb v1.0.29 github.com/coreos/go-oidc v2.2.1+incompatible github.com/cs3org/cato v0.0.0-20200828125504-e418fc54dd5e @@ -34,7 +34,7 @@ require ( github.com/mitchellh/mapstructure v1.4.1 github.com/onsi/ginkgo v1.15.1 github.com/onsi/gomega v1.11.0 - github.com/ory/fosite v0.38.0 + github.com/ory/fosite v0.39.0 github.com/pkg/errors v0.9.1 github.com/pkg/xattr v0.4.3 github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect @@ -54,8 +54,9 @@ require ( go 1.13 -replace github.com/eventials/go-tus => github.com/andrewmostello/go-tus v0.0.0-20200314041820-904a9904af9a - -replace github.com/oleiade/reflections => github.com/oleiade/reflections v1.0.1 - -replace google.golang.org/grpc => google.golang.org/grpc v1.26.0 // temporary downgrade +replace ( + github.com/cs3org/go-cs3apis => ../cs3apis/build/go-cs3apis + github.com/eventials/go-tus => github.com/andrewmostello/go-tus v0.0.0-20200314041820-904a9904af9a +github.com/oleiade/reflections => github.com/oleiade/reflections v1.0.1 +google.golang.org/grpc => google.golang.org/grpc v1.26.0 // temporary downgrade +) diff --git a/go.sum b/go.sum index 70632aaa8c0..acf80669dca 100644 --- a/go.sum +++ b/go.sum @@ -87,6 +87,8 @@ github.com/bmatcuk/doublestar/v2 v2.0.3/go.mod h1:QMmcs3H2AUQICWhfzLXz+IYln8lRQm github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40 h1:y4B3+GPxKlrigF1ha5FFErxK+sr6sWxQovRMzwMhejo= github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c= +github.com/c-bata/go-prompt v0.2.5 h1:3zg6PecEywxNn0xiqcXHD96fkbxghD+gdB2tbsYfl+Y= +github.com/c-bata/go-prompt v0.2.5/go.mod h1:vFnjEGDIIA/Lib7giyE4E9c50Lvl8j0S+7FVlAwDAVw= github.com/c-bata/go-prompt v0.2.6 h1:POP+nrHE+DfLYx370bedwNhsqmpCUynWPxuHi0C5vZI= github.com/c-bata/go-prompt v0.2.6/go.mod h1:/LMAke8wD2FsNu9EXNdHxNLbd9MedkPnCdfpU9wwHfY= github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= @@ -750,6 +752,8 @@ github.com/ory/dockertest/v3 v3.5.4/go.mod h1:J8ZUbNB2FOhm1cFZW9xBpDsODqsSWcyYgt github.com/ory/fosite v0.29.0/go.mod h1:0atSZmXO7CAcs6NPMI/Qtot8tmZYj04Nddoold4S2h0= github.com/ory/fosite v0.38.0 h1:4y+IurqBAu/Gf0NlW47gabRJZyYIqda+OFHMx5fsy6Q= github.com/ory/fosite v0.38.0/go.mod h1:37r59qkOSPueYKmaA7EHiXrDMF1B+XPN+MgkZgTRg3Y= +github.com/ory/fosite v0.39.0 h1:u1Ct/ME7XYzREvufr7ehBIdq/KatjVLIYg/ABqWzprw= +github.com/ory/fosite v0.39.0/go.mod h1:37r59qkOSPueYKmaA7EHiXrDMF1B+XPN+MgkZgTRg3Y= github.com/ory/go-acc v0.0.0-20181118080137-ddc355013f90/go.mod h1:sxnvPCxChFuSmTJGj8FdMupeq1BezCiEpDjTUXQ4hf4= github.com/ory/go-acc v0.2.5 h1:31irXHzG2vnKQSE4weJm7AdfrnpaVjVCq3nD7viXCJE= github.com/ory/go-acc v0.2.5/go.mod h1:4Kb/UnPcT8qRAk3IAxta+hvVapdxTLWtrr7bFLlEgpw= @@ -788,6 +792,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/pkg/term v1.1.0 h1:xIAAdCMh3QIAy+5FrE8Ad8XoDhEU4ufwbaSozViP9kk= +github.com/pkg/term v1.1.0/go.mod h1:E25nymQcrSllhX42Ok8MRm1+hyBdHY0dCeiKZ9jpNGw= github.com/pkg/term v1.2.0-beta.2 h1:L3y/h2jkuBVFdWiJvNfYfKmzcCnILw7mJWm2JQuMppw= github.com/pkg/term v1.2.0-beta.2/go.mod h1:E25nymQcrSllhX42Ok8MRm1+hyBdHY0dCeiKZ9jpNGw= github.com/pkg/xattr v0.4.3 h1:5Jx4GCg5ABtqWZH8WLzeI4fOtM1HyX4RBawuCoua1es= diff --git a/internal/grpc/services/gateway/ocminvitemanager.go b/internal/grpc/services/gateway/ocminvitemanager.go index 47da1fbcd1c..8d4a6026ceb 100644 --- a/internal/grpc/services/gateway/ocminvitemanager.go +++ b/internal/grpc/services/gateway/ocminvitemanager.go @@ -75,17 +75,33 @@ func (s *svc) AcceptInvite(ctx context.Context, req *invitepb.AcceptInviteReques return res, nil } -func (s *svc) GetRemoteUser(ctx context.Context, req *invitepb.GetRemoteUserRequest) (*invitepb.GetRemoteUserResponse, error) { +func (s *svc) GetAcceptedUser(ctx context.Context, req *invitepb.GetAcceptedUserRequest) (*invitepb.GetAcceptedUserResponse, error) { c, err := pool.GetOCMInviteManagerClient(s.c.OCMInviteManagerEndpoint) if err != nil { - return &invitepb.GetRemoteUserResponse{ + return &invitepb.GetAcceptedUserResponse{ Status: status.NewInternal(ctx, err, "error getting user invite provider client"), }, nil } - res, err := c.GetRemoteUser(ctx, req) + res, err := c.GetAcceptedUser(ctx, req) if err != nil { - return nil, errors.Wrap(err, "gateway: error calling AcceptInvite") + return nil, errors.Wrap(err, "gateway: error calling GetAcceptedUser") + } + + return res, nil +} + +func (s *svc) FindAcceptedUsers(ctx context.Context, req *invitepb.FindAcceptedUsersRequest) (*invitepb.FindAcceptedUsersResponse, error) { + c, err := pool.GetOCMInviteManagerClient(s.c.OCMInviteManagerEndpoint) + if err != nil { + return &invitepb.FindAcceptedUsersResponse{ + Status: status.NewInternal(ctx, err, "error getting user invite provider client"), + }, nil + } + + res, err := c.FindAcceptedUsers(ctx, req) + if err != nil { + return nil, errors.Wrap(err, "gateway: error calling FindAcceptedUsers") } return res, nil diff --git a/internal/grpc/services/ocminvitemanager/ocminvitemanager.go b/internal/grpc/services/ocminvitemanager/ocminvitemanager.go index 072fc55a053..d4ed5acd600 100644 --- a/internal/grpc/services/ocminvitemanager/ocminvitemanager.go +++ b/internal/grpc/services/ocminvitemanager/ocminvitemanager.go @@ -141,16 +141,30 @@ func (s *service) AcceptInvite(ctx context.Context, req *invitepb.AcceptInviteRe }, nil } -func (s *service) GetRemoteUser(ctx context.Context, req *invitepb.GetRemoteUserRequest) (*invitepb.GetRemoteUserResponse, error) { - remoteUser, err := s.im.GetRemoteUser(ctx, req.RemoteUserId) +func (s *service) GetAcceptedUser(ctx context.Context, req *invitepb.GetAcceptedUserRequest) (*invitepb.GetAcceptedUserResponse, error) { + remoteUser, err := s.im.GetAcceptedUser(ctx, req.RemoteUserId) if err != nil { - return &invitepb.GetRemoteUserResponse{ + return &invitepb.GetAcceptedUserResponse{ Status: status.NewInternal(ctx, err, "error fetching remote user details"), }, nil } - return &invitepb.GetRemoteUserResponse{ + return &invitepb.GetAcceptedUserResponse{ Status: status.NewOK(ctx), RemoteUser: remoteUser, }, nil } + +func (s *service) FindAcceptedUsers(ctx context.Context, req *invitepb.FindAcceptedUsersRequest) (*invitepb.FindAcceptedUsersResponse, error) { + acceptedUsers, err := s.im.FindAcceptedUsers(ctx, req.Filter) + if err != nil { + return &invitepb.FindAcceptedUsersResponse{ + Status: status.NewInternal(ctx, err, "error finding remote users"), + }, nil + } + + return &invitepb.FindAcceptedUsersResponse{ + Status: status.NewOK(ctx), + AcceptedUsers: acceptedUsers, + }, nil +} diff --git a/internal/http/services/oidcprovider/oidcprovider.go b/internal/http/services/oidcprovider/oidcprovider.go index 98468e38c53..d4a8b3c7c80 100644 --- a/internal/http/services/oidcprovider/oidcprovider.go +++ b/internal/http/services/oidcprovider/oidcprovider.go @@ -203,7 +203,7 @@ func getStore(clients map[string]fosite.Client) *storage.MemoryStore { Clients: clients, AuthorizeCodes: map[string]storage.StoreAuthorizeCode{}, AccessTokens: map[string]fosite.Requester{}, - RefreshTokens: map[string]fosite.Requester{}, + RefreshTokens: map[string]storage.StoreRefreshToken{}, PKCES: map[string]fosite.Requester{}, AccessTokenRequestIDs: map[string]string{}, RefreshTokenRequestIDs: map[string]string{}, diff --git a/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/remote.go b/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/remote.go index ce685315b78..f77db99cf62 100644 --- a/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/remote.go +++ b/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/remote.go @@ -58,7 +58,7 @@ func (h *Handler) createFederatedCloudShare(w http.ResponseWriter, r *http.Reque return } - remoteUserRes, err := c.GetRemoteUser(ctx, &invitepb.GetRemoteUserRequest{ + remoteUserRes, err := c.GetAcceptedUser(ctx, &invitepb.GetAcceptedUserRequest{ RemoteUserId: &userpb.UserId{OpaqueId: shareWithUser, Idp: shareWithProvider}, }) if err != nil { diff --git a/pkg/ocm/invite/invite.go b/pkg/ocm/invite/invite.go index 9c11b248e5f..c771551c83f 100644 --- a/pkg/ocm/invite/invite.go +++ b/pkg/ocm/invite/invite.go @@ -37,6 +37,9 @@ type Manager interface { // AcceptInvite completes an invitation acceptance. AcceptInvite(ctx context.Context, invite *invitepb.InviteToken, remoteUser *userpb.User) error - // GetRemoteUser retrieves details about a remote user who has accepted an invite to share. - GetRemoteUser(ctx context.Context, remoteUserID *userpb.UserId) (*userpb.User, error) + // GetAcceptedUser retrieves details about a remote user who has accepted an invite to share. + GetAcceptedUser(ctx context.Context, remoteUserID *userpb.UserId) (*userpb.User, error) + + // FindAcceptedUsers finds remote users who have accepted invites based on their attributes. + FindAcceptedUsers(ctx context.Context, query string) ([]*userpb.User, error) } diff --git a/pkg/ocm/invite/manager/json/json.go b/pkg/ocm/invite/manager/json/json.go index 49fc0880b8c..303863c4028 100644 --- a/pkg/ocm/invite/manager/json/json.go +++ b/pkg/ocm/invite/manager/json/json.go @@ -273,7 +273,7 @@ func (m *manager) AcceptInvite(ctx context.Context, invite *invitepb.InviteToken return nil } -func (m *manager) GetRemoteUser(ctx context.Context, remoteUserID *userpb.UserId) (*userpb.User, error) { +func (m *manager) GetAcceptedUser(ctx context.Context, remoteUserID *userpb.UserId) (*userpb.User, error) { userKey := user.ContextMustGetUser(ctx).GetId().GetOpaqueId() for _, acceptedUser := range m.model.AcceptedUsers[userKey] { @@ -284,6 +284,23 @@ func (m *manager) GetRemoteUser(ctx context.Context, remoteUserID *userpb.UserId return nil, errtypes.NotFound(remoteUserID.OpaqueId) } +func (m *manager) FindAcceptedUsers(ctx context.Context, query string) ([]*userpb.User, error) { + users := []*userpb.User{} + userKey := user.ContextMustGetUser(ctx).GetId().GetOpaqueId() + for _, acceptedUser := range m.model.AcceptedUsers[userKey] { + if query == "" || userContains(acceptedUser, query) { + users = append(users, acceptedUser) + } + } + return users, nil +} + +func userContains(u *userpb.User, query string) bool { + query = strings.ToLower(query) + return strings.Contains(strings.ToLower(u.Username), query) || strings.Contains(strings.ToLower(u.DisplayName), query) || + strings.Contains(strings.ToLower(u.Mail), query) || strings.Contains(strings.ToLower(u.Id.OpaqueId), query) +} + func (m *manager) getTokenIfValid(token *invitepb.InviteToken) (*invitepb.InviteToken, error) { inviteToken, ok := m.model.Invites[token.GetToken()] if !ok { diff --git a/pkg/ocm/invite/manager/memory/memory.go b/pkg/ocm/invite/manager/memory/memory.go index 9a0350b35e0..4e0f68388d8 100644 --- a/pkg/ocm/invite/manager/memory/memory.go +++ b/pkg/ocm/invite/manager/memory/memory.go @@ -171,8 +171,7 @@ func (m *manager) AcceptInvite(ctx context.Context, invite *invitepb.InviteToken return nil } -func (m *manager) GetRemoteUser(ctx context.Context, remoteUserID *userpb.UserId) (*userpb.User, error) { - +func (m *manager) GetAcceptedUser(ctx context.Context, remoteUserID *userpb.UserId) (*userpb.User, error) { currUser := user.ContextMustGetUser(ctx).GetId().GetOpaqueId() usersList, ok := m.AcceptedUsers.Load(currUser) if !ok { @@ -186,7 +185,29 @@ func (m *manager) GetRemoteUser(ctx context.Context, remoteUserID *userpb.UserId } } return nil, errtypes.NotFound(remoteUserID.OpaqueId) +} + +func (m *manager) FindAcceptedUsers(ctx context.Context, query string) ([]*userpb.User, error) { + currUser := user.ContextMustGetUser(ctx).GetId().GetOpaqueId() + usersList, ok := m.AcceptedUsers.Load(currUser) + if !ok { + return []*userpb.User{}, nil + } + + users := []*userpb.User{} + acceptedUsers := usersList.([]*userpb.User) + for _, acceptedUser := range acceptedUsers { + if query == "" || userContains(acceptedUser, query) { + users = append(users, acceptedUser) + } + } + return users, nil +} +func userContains(u *userpb.User, query string) bool { + query = strings.ToLower(query) + return strings.Contains(strings.ToLower(u.Username), query) || strings.Contains(strings.ToLower(u.DisplayName), query) || + strings.Contains(strings.ToLower(u.Mail), query) || strings.Contains(strings.ToLower(u.Id.OpaqueId), query) } func (m *manager) getTokenIfValid(token *invitepb.InviteToken) (*invitepb.InviteToken, error) {