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 }