github.com/cs3org/reva/v2@v2.27.7/pkg/auth/scope/resourceinfo.go (about) 1 // Copyright 2018-2021 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 "fmt" 24 "strings" 25 26 appprovider "github.com/cs3org/go-cs3apis/cs3/app/provider/v1beta1" 27 authpb "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1" 28 gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1" 29 provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" 30 registry "github.com/cs3org/go-cs3apis/cs3/storage/registry/v1beta1" 31 "github.com/rs/zerolog" 32 33 types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1" 34 "github.com/cs3org/reva/v2/pkg/errtypes" 35 "github.com/cs3org/reva/v2/pkg/utils" 36 ) 37 38 func resourceinfoScope(_ context.Context, scope *authpb.Scope, resource interface{}, logger *zerolog.Logger) (bool, error) { 39 var r provider.ResourceInfo 40 err := utils.UnmarshalJSONToProtoV1(scope.Resource.Value, &r) 41 if err != nil { 42 return false, err 43 } 44 45 switch v := resource.(type) { 46 // Viewer role 47 case *registry.GetStorageProvidersRequest: 48 return checkResourceInfo(&r, v.GetRef()), nil 49 case *registry.ListStorageProvidersRequest: 50 // the call will only return spaces the current user has access to 51 ref := &provider.Reference{} 52 if v.Opaque != nil && v.Opaque.Map != nil { 53 if e, ok := v.Opaque.Map["storage_id"]; ok { 54 ref.ResourceId = &provider.ResourceId{ 55 StorageId: string(e.Value), 56 } 57 } 58 if e, ok := v.Opaque.Map["opaque_id"]; ok { 59 if ref.ResourceId == nil { 60 ref.ResourceId = &provider.ResourceId{} 61 } 62 ref.ResourceId.OpaqueId = string(e.Value) 63 } 64 if e, ok := v.Opaque.Map["path"]; ok { 65 ref.Path = string(e.Value) 66 } 67 } 68 return checkResourceInfo(&r, ref), nil 69 case *provider.ListStorageSpacesRequest: 70 // the call will only return spaces the current user has access to 71 return true, nil 72 case *provider.StatRequest: 73 return checkResourceInfo(&r, v.GetRef()), nil 74 case *provider.ListContainerRequest: 75 return checkResourceInfo(&r, v.GetRef()), nil 76 case *provider.InitiateFileDownloadRequest: 77 return checkResourceInfo(&r, v.GetRef()), nil 78 case *appprovider.OpenInAppRequest: 79 return checkResourceInfo(&r, &provider.Reference{ResourceId: v.ResourceInfo.Id}), nil 80 case *gateway.OpenInAppRequest: 81 return checkResourceInfo(&r, v.GetRef()), nil 82 83 // Editor role 84 // need to return appropriate status codes in the ocs/ocdav layers. 85 case *provider.CreateContainerRequest: 86 return hasRoleEditor(scope) && checkResourceInfo(&r, v.GetRef()), nil 87 case *provider.TouchFileRequest: 88 return hasRoleEditor(scope) && checkResourceInfo(&r, v.GetRef()), nil 89 case *provider.DeleteRequest: 90 return hasRoleEditor(scope) && checkResourceInfo(&r, v.GetRef()), nil 91 case *provider.MoveRequest: 92 return hasRoleEditor(scope) && checkResourceInfo(&r, v.GetSource()) && checkResourceInfo(&r, v.GetDestination()), nil 93 case *provider.InitiateFileUploadRequest: 94 return hasRoleEditor(scope) && checkResourceInfo(&r, v.GetRef()), nil 95 case *provider.SetArbitraryMetadataRequest: 96 return hasRoleEditor(scope) && checkResourceInfo(&r, v.GetRef()), nil 97 case *provider.UnsetArbitraryMetadataRequest: 98 return hasRoleEditor(scope) && checkResourceInfo(&r, v.GetRef()), nil 99 100 case string: 101 return checkResourcePath(v), nil 102 } 103 104 msg := fmt.Sprintf("resource type assertion failed: %+v", resource) 105 logger.Debug().Str("scope", "resourceinfoScope").Msg(msg) 106 return false, errtypes.InternalError(msg) 107 } 108 109 func checkResourceInfo(inf *provider.ResourceInfo, ref *provider.Reference) bool { 110 // ref: <resource_id:<storage_id:$storageID opaque_id:$opaqueID path:$path> > 111 if ref.ResourceId != nil { // path can be empty or a relative path 112 if inf.Id.SpaceId == ref.ResourceId.SpaceId && inf.Id.OpaqueId == ref.ResourceId.OpaqueId { 113 if ref.Path == "" { 114 // id only reference 115 return true 116 } 117 // check path has same prefix below 118 } else { 119 return false 120 } 121 } 122 // ref: <path:$path > 123 if strings.HasPrefix(ref.GetPath(), inf.Path) { 124 return true 125 } 126 return false 127 } 128 129 func checkResourcePath(path string) bool { 130 paths := []string{ 131 "/dataprovider", 132 "/data", 133 "/app/open", 134 "/app/new", 135 "/archiver", 136 "/ocs/v2.php/cloud/capabilities", 137 "/ocs/v1.php/cloud/capabilities", 138 } 139 for _, p := range paths { 140 if strings.HasPrefix(path, p) { 141 return true 142 } 143 } 144 return false 145 } 146 147 // AddResourceInfoScope adds the scope to allow access to a resource info object. 148 func AddResourceInfoScope(r *provider.ResourceInfo, role authpb.Role, scopes map[string]*authpb.Scope) (map[string]*authpb.Scope, error) { 149 // Create a new "scope info" to only expose the required fields `Id` and `Path` to the scope. 150 scopeInfo := &provider.ResourceInfo{Id: r.Id, Path: r.Path} 151 val, err := utils.MarshalProtoV1ToJSON(scopeInfo) 152 if err != nil { 153 return nil, err 154 } 155 if scopes == nil { 156 scopes = make(map[string]*authpb.Scope) 157 } 158 scopes["resourceinfo:"+r.Id.String()] = &authpb.Scope{ 159 Resource: &types.OpaqueEntry{ 160 Decoder: "json", 161 Value: val, 162 }, 163 Role: role, 164 } 165 return scopes, nil 166 }