github.com/cs3org/reva/v2@v2.27.7/pkg/auth/scope/ocmshare.go (about)

     1  // Copyright 2018-2023 CERN
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  //
    15  // In applying this license, CERN does not waive the privileges and immunities
    16  // granted to it by virtue of its status as an Intergovernmental Organization
    17  // or submit itself to any jurisdiction.
    18  
    19  package scope
    20  
    21  import (
    22  	"context"
    23  	"path/filepath"
    24  	"strings"
    25  
    26  	appprovider "github.com/cs3org/go-cs3apis/cs3/app/provider/v1beta1"
    27  	appregistry "github.com/cs3org/go-cs3apis/cs3/app/registry/v1beta1"
    28  	authpb "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1"
    29  	gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
    30  	userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
    31  	collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1"
    32  	ocmv1beta1 "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
    33  	provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
    34  	registry "github.com/cs3org/go-cs3apis/cs3/storage/registry/v1beta1"
    35  	types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
    36  	"github.com/cs3org/reva/v2/pkg/errtypes"
    37  	"github.com/cs3org/reva/v2/pkg/utils"
    38  	"github.com/rs/zerolog"
    39  )
    40  
    41  // FIXME: the namespace here is hardcoded
    42  // find a way to pass it from the config.
    43  const ocmNamespace = "/ocm"
    44  
    45  func ocmShareScope(_ context.Context, scope *authpb.Scope, resource interface{}, _ *zerolog.Logger) (bool, error) {
    46  	var share ocmv1beta1.Share
    47  	if err := utils.UnmarshalJSONToProtoV1(scope.Resource.Value, &share); err != nil {
    48  		return false, err
    49  	}
    50  
    51  	switch v := resource.(type) {
    52  	// viewer role
    53  	case *registry.ListStorageProvidersRequest:
    54  		ref := &provider.Reference{}
    55  		if v.Opaque != nil && v.Opaque.Map != nil {
    56  			if e, ok := v.Opaque.Map["storage_id"]; ok {
    57  				if ref.ResourceId == nil {
    58  					ref.ResourceId = &provider.ResourceId{}
    59  				}
    60  				ref.ResourceId.StorageId = string(e.Value)
    61  			}
    62  			if e, ok := v.Opaque.Map["space_id"]; ok {
    63  				if ref.ResourceId == nil {
    64  					ref.ResourceId = &provider.ResourceId{}
    65  				}
    66  				ref.ResourceId.SpaceId = string(e.Value)
    67  			}
    68  			if e, ok := v.Opaque.Map["opaque_id"]; ok {
    69  				if ref.ResourceId == nil {
    70  					ref.ResourceId = &provider.ResourceId{}
    71  				}
    72  				ref.ResourceId.OpaqueId = string(e.Value)
    73  			}
    74  			if e, ok := v.Opaque.Map["path"]; ok {
    75  				ref.Path = string(e.Value)
    76  			}
    77  		}
    78  		return checkStorageRefForOCMShare(&share, ref, ocmNamespace), nil
    79  	case *registry.GetStorageProvidersRequest:
    80  		return checkStorageRefForOCMShare(&share, v.GetRef(), ocmNamespace), nil
    81  	case *provider.StatRequest:
    82  		return checkStorageRefForOCMShare(&share, v.GetRef(), ocmNamespace), nil
    83  	case *provider.ListContainerRequest:
    84  		return checkStorageRefForOCMShare(&share, v.GetRef(), ocmNamespace), nil
    85  	case *provider.InitiateFileDownloadRequest:
    86  		return checkStorageRefForOCMShare(&share, v.GetRef(), ocmNamespace), nil
    87  	case *appprovider.OpenInAppRequest:
    88  		return checkStorageRefForOCMShare(&share, &provider.Reference{ResourceId: v.ResourceInfo.Id}, ocmNamespace), nil
    89  	case *gateway.OpenInAppRequest:
    90  		return checkStorageRefForOCMShare(&share, v.GetRef(), ocmNamespace), nil
    91  	case *provider.GetLockRequest:
    92  		return checkStorageRefForOCMShare(&share, v.GetRef(), ocmNamespace), nil
    93  
    94  	// editor role
    95  	case *provider.CreateContainerRequest:
    96  		return hasRoleEditor(scope) && checkStorageRefForOCMShare(&share, v.GetRef(), ocmNamespace), nil
    97  	case *provider.TouchFileRequest:
    98  		return hasRoleEditor(scope) && checkStorageRefForOCMShare(&share, v.GetRef(), ocmNamespace), nil
    99  	case *provider.DeleteRequest:
   100  		return hasRoleEditor(scope) && checkStorageRefForOCMShare(&share, v.GetRef(), ocmNamespace), nil
   101  	case *provider.MoveRequest:
   102  		return hasRoleEditor(scope) && checkStorageRefForOCMShare(&share, v.GetSource(), ocmNamespace) && checkStorageRefForOCMShare(&share, v.GetDestination(), ocmNamespace), nil
   103  	case *provider.InitiateFileUploadRequest:
   104  		return hasRoleEditor(scope) && checkStorageRefForOCMShare(&share, v.GetRef(), ocmNamespace), nil
   105  	case *provider.SetArbitraryMetadataRequest:
   106  		return hasRoleEditor(scope) && checkStorageRefForOCMShare(&share, v.GetRef(), ocmNamespace), nil
   107  	case *provider.UnsetArbitraryMetadataRequest:
   108  		return hasRoleEditor(scope) && checkStorageRefForOCMShare(&share, v.GetRef(), ocmNamespace), nil
   109  	case *provider.SetLockRequest:
   110  		return hasRoleEditor(scope) && checkStorageRefForOCMShare(&share, v.GetRef(), ocmNamespace), nil
   111  	case *provider.RefreshLockRequest:
   112  		return hasRoleEditor(scope) && checkStorageRefForOCMShare(&share, v.GetRef(), ocmNamespace), nil
   113  	case *provider.UnlockRequest:
   114  		return hasRoleEditor(scope) && checkStorageRefForOCMShare(&share, v.GetRef(), ocmNamespace), nil
   115  
   116  	// App provider requests
   117  	case *appregistry.GetDefaultAppProviderForMimeTypeRequest:
   118  		return true, nil
   119  	case *appregistry.GetAppProvidersRequest:
   120  		return true, nil
   121  	case *userv1beta1.GetUserByClaimRequest:
   122  		return true, nil
   123  	case *userv1beta1.GetUserRequest:
   124  		return true, nil
   125  	case *provider.ListStorageSpacesRequest:
   126  		return true, nil
   127  		// 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
   128  	case *ocmv1beta1.ListReceivedOCMSharesRequest:
   129  		return true, nil
   130  	case *ocmv1beta1.ListOCMSharesRequest:
   131  		return true, nil
   132  	case *collaboration.ListReceivedSharesRequest:
   133  		return true, nil
   134  
   135  	case *ocmv1beta1.GetOCMShareRequest:
   136  		return checkOCMShareRef(&share, v.GetRef()), nil
   137  	case *ocmv1beta1.GetOCMShareByTokenRequest:
   138  		return share.Token == v.GetToken(), nil
   139  	case string:
   140  		return checkResourcePath(v), nil
   141  	}
   142  	return false, nil
   143  }
   144  
   145  func checkStorageRefForOCMShare(s *ocmv1beta1.Share, r *provider.Reference, ns string) bool {
   146  	if r.ResourceId != nil {
   147  		return utils.ResourceIDEqual(s.ResourceId, r.GetResourceId()) || strings.HasPrefix(r.ResourceId.OpaqueId, s.GetId().GetOpaqueId())
   148  	}
   149  
   150  	// FIXME: the paths here are hardcoded
   151  	if strings.HasPrefix(r.GetPath(), "/public/"+s.GetId().GetOpaqueId()) {
   152  		return true
   153  	}
   154  	return strings.HasPrefix(r.GetPath(), filepath.Join(ns, s.GetId().GetOpaqueId()))
   155  }
   156  
   157  func checkOCMShareRef(s *ocmv1beta1.Share, ref *ocmv1beta1.ShareReference) bool {
   158  	return ref.GetId().GetOpaqueId() == s.GetId().GetOpaqueId()
   159  }
   160  
   161  // AddOCMShareScope adds the scope to allow access to an OCM share and the share resource.
   162  func AddOCMShareScope(share *ocmv1beta1.Share, role authpb.Role, scopes map[string]*authpb.Scope) (map[string]*authpb.Scope, error) {
   163  	// Create a new "scope share" to only expose the required fields `ResourceId`, `Id` and `Token` to the scope.
   164  	scopeShare := ocmv1beta1.Share{ResourceId: share.ResourceId, Id: share.GetId(), Token: share.Token}
   165  	val, err := utils.MarshalProtoV1ToJSON(&scopeShare)
   166  	if err != nil {
   167  		return nil, err
   168  	}
   169  	if scopes == nil {
   170  		scopes = make(map[string]*authpb.Scope)
   171  	}
   172  
   173  	scopes["ocmshare:"+share.Id.OpaqueId] = &authpb.Scope{
   174  		Resource: &types.OpaqueEntry{
   175  			Decoder: "json",
   176  			Value:   val,
   177  		},
   178  		Role: role,
   179  	}
   180  	return scopes, nil
   181  }
   182  
   183  // GetOCMSharesFromScopes returns all OCM shares in the given scope.
   184  func GetOCMSharesFromScopes(scopes map[string]*authpb.Scope) ([]*ocmv1beta1.Share, error) {
   185  	var shares []*ocmv1beta1.Share
   186  	for k, s := range scopes {
   187  		if strings.HasPrefix(k, "ocmshare:") {
   188  			res := s.Resource
   189  			if res.Decoder != "json" {
   190  				return nil, errtypes.InternalError("resource should be json encoded")
   191  			}
   192  			var share ocmv1beta1.Share
   193  			err := utils.UnmarshalJSONToProtoV1(res.Value, &share)
   194  			if err != nil {
   195  				return nil, err
   196  			}
   197  			shares = append(shares, &share)
   198  		}
   199  	}
   200  	return shares, nil
   201  }