comparison roundup/rest.py @ 6111:2a513a057691

Fix transitive property check in REST API Checking Search permissin on a displayed property is wrong, we now check *View* Permission on each component of a transitive prop.
author Ralf Schlatterbeck <rsc@runtux.com>
date Fri, 28 Feb 2020 11:47:40 +0100
parents 53c4668a6600
children 1cb2375015f0
comparison
equal deleted inserted replaced
6110:af81e7a4302f 6111:2a513a057691
471 return prop 471 return prop
472 472
473 def transitive_props (self, class_name, props): 473 def transitive_props (self, class_name, props):
474 """Construct a list of transitive properties from the given 474 """Construct a list of transitive properties from the given
475 argument, and return it after permission check. Raises 475 argument, and return it after permission check. Raises
476 Unauthorised if no permission. Permission is checked by checking 476 Unauthorised if no permission. Permission is checked by
477 search-permission on the path (delimited by '.') excluding the 477 checking View permission on each component. We do not allow to
478 last component and then checking View permission on the last 478 traverse multilinks -- the last item of an expansion *may* be a
479 component. We do not allow to traverse multilinks -- the last 479 multilink but in the middle of a transitive prop.
480 item of an expansion *may* be a multilink but in the middle of a
481 transitive prop.
482 """ 480 """
483 checked_props = [] 481 checked_props = []
484 uid = self.db.getuid() 482 uid = self.db.getuid()
485 for p in props: 483 for p in props:
486 pn = p 484 pn = p
487 cn = class_name 485 cn = class_name
488 if '.' in p: 486 if '.' in p:
489 path, lc = p.rsplit('.', 1) 487 prop = None
490 if not self.db.security.hasSearchPermission(uid, class_name, p): 488 for pn in p.split('.'):
491 raise (Unauthorised 489 # Tried to dereference a non-Link property
492 ('User does not have permission on "%s.%s"' 490 if cn is None:
493 % (class_name, p))) 491 raise AttributeError("Unknown: %s" % p)
494 prev = prop = None
495 # This shouldn't raise any errors, otherwise the search
496 # permission check above would have failed
497 for pn in path.split('.'):
498 cls = self.db.getclass(cn) 492 cls = self.db.getclass(cn)
499 prop = cls.getprops(protected=True)[pn] 493 # This raises a KeyError for unknown prop:
494 try:
495 prop = cls.getprops(protected=True)[pn]
496 except KeyError:
497 raise AttributeError("Unknown: %s" % p)
500 if isinstance(prop, hyperdb.Multilink): 498 if isinstance(prop, hyperdb.Multilink):
501 raise UsageError( 499 raise UsageError(
502 'Multilink Traversal not allowed: %s' % p) 500 'Multilink Traversal not allowed: %s' % p)
503 cn = prop.classname 501 # Now we have the classname in cn and the prop name in pn.
504 cls = self.db.getclass(cn) 502 if not self.db.security.hasPermission('View', uid, cn, pn):
505 # Now we have the classname in cn and the prop name in pn. 503 raise(Unauthorised
506 if not self.db.security.hasPermission('View', uid, cn, pn): 504 ('User does not have permission on "%s.%s"'
507 raise(Unauthorised 505 % (cn, pn)))
508 ('User does not have permission on "%s.%s"' % (cn, pn))) 506 try:
507 cn = prop.classname
508 except AttributeError:
509 cn = None
509 checked_props.append (p) 510 checked_props.append (p)
510 return checked_props 511 return checked_props
511 512
512 def error_obj(self, status, msg, source=None): 513 def error_obj(self, status, msg, source=None):
513 """Return an error object""" 514 """Return an error object"""

Roundup Issue Tracker: http://roundup-tracker.org/