Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1"""Permission library 

2 

3* Computing permissions 

4* Support for the authorization system 

5""" 

6 

7from config import Config as C, Names as N 

8from control.utils import pick as G 

9 

10CT = C.tables 

11CP = C.perm 

12 

13DEFAULT_PERM = CP.default 

14TABLE_PERM = CT.perm 

15 

16NOBODY = N.nobody 

17UNAUTH = N.public 

18AUTH = N.auth 

19EDIT = N.edit 

20OWN = N.own 

21COORD = N.coord 

22OFFICE = N.office 

23SYSTEM = N.system 

24ROOT = N.root 

25 

26ALLOW_OUR = set(CT.userTables) | set(CT.userEntryTables) 

27 

28 

29def checkTable( 

30 auth, table 

31): 

32 """Verify whether user's credentials match the requirements for a table. 

33 

34 Every table can only be listed on the interface if the user has permissions 

35 for it. 

36 The table permissions are configured in `tables.yaml`, under the key `perm`. 

37 For each table the minimal role is stated that can access the table. 

38 

39 If a table is not permitted, then its records are also not permitted, 

40 neither are fields in those records. 

41 

42 However, this holds for the generic interface. Individual tables and records 

43 and fields may be regulated in addition by 

44 `control.workflow.apply.WorkflowItem` conditions, 

45 which can open up and close off material. 

46 

47 Parameters 

48 ---------- 

49 auth: object 

50 The `control.auth.Auth` singleton, from which the group of the current 

51 user can be obtained. 

52 table: string 

53 The table for which permission is required. 

54 

55 Returns 

56 ------- 

57 boolean 

58 """ 

59 

60 require = G(TABLE_PERM, table) 

61 if require is None: 61 ↛ 62line 61 didn't jump to line 62, because the condition on line 61 was never true

62 return False 

63 

64 if require == UNAUTH: 

65 return True 

66 

67 group = auth.groupRep() 

68 

69 if require == NOBODY: 69 ↛ 70line 69 didn't jump to line 70, because the condition on line 69 was never true

70 return False 

71 

72 if require == AUTH: 72 ↛ 73line 72 didn't jump to line 73, because the condition on line 72 was never true

73 return group != UNAUTH 

74 

75 isSuper = group in {OFFICE, SYSTEM, ROOT} 

76 

77 if require == OFFICE: 

78 return isSuper 

79 

80 if require == SYSTEM: 80 ↛ 83line 80 didn't jump to line 83, because the condition on line 80 was never false

81 return group in {SYSTEM, ROOT} 

82 

83 if require == ROOT: 

84 return group == ROOT 

85 

86 if require == COORD: 

87 return group == COORD or isSuper 

88 

89 

90def checkPerm( 

91 require, perm, 

92): 

93 """Verify whether user's credentials match the requirements. 

94 

95 Parameters 

96 ---------- 

97 require: string 

98 The required permission level (see the perm.yaml configuration file under 

99 the key `roles`). 

100 perm: dict 

101 User attributes, in paticular `group` which is the role a user can play on the 

102 basis of his/her identity. 

103 But it also contains attributes that links a user to ceertain records, e.g. the 

104 records of which (s)he is creator/editor, or National Coordinator. 

105 

106 Returns 

107 ------- 

108 boolean 

109 """ 

110 

111 if require == UNAUTH: 

112 return True 

113 

114 group = G(perm, N.group) 

115 

116 if require == NOBODY: 

117 return False 

118 

119 if require == AUTH: 

120 return group != UNAUTH 

121 

122 isSuper = group in {OFFICE, SYSTEM, ROOT} 

123 

124 if require == OFFICE: 

125 return isSuper 

126 

127 if require == SYSTEM: 127 ↛ 128line 127 didn't jump to line 128, because the condition on line 127 was never true

128 return group in {SYSTEM, ROOT} 

129 

130 if require == ROOT: 130 ↛ 131line 130 didn't jump to line 131, because the condition on line 130 was never true

131 return group == ROOT 

132 

133 if require == EDIT: 

134 return group != UNAUTH and (G(perm, N.isEdit) or isSuper) 

135 

136 if require == OWN: 

137 return group != UNAUTH and (G(perm, N.isOwn) or isSuper) 

138 

139 if require == COORD: 139 ↛ exitline 139 didn't return from function 'checkPerm', because the condition on line 139 was never false

140 return group == COORD and G(perm, N.sameCountry) or isSuper 

141 

142 

143def getPermField(table, permRecord, require): 

144 """Determine read/edit permissions for a field in a record in a table. 

145 

146 !!! hint 

147 When it comes to checking a field permission, first get the 

148 record permission, then the field requirements. 

149 Then apply this function to get the result. 

150 

151 Parameters 

152 ---------- 

153 table: string 

154 Where the record resides 

155 permRecord: 

156 Permissions based on the record as a whole. 

157 require: 

158 Permissions required for reading/editing a particular field, 

159 coming from the table specific .yaml files with field specifications. 

160 

161 Returns 

162 ------- 

163 mayRead: boolean 

164 mayEdit: boolean 

165 """ 

166 

167 mayRead = None 

168 if table in ALLOW_OUR: 

169 mayRead = G(permRecord, N.isOur) or None 

170 if mayRead is None: 

171 readRequire = ( 

172 G(DEFAULT_PERM, N.read) 

173 if require is None or N.read not in require 

174 else G(require, N.read) 

175 ) 

176 mayRead = checkPerm(readRequire, permRecord) 

177 

178 editRequire = ( 

179 G(DEFAULT_PERM, N.edit) 

180 if require is None or N.edit not in require 

181 else G(require, N.edit) 

182 ) 

183 mayEdit = checkPerm(editRequire, permRecord) 

184 return (mayRead, mayEdit) 

185 

186 

187def permRecord(context, table, record): 

188 """Determine record permissions. 

189 

190 Various possible relationships between this user and the record will be examined. 

191 

192 Parameters 

193 ---------- 

194 

195 Returns 

196 ------- 

197 group: string 

198 Permission group of current user 

199 country: ObjectId 

200 Country to which the record belongs. Follow the detail-master chain from the 

201 record to the contrib record and read the country from the contrib. 

202 isOwn: boolean 

203 Is the record created by the current user? 

204 isEdit: boolean 

205 Is the record created by the current user or is (s)he in the list of 

206 editors of this record? 

207 sameCountry: boolean 

208 Does the record belong to the same country as the currennt user? 

209 isCoordinated: boolean 

210 Is this record under the jurisdiction of the current user as National 

211 Coordinator? 

212 isOur: boolean 

213 Is this record in the workflow of the current user? 

214 As creator/editor/reviewer/coordinator? 

215 contribId: ObjectId 

216 The id of the contrib to which this record is linked. 

217 

218 These attributes are returned as a `dict`. 

219 """ 

220 auth = context.auth 

221 user = auth.user 

222 uid = G(user, N._id) 

223 group = auth.groupRep() 

224 uCountry = G(user, N.country) 

225 

226 cRecord = {} 

227 aRecord = {} 

228 

229 if table == N.contrib: 

230 cRecord = record 

231 elif table == N.assessment: 

232 aRecord = record 

233 contribId = G(record, N.contrib) 

234 cRecord = context.getItem(N.contrib, contribId) 

235 elif table in {N.review, N.criteriaEntry, N.reviewEntry}: 

236 assessmentId = G(record, N.assessment) 

237 aRecord = context.getItem(N.assessment, assessmentId) 

238 contribId = G(aRecord, N.contrib) 

239 cRecord = context.getItem(N.contrib, contribId) 

240 

241 refCountry = G(cRecord, N.country) 

242 reviewerE = G(aRecord, N.reviewerE) 

243 reviewerF = G(aRecord, N.reviewerF) 

244 reviewers = {reviewerE, reviewerF} - {None} 

245 

246 sameCountry = refCountry is not None and refCountry == uCountry 

247 isAuth = group != UNAUTH and uid is not None 

248 isCreator = uid is not None and uid == G(record, N.creator) 

249 isEditor = uid is not None and uid in (G(record, N.editors) or set()) 

250 isCoordinated = isAuth and sameCountry and group == COORD 

251 isACreator = uid is not None and uid == G(aRecord, N.creator) 

252 isAEditor = uid is not None and uid in (G(aRecord, N.editors) or set()) 

253 isReviewer = uid is not None and uid in reviewers 

254 

255 isOur = table in ALLOW_OUR and ( 

256 isCoordinated 

257 or isCreator 

258 or isEditor 

259 or isACreator 

260 or isAEditor 

261 or isReviewer 

262 ) 

263 

264 return { 

265 N.group: group, 

266 N.country: refCountry, 

267 N.isOwn: isAuth and isCreator, 

268 N.isEdit: isAuth and (isCreator or isEditor), 

269 N.sameCountry: sameCountry, 

270 N.isCoordinated: isCoordinated, 

271 N.isOur: isOur, 

272 N.isReviewer: isReviewer, 

273 N.contribId: G(cRecord, N._id), 

274 }