259 self.has_perm(req, 'read')): |
259 self.has_perm(req, 'read')): |
260 return False |
260 return False |
261 return self.has_local_role(action) or self.has_perm(req, action) |
261 return self.has_local_role(action) or self.has_perm(req, action) |
262 PermissionMixIn.may_have_permission = may_have_permission |
262 PermissionMixIn.may_have_permission = may_have_permission |
263 |
263 |
264 def has_perm(self, session, action, **kwargs): |
264 def has_perm(self, _cw, action, **kwargs): |
265 """return true if the action is granted globaly or localy""" |
265 """return true if the action is granted globaly or localy""" |
266 try: |
266 try: |
267 self.check_perm(session, action, **kwargs) |
267 self.check_perm(_cw, action, **kwargs) |
268 return True |
268 return True |
269 except Unauthorized: |
269 except Unauthorized: |
270 return False |
270 return False |
271 PermissionMixIn.has_perm = has_perm |
271 PermissionMixIn.has_perm = has_perm |
272 |
272 |
273 def check_perm(self, session, action, **kwargs): |
273 def check_perm(self, _cw, action, **kwargs): |
274 # NB: session may be a server session or a request object check user is |
274 # NB: _cw may be a server transaction or a request object. |
275 # in an allowed group, if so that's enough internal sessions should |
275 # |
276 # always stop there |
276 # check user is in an allowed group, if so that's enough internal |
|
277 # transactions should always stop there |
277 groups = self.get_groups(action) |
278 groups = self.get_groups(action) |
278 if session.user.matching_groups(groups): |
279 if _cw.user.matching_groups(groups): |
279 return |
280 return |
280 # if 'owners' in allowed groups, check if the user actually owns this |
281 # if 'owners' in allowed groups, check if the user actually owns this |
281 # object, if so that's enough |
282 # object, if so that's enough |
|
283 # |
|
284 # NB: give _cw to user.owns since user is not be bound to a transaction on |
|
285 # the repository side |
282 if 'owners' in groups and ( |
286 if 'owners' in groups and ( |
283 kwargs.get('creating') |
287 kwargs.get('creating') |
284 or ('eid' in kwargs and session.user.owns(kwargs['eid']))): |
288 or ('eid' in kwargs and _cw.user.owns(kwargs['eid']))): |
285 return |
289 return |
286 # else if there is some rql expressions, check them |
290 # else if there is some rql expressions, check them |
287 if any(rqlexpr.check(session, **kwargs) |
291 if any(rqlexpr.check(_cw, **kwargs) |
288 for rqlexpr in self.get_rqlexprs(action)): |
292 for rqlexpr in self.get_rqlexprs(action)): |
289 return |
293 return |
290 raise Unauthorized(action, str(self)) |
294 raise Unauthorized(action, str(self)) |
291 PermissionMixIn.check_perm = check_perm |
295 PermissionMixIn.check_perm = check_perm |
292 |
296 |
465 for rdef in self.rdefs.itervalues(): |
469 for rdef in self.rdefs.itervalues(): |
466 if rdef.may_have_permission(action, req): |
470 if rdef.may_have_permission(action, req): |
467 return True |
471 return True |
468 return False |
472 return False |
469 |
473 |
470 def has_perm(self, session, action, **kwargs): |
474 def has_perm(self, _cw, action, **kwargs): |
471 """return true if the action is granted globaly or localy""" |
475 """return true if the action is granted globaly or localy""" |
472 if self.final: |
476 if self.final: |
473 assert not ('fromeid' in kwargs or 'toeid' in kwargs), kwargs |
477 assert not ('fromeid' in kwargs or 'toeid' in kwargs), kwargs |
474 assert action in ('read', 'update') |
478 assert action in ('read', 'update') |
475 if 'eid' in kwargs: |
479 if 'eid' in kwargs: |
476 subjtype = session.describe(kwargs['eid'])[0] |
480 subjtype = _cw.describe(kwargs['eid'])[0] |
477 else: |
481 else: |
478 subjtype = objtype = None |
482 subjtype = objtype = None |
479 else: |
483 else: |
480 assert not 'eid' in kwargs, kwargs |
484 assert not 'eid' in kwargs, kwargs |
481 assert action in ('read', 'add', 'delete') |
485 assert action in ('read', 'add', 'delete') |
482 if 'fromeid' in kwargs: |
486 if 'fromeid' in kwargs: |
483 subjtype = session.describe(kwargs['fromeid'])[0] |
487 subjtype = _cw.describe(kwargs['fromeid'])[0] |
484 elif 'frometype' in kwargs: |
488 elif 'frometype' in kwargs: |
485 subjtype = kwargs.pop('frometype') |
489 subjtype = kwargs.pop('frometype') |
486 else: |
490 else: |
487 subjtype = None |
491 subjtype = None |
488 if 'toeid' in kwargs: |
492 if 'toeid' in kwargs: |
489 objtype = session.describe(kwargs['toeid'])[0] |
493 objtype = _cw.describe(kwargs['toeid'])[0] |
490 elif 'toetype' in kwargs: |
494 elif 'toetype' in kwargs: |
491 objtype = kwargs.pop('toetype') |
495 objtype = kwargs.pop('toetype') |
492 else: |
496 else: |
493 objtype = None |
497 objtype = None |
494 if objtype and subjtype: |
498 if objtype and subjtype: |
495 return self.rdef(subjtype, objtype).has_perm(session, action, **kwargs) |
499 return self.rdef(subjtype, objtype).has_perm(_cw, action, **kwargs) |
496 elif subjtype: |
500 elif subjtype: |
497 for tschema in self.targets(subjtype, 'subject'): |
501 for tschema in self.targets(subjtype, 'subject'): |
498 rdef = self.rdef(subjtype, tschema) |
502 rdef = self.rdef(subjtype, tschema) |
499 if not rdef.has_perm(session, action, **kwargs): |
503 if not rdef.has_perm(_cw, action, **kwargs): |
500 return False |
504 return False |
501 elif objtype: |
505 elif objtype: |
502 for tschema in self.targets(objtype, 'object'): |
506 for tschema in self.targets(objtype, 'object'): |
503 rdef = self.rdef(tschema, objtype) |
507 rdef = self.rdef(tschema, objtype) |
504 if not rdef.has_perm(session, action, **kwargs): |
508 if not rdef.has_perm(_cw, action, **kwargs): |
505 return False |
509 return False |
506 else: |
510 else: |
507 for rdef in self.rdefs.itervalues(): |
511 for rdef in self.rdefs.itervalues(): |
508 if not rdef.has_perm(session, action, **kwargs): |
512 if not rdef.has_perm(_cw, action, **kwargs): |
509 return False |
513 return False |
510 return True |
514 return True |
511 |
515 |
512 @deprecated('use .rdef(subjtype, objtype).role_cardinality(role)') |
516 @deprecated('use .rdef(subjtype, objtype).role_cardinality(role)') |
513 def cardinality(self, subjtype, objtype, target): |
517 def cardinality(self, subjtype, objtype, target): |
752 keyarg = None |
756 keyarg = None |
753 rqlst.recover() |
757 rqlst.recover() |
754 return rql, found, keyarg |
758 return rql, found, keyarg |
755 return rqlst.as_string(), None, None |
759 return rqlst.as_string(), None, None |
756 |
760 |
757 def _check(self, session, **kwargs): |
761 def _check(self, _cw, **kwargs): |
758 """return True if the rql expression is matching the given relation |
762 """return True if the rql expression is matching the given relation |
759 between fromeid and toeid |
763 between fromeid and toeid |
760 |
764 |
761 session may actually be a request as well |
765 _cw may be a request or a server side transaction |
762 """ |
766 """ |
763 creating = kwargs.get('creating') |
767 creating = kwargs.get('creating') |
764 if not creating and self.eid is not None: |
768 if not creating and self.eid is not None: |
765 key = (self.eid, tuple(sorted(kwargs.iteritems()))) |
769 key = (self.eid, tuple(sorted(kwargs.iteritems()))) |
766 try: |
770 try: |
767 return session.local_perm_cache[key] |
771 return _cw.local_perm_cache[key] |
768 except KeyError: |
772 except KeyError: |
769 pass |
773 pass |
770 rql, has_perm_defs, keyarg = self.transform_has_permission() |
774 rql, has_perm_defs, keyarg = self.transform_has_permission() |
771 # when creating an entity, expression related to X satisfied |
775 # when creating an entity, expression related to X satisfied |
772 if creating and 'X' in self.rqlst.defined_vars: |
776 if creating and 'X' in self.rqlst.defined_vars: |
773 return True |
777 return True |
774 if keyarg is None: |
778 if keyarg is None: |
775 kwargs.setdefault('u', session.user.eid) |
779 kwargs.setdefault('u', _cw.user.eid) |
776 try: |
780 try: |
777 rset = session.execute(rql, kwargs, build_descr=True) |
781 rset = _cw.execute(rql, kwargs, build_descr=True) |
778 except NotImplementedError: |
782 except NotImplementedError: |
779 self.critical('cant check rql expression, unsupported rql %s', rql) |
783 self.critical('cant check rql expression, unsupported rql %s', rql) |
780 if self.eid is not None: |
784 if self.eid is not None: |
781 session.local_perm_cache[key] = False |
785 _cw.local_perm_cache[key] = False |
782 return False |
786 return False |
783 except TypeResolverException, ex: |
787 except TypeResolverException as ex: |
784 # some expression may not be resolvable with current kwargs |
788 # some expression may not be resolvable with current kwargs |
785 # (type conflict) |
789 # (type conflict) |
786 self.warning('%s: %s', rql, str(ex)) |
790 self.warning('%s: %s', rql, str(ex)) |
787 if self.eid is not None: |
791 if self.eid is not None: |
788 session.local_perm_cache[key] = False |
792 _cw.local_perm_cache[key] = False |
789 return False |
793 return False |
790 except Unauthorized, ex: |
794 except Unauthorized as ex: |
791 self.debug('unauthorized %s: %s', rql, str(ex)) |
795 self.debug('unauthorized %s: %s', rql, str(ex)) |
792 if self.eid is not None: |
796 if self.eid is not None: |
793 session.local_perm_cache[key] = False |
797 _cw.local_perm_cache[key] = False |
794 return False |
798 return False |
795 else: |
799 else: |
796 rset = session.eid_rset(kwargs[keyarg]) |
800 rset = _cw.eid_rset(kwargs[keyarg]) |
797 # if no special has_*_permission relation in the rql expression, just |
801 # if no special has_*_permission relation in the rql expression, just |
798 # check the result set contains something |
802 # check the result set contains something |
799 if has_perm_defs is None: |
803 if has_perm_defs is None: |
800 if rset: |
804 if rset: |
801 if self.eid is not None: |
805 if self.eid is not None: |
802 session.local_perm_cache[key] = True |
806 _cw.local_perm_cache[key] = True |
803 return True |
807 return True |
804 elif rset: |
808 elif rset: |
805 # check every special has_*_permission relation is satisfied |
809 # check every special has_*_permission relation is satisfied |
806 get_eschema = session.vreg.schema.eschema |
810 get_eschema = _cw.vreg.schema.eschema |
807 try: |
811 try: |
808 for eaction, col in has_perm_defs: |
812 for eaction, col in has_perm_defs: |
809 for i in xrange(len(rset)): |
813 for i in xrange(len(rset)): |
810 eschema = get_eschema(rset.description[i][col]) |
814 eschema = get_eschema(rset.description[i][col]) |
811 eschema.check_perm(session, eaction, eid=rset[i][col]) |
815 eschema.check_perm(_cw, eaction, eid=rset[i][col]) |
812 if self.eid is not None: |
816 if self.eid is not None: |
813 session.local_perm_cache[key] = True |
817 _cw.local_perm_cache[key] = True |
814 return True |
818 return True |
815 except Unauthorized: |
819 except Unauthorized: |
816 pass |
820 pass |
817 if self.eid is not None: |
821 if self.eid is not None: |
818 session.local_perm_cache[key] = False |
822 _cw.local_perm_cache[key] = False |
819 return False |
823 return False |
820 |
824 |
821 @property |
825 @property |
822 def minimal_rql(self): |
826 def minimal_rql(self): |
823 return 'Any %s WHERE %s' % (','.join(sorted(self.mainvars)), |
827 return 'Any %s WHERE %s' % (','.join(sorted(self.mainvars)), |
841 rql += ', X eid %(x)s' |
845 rql += ', X eid %(x)s' |
842 if 'U' in defined: |
846 if 'U' in defined: |
843 rql += ', U eid %(u)s' |
847 rql += ', U eid %(u)s' |
844 return rql |
848 return rql |
845 |
849 |
846 def check(self, session, eid=None, creating=False, **kwargs): |
850 def check(self, _cw, eid=None, creating=False, **kwargs): |
847 if 'X' in self.rqlst.defined_vars: |
851 if 'X' in self.rqlst.defined_vars: |
848 if eid is None: |
852 if eid is None: |
849 if creating: |
853 if creating: |
850 return self._check(session, creating=True, **kwargs) |
854 return self._check(_cw, creating=True, **kwargs) |
851 return False |
855 return False |
852 assert creating == False |
856 assert creating == False |
853 return self._check(session, x=eid, **kwargs) |
857 return self._check(_cw, x=eid, **kwargs) |
854 return self._check(session, **kwargs) |
858 return self._check(_cw, **kwargs) |
855 |
859 |
856 |
860 |
857 def vargraph(rqlst): |
861 def vargraph(rqlst): |
858 """ builds an adjacency graph of variables from the rql syntax tree, e.g: |
862 """ builds an adjacency graph of variables from the rql syntax tree, e.g: |
859 Any O,S WHERE T subworkflow_exit S, T subworkflow WF, O state_of WF |
863 Any O,S WHERE T subworkflow_exit S, T subworkflow WF, O state_of WF |
902 rql += ', O eid %(o)s' |
906 rql += ', O eid %(o)s' |
903 if 'U' in defined: |
907 if 'U' in defined: |
904 rql += ', U eid %(u)s' |
908 rql += ', U eid %(u)s' |
905 return rql |
909 return rql |
906 |
910 |
907 def check(self, session, fromeid=None, toeid=None): |
911 def check(self, _cw, fromeid=None, toeid=None): |
908 kwargs = {} |
912 kwargs = {} |
909 if 'S' in self.rqlst.defined_vars: |
913 if 'S' in self.rqlst.defined_vars: |
910 if fromeid is None: |
914 if fromeid is None: |
911 return False |
915 return False |
912 kwargs['s'] = fromeid |
916 kwargs['s'] = fromeid |
913 if 'O' in self.rqlst.defined_vars: |
917 if 'O' in self.rqlst.defined_vars: |
914 if toeid is None: |
918 if toeid is None: |
915 return False |
919 return False |
916 kwargs['o'] = toeid |
920 kwargs['o'] = toeid |
917 return self._check(session, **kwargs) |
921 return self._check(_cw, **kwargs) |
918 |
922 |
919 |
923 |
920 # in yams, default 'update' perm for attributes granted to managers and owners. |
924 # in yams, default 'update' perm for attributes granted to managers and owners. |
921 # Within cw, we want to default to users who may edit the entity holding the |
925 # Within cw, we want to default to users who may edit the entity holding the |
922 # attribute. |
926 # attribute. |
1022 msg = '%(constraint)s %(expression)s failed' % { |
1026 msg = '%(constraint)s %(expression)s failed' % { |
1023 'constraint': session._(self.type()), |
1027 'constraint': session._(self.type()), |
1024 'expression': self.expression} |
1028 'expression': self.expression} |
1025 raise ValidationError(maineid, {qname: msg}) |
1029 raise ValidationError(maineid, {qname: msg}) |
1026 |
1030 |
1027 def exec_query(self, session, eidfrom, eidto): |
1031 def exec_query(self, _cw, eidfrom, eidto): |
1028 if eidto is None: |
1032 if eidto is None: |
1029 # checking constraint for an attribute relation |
1033 # checking constraint for an attribute relation |
1030 expression = 'S eid %(s)s, ' + self.expression |
1034 expression = 'S eid %(s)s, ' + self.expression |
1031 args = {'s': eidfrom} |
1035 args = {'s': eidfrom} |
1032 else: |
1036 else: |
1033 expression = 'S eid %(s)s, O eid %(o)s, ' + self.expression |
1037 expression = 'S eid %(s)s, O eid %(o)s, ' + self.expression |
1034 args = {'s': eidfrom, 'o': eidto} |
1038 args = {'s': eidfrom, 'o': eidto} |
1035 if 'U' in self.rqlst.defined_vars: |
1039 if 'U' in self.rqlst.defined_vars: |
1036 expression = 'U eid %(u)s, ' + expression |
1040 expression = 'U eid %(u)s, ' + expression |
1037 args['u'] = session.user.eid |
1041 args['u'] = _cw.user.eid |
1038 rql = 'Any %s WHERE %s' % (','.join(sorted(self.mainvars)), expression) |
1042 rql = 'Any %s WHERE %s' % (','.join(sorted(self.mainvars)), expression) |
1039 if self.distinct_query: |
1043 if self.distinct_query: |
1040 rql = 'DISTINCT ' + rql |
1044 rql = 'DISTINCT ' + rql |
1041 return session.execute(rql, args, build_descr=False) |
1045 return _cw.execute(rql, args, build_descr=False) |
1042 |
1046 |
1043 |
1047 |
1044 class RQLConstraint(RepoEnforcedRQLConstraintMixIn, RQLVocabularyConstraint): |
1048 class RQLConstraint(RepoEnforcedRQLConstraintMixIn, RQLVocabularyConstraint): |
1045 """the rql constraint is similar to the RQLVocabularyConstraint but |
1049 """the rql constraint is similar to the RQLVocabularyConstraint but |
1046 are also enforced at the repository level |
1050 are also enforced at the repository level |