70 try: |
71 try: |
71 return solution[term.name] |
72 return solution[term.name] |
72 except AttributeError: |
73 except AttributeError: |
73 return cnx.entity_metas(term.eval(args))['type'] |
74 return cnx.entity_metas(term.eval(args))['type'] |
74 |
75 |
75 def check_read_access(cnx, rqlst, solution, args): |
76 def check_relations_read_access(cnx, select, args): |
|
77 """Raise :exc:`Unauthorized` if the given user doesn't have credentials to |
|
78 read relations used in the givel syntaxt tree |
|
79 """ |
|
80 # use `term_etype` since we've to deal with rewritten constants here, |
|
81 # when used as an external source by another repository. |
|
82 # XXX what about local read security w/ those rewritten constants... |
|
83 # XXX constants can also happen in some queries generated by req.find() |
|
84 DBG = (server.DEBUG & server.DBG_SEC) and 'read' in server._SECURITY_CAPS |
|
85 schema = cnx.repo.schema |
|
86 user = cnx.user |
|
87 if select.where is not None: |
|
88 for rel in select.where.iget_nodes(Relation): |
|
89 for solution in select.solutions: |
|
90 # XXX has_text may have specific perm ? |
|
91 if rel.r_type in READ_ONLY_RTYPES: |
|
92 continue |
|
93 rschema = schema.rschema(rel.r_type) |
|
94 if rschema.final: |
|
95 eschema = schema.eschema(term_etype(cnx, rel.children[0], |
|
96 solution, args)) |
|
97 rdef = eschema.rdef(rschema) |
|
98 else: |
|
99 rdef = rschema.rdef(term_etype(cnx, rel.children[0], |
|
100 solution, args), |
|
101 term_etype(cnx, rel.children[1].children[0], |
|
102 solution, args)) |
|
103 if not user.matching_groups(rdef.get_groups('read')): |
|
104 if DBG: |
|
105 print ('check_read_access: %s %s does not match %s' % |
|
106 (rdef, user.groups, rdef.get_groups('read'))) |
|
107 # XXX rqlexpr not allowed |
|
108 raise Unauthorized('read', rel.r_type) |
|
109 if DBG: |
|
110 print ('check_read_access: %s %s matches %s' % |
|
111 (rdef, user.groups, rdef.get_groups('read'))) |
|
112 |
|
113 def get_local_checks(cnx, rqlst, solution): |
76 """Check that the given user has credentials to access data read by the |
114 """Check that the given user has credentials to access data read by the |
77 query and return a dict defining necessary "local checks" (i.e. rql |
115 query and return a dict defining necessary "local checks" (i.e. rql |
78 expression in read permission defined in the schema) where no group grants |
116 expression in read permission defined in the schema) where no group grants |
79 him the permission. |
117 him the permission. |
80 |
118 |
81 Returned dictionary's keys are variable names and values the rql expressions |
119 Returned dictionary's keys are variable names and values the rql expressions |
82 for this variable (with the given solution). |
120 for this variable (with the given solution). |
|
121 |
|
122 Raise :exc:`Unauthorized` if access is known to be defined, i.e. if there is |
|
123 no matching group and no local permissions. |
83 """ |
124 """ |
84 # use `term_etype` since we've to deal with rewritten constants here, |
|
85 # when used as an external source by another repository. |
|
86 # XXX what about local read security w/ those rewritten constants... |
|
87 DBG = (server.DEBUG & server.DBG_SEC) and 'read' in server._SECURITY_CAPS |
125 DBG = (server.DEBUG & server.DBG_SEC) and 'read' in server._SECURITY_CAPS |
88 schema = cnx.repo.schema |
126 schema = cnx.repo.schema |
89 if rqlst.where is not None: |
127 user = cnx.user |
90 for rel in rqlst.where.iget_nodes(Relation): |
|
91 # XXX has_text may have specific perm ? |
|
92 if rel.r_type in READ_ONLY_RTYPES: |
|
93 continue |
|
94 rschema = schema.rschema(rel.r_type) |
|
95 if rschema.final: |
|
96 eschema = schema.eschema(term_etype(cnx, rel.children[0], |
|
97 solution, args)) |
|
98 rdef = eschema.rdef(rschema) |
|
99 else: |
|
100 rdef = rschema.rdef(term_etype(cnx, rel.children[0], |
|
101 solution, args), |
|
102 term_etype(cnx, rel.children[1].children[0], |
|
103 solution, args)) |
|
104 if not cnx.user.matching_groups(rdef.get_groups('read')): |
|
105 if DBG: |
|
106 print ('check_read_access: %s %s does not match %s' % |
|
107 (rdef, cnx.user.groups, rdef.get_groups('read'))) |
|
108 # XXX rqlexpr not allowed |
|
109 raise Unauthorized('read', rel.r_type) |
|
110 if DBG: |
|
111 print ('check_read_access: %s %s matches %s' % |
|
112 (rdef, cnx.user.groups, rdef.get_groups('read'))) |
|
113 localchecks = {} |
128 localchecks = {} |
114 # iterate on defined_vars and not on solutions to ignore column aliases |
129 # iterate on defined_vars and not on solutions to ignore column aliases |
115 for varname in rqlst.defined_vars: |
130 for varname in rqlst.defined_vars: |
116 eschema = schema.eschema(solution[varname]) |
131 eschema = schema.eschema(solution[varname]) |
117 if eschema.final: |
132 if eschema.final: |
118 continue |
133 continue |
119 if not cnx.user.matching_groups(eschema.get_groups('read')): |
134 if not user.matching_groups(eschema.get_groups('read')): |
120 erqlexprs = eschema.get_rqlexprs('read') |
135 erqlexprs = eschema.get_rqlexprs('read') |
121 if not erqlexprs: |
136 if not erqlexprs: |
122 ex = Unauthorized('read', solution[varname]) |
137 ex = Unauthorized('read', solution[varname]) |
123 ex.var = varname |
138 ex.var = varname |
124 if DBG: |
139 if DBG: |
125 print ('check_read_access: %s %s %s %s' % |
140 print ('check_read_access: %s %s %s %s' % |
126 (varname, eschema, cnx.user.groups, eschema.get_groups('read'))) |
141 (varname, eschema, user.groups, eschema.get_groups('read'))) |
127 raise ex |
142 raise ex |
128 # don't insert security on variable only referenced by 'NOT X relation Y' or |
143 # don't insert security on variable only referenced by 'NOT X relation Y' or |
129 # 'NOT EXISTS(X relation Y)' |
144 # 'NOT EXISTS(X relation Y)' |
130 varinfo = rqlst.defined_vars[varname].stinfo |
145 varinfo = rqlst.defined_vars[varname].stinfo |
131 if varinfo['selected'] or ( |
146 if varinfo['selected'] or ( |
132 len([r for r in varinfo['relations'] |
147 len([r for r in varinfo['relations'] |
133 if (not schema.rschema(r.r_type).final |
148 if (not schema.rschema(r.r_type).final |
134 and ((isinstance(r.parent, Exists) and r.parent.neged(strict=True)) |
149 and ((isinstance(r.parent, Exists) and r.parent.neged(strict=True)) |
135 or isinstance(r.parent, Not)))]) |
150 or isinstance(r.parent, Not)))]) |
136 != len(varinfo['relations'])): |
151 != |
|
152 len(varinfo['relations'])): |
137 localchecks[varname] = erqlexprs |
153 localchecks[varname] = erqlexprs |
138 return localchecks |
154 return localchecks |
139 |
155 |
140 |
156 |
141 # Plans ####################################################################### |
157 # Plans ####################################################################### |