github.com/cs3org/reva/v2@v2.27.7/pkg/storage/utils/decomposedfs/grants.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 decomposedfs 20 21 import ( 22 "context" 23 "path/filepath" 24 "strings" 25 26 provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" 27 "github.com/cs3org/reva/v2/internal/grpc/services/storageprovider" 28 "github.com/cs3org/reva/v2/pkg/appctx" 29 ctxpkg "github.com/cs3org/reva/v2/pkg/ctx" 30 "github.com/cs3org/reva/v2/pkg/errtypes" 31 "github.com/cs3org/reva/v2/pkg/storage/utils/ace" 32 "github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/metadata" 33 "github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/metadata/prefixes" 34 "github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/node" 35 "github.com/cs3org/reva/v2/pkg/storagespace" 36 "github.com/cs3org/reva/v2/pkg/utils" 37 ) 38 39 // DenyGrant denies access to a resource. 40 func (fs *Decomposedfs) DenyGrant(ctx context.Context, ref *provider.Reference, grantee *provider.Grantee) error { 41 _, span := tracer.Start(ctx, "DenyGrant") 42 defer span.End() 43 log := appctx.GetLogger(ctx) 44 45 log.Debug().Interface("ref", ref).Interface("grantee", grantee).Msg("DenyGrant()") 46 47 grantNode, err := fs.lu.NodeFromResource(ctx, ref) 48 if err != nil { 49 return err 50 } 51 if !grantNode.Exists { 52 return errtypes.NotFound(filepath.Join(grantNode.ParentID, grantNode.Name)) 53 } 54 55 // set all permissions to false 56 grant := &provider.Grant{ 57 Grantee: grantee, 58 Permissions: &provider.ResourcePermissions{}, 59 } 60 61 // add acting user 62 u := ctxpkg.ContextMustGetUser(ctx) 63 grant.Creator = u.GetId() 64 65 rp, err := fs.p.AssemblePermissions(ctx, grantNode) 66 67 switch { 68 case err != nil: 69 return err 70 case !rp.DenyGrant: 71 return errtypes.PermissionDenied(filepath.Join(grantNode.ParentID, grantNode.Name)) 72 } 73 74 return fs.storeGrant(ctx, grantNode, grant) 75 } 76 77 // AddGrant adds a grant to a resource 78 func (fs *Decomposedfs) AddGrant(ctx context.Context, ref *provider.Reference, g *provider.Grant) (err error) { 79 _, span := tracer.Start(ctx, "AddGrant") 80 defer span.End() 81 log := appctx.GetLogger(ctx) 82 log.Debug().Interface("ref", ref).Interface("grant", g).Msg("AddGrant()") 83 grantNode, unlockFunc, grant, err := fs.loadGrant(ctx, ref, g) 84 if err != nil { 85 return err 86 } 87 defer func() { 88 _ = unlockFunc() 89 }() 90 91 if grant != nil { 92 return errtypes.AlreadyExists(filepath.Join(grantNode.ParentID, grantNode.Name)) 93 } 94 95 owner := grantNode.Owner() 96 grants, err := grantNode.ListGrants(ctx) 97 if err != nil { 98 return err 99 } 100 101 // If the owner is empty and there are no grantees then we are dealing with a just created project space. 102 // In this case we don't need to check for permissions and just add the grant since this will be the project 103 // manager. 104 // When the owner is empty but grants are set then we do want to check the grants. 105 // However, if we are trying to edit an existing grant we do not have to check for permission if the user owns the grant 106 // TODO: find a better to check this 107 if !(len(grants) == 0 && (owner == nil || owner.OpaqueId == "" || (owner.OpaqueId == grantNode.SpaceID && owner.Type == 8))) { 108 rp, err := fs.p.AssemblePermissions(ctx, grantNode) 109 switch { 110 case err != nil: 111 return err 112 case !rp.AddGrant: 113 f, _ := storagespace.FormatReference(ref) 114 if rp.Stat { 115 return errtypes.PermissionDenied(f) 116 } 117 return errtypes.NotFound(f) 118 } 119 } 120 121 return fs.storeGrant(ctx, grantNode, g) 122 } 123 124 // ListGrants lists the grants on the specified resource 125 func (fs *Decomposedfs) ListGrants(ctx context.Context, ref *provider.Reference) (grants []*provider.Grant, err error) { 126 _, span := tracer.Start(ctx, "ListGrants") 127 defer span.End() 128 var grantNode *node.Node 129 if grantNode, err = fs.lu.NodeFromResource(ctx, ref); err != nil { 130 return 131 } 132 if !grantNode.Exists { 133 err = errtypes.NotFound(filepath.Join(grantNode.ParentID, grantNode.Name)) 134 return 135 } 136 rp, err := fs.p.AssemblePermissions(ctx, grantNode) 137 switch { 138 case err != nil: 139 return nil, err 140 case !rp.ListGrants && !rp.Stat: 141 f, _ := storagespace.FormatReference(ref) 142 return nil, errtypes.NotFound(f) 143 } 144 log := appctx.GetLogger(ctx) 145 var attrs node.Attributes 146 if attrs, err = grantNode.Xattrs(ctx); err != nil { 147 log.Error().Err(err).Msg("error listing attributes") 148 return nil, err 149 } 150 151 aces := []*ace.ACE{} 152 for k, v := range attrs { 153 if strings.HasPrefix(k, prefixes.GrantPrefix) { 154 var err error 155 var e *ace.ACE 156 principal := k[len(prefixes.GrantPrefix):] 157 if e, err = ace.Unmarshal(principal, v); err != nil { 158 log.Error().Err(err).Str("principal", principal).Str("attr", k).Msg("could not unmarshal ace") 159 continue 160 } 161 aces = append(aces, e) 162 } 163 } 164 165 uid := ctxpkg.ContextMustGetUser(ctx).GetId() 166 grants = make([]*provider.Grant, 0, len(aces)) 167 for i := range aces { 168 g := aces[i].Grant() 169 170 // you may list your own grants even without listgrants permission 171 if !rp.ListGrants && !utils.UserIDEqual(g.Creator, uid) && !utils.UserIDEqual(g.Grantee.GetUserId(), uid) { 172 continue 173 } 174 175 grants = append(grants, g) 176 } 177 178 return grants, nil 179 } 180 181 // RemoveGrant removes a grant from resource 182 func (fs *Decomposedfs) RemoveGrant(ctx context.Context, ref *provider.Reference, g *provider.Grant) (err error) { 183 _, span := tracer.Start(ctx, "RemoveGrant") 184 defer span.End() 185 grantNode, unlockFunc, grant, err := fs.loadGrant(ctx, ref, g) 186 if err != nil { 187 return err 188 } 189 defer func() { 190 _ = unlockFunc() 191 }() 192 193 if grant == nil { 194 return errtypes.NotFound("grant not found") 195 } 196 197 // you are allowed to remove grants if you created them yourself or have the proper permission 198 if !utils.UserIDEqual(grant.Creator, ctxpkg.ContextMustGetUser(ctx).GetId()) { 199 rp, err := fs.p.AssemblePermissions(ctx, grantNode) 200 switch { 201 case err != nil: 202 return err 203 case !rp.RemoveGrant: 204 f, _ := storagespace.FormatReference(ref) 205 if rp.Stat { 206 return errtypes.PermissionDenied(f) 207 } 208 return errtypes.NotFound(f) 209 } 210 } 211 212 if err := grantNode.DeleteGrant(ctx, g, false); err != nil { 213 return err 214 } 215 216 if isShareGrant(ctx) { 217 // do not invalidate by user or group indexes 218 // FIXME we should invalidate the by-type index, but that requires reference counting 219 } else { 220 // invalidate space grant 221 switch { 222 case g.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_USER: 223 // remove from user index 224 if err := fs.userSpaceIndex.Remove(g.Grantee.GetUserId().GetOpaqueId(), grantNode.SpaceID); err != nil { 225 return err 226 } 227 case g.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_GROUP: 228 // remove from group index 229 if err := fs.groupSpaceIndex.Remove(g.Grantee.GetGroupId().GetOpaqueId(), grantNode.SpaceID); err != nil { 230 return err 231 } 232 } 233 } 234 235 return fs.tp.Propagate(ctx, grantNode, 0) 236 } 237 238 func isShareGrant(ctx context.Context) bool { 239 _, ok := storageprovider.SpaceTypeFromContext(ctx) 240 return !ok 241 } 242 243 // UpdateGrant updates a grant on a resource 244 // TODO remove AddGrant or UpdateGrant grant from CS3 api, redundant? tracked in https://github.com/cs3org/cs3apis/issues/92 245 func (fs *Decomposedfs) UpdateGrant(ctx context.Context, ref *provider.Reference, g *provider.Grant) error { 246 _, span := tracer.Start(ctx, "UpdateGrant") 247 defer span.End() 248 log := appctx.GetLogger(ctx) 249 log.Debug().Interface("ref", ref).Interface("grant", g).Msg("UpdateGrant()") 250 251 grantNode, unlockFunc, grant, err := fs.loadGrant(ctx, ref, g) 252 if err != nil { 253 return err 254 } 255 defer func() { 256 _ = unlockFunc() 257 }() 258 259 if grant == nil { 260 // grant not found 261 // TODO: fallback to AddGrant? 262 return errtypes.NotFound(g.Grantee.GetUserId().GetOpaqueId()) 263 } 264 265 // You may update a grant when you have the UpdateGrant permission or created the grant (regardless what your permissions are now) 266 if !utils.UserIDEqual(grant.Creator, ctxpkg.ContextMustGetUser(ctx).GetId()) { 267 rp, err := fs.p.AssemblePermissions(ctx, grantNode) 268 switch { 269 case err != nil: 270 return err 271 case !rp.UpdateGrant: 272 f, _ := storagespace.FormatReference(ref) 273 if rp.Stat { 274 return errtypes.PermissionDenied(f) 275 } 276 return errtypes.NotFound(f) 277 } 278 } 279 280 return fs.storeGrant(ctx, grantNode, g) 281 } 282 283 // checks if the given grant exists and returns it. Nil grant means it doesn't exist 284 func (fs *Decomposedfs) loadGrant(ctx context.Context, ref *provider.Reference, g *provider.Grant) (*node.Node, metadata.UnlockFunc, *provider.Grant, error) { 285 _, span := tracer.Start(ctx, "loadGrant") 286 defer span.End() 287 n, err := fs.lu.NodeFromResource(ctx, ref) 288 if err != nil { 289 return nil, nil, nil, err 290 } 291 if !n.Exists { 292 return nil, nil, nil, errtypes.NotFound(filepath.Join(n.ParentID, n.Name)) 293 } 294 295 // lock the metadata file 296 unlockFunc, err := fs.lu.MetadataBackend().Lock(n.InternalPath()) 297 if err != nil { 298 return nil, nil, nil, err 299 } 300 301 grants, err := n.ListGrants(ctx) 302 if err != nil { 303 return nil, nil, nil, err 304 } 305 306 for _, grant := range grants { 307 switch grant.Grantee.GetType() { 308 case provider.GranteeType_GRANTEE_TYPE_USER: 309 if g.Grantee.GetUserId().GetOpaqueId() == grant.Grantee.GetUserId().GetOpaqueId() { 310 return n, unlockFunc, grant, nil 311 } 312 case provider.GranteeType_GRANTEE_TYPE_GROUP: 313 if g.Grantee.GetGroupId().GetOpaqueId() == grant.Grantee.GetGroupId().GetOpaqueId() { 314 return n, unlockFunc, grant, nil 315 } 316 } 317 } 318 319 return n, unlockFunc, nil, nil 320 } 321 322 func (fs *Decomposedfs) storeGrant(ctx context.Context, n *node.Node, g *provider.Grant) error { 323 _, span := tracer.Start(ctx, "storeGrant") 324 defer span.End() 325 // if is a grant to a space root, the receiver needs the space type to update the indexes 326 spaceType, ok := storageprovider.SpaceTypeFromContext(ctx) 327 if !ok { 328 // this is not a grant on a space root we are just adding a share 329 spaceType = spaceTypeShare 330 } 331 332 // set the grant 333 e := ace.FromGrant(g) 334 principal, value := e.Marshal() 335 attribs := node.Attributes{ 336 prefixes.GrantPrefix + principal: value, 337 } 338 if err := n.SetXattrsWithContext(ctx, attribs, false); err != nil { 339 appctx.GetLogger(ctx).Error().Err(err). 340 Str("principal", principal).Msg("Could not set grant for principal") 341 return err 342 } 343 344 // update the indexes only after successfully setting the grant 345 err := fs.updateIndexes(ctx, g.GetGrantee(), spaceType, n.SpaceID, n.ID) 346 if err != nil { 347 return err 348 } 349 350 return fs.tp.Propagate(ctx, n, 0) 351 }