Skip to content

Commit

Permalink
work
Browse files Browse the repository at this point in the history
Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>
  • Loading branch information
butonic committed Apr 22, 2024
1 parent 2f85146 commit 70fd84d
Show file tree
Hide file tree
Showing 9 changed files with 157 additions and 51 deletions.
14 changes: 12 additions & 2 deletions internal/grpc/interceptors/auth/scope.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func expandAndVerifyScope(ctx context.Context, req interface{}, tokenScope map[s
return nil
}
}
log.Err(err).Msgf("error resolving reference %s under scope %+v", ref.String(), k)
log.Err(err).Interface("ref", ref).Interface("scope", k).Msg("error resolving reference under scope")
}

} else if ref, ok := extractShareRef(req); ok {
Expand Down Expand Up @@ -179,6 +179,11 @@ func resolveOCMShare(ctx context.Context, ref *provider.Reference, scope *authpb
return err
}

// for ListOCMSharesRequest, the ref resource id is empty and we set path to . to indicate the root of the share
if ref.GetResourceId() == nil && ref.Path == "." {
ref.ResourceId = share.GetResourceId()
}

if err := checkCacheForNestedResource(ctx, ref, share.ResourceId, client, mgr); err == nil {
return nil
}
Expand Down Expand Up @@ -213,7 +218,7 @@ func checkRelativeReference(ctx context.Context, requested *provider.Reference,
if sharedResource.ParentId == nil {
// Is the requested resource part of the shared space?
if requested.ResourceId.StorageId != sharedResource.Id.StorageId || requested.ResourceId.SpaceId != sharedResource.Id.SpaceId {
return errtypes.PermissionDenied("access forbidden via public link")
return errtypes.PermissionDenied("space access forbidden via public link")
}
} else {
parentID := sharedResource.ParentId
Expand Down Expand Up @@ -380,6 +385,11 @@ func extractRefForReaderRole(req interface{}) (*provider.Reference, bool) {
return v.GetRef(), true
case *provider.UnlockRequest:
return v.GetRef(), true

// OCM shares
case *ocmv1beta1.ListReceivedOCMSharesRequest:
return &provider.Reference{Path: "."}, true // we will try to stat the shared node

}

return nil, false
Expand Down
35 changes: 20 additions & 15 deletions internal/grpc/services/gateway/ocmshareprovider.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ import (

// TODO(labkode): add multi-phase commit logic when commit share or commit ref is enabled.
func (s *svc) CreateOCMShare(ctx context.Context, req *ocm.CreateOCMShareRequest) (*ocm.CreateOCMShareResponse, error) {
if len(req.AccessMethods) == 0 {
return &ocm.CreateOCMShareResponse{
Status: status.NewInvalidArg(ctx, "access methods cannot be empty"),
}, nil
}
c, err := pool.GetOCMShareProviderClient(s.c.OCMShareProviderEndpoint)
if err != nil {
return &ocm.CreateOCMShareResponse{
Expand All @@ -48,7 +53,7 @@ func (s *svc) CreateOCMShare(ctx context.Context, req *ocm.CreateOCMShareRequest

res, err := c.CreateOCMShare(ctx, req)
if err != nil {
return nil, errors.Wrap(err, "gateway: error calling CreateShare")
return nil, errors.Wrap(err, "gateway: error calling CreateOCMShare")
}

status, err := s.addGrant(ctx, req.ResourceId, req.Grantee, req.AccessMethods[0].GetWebdavOptions().Permissions, req.Expiration, nil)
Expand Down Expand Up @@ -78,7 +83,7 @@ func (s *svc) RemoveOCMShare(ctx context.Context, req *ocm.RemoveOCMShareRequest

res, err := c.RemoveOCMShare(ctx, req)
if err != nil {
return nil, errors.Wrap(err, "gateway: error calling RemoveShare")
return nil, errors.Wrap(err, "gateway: error calling RemoveOCMShare")
}

return res, nil
Expand All @@ -102,7 +107,7 @@ func (s *svc) getOCMShare(ctx context.Context, req *ocm.GetOCMShareRequest) (*oc

res, err := c.GetOCMShare(ctx, req)
if err != nil {
return nil, errors.Wrap(err, "gateway: error calling GetShare")
return nil, errors.Wrap(err, "gateway: error calling GetOCMShare")
}

return res, nil
Expand Down Expand Up @@ -134,7 +139,7 @@ func (s *svc) ListOCMShares(ctx context.Context, req *ocm.ListOCMSharesRequest)

res, err := c.ListOCMShares(ctx, req)
if err != nil {
return nil, errors.Wrap(err, "gateway: error calling ListShares")
return nil, errors.Wrap(err, "gateway: error calling ListOCMShares")
}

return res, nil
Expand All @@ -151,7 +156,7 @@ func (s *svc) UpdateOCMShare(ctx context.Context, req *ocm.UpdateOCMShareRequest

res, err := c.UpdateOCMShare(ctx, req)
if err != nil {
return nil, errors.Wrap(err, "gateway: error calling UpdateShare")
return nil, errors.Wrap(err, "gateway: error calling UpdateOCMShare")
}

return res, nil
Expand All @@ -168,7 +173,7 @@ func (s *svc) ListReceivedOCMShares(ctx context.Context, req *ocm.ListReceivedOC

res, err := c.ListReceivedOCMShares(ctx, req)
if err != nil {
return nil, errors.Wrap(err, "gateway: error calling ListReceivedShares")
return nil, errors.Wrap(err, "gateway: error calling ListReceivedOCMShares")
}

return res, nil
Expand Down Expand Up @@ -223,7 +228,7 @@ func (s *svc) UpdateReceivedOCMShare(ctx context.Context, req *ocm.UpdateReceive

res, err := c.UpdateReceivedOCMShare(ctx, req)
if err != nil {
log.Err(err).Msg("gateway: error calling UpdateReceivedShare")
log.Err(err).Msg("gateway: error calling UpdateReceivedOCMShare")
return &ocm.UpdateReceivedOCMShareResponse{
Status: &rpc.Status{
Code: rpc.Code_CODE_INTERNAL,
Expand Down Expand Up @@ -256,7 +261,7 @@ func (s *svc) UpdateReceivedOCMShare(ctx context.Context, req *ocm.UpdateReceive
// handle transfer in case it has not already been accepted
if s.isTransferShare(share) && req.GetShare().State == ocm.ShareState_SHARE_STATE_ACCEPTED {
if share.State == ocm.ShareState_SHARE_STATE_ACCEPTED {
log.Err(err).Msg("gateway: error calling UpdateReceivedShare, share already accepted.")
log.Err(err).Msg("gateway: error calling UpdateReceivedOCMShare, share already accepted.")
return &ocm.UpdateReceivedOCMShareResponse{
Status: &rpc.Status{
Code: rpc.Code_CODE_FAILED_PRECONDITION,
Expand All @@ -268,7 +273,7 @@ func (s *svc) UpdateReceivedOCMShare(ctx context.Context, req *ocm.UpdateReceive
transferDestinationPath, err := s.getTransferDestinationPath(ctx, req)
if err != nil {
if err != nil {
log.Err(err).Msg("gateway: error calling UpdateReceivedShare")
log.Err(err).Msg("gateway: error calling UpdateReceivedOCMShare")
return &ocm.UpdateReceivedOCMShareResponse{
Status: &rpc.Status{
Code: rpc.Code_CODE_INTERNAL,
Expand All @@ -279,7 +284,7 @@ func (s *svc) UpdateReceivedOCMShare(ctx context.Context, req *ocm.UpdateReceive

error := s.handleTransfer(ctx, share, transferDestinationPath)
if error != nil {
log.Err(error).Msg("gateway: error handling transfer in UpdateReceivedShare")
log.Err(error).Msg("gateway: error handling transfer in UpdateReceivedOCMShare")
return &ocm.UpdateReceivedOCMShareResponse{
Status: &rpc.Status{
Code: rpc.Code_CODE_INTERNAL,
Expand Down Expand Up @@ -309,17 +314,17 @@ func (s *svc) handleTransfer(ctx context.Context, share *ocm.ReceivedShare, tran
}
destWebdavEndpoint, err := s.getWebdavEndpoint(ctx, granteeIdp)
if err != nil {
log.Err(err).Msg("gateway: error calling UpdateReceivedShare")
log.Err(err).Msg("gateway: error calling UpdateReceivedOCMShare")
return err
}
destWebdavEndpointURL, err := url.Parse(destWebdavEndpoint)
if err != nil {
log.Err(err).Msg("gateway: error calling UpdateReceivedShare: unable to parse webdav endpoint \"" + destWebdavEndpoint + "\" into URL structure")
log.Err(err).Msg("gateway: error calling UpdateReceivedOCMShare: unable to parse webdav endpoint \"" + destWebdavEndpoint + "\" into URL structure")
return err
}
destWebdavHost, err := s.getWebdavHost(ctx, granteeIdp)
if err != nil {
log.Err(err).Msg("gateway: error calling UpdateReceivedShare")
log.Err(err).Msg("gateway: error calling UpdateReceivedOCMShare")
return err
}
var dstWebdavURLString string
Expand All @@ -330,7 +335,7 @@ func (s *svc) handleTransfer(ctx context.Context, share *ocm.ReceivedShare, tran
}
dstWebdavHostURL, err := url.Parse(dstWebdavURLString)
if err != nil {
log.Err(err).Msg("gateway: error calling UpdateReceivedShare: unable to parse webdav service host \"" + dstWebdavURLString + "\" into URL structure")
log.Err(err).Msg("gateway: error calling UpdateReceivedOCMShare: unable to parse webdav service host \"" + dstWebdavURLString + "\" into URL structure")
return err
}
destServiceHost := dstWebdavHostURL.Host + dstWebdavHostURL.Path
Expand Down Expand Up @@ -393,7 +398,7 @@ func (s *svc) GetReceivedOCMShare(ctx context.Context, req *ocm.GetReceivedOCMSh

res, err := c.GetReceivedOCMShare(ctx, req)
if err != nil {
return nil, errors.Wrap(err, "gateway: error calling GetReceivedShare")
return nil, errors.Wrap(err, "gateway: error calling GetReceivedOCMShare")
}

return res, nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ func (s *service) ListStorageSpaces(ctx context.Context, req *provider.ListStora
Status: &rpc.Status{Code: rpc.Code_CODE_INVALID_ARGUMENT, Message: err.Error()},
}, nil
}
if resID.SpaceId != utils.PublicStorageSpaceID {
if resID.SpaceId != utils.PublicStorageSpaceID && resID.SpaceId != utils.OCMStorageSpaceID {
return &provider.ListStorageSpacesResponse{
// a specific id was requested, return not found instead of empty list
Status: &rpc.Status{Code: rpc.Code_CODE_NOT_FOUND},
Expand All @@ -415,7 +415,7 @@ func (s *service) ListStorageSpaces(ctx context.Context, req *provider.ListStora
}
}

info, _, grantee, token, err := s.extractLinkFromScope(ctx)
info, share, grantee, token, err := s.extractLinkFromScope(ctx)
if err != nil {
switch err.(type) {
case errtypes.NotFound:
Expand Down Expand Up @@ -468,6 +468,9 @@ func (s *service) ListStorageSpaces(ctx context.Context, req *provider.ListStora
SpaceId: utils.PublicStorageSpaceID,
OpaqueId: token, // the link share has no id, only the token
}
if ocmShare, ok := share.(*ocm.Share); ok {
root.OpaqueId = ocmShare.GetId().GetOpaqueId()
}
if spaceID != nil {
switch {
case utils.ResourceIDEqual(spaceID, root):
Expand Down Expand Up @@ -506,7 +509,7 @@ func (s *service) extractLinkFromScope(ctx context.Context) (*provider.ResourceI
share := &ocm.Share{}
err := utils.UnmarshalJSONToProtoV1(v.Resource.Value, share)
if err != nil {
return nil, nil, nil, "", errtypes.InternalError("failed to unmarshal public share")
return nil, nil, nil, "", errtypes.InternalError("failed to unmarshal ocm share")
}

// the share is minimally populated, we need more than the token
Expand Down
2 changes: 1 addition & 1 deletion pkg/auth/manager/ocmshares/ocmshares.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ func (m *manager) Configure(ml map[string]interface{}) error {

func (m *manager) Authenticate(ctx context.Context, ocmshare, sharedSecret string) (*userpb.User, map[string]*authpb.Scope, error) {
log := appctx.GetLogger(ctx).With().Str("ocmshare", ocmshare).Logger()
// We need to use GetOCMShareByToken, as GetOCMShare would requir a user in the context
// We need to use GetOCMShareByToken, as GetOCMShare would require a user in the context
shareRes, err := m.gw.GetOCMShareByToken(ctx, &ocm.GetOCMShareByTokenRequest{
Token: sharedSecret,
})
Expand Down
20 changes: 14 additions & 6 deletions pkg/auth/scope/ocmshare.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
authpb "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1"
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1"
ocmv1beta1 "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
registry "github.com/cs3org/go-cs3apis/cs3/storage/registry/v1beta1"
Expand Down Expand Up @@ -123,6 +124,13 @@ func ocmShareScope(_ context.Context, scope *authpb.Scope, resource interface{},
return true, nil
case *provider.ListStorageSpacesRequest:
return true, nil
// FIXME why do we need to add them? I think the whole listing of received OCM shares change might be unnecessary ... need to reevaluate that after switching the dav namespace for from /ocm back to /public
case *ocmv1beta1.ListReceivedOCMSharesRequest:
return true, nil
case *ocmv1beta1.ListOCMSharesRequest:
return true, nil
case *collaboration.ListReceivedSharesRequest:
return true, nil

case *ocmv1beta1.GetOCMShareRequest:
return checkOCMShareRef(&share, v.GetRef()), nil
Expand All @@ -136,24 +144,24 @@ func ocmShareScope(_ context.Context, scope *authpb.Scope, resource interface{},

func checkStorageRefForOCMShare(s *ocmv1beta1.Share, r *provider.Reference, ns string) bool {
if r.ResourceId != nil {
return utils.ResourceIDEqual(s.ResourceId, r.GetResourceId()) || strings.HasPrefix(r.ResourceId.OpaqueId, s.Token)
return utils.ResourceIDEqual(s.ResourceId, r.GetResourceId()) || strings.HasPrefix(r.ResourceId.OpaqueId, s.GetId().GetOpaqueId())
}

// FIXME: the paths here are hardcoded
if strings.HasPrefix(r.GetPath(), "/public/"+s.Token) {
if strings.HasPrefix(r.GetPath(), "/public/"+s.GetId().GetOpaqueId()) {
return true
}
return strings.HasPrefix(r.GetPath(), filepath.Join(ns, s.Token))
return strings.HasPrefix(r.GetPath(), filepath.Join(ns, s.GetId().GetOpaqueId()))
}

func checkOCMShareRef(s *ocmv1beta1.Share, ref *ocmv1beta1.ShareReference) bool {
return ref.GetToken() == s.Token
return ref.GetId().GetOpaqueId() == s.GetId().GetOpaqueId()
}

// AddOCMShareScope adds the scope to allow access to an OCM share and the share resource.
func AddOCMShareScope(share *ocmv1beta1.Share, role authpb.Role, scopes map[string]*authpb.Scope) (map[string]*authpb.Scope, error) {
// Create a new "scope share" to only expose the required fields `ResourceId` and `Token` to the scope.
scopeShare := ocmv1beta1.Share{ResourceId: share.ResourceId, Token: share.Token}
// Create a new "scope share" to only expose the required fields `ResourceId`, `Id` and `Token` to the scope.
scopeShare := ocmv1beta1.Share{ResourceId: share.ResourceId, Id: share.GetId(), Token: share.Token}
val, err := utils.MarshalProtoV1ToJSON(&scopeShare)
if err != nil {
return nil, err
Expand Down
2 changes: 1 addition & 1 deletion pkg/ocm/share/repository/json/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ func (m *mgr) ListShares(ctx context.Context, user *userpb.User, filters []*ocm.
}

for _, share := range m.model.Shares {
if utils.UserEqual(user.Id, share.Owner) || utils.UserEqual(user.Id, share.Creator) {
if utils.UserEqual(user.Id, share.Owner) || utils.UserEqual(user.Id, share.Creator) || utils.UserEqual(user.Id, share.GetGrantee().GetUserId()) {
// no filter we return earlier
if len(filters) == 0 {
ss = append(ss, share)
Expand Down
54 changes: 42 additions & 12 deletions pkg/ocm/storage/received/ocm.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,12 @@ func (c *config) ApplyDefaults() {

// BearerAuthenticator represents an authenticator that adds a Bearer token to the Authorization header of HTTP requests.
type BearerAuthenticator struct {
token string
Token string
}

// Authorize adds the Bearer token to the Authorization header of the provided HTTP request.
func (b BearerAuthenticator) Authorize(_ *http.Client, r *http.Request, _ string) error {
r.Header.Add("Authorization", "Bearer "+b.token)
r.Header.Add("Authorization", "Bearer "+b.Token)
return nil
}

Expand All @@ -88,8 +88,8 @@ func (BearerAuthenticator) Verify(*http.Client, *http.Response, string) (bool, e
}

// Clone creates a new instance of the BearerAuthenticator.
func (BearerAuthenticator) Clone() gowebdav.Authenticator {
return BearerAuthenticator{}
func (b BearerAuthenticator) Clone() gowebdav.Authenticator {
return BearerAuthenticator{Token: b.Token}
}

// Close is not implemented for the BearerAuthenticator. It always returns nil.
Expand Down Expand Up @@ -196,7 +196,7 @@ func (d *driver) webdavClient(ctx context.Context, forUser *userpb.UserId, ref *

// FIXME: it's still not clear from the OCM APIs how to use the shared secret
// will use as a token in the bearer authentication as this is the reva implementation
c := gowebdav.NewAuthClient(endpoint, gowebdav.NewPreemptiveAuth(BearerAuthenticator{token: secret}))
c := gowebdav.NewAuthClient(endpoint, gowebdav.NewPreemptiveAuth(BearerAuthenticator{Token: secret}))
if d.c.Insecure {
c.SetTransport(&http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
Expand Down Expand Up @@ -250,17 +250,21 @@ func convertStatToResourceInfo(ref *provider.Reference, f fs.FileInfo, share *oc
t = provider.ResourceType_RESOURCE_TYPE_CONTAINER
}

var name string
if share.ResourceType == provider.ResourceType_RESOURCE_TYPE_FILE {
name = share.Name
} else {
name = f.Name()
}

webdavFile, ok := f.(gowebdav.File)
if !ok {
return nil, errtypes.InternalError("could not get webdav props")
}

var name string
switch {
case share.ResourceType == provider.ResourceType_RESOURCE_TYPE_FILE:
name = share.Name
case webdavFile.Path() == "/":
name = share.Name
default:
name = webdavFile.Name()
}

opaqueid := base64.StdEncoding.EncodeToString([]byte(webdavFile.Path()))

// ids are of the format <ocmstorageproviderid>$<shareid>!<opaqueid>
Expand Down Expand Up @@ -461,6 +465,13 @@ func (d *driver) ListStorageSpaces(ctx context.Context, filters []*provider.List
if err != nil {
return nil, err
}
// FIXME This might have to be ListOCMShares
// these are grants

lsRes, err := d.gateway.ListOCMShares(ctx, &ocmpb.ListOCMSharesRequest{})
if err != nil {
return nil, err
}

if len(spaceTypes) == 0 {
spaceTypes["mountpoint"] = exists
Expand Down Expand Up @@ -489,6 +500,25 @@ func (d *driver) ListStorageSpaces(ctx context.Context, filters []*provider.List
Root: root,
}

spaces = append(spaces, space)
}
for _, share := range lsRes.Shares {
root := &provider.ResourceId{
StorageId: utils.OCMStorageProviderID,
SpaceId: share.Id.OpaqueId,
OpaqueId: share.Id.OpaqueId,
}
space := &provider.StorageSpace{
Id: &provider.StorageSpaceId{
OpaqueId: storagespace.FormatResourceID(*root),
},
SpaceType: "mountpoint",
Owner: &userv1beta1.User{
Id: share.Grantee.GetUserId(),
},
Root: root,
}

spaces = append(spaces, space)
}
}
Expand Down
Loading

0 comments on commit 70fd84d

Please sign in to comment.