Changeset 78f2668
- Timestamp:
- Nov 30, 2010 10:48:51 AM (14 years ago)
- Branches:
- axis_example, compt_changes, info-ops, master
- Children:
- 822d31b
- Parents:
- 027b87b
- Location:
- fedd/federation
- Files:
-
- 1 added
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
fedd/federation/access.py
r027b87b r78f2668 124 124 125 125 126 def read_access(self, config, access_obj=None): 127 """ 128 Read an access DB with filename config of the form: 129 (id, id, id) -> attribute, something 130 where the ids can be fedids, strings, or <any> or <none>, attribute is 131 the attribute to assign , and something is any set of charcters. The 132 hash self.access is populated with mappings from those triples to the 133 results of access_obj being called on the remainder of the line (if 134 present). If access_obj is not given, the string itself is entered in 135 the hash. Additionally, a triple with <any> and <none> mapped to None 136 is entered in self.auth with the attribute given. 137 138 Parsing errors result in a self.parse_error exception being raised. 139 access_obj should throw that as well. 140 """ 141 lineno=0 142 name_expr = "["+string.ascii_letters + string.digits + "\.\-_]+" 143 fedid_expr = "fedid:[" + string.hexdigits + "]+" 144 key_name = "(<ANY>|<NONE>|"+fedid_expr + "|"+ name_expr + ")" 145 access_re = re.compile('\('+key_name+'\s*,\s*'+key_name+'\s*,\s*'+ 146 key_name+'\s*\)\s*->\s*([^,]+)\s*(.*)', re.IGNORECASE) 147 148 def parse_name(n): 149 if n.startswith('fedid:'): return fedid(hexstr=n[len('fedid:'):]) 150 else: return n 151 152 def auth_name(n): 153 if isinstance(n, basestring): 154 if n =='<any>' or n =='<none>': return None 155 else: return unicode(n) 156 else: 157 return n 158 def strip_comma(s): 159 s = s.strip() 160 if s.startswith(','): 161 s = s[1:].strip() 162 return s 163 164 if access_obj is None: 165 access_obj = lambda(x): "%s" % x 166 167 f = open(config, "r"); 168 try: 169 for line in f: 170 lineno += 1 171 line = line.strip(); 172 if len(line) == 0 or line.startswith('#'): 173 continue 174 175 # Access line (t, p, u) -> anything 176 m = access_re.match(line) 177 if m != None: 178 access_key = tuple([ parse_name(x) \ 179 for x in m.group(1,2,3)]) 180 attribute = m.group(4) 181 auth_key = tuple([ auth_name(x) for x in access_key]) 182 self.auth.set_attribute(auth_key, attribute) 183 if len(m.group(5)) > 0: 184 access_val = access_obj(strip_comma(m.group(5))) 185 self.access[access_key] = access_val 186 continue 187 188 # Nothing matched to here: unknown line - raise exception 189 f.close() 190 raise self.parse_error( 191 "Unknown statement at line %d of %s" % \ 192 (lineno, config)) 193 finally: 194 if f: f.close() 195 196 def read_abac_access(self, fn, access_obj=None): 126 def read_access(self, fn, access_obj=None): 197 127 """ 198 128 Read an access DB of the form … … 228 158 finally: 229 159 if f: f.close() 230 231 232 def get_users(self, obj):233 """234 Return a list of the IDs of the users in dict235 """236 if obj.has_key('user'):237 return [ unpack_id(u['userID']) \238 for u in obj['user'] if u.has_key('userID') ]239 else:240 return None241 160 242 161 def write_state(self): … … 279 198 280 199 281 282 def permute_wildcards(self, a, p):283 """Return a copy of a with various fields wildcarded.284 285 The bits of p control the wildcards. A set bit is a wildcard286 replacement with the lowest bit being user then project then testbed.287 """288 if p & 1: user = ["<any>"]289 else: user = a[2]290 if p & 2: proj = "<any>"291 else: proj = a[1]292 if p & 4: tb = "<any>"293 else: tb = a[0]294 295 return (tb, proj, user)296 297 def find_access(self, search):298 """299 Search the access DB for a match on this tuple. Return the matching300 access tuple and the user that matched.301 302 NB, if the initial tuple fails to match we start inserting wildcards in303 an order determined by self.project_priority. Try the list of users in304 order (when wildcarded, there's only one user in the list).305 """306 if self.project_priority: perm = (0, 1, 2, 3, 4, 5, 6, 7)307 else: perm = (0, 2, 1, 3, 4, 6, 5, 7)308 309 for p in perm:310 s = self.permute_wildcards(search, p)311 # s[2] is None on an anonymous, unwildcarded request312 if s[2] != None:313 for u in s[2]:314 if self.access.has_key((s[0], s[1], u)):315 return (self.access[(s[0], s[1], u)], u)316 else:317 if self.access.has_key(s):318 return (self.access[s], None)319 return None, None320 321 def lookup_access_base(self, req, fid):322 """323 Determine the allowed access for this request. Return the access and324 which fields are dynamic.325 326 The fedid is needed to construct the request327 """328 user_re = re.compile("user:\s(.*)")329 project_re = re.compile("project:\s(.*)")330 331 # Search keys332 tb = fid333 user = [ user_re.findall(x)[0] for x in req.get('credential', []) \334 if user_re.match(x)]335 project = [ project_re.findall(x)[0] \336 for x in req.get('credential', []) \337 if project_re.match(x)]338 339 if len(project) == 1: project = project[0]340 elif len(project) == 0: project = None341 else:342 raise service_error(service_error.req,343 "More than one project credential")344 345 # Confirm authorization346 for u in user:347 self.log.debug("[lookup_access] Checking access for %s" % \348 ((tb, project, u),))349 if self.auth.check_attribute((tb, project, u), 'access'):350 self.log.debug("[lookup_access] Access granted")351 break352 else:353 self.log.debug("[lookup_access] Access Denied")354 else:355 raise service_error(service_error.access, "Access denied")356 357 # This maps a valid user to the Emulab projects and users to use358 found, user_match = self.find_access((tb, project, user))359 360 return (found, (tb, project, user_match))361 362 363 200 def get_handler(self, path, fid): 201 """ 202 This function is somewhat oddly named. It doesn't get a handler, it 203 handles GETs. Specifically, it handls https GETs for retrieving data 204 from the repository exported by the access server. 205 """ 364 206 self.log.info("Get handler %s %s" % (path, fid)) 365 207 if self.auth.check_attribute(fid, path) and self.userconfdir: -
fedd/federation/emulab_access.py
r027b87b r78f2668 16 16 17 17 from access import access_base 18 from legacy_access import legacy_access 18 19 19 20 from util import * … … 41 42 fl.addHandler(nullHandler()) 42 43 43 class access(access_base ):44 class access(access_base, legacy_access): 44 45 """ 45 46 The implementation of access control based on mapping users to projects. … … 119 120 if self.auth_type == 'legacy': 120 121 if accessdb: 121 self. read_access(accessdb, self.make_access_project)122 self.legacy_read_access(accessdb, self.legacy_access_tuple) 122 123 elif self.auth_type == 'abac': 123 124 self.auth = abac_authorizer(load=self.auth_dir) 124 125 if accessdb: 125 self.read_a bac_access(accessdb, self.make_abac_access_project)126 self.read_access(accessdb, self.access_tuple) 126 127 else: 127 128 raise service_error(service_error.internal, … … 205 206 206 207 @staticmethod 207 def make_access_project(str):208 def legacy_access_tuple(str): 208 209 """ 209 210 Convert a string of the form (id[:resources:resouces], id, id) into a … … 235 236 236 237 @staticmethod 237 def make_abac_access_project(str):238 def access_tuple(str): 238 239 """ 239 240 Convert a string of the form (id, id) into an access_project. This is 240 called by read_a bac_access to convert to local attributes. It returns241 called by read_access to convert to local attributes. It returns 241 242 a tuple of the form (project, user, user) where the two users are 242 243 always the same. … … 255 256 # RequestAccess support routines 256 257 257 def l ookup_access(self, req, fid):258 def legacy_lookup_access(self, req, fid): 258 259 """ 259 260 Look up the local access control information mapped to this fedid and … … 270 271 ru = None 271 272 # This maps a valid user to the Emulab projects and users to use 272 found, match = self.l ookup_access_base(req, fid)273 found, match = self.legacy_lookup_access_base(req, fid) 273 274 tb, project, user = match 274 275 … … 326 327 [ fid ] 327 328 328 def lookup_abac_access(self, req, fid): 329 def lookup_access(self, req, fid): 330 """ 331 Check all the attributes that this controller knows how to map and see 332 if the requester is allowed to use any of them. If so return one. 333 """ 329 334 # Import request credentials into this (clone later??) 330 if self.auth.import_credentials(data_list=req.get('abac_credential', [])): 335 if self.auth.import_credentials( 336 data_list=req.get('abac_credential', [])): 331 337 self.auth.save() 332 338 333 339 # Check every attribute that we know how to map and take the first 334 340 # success. 335 print "%s" %self.auth336 341 for attr in (self.access.keys()): 337 342 if self.auth.check_attribute(fid, attr): … … 491 496 492 497 if self.auth_type == "legacy": 498 found, dyn, owners = self.legacy_lookup_access(req, fid) 499 elif self.auth_type == 'abac': 493 500 found, dyn, owners = self.lookup_access(req, fid) 494 elif self.auth_type == 'abac':495 found, dyn, owners = self.lookup_abac_access(req, fid)496 501 else: 497 502 raise service_error(service_error.internal,
Note: See TracChangeset
for help on using the changeset viewer.