Changeset 0a49bd7 for fedd/federation
- Timestamp:
- Jan 15, 2011 5:52:15 PM (14 years ago)
- Branches:
- axis_example, compt_changes, info-ops, master
- Children:
- aaf7f41
- Parents:
- ac15159 (diff), 944b746 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - git-author:
- Ted Faber <faber@…> (01/15/11 17:51:40)
- git-committer:
- Ted Faber <faber@…> (01/15/11 17:52:15)
- Location:
- fedd/federation
- Files:
-
- 1 added
- 16 edited
Legend:
- Unmodified
- Added
- Removed
-
fedd/federation/access.py
rac15159 r0a49bd7 234 234 "Unpickling failed: %s") % e) 235 235 236 def append_allocation_authorization(self, aid, attrs, 237 need_state_lock=False, write_state_file=False, state_attr='state'): 238 """ 239 Append the authorization information to system state. By default we 240 assume this is called with the state lock and with a write of the state 241 file in the near future, need_state_lock and write_state_file can 242 override this. The state_attr is the attribute in the access class 243 that holds the per allocation information. Some complex classes use 244 different names for the dict. 245 """ 246 247 for p, a in attrs: 248 self.auth.set_attribute(p, a) 249 self.auth.save() 250 251 if need_state_lock: self.state_lock.acquire() 252 d = getattr(self, state_attr) 253 if aid in d and 'auth' in d[aid]: 254 d[aid]['auth'].update(attrs) 255 if write_state_file: self.write_state() 256 if need_state_lock: self.state_lock.release() 257 258 def clear_allocation_authorization(self, aid, need_state_lock=False, 259 write_state_file=False, state_attr='state'): 260 """ 261 Attrs is a set of attribute principal pairs that need to be removed 262 from the authenticator. Remove them and save the authenticator. See 263 append_allocation_authorization for the various overrides. 264 """ 265 266 if need_state_lock: self.state_lock.acquire() 267 d = getattr(self, state_attr) 268 if aid in d and 'auth' in d[aid]: 269 for p, a in d[aid]['auth']: 270 self.auth.unset_attribute(p, a) 271 d[aid]['auth'] = set() 272 if write_state_file: self.write_state() 273 if need_state_lock: self.state_lock.release() 274 self.auth.save() 275 236 276 def lookup_access(self, req, fid, filter=None, compare=None): 237 277 """ … … 261 301 # Check every attribute that we know how to map and take the first 262 302 # success. 303 fail_proofs = [ ] 263 304 for attr in check: 264 if self.auth.check_attribute(fid, attr.attr): 305 access_ok, proof = self.auth.check_attribute(fid, attr.attr, 306 with_proof=True) 307 if access_ok: 265 308 self.log.debug("Access succeeded for %s %s" % (attr.attr, fid)) 266 309 # XXX: needs to deal with dynamics 267 310 return copy.copy(attr.value), (False, False, False), \ 268 [ fid ] 311 [ fid ], proof 269 312 else: 313 fail_proofs.append(proof) 270 314 self.log.debug("Access failed for %s %s" % (attr.attr, fid)) 271 315 else: 272 raise service_error(service_error.access, "Access denied") 316 raise service_error(service_error.access, "Access denied", 317 proof=fail_proofs) 273 318 274 319 … … 408 453 return (exp, state) 409 454 410 def build_access_response(self, alloc_id, ap, services ):455 def build_access_response(self, alloc_id, ap, services, proof): 411 456 """ 412 457 Create the SOAP response. … … 421 466 msg = { 422 467 'allocID': alloc_id, 468 'proof': proof.to_dict(), 423 469 'fedAttr': [ 424 470 { 'attribute': 'domain', 'value': self.domain } , … … 730 776 except EnvironmentError, e: 731 777 self.log.error("Error deleting directory tree in %s" % e); 778 779 def RequestAccess(self, req, fid): 780 """ 781 Handle an access request. Success here maps the requester into the 782 local access control space and establishes state about that user keyed 783 to a fedid. We also save a copy of the certificate underlying that 784 fedid so this allocation can access configuration information and 785 shared parameters on the experiment controller. 786 """ 787 788 # The dance to get into the request body 789 if req.has_key('RequestAccessRequestBody'): 790 req = req['RequestAccessRequestBody'] 791 else: 792 raise service_error(service_error.req, "No request!?") 793 794 # Base class lookup routine. If this fails, it throws a service 795 # exception denying access that triggers a fault response back to the 796 # caller. 797 found, match, owners, proof = self.lookup_access(req, fid) 798 self.log.info( 799 "[RequestAccess] Access granted to %s with local creds %s" % \ 800 (match, found)) 801 # Make a fedid for this allocation 802 allocID, alloc_cert = generate_fedid(subj="alloc", log=self.log) 803 aid = unicode(allocID) 804 805 # Store the data about this allocation: 806 self.state_lock.acquire() 807 self.state[aid] = { } 808 self.state[aid]['user'] = found 809 self.state[aid]['owners'] = owners 810 self.state[aid]['auth'] = set() 811 # Authorize the creating fedid and the principal representing the 812 # allocation to manipulate it. 813 self.append_allocation_authorization(aid, 814 ((fid, allocID), (allocID, allocID))) 815 self.write_state() 816 self.state_lock.release() 817 818 # Create a directory to stash the certificate in, ans stash it. 819 try: 820 f = open("%s/%s.pem" % (self.certdir, aid), "w") 821 print >>f, alloc_cert 822 f.close() 823 except EnvironmentError, e: 824 raise service_error(service_error.internal, 825 "Can't open %s/%s : %s" % (self.certdir, aid, e)) 826 self.log.debug('[RequestAccess] Returning allocation ID: %s' % allocID) 827 return { 'allocID': { 'fedid': allocID }, 'proof': proof.to_dict() } 828 829 def ReleaseAccess(self, req, fid): 830 """ 831 Release the allocation granted earlier. Access to the allocation is 832 checked and if valid, the state and cached certificate are destroyed. 833 """ 834 # The dance to get into the request body 835 if req.has_key('ReleaseAccessRequestBody'): 836 req = req['ReleaseAccessRequestBody'] 837 else: 838 raise service_error(service_error.req, "No request!?") 839 840 # Pull a key out of the request. One can request to delete an 841 # allocation by a local human readable name or by a fedid. This finds 842 # both choices. 843 try: 844 if 'localname' in req['allocID']: 845 auth_attr = aid = req['allocID']['localname'] 846 elif 'fedid' in req['allocID']: 847 aid = unicode(req['allocID']['fedid']) 848 auth_attr = req['allocID']['fedid'] 849 else: 850 raise service_error(service_error.req, 851 "Only localnames and fedids are understood") 852 except KeyError: 853 raise service_error(service_error.req, "Badly formed request") 854 855 self.log.debug("[ReleaseAccess] deallocation requested for %s", aid) 856 # Confirm access 857 access_ok, proof = self.auth.check_attribute(fid, auth_attr, 858 with_proof=True) 859 if not access_ok: 860 self.log.debug("[ReleaseAccess] deallocation denied for %s", aid) 861 raise service_error(service_error.access, "Access Denied", 862 proof=proof) 863 864 # If there is an allocation in the state, delete it. Note the locking. 865 self.state_lock.acquire() 866 if aid in self.state: 867 self.log.debug("[ReleaseAccess] Found allocation for %s" %aid) 868 self.clear_allocation_authorization(aid) 869 del self.state[aid] 870 self.write_state() 871 self.state_lock.release() 872 # And remove the access cert 873 cf = "%s/%s.pem" % (self.certdir, aid) 874 self.log.debug("[ReleaseAccess] Removing %s" % cf) 875 os.remove(cf) 876 return { 'allocID': req['allocID'], 'proof': proof.to_dict() } 877 else: 878 self.state_lock.release() 879 raise service_error(service_error.req, "No such allocation") -
fedd/federation/authorizer.py
rac15159 r0a49bd7 1 1 #/usr/local/bin/python 2 2 3 from string import join4 3 from tempfile import mkstemp 5 4 from subprocess import call … … 12 11 from service_error import service_error 13 12 from util import abac_pem_type, abac_split_cert 13 from proof import proof 14 14 15 15 … … 116 116 if attrs: attrs.discard(attr) 117 117 118 def check_attribute(self, name, attr ):118 def check_attribute(self, name, attr, with_proof=False): 119 119 """ 120 120 Return True if name has attr (or if attr is global). Tuple names match … … 130 130 self.valid_name(name) 131 131 if attr in self.globals: 132 return True 132 if with_proof: return True, proof("me", name, attr) 133 else: return True 133 134 134 135 if isinstance(name, tuple): … … 137 138 if self.attrs.has_key(lookup): 138 139 if attr in self.attrs[lookup]: 139 return True 140 else: 141 return attr in self.attrs.get(self.auth_name(name), set()) 140 if with_proof: return True, proof("me", name, attr) 141 else: return True 142 # Drop through 143 if with_proof: return False, proof("me", name, attr) 144 else: return False 145 else: 146 if with_proof: 147 return attr in self.attrs.get(self.auth_name(name), set()), \ 148 proof("me", name, attr) 149 else: 150 return attr in self.attrs.get(self.auth_name(name), set()) 142 151 143 152 def set_global_attribute(self, attr): … … 209 218 if self.me is not None and abac_pem_type(self.me) == 'both': 210 219 if self.save_dir: 211 self.key, self.me = abac_split_cert(self.me, 212 keyfile="%s/key.pem" % self.save_dir, 213 certfile = "%s/cert.pem" % self.save_dir) 220 keyfile="%s/key.pem" % self.save_dir 221 certfile = "%s/cert.pem" % self.save_dir 222 223 # Clear a spot for the new key and cert files. 224 for fn in (keyfile, certfile): 225 if os.access(fn, os.F_OK): 226 os.unlink(fn) 227 228 self.key, self.me = abac_split_cert(self.me, keyfile, certfile) 214 229 else: 215 230 raise abac_authorizer.bad_cert_error("Combination " + \ … … 223 238 if rv != 0: 224 239 raise abac_authorizer.bad_name( 225 'Cannot load identity from %s' % me .cert)240 'Cannot load identity from %s' % me) 226 241 else: 227 242 self.fedid = None … … 235 250 if load: 236 251 self.load(load) 252 253 # Modify the pickling operations so that the context and lock are not 254 # pickled 255 256 def __getstate__(self): 257 d = self.__dict__.copy() 258 del d['lock'] 259 del d['context'] 260 return d 261 262 def __setstate__(self, d): 263 # Import everything from the pickle dict (except what we excluded in 264 # __getstate__) 265 self.__dict__.update(d) 266 # Initialize the unpicklables 267 self.context = ABAC.Context() 268 self.lock = Lock() 237 269 238 270 @staticmethod … … 352 384 353 385 354 def check_attribute(self, name, attr): 355 # XXX proof soon 386 def check_attribute(self, name, attr, with_proof=False): 356 387 if isinstance(name, tuple): 357 388 raise abac_authorizer.bad_name( … … 376 407 # Sigh. Unicode vs swig and swig seems to lose. Make sure 377 408 # everything we pass into ABAC is a str not a unicode. 378 rv, p roof= self.context.query(a, n)409 rv, p = self.context.query(a, n) 379 410 # XXX delete soon 380 if not rv and attr in self.globals: rv = True 381 self.lock.release() 382 383 return rv 411 if not rv and attr in self.globals: 412 rv = True 413 p = None 414 self.lock.release() 415 if with_proof: return rv, proof(self.fedid, name, a, p) 416 else: return rv 384 417 385 418 def set_global_attribute(self, attr): … … 421 454 if not os.access(dir, os.F_OK): 422 455 os.mkdir(dir) 423 # These are unpicklable, so set them aside424 context = self.context425 lock = self.lock426 self.context = None427 self.lock = None428 456 429 457 f = open("%s/state" % dir, "w") … … 433 461 if not os.access("%s/certs" %dir, os.F_OK): 434 462 os.mkdir("%s/certs" % dir) 435 seenid = set() 436 seenattr = set() 437 438 #restore unpicklable state 439 self.context = context 440 self.lock = lock 441 #remove old certs 463 464 # Clear the certs subdir 442 465 for fn in [ f for f in os.listdir("%s/certs" % dir) \ 443 466 if abac_authorizer.cred_file_re.match(f)]: 444 467 os.unlink('%s/certs/%s' % (dir, fn)) 468 469 # Save the context 445 470 ii = 0 446 471 ai = 0 472 seenid = set() 473 seenattr = set() 447 474 for c in self.context.credentials(): 448 475 id = c.issuer_cert() … … 463 490 seenattr.add(attr) 464 491 except EnvironmentError, e: 465 # If we've mislaid self.lock, release lock (they're the same object) 466 if self.lock: self.lock.release() 467 elif lock: lock.release() 492 self.lock.release() 468 493 raise e 469 494 except pickle.PickleError, e: 470 # If we've mislaid self.lock, release lock (they're the same object) 471 if self.lock: self.lock.release() 472 elif lock: lock.release() 495 self.lock.release() 473 496 raise e 474 497 self.lock.release() -
fedd/federation/client_lib.py
rac15159 r0a49bd7 7 7 8 8 from string import join 9 from datetime import datetime 9 10 10 11 11 12 from fedid import fedid 12 from util import fedd_ssl_context 13 from util import fedd_ssl_context, file_expanding_opts 13 14 from remote_service import service_caller 14 15 from service_error import service_error … … 17 18 18 19 19 class client_opts( OptionParser):20 class client_opts(file_expanding_opts): 20 21 """ 21 22 Standatd set of options that all clients talking to fedd can probably use. 22 23 Client code usually specializes this. 23 24 """ 25 24 26 def __init__(self): 25 OptionParser.__init__(self, usage="%prog [opts] (--help for details)", 27 file_expanding_opts.__init__(self, 28 usage="%prog [opts] (--help for details)", 26 29 version="0.1") 27 30 28 self.add_option("--cert", action="store", dest="cert", 31 self.add_option("--cert", action="callback", dest="cert", 32 callback=self.expand_file, 29 33 type="string", help="my certificate file") 30 self.add_option("--abac", action="store", dest="abac_dir", 31 type="string", help="Directory with abac certs") 34 self.add_option("--auth_log", action="callback", dest="auth_log", 35 callback=self.expand_file, default=None, 36 type="string", help="Log authentication decisions to this file") 37 self.add_option("--abac", action="callback", dest="abac_dir", 38 callback=self.expand_file, 39 type="string", default=os.path.expanduser('~/.abac'), 40 help="Directory with abac certs") 41 self.add_option('--no_abac', action='store_const', const=None, 42 dest='abac_dir', help='Do not use abac authorization') 32 43 self.add_option( "--debug", action="count", dest="debug", 33 44 default=0, help="Set debug. Repeat for more information") … … 35 46 dest="serialize_only", default=False, 36 47 help="Print the SOAP request that would be sent and exit") 37 self.add_option("--trusted", action="store", dest="trusted", 48 self.add_option("--trusted", action="callback", dest="trusted", 49 callback=self.expand_file, 38 50 type="string", help="Trusted certificates (required)") 39 51 self.add_option("--url", action="store", dest="url", … … 45 57 const=sys.stderr, help="Print SOAP exchange to stderr") 46 58 47 def exit_with_fault(exc, out=sys.stderr): 59 def log_authentication(fn, action, outcome, proof): 60 f = open(fn, 'a') 61 print >>f, '%s %s at %s' % (action, outcome, datetime.now()) 62 if isinstance(proof, list): 63 for p in proof: 64 print >>f, p.to_xml() 65 else: 66 print >>f, proof.to_xml() 67 f.close() 68 69 70 def exit_with_fault(exc, action, opts, out=sys.stderr): 48 71 """ 49 72 Print an error message and exit. exc is the RPCException that caused the … … 64 87 code = -1 65 88 89 if exc.code == service_error.access and opts.auth_log: 90 try: 91 log_authentication(opts.auth_log, action, 'failed', exc.proof) 92 except EnvironmentError, e: 93 print >>sys.stderr, "Failed to log to %s: %s" % \ 94 (e.filename, e.strerror) 95 66 96 print>>out, codestr 67 97 print>>out, "Description: %s" % exc.desc … … 73 103 XMLPRC calls. 74 104 """ 75 def __init__(self, desc=None, code=None, errstr=None ):105 def __init__(self, desc=None, code=None, errstr=None, proof=None): 76 106 RuntimeError.__init__(self) 77 107 self.desc = desc … … 79 109 else: self.code = -1 80 110 self.errstr = errstr 111 self.proof = proof 81 112 82 113 class CertificateMismatchError(RuntimeError): pass … … 98 129 ''' 99 130 rv = [ ] 100 if dir :131 if dir and os.path.isdir(dir): 101 132 for fn in ["%s/%s" % (dir, p) for p in os.listdir(dir) \ 102 133 if os.path.isfile("%s/%s" % (dir,p))]: … … 138 169 elif 'FEDD_URL' in os.environ: url = os.environ['FEDD_URL'] 139 170 else: url = default_url 171 172 if opts.abac_dir: 173 if not os.access(opts.abac_dir, os.F_OK): 174 raise RuntimeError("No ABAC directory: %s" % opts.abac_dir) 175 elif not os.path.isdir(opts.abac_dir): 176 raise RuntimeError("ABAC directory not a directory: %s" \ 177 % opts.abac_dir) 178 elif not os.access(opts.abac_dir, os.W_OK): 179 raise RuntimeError("Cannot write to ABAC directory: %s" \ 180 % opts.abac_dir) 181 140 182 141 183 … … 189 231 except service_error, e: 190 232 raise RPCException(desc=e.desc, code=e.code, 191 errstr=e.code_string() )233 errstr=e.code_string(), proof=e.proof) 192 234 elif transport == "xmlrpc": 193 235 if serialize_only: -
fedd/federation/deter_internal_access.py
rac15159 r0a49bd7 142 142 } 143 143 144 def RequestAccess(self, req, fid): 145 """ 146 Handle the access request. Proxy if not for us. 147 148 Parse out the fields and make the allocations or rejections if for us, 149 otherwise, assuming we're willing to proxy, proxy the request out. 150 """ 151 152 # The dance to get into the request body 153 if req.has_key('RequestAccessRequestBody'): 154 req = req['RequestAccessRequestBody'] 155 else: 156 raise service_error(service_error.req, "No request!?") 157 158 found, match, owners = self.lookup_access(req, fid) 159 # keep track of what's been added 160 allocID, alloc_cert = generate_fedid(subj="alloc", log=self.log) 161 aid = unicode(allocID) 162 163 self.state_lock.acquire() 164 self.state[aid] = { } 165 self.state[aid]['user'] = found 166 self.state[aid]['owners'] = owners 167 self.state[aid]['vlan'] = None 168 self.write_state() 169 self.state_lock.release() 170 self.auth.set_attribute(fid, allocID) 171 self.auth.set_attribute(allocID, allocID) 172 self.auth.save() 173 174 try: 175 f = open("%s/%s.pem" % (self.certdir, aid), "w") 176 print >>f, alloc_cert 177 f.close() 178 except EnvironmentError, e: 179 raise service_error(service_error.internal, 180 "Can't open %s/%s : %s" % (self.certdir, aid, e)) 181 return { 'allocID': { 'fedid': allocID } } 182 183 def ReleaseAccess(self, req, fid): 184 # The dance to get into the request body 185 if req.has_key('ReleaseAccessRequestBody'): 186 req = req['ReleaseAccessRequestBody'] 187 else: 188 raise service_error(service_error.req, "No request!?") 189 190 # Local request 191 try: 192 if req['allocID'].has_key('localname'): 193 auth_attr = aid = req['allocID']['localname'] 194 elif req['allocID'].has_key('fedid'): 195 aid = unicode(req['allocID']['fedid']) 196 auth_attr = req['allocID']['fedid'] 197 else: 198 raise service_error(service_error.req, 199 "Only localnames and fedids are understood") 200 except KeyError: 201 raise service_error(service_error.req, "Badly formed request") 202 203 self.log.debug("[access] deallocation requested for %s", aid) 204 if not self.auth.check_attribute(fid, auth_attr): 205 self.log.debug("[access] deallocation denied for %s", aid) 206 raise service_error(service_error.access, "Access Denied") 207 208 self.state_lock.acquire() 209 if self.state.has_key(aid): 210 self.log.debug("Found allocation for %s" %aid) 211 del self.state[aid] 212 self.write_state() 213 self.state_lock.release() 214 # And remove the access cert 215 cf = "%s/%s.pem" % (self.certdir, aid) 216 self.log.debug("Removing %s" % cf) 217 os.remove(cf) 218 return { 'allocID': req['allocID'] } 219 else: 220 self.state_lock.release() 221 raise service_error(service_error.req, "No such allocation") 144 # RequestAccess and ReleaseAccess come from the base 222 145 223 146 def extract_parameters(self, top): … … 292 215 aid = "%s" % auth_attr 293 216 attrs = req.get('fedAttr', []) 294 if not self.auth.check_attribute(fid, auth_attr): 217 access_ok, proof = self.auth.check_attribute(fid, auth_attr, 218 with_proof=True) 219 if not access_ok: 295 220 raise service_error(service_error.access, "Access denied") 296 221 else: … … 348 273 'allocID': req['allocID'], 349 274 'allocationLog': logv, 350 'segmentdescription': { 'topdldescription': rtopo.to_dict() } 275 'segmentdescription': { 'topdldescription': rtopo.to_dict() }, 276 'proof': proof.to_dict(), 351 277 } 352 278 retval = copy.deepcopy(self.state[aid]['started']) … … 366 292 367 293 self.log.debug("Terminate request for %s" %aid) 368 if not self.auth.check_attribute(fid, auth_attr): 294 access_ok, proof = self.auth.check_attribute(fid, auth_attr, 295 with_proof=True) 296 if not access_ok: 369 297 raise service_error(service_error.access, "Access denied") 370 298 … … 385 313 self.state[aid]['vlan'] = None 386 314 self.state_lock.release() 387 return { 'allocID': req['allocID'] }315 return { 'allocID': req['allocID'], 'proof': proof.to_dict() } -
fedd/federation/dragon_access.py
rac15159 r0a49bd7 122 122 else: raise self.parse_error("Repo should be in parens"); 123 123 124 def RequestAccess(self, req, fid): 125 """ 126 Handle the access request. 127 128 Parse out the fields and make the allocations or rejections if for us, 129 otherwise, assuming we're willing to proxy, proxy the request out. 130 """ 131 132 # The dance to get into the request body 133 if req.has_key('RequestAccessRequestBody'): 134 req = req['RequestAccessRequestBody'] 135 else: 136 raise service_error(service_error.req, "No request!?") 137 138 if req.has_key('destinationTestbed'): 139 dt = unpack_id(req['destinationTestbed']) 140 141 # Request for this fedd 142 found, match, owners = self.lookup_access(req, fid) 143 # keep track of what's been added 144 allocID, alloc_cert = generate_fedid(subj="alloc", log=self.log) 145 aid = unicode(allocID) 146 147 self.state_lock.acquire() 148 self.state[aid] = { } 149 self.state[aid]['user'] = found 150 self.state[aid]['owners'] = owners 151 self.write_state() 152 self.state_lock.release() 153 self.auth.set_attribute(fid, allocID) 154 self.auth.set_attribute(allocID, allocID) 155 self.auth.save() 156 157 try: 158 f = open("%s/%s.pem" % (self.certdir, aid), "w") 159 print >>f, alloc_cert 160 f.close() 161 except EnvironmentError, e: 162 raise service_error(service_error.internal, 163 "Can't open %s/%s : %s" % (self.certdir, aid, e)) 164 return { 'allocID': { 'fedid': allocID } } 165 166 def ReleaseAccess(self, req, fid): 167 # The dance to get into the request body 168 if req.has_key('ReleaseAccessRequestBody'): 169 req = req['ReleaseAccessRequestBody'] 170 else: 171 raise service_error(service_error.req, "No request!?") 172 173 try: 174 if req['allocID'].has_key('localname'): 175 auth_attr = aid = req['allocID']['localname'] 176 elif req['allocID'].has_key('fedid'): 177 aid = unicode(req['allocID']['fedid']) 178 auth_attr = req['allocID']['fedid'] 179 else: 180 raise service_error(service_error.req, 181 "Only localnames and fedids are understood") 182 except KeyError: 183 raise service_error(service_error.req, "Badly formed request") 184 185 self.log.debug("[access] deallocation requested for %s", aid) 186 if not self.auth.check_attribute(fid, auth_attr): 187 self.log.debug("[access] deallocation denied for %s", aid) 188 raise service_error(service_error.access, "Access Denied") 189 190 self.state_lock.acquire() 191 if self.state.has_key(aid): 192 self.log.debug("Found allocation for %s" %aid) 193 del self.state[aid] 194 self.write_state() 195 self.state_lock.release() 196 # And remove the access cert 197 cf = "%s/%s.pem" % (self.certdir, aid) 198 self.log.debug("Removing %s" % cf) 199 os.remove(cf) 200 return { 'allocID': req['allocID'] } 201 else: 202 self.state_lock.release() 203 raise service_error(service_error.req, "No such allocation") 124 # RequestAccess and ReleaseAccess come from the base class 204 125 205 126 def extract_parameters(self, top): … … 497 418 return (repo, alloc_log) 498 419 499 def finalize_experiment(self, topo, vlan_no, gri, aid, alloc_id ):420 def finalize_experiment(self, topo, vlan_no, gri, aid, alloc_id, proof): 500 421 """ 501 422 Place the relevant information in the global state block, and prepare … … 521 442 'topdldescription': rtopo.to_dict() 522 443 }, 444 'proof': proof.to_dict(), 523 445 } 524 446 retval = copy.deepcopy(self.state[aid]['started']) … … 541 463 aid = "%s" % auth_attr 542 464 attrs = req.get('fedAttr', []) 543 if not self.auth.check_attribute(fid, auth_attr): 465 access_ok, proof = self.auth.check_attribute(fid, auth_attr, 466 with_proof=True) 467 if not access_ok: 544 468 raise service_error(service_error.access, "Access denied") 545 469 else: … … 587 511 if gri: 588 512 return self.finalize_experiment(topo, vlan_no, gri, aid, 589 req['allocID'] )513 req['allocID'], proof) 590 514 elif err: 591 515 raise service_error(service_error.federant, … … 605 529 self.log.debug("Terminate request for %s" %aid) 606 530 attrs = req.get('fedAttr', []) 607 if not self.auth.check_attribute(fid, auth_attr): 531 access_ok, proof = self.auth.check_attribute(fid, auth_attr, 532 with_proof=True) 533 if not access_ok: 608 534 raise service_error(service_error.access, "Access denied") 609 535 … … 628 554 self.log.debug("Stop segment for GRI: %s" %gri) 629 555 self.stop_segment(user, gri) 630 return { 'allocID': req['allocID'] }556 return { 'allocID': req['allocID'], 'proof': proof.to_dict() } -
fedd/federation/emulab_access.py
rac15159 r0a49bd7 24 24 from service_error import service_error 25 25 from remote_service import xmlrpc_handler, soap_handler, service_caller 26 from proof import proof as access_proof 26 27 27 28 import httplib … … 254 255 'Bad mapping (unbalanced parens or more than 1 comma)') 255 256 256 257 257 # RequestAccess support routines 258 258 … … 384 384 self.state_lock.acquire() 385 385 self.allocation[aid] = { } 386 self.allocation[aid]['auth'] = set() 386 387 try: 387 388 pname = ap['project']['name']['localname'] … … 480 481 481 482 if self.auth_type == "legacy": 482 found, dyn, owners = self.legacy_lookup_access(req, fid) 483 found, dyn, owners= self.legacy_lookup_access(req, fid) 484 proof = access_proof("me", fid, "create") 483 485 elif self.auth_type == 'abac': 484 found, dyn, owners = self.lookup_access(req, fid, filter=pf)486 found, dyn, owners, proof = self.lookup_access(req, fid, filter=pf) 485 487 else: 486 488 raise service_error(service_error.internal, … … 511 513 for k, v in svc_state.items(): 512 514 self.allocation[aid][k] = v 515 self.append_allocation_authorization(aid, 516 set([(o, allocID) for o in owners]), state_attr='allocation') 513 517 self.write_state() 514 518 self.state_lock.release() 515 # Give the owners the right to change this allocation516 for o in owners:517 self.auth.set_attribute(o, allocID)518 self.auth.save()519 519 try: 520 520 f = open("%s/%s.pem" % (self.certdir, aid), "w") … … 525 525 "Can't open %s/%s : %s" % (self.certdir, aid, e)) 526 526 resp = self.build_access_response({ 'fedid': allocID } , 527 ap, services )527 ap, services, proof) 528 528 return resp 529 529 … … 572 572 self.log.debug("[access] deallocation requested for %s by %s" % \ 573 573 (aid, fid)) 574 if not self.auth.check_attribute(fid, auth_attr): 574 access_ok, proof = self.auth.check_attribute(fid, auth_attr, 575 with_proof=True) 576 if not access_ok: 575 577 self.log.debug("[access] deallocation denied for %s", aid) 576 578 raise service_error(service_error.access, "Access Denied") … … 591 593 if aid in self.allocation: 592 594 self.log.debug("Found allocation for %s" %aid) 595 self.clear_allocation_authorization(aid, state_attr='allocation') 593 596 for k in self.allocation[aid]['keys']: 594 597 kk = "%s:%s" % k … … 625 628 self.log.debug("Removing %s" % cf) 626 629 os.remove(cf) 627 return { 'allocID': req['allocID'] }630 return { 'allocID': req['allocID'], 'proof': proof.to_dict() } 628 631 else: 629 632 self.state_lock.release() … … 998 1001 return (ename, proj, user, pubkey_base, secretkey_base, alloc_log) 999 1002 1000 def finalize_experiment(self, starter, topo, aid, alloc_id ):1003 def finalize_experiment(self, starter, topo, aid, alloc_id, proof): 1001 1004 """ 1002 1005 Store key bits of experiment state in the global repository, including … … 1023 1026 'topdldescription': topo.clone().to_dict() 1024 1027 }, 1025 'embedding': embedding 1028 'embedding': embedding, 1029 'proof': proof.to_dict(), 1026 1030 } 1027 1031 retval = copy.copy(self.allocation[aid]['started']) … … 1047 1051 aid = "%s" % auth_attr 1048 1052 attrs = req.get('fedAttr', []) 1049 if not self.auth.check_attribute(fid, auth_attr): 1053 1054 access_ok, proof = self.auth.check_attribute(fid, auth_attr, 1055 with_proof=True) 1056 if not access_ok: 1050 1057 raise service_error(service_error.access, "Access denied") 1051 1058 else: … … 1113 1120 1114 1121 if rv: 1115 return self.finalize_experiment(starter, topo, aid, req['allocID']) 1122 return self.finalize_experiment(starter, topo, aid, req['allocID'], 1123 proof) 1116 1124 elif err: 1117 1125 raise service_error(service_error.federant, … … 1129 1137 aid = "%s" % auth_attr 1130 1138 attrs = req.get('fedAttr', []) 1131 if not self.auth.check_attribute(fid, auth_attr): 1139 1140 access_ok, proof = self.auth.check_attribute(fid, auth_attr, 1141 with_proof=True) 1142 if not access_ok: 1132 1143 raise service_error(service_error.access, "Access denied") 1133 1144 … … 1158 1169 debug=self.create_debug, boss=self.boss, cert=self.xmlrpc_cert) 1159 1170 stopper(self, user, proj, ename) 1160 return { 'allocID': req['allocID'] }1171 return { 'allocID': req['allocID'], 'proof': proof.to_dict() } -
fedd/federation/experiment_control.py
rac15159 r0a49bd7 151 151 accessdb_file = config.get("experiment_control", "accessdb") 152 152 153 self.ssh_pubkey_file = config.get("experiment_control",154 "ssh_pubkey_file")155 self.ssh_privkey_file = config.get("experiment_control",156 "ssh_privkey_file")157 153 dt = config.get("experiment_control", "direct_transit") 158 154 self.auth_type = config.get('experiment_control', 'auth_type') \ … … 209 205 raise service_error(service_error.internal, 210 206 "Unknown auth_type: %s" % self.auth_type) 211 212 213 if self.ssh_pubkey_file:214 try:215 f = open(self.ssh_pubkey_file, 'r')216 self.ssh_pubkey = f.read()217 f.close()218 except EnvironmentError:219 raise service_error(service_error.internal,220 "Cannot read sshpubkey")221 else:222 raise service_error(service_error.internal,223 "No SSH public key file?")224 225 if not self.ssh_privkey_file:226 raise service_error(service_error.internal,227 "No SSH public key file?")228 229 207 230 208 if mapdb_file: … … 801 779 self.response = None 802 780 self.node = { } 781 self.proof = None 803 782 804 783 def make_map(self, resp): … … 850 829 self.log_collector.write(line) 851 830 self.make_map(r['StartSegmentResponseBody']) 831 if 'proof' in r: self.proof = r['proof'] 852 832 self.response = r 853 833 else: … … 1021 1001 # mapping. 1022 1002 embedding = [ ] 1003 proofs = { } 1023 1004 for s in starters: 1024 1005 for k, v in s.node.items(): … … 1028 1009 'testbed': s.testbed 1029 1010 }) 1011 if s.proof: 1012 proofs[s.testbed] = s.proof 1030 1013 log.info("[start_segment]: Experiment %s active" % eid) 1031 1014 … … 1044 1027 top.to_dict() 1045 1028 self.state[eid]['embedding'] = embedding 1029 # Append startup proofs 1030 for f in self.state[eid]['federant']: 1031 if 'name' in f and 'localname' in f['name']: 1032 if f['name']['localname'] in proofs: 1033 f['proof'].append(proofs[f['name']['localname']]) 1034 1046 1035 if self.state_filename: self.write_state() 1047 1036 self.state_lock.release() … … 1061 1050 if isinstance(e.software, list): e.software.extend(s) 1062 1051 else: e.software = s 1052 1053 def append_experiment_authorization(self, expid, attrs, 1054 need_state_lock=True): 1055 """ 1056 Append the authorization information to system state 1057 """ 1058 1059 for p, a in attrs: 1060 self.auth.set_attribute(p, a) 1061 self.auth.save() 1062 1063 if need_state_lock: self.state_lock.acquire() 1064 self.state[expid]['auth'].update(attrs) 1065 if self.state_filename: self.write_state() 1066 if need_state_lock: self.state_lock.release() 1067 1068 def clear_experiment_authorization(self, expid, need_state_lock=True): 1069 """ 1070 Attrs is a set of attribute principal pairs that need to be removed 1071 from the authenticator. Remove them and save the authenticator. 1072 """ 1073 1074 if need_state_lock: self.state_lock.acquire() 1075 if expid in self.state and 'auth' in self.state[expid]: 1076 for p, a in self.state[expid]['auth']: 1077 self.auth.unset_attribute(p, a) 1078 self.state[expid]['auth'] = set() 1079 if self.state_filename: self.write_state() 1080 if need_state_lock: self.state_lock.release() 1081 self.auth.save() 1063 1082 1064 1083 … … 1087 1106 status = self.state[eid].get('experimentStatus', None) 1088 1107 if status and status == 'failed': 1089 # remove the old access attribute 1090 self. auth.unset_attribute(fid, old_expid)1091 self.auth.save()1108 # remove the old access attributes 1109 self.clear_experiment_authorization(eid, 1110 need_state_lock=False) 1092 1111 overwrite = True 1093 1112 del self.state[eid] … … 1105 1124 'owner': fid, 1106 1125 'log' : [], 1126 'auth': set(), 1107 1127 } 1108 1128 self.state[expid] = self.state[eid] 1109 1110 1129 if self.state_filename: self.write_state() 1130 self.state_lock.release() 1111 1131 else: 1112 1132 eid = self.exp_stem … … 1126 1146 'owner': fid, 1127 1147 'log' : [], 1148 'auth': set(), 1128 1149 } 1129 1150 self.state[expid] = self.state[eid] 1130 if self.state_filename: self.write_state() 1131 self.state_lock.release() 1151 if self.state_filename: self.write_state() 1152 self.state_lock.release() 1153 1154 # Let users touch the state. Authorize this fid and the expid itself 1155 # to touch the experiment, as well as allowing th eoverrides. 1156 self.append_experiment_authorization(eid, 1157 set([(fid, expid), (expid,expid)] + \ 1158 [ (o, expid) for o in self.overrides])) 1132 1159 1133 1160 return eid … … 1288 1315 raise service_error(service_error.protocol, 1289 1316 "Bad proxy response") 1317 if 'proof' not in r: 1318 raise service_error(service_error.protocol, 1319 "Bad access response (no access proof)") 1290 1320 1291 1321 tbparam[tb] = { 1292 1322 "allocID" : r['allocID'], 1293 1323 "uri": uri, 1324 "proof": [ r['proof'] ], 1294 1325 } 1295 1326 … … 1337 1368 topo[tb].make_indices() 1338 1369 1370 def confirm_software(self, top): 1371 """ 1372 Make sure that the software to be loaded in the topo is all available 1373 before we begin making access requests, etc. This is a subset of 1374 wrangle_software. 1375 """ 1376 pkgs = set([ d for i, d in self.fedkit + self.gatewaykit ]) 1377 pkgs.update([x.location for e in top.elements for x in e.software]) 1378 1379 for pkg in pkgs: 1380 loc = pkg 1381 1382 scheme, host, path = urlparse(loc)[0:3] 1383 dest = os.path.basename(path) 1384 if not scheme: 1385 if not loc.startswith('/'): 1386 loc = "/%s" % loc 1387 loc = "file://%s" %loc 1388 # NB: if scheme was found, loc == pkg 1389 try: 1390 u = urlopen(loc) 1391 u.close() 1392 except Exception, e: 1393 raise service_error(service_error.req, 1394 "Cannot open %s: %s" % (loc, e)) 1395 return True 1396 1339 1397 def wrangle_software(self, expid, top, topo, tbparams): 1340 1398 """ … … 1349 1407 softdir ="%s/%s" % ( self.repodir, linkpath) 1350 1408 softmap = { } 1351 # These are in a list of tuples format (each kit). This comprehension 1352 # unwraps them into a single list of tuples that initilaizes the set of 1353 # tuples. 1354 pkgs = set([ t for l in [self.fedkit, self.gatewaykit] \ 1355 for p, t in l ]) 1356 pkgs.update([x.location for e in top.elements \ 1357 for x in e.software]) 1409 1410 # self.fedkit and self.gateway kit are lists of tuples of 1411 # (install_location, download_location) this extracts the download 1412 # locations. 1413 pkgs = set([ d for i, d in self.fedkit + self.gatewaykit ]) 1414 pkgs.update([x.location for e in top.elements for x in e.software]) 1358 1415 try: 1359 1416 os.makedirs(softdir) … … 1362 1419 "Cannot create software directory: %s" % e) 1363 1420 # The actual copying. Everything's converted into a url for copying. 1421 auth_attrs = set() 1364 1422 for pkg in pkgs: 1365 1423 loc = pkg … … 1371 1429 loc = "/%s" % loc 1372 1430 loc = "file://%s" %loc 1431 # NB: if scheme was found, loc == pkg 1373 1432 try: 1374 1433 u = urlopen(loc) … … 1394 1453 ( self.repo_url, path, dest) 1395 1454 1396 # Allow the individual segments to access the software. 1397 for tb in tbparams.keys(): 1398 self.auth.set_attribute(tbparams[tb]['allocID']['fedid'], 1399 "/%s/%s" % ( path, dest)) 1400 self.auth.save() 1455 # Allow the individual segments to access the software by assigning 1456 # an attribute to each testbed allocation that encodes the data to 1457 # be released. This expression collects the data for each run of 1458 # the loop. 1459 auth_attrs.update([ 1460 (tbparams[tb]['allocID']['fedid'], "/%s/%s" % ( path, dest)) \ 1461 for tb in tbparams.keys()]) 1462 1463 self.append_experiment_authorization(expid, auth_attrs) 1401 1464 1402 1465 # Convert the software locations in the segments into the local … … 1428 1491 self.auth.save() 1429 1492 1430 if not self.auth.check_attribute(fid, 'new'): 1431 raise service_error(service_error.access, "New access denied") 1493 access_ok, proof = self.auth.check_attribute(fid, 'new', 1494 with_proof=True) 1495 1496 if not access_ok: 1497 raise service_error(service_error.access, "New access denied", 1498 proof=[proof]) 1432 1499 1433 1500 try: … … 1468 1535 state='empty') 1469 1536 1470 # Let users touch the state1471 self.auth.set_attribute(fid, expid)1472 self.auth.set_attribute(expid, expid)1473 # Override fedids can manipulate state as well1474 for o in self.overrides:1475 self.auth.set_attribute(o, expid)1476 self.auth.save()1477 1478 1537 rv = { 1479 1538 'experimentID': [ … … 1481 1540 ], 1482 1541 'experimentStatus': 'empty', 1483 'experimentAccess': { 'X509' : expcert } 1542 'experimentAccess': { 'X509' : expcert }, 1543 'proof': proof.to_dict(), 1484 1544 } 1485 1545 … … 1609 1669 return top 1610 1670 1611 def get_testbed_services(self, req ):1671 def get_testbed_services(self, req, testbeds): 1612 1672 """ 1613 1673 Parse the services section of the request into into two dicts mapping … … 1700 1760 "Cannot copy keyfiles: %s" % e) 1701 1761 1702 # Allow the individual testbeds to access the configuration files .1703 for tb in tbparams.keys():1704 asignee = tbparams[tb]['allocID']['fedid']1705 for f in ("hosts", gw_secretkey_base, gw_pubkey_base):1706 self.auth.set_attribute(asignee, "%s/%s" %\1707 (configpath, f))1708 self.auth.save()1762 # Allow the individual testbeds to access the configuration files, 1763 # again by setting an attribute for the relevant pathnames on each 1764 # allocation principal. Yeah, that's a long list comprehension. 1765 self.append_experiment_authorization(expid, set([ 1766 (tbparams[tb]['allocID']['fedid'], "%s/%s" % (configpath, f)) \ 1767 for tb in tbparams.keys() \ 1768 for f in ("hosts", gw_secretkey_base, gw_pubkey_base)])) 1709 1769 1710 1770 attrs = [ … … 1752 1812 raise service_error(service_error.req, "No request?") 1753 1813 1754 self.check_experiment_access(fid, key)1814 proof = self.check_experiment_access(fid, key) 1755 1815 1756 1816 self.state_lock.acquire() 1757 1817 if self.state.has_key(key): 1758 1818 if self.state[key].has_key('vtopo'): 1759 rv = { 'experiment' : {keytype: key },\ 1760 'vtopo': self.state[key]['vtopo'],\ 1819 rv = { 'experiment' : {keytype: key }, 1820 'vtopo': self.state[key]['vtopo'], 1821 'proof': proof.to_dict(), 1761 1822 } 1762 1823 else: … … 1796 1857 raise service_error(service_error.req, "No request?") 1797 1858 1798 self.check_experiment_access(fid, key)1859 proof = self.check_experiment_access(fid, key) 1799 1860 1800 1861 self.state_lock.acquire() 1801 1862 if self.state.has_key(key): 1802 1863 if self.state[key].has_key('vis'): 1803 rv = { 'experiment' : {keytype: key },\ 1804 'vis': self.state[key]['vis'],\ 1864 rv = { 'experiment' : {keytype: key }, 1865 'vis': self.state[key]['vis'], 1866 'proof': proof.to_dict(), 1805 1867 } 1806 1868 else: … … 1823 1885 between when it was started and the beginning of resource allocation. 1824 1886 This is basically the information about each local allocation. This 1825 fills in the values of the placeholder allocation in the state. 1887 fills in the values of the placeholder allocation in the state. It 1888 also collects the access proofs and returns them as dicts for a 1889 response message. 1826 1890 """ 1827 1891 # save federant information … … 1831 1895 'allocID' : tbparams[k]['allocID'], 1832 1896 'uri': tbparams[k]['uri'], 1897 'proof': tbparams[k]['proof'], 1833 1898 } 1834 1899 … … 1841 1906 [ tbparams[tb]['federant'] for tb in tbparams.keys() \ 1842 1907 if tbparams[tb].has_key('federant') ] 1908 # Access proofs for the response message 1909 proofs = [copy.deepcopy(p) for k in tbparams.keys()\ 1910 for p in tbparams[k]['federant']['proof']] 1843 1911 if self.state_filename: 1844 1912 self.write_state() 1845 1913 self.state_lock.release() 1914 return proofs 1846 1915 1847 1916 def clear_placeholder(self, eid, expid, tmpdir): … … 1883 1952 1884 1953 # Make sure that the caller can talk to us 1885 self.check_experiment_access(fid, key)1954 proof = self.check_experiment_access(fid, key) 1886 1955 1887 1956 # Install the testbed map entries supplied with the request into a copy … … 1911 1980 1912 1981 top = self.get_topology(req, tmpdir) 1982 self.confirm_software(top) 1913 1983 # Assign the IPs 1914 1984 hosts, ip_allocator = self.allocate_ips_to_topo(top) … … 1924 1994 testbeds.append(tb) 1925 1995 1926 masters, pmasters = self.get_testbed_services(req )1996 masters, pmasters = self.get_testbed_services(req, testbeds) 1927 1997 allocated = { } # Testbeds we can access 1928 1998 topo ={ } # Sub topologies 1929 1999 connInfo = { } # Connection information 1930 2000 2001 self.split_topology(top, topo, testbeds) 2002 1931 2003 self.get_access_to_testbeds(testbeds, fid, allocated, 1932 2004 tbparams, masters, tbmap, expid, expcert_file) 1933 1934 self.split_topology(top, topo, testbeds)1935 2005 1936 2006 attrs = self.generate_keys_and_hosts(tmpdir, expid, hosts, tbparams) … … 1940 2010 part.add_portals(top, topo, eid, pmasters, tbparams, ip_allocator, 1941 2011 connInfo, expid) 2012 2013 auth_attrs = set() 1942 2014 # Now get access to the dynamic testbeds (those added above) 1943 2015 for tb in [ t for t in topo if t not in allocated]: … … 1948 2020 # Give the testbed access to keys it exports or imports 1949 2021 if store_keys: 1950 for sk in store_keys.split(" "): 1951 self.auth.set_attribute(\ 1952 tbparams[tb]['allocID']['fedid'], sk) 1953 self.auth.save() 2022 auth_attrs.update(set([ 2023 (tbparams[tb]['allocID']['fedid'], sk) \ 2024 for sk in store_keys.split(" ")])) 2025 2026 if auth_attrs: 2027 self.append_experiment_authorization(expid, auth_attrs) 1954 2028 1955 2029 # transit and disconnected testbeds may not have a connInfo entry. … … 1963 2037 vtopo = topdl.topology_to_vtopo(top) 1964 2038 vis = self.genviz(vtopo) 1965 self.save_federant_information(allocated, tbparams, eid, vtopo,1966 vis, top)2039 proofs = self.save_federant_information(allocated, tbparams, 2040 eid, vtopo, vis, top) 1967 2041 except service_error, e: 1968 2042 # If something goes wrong in the parse (usually an access error) … … 1975 2049 # Start the background swapper and return the starting state. From 1976 2050 # here on out, the state will stick around a while. 1977 1978 # Let users touch the state1979 self.auth.set_attribute(fid, expid)1980 self.auth.set_attribute(expid, expid)1981 # Override fedids can manipulate state as well1982 for o in self.overrides:1983 self.auth.set_attribute(o, expid)1984 self.auth.save()1985 2051 1986 2052 # Create a logger that logs to the experiment's state object as well as … … 2008 2074 ], 2009 2075 'experimentStatus': 'starting', 2076 'proof': [ proof.to_dict() ] + proofs, 2010 2077 } 2011 2078 … … 2053 2120 key = self.get_experiment_fedid(key) 2054 2121 2055 if self.auth.check_attribute(fid, key): 2056 return True 2122 access_ok, proof = self.auth.check_attribute(fid, key, with_proof=True) 2123 2124 if access_ok: 2125 return proof 2057 2126 else: 2058 raise service_error(service_error.access, "Access Denied") 2127 raise service_error(service_error.access, "Access Denied", 2128 proof) 2059 2129 2060 2130 … … 2065 2135 """ 2066 2136 self.log.info("Get handler %s %s" % (path, fid)) 2137 # XXX: log proofs? 2067 2138 if self.auth.check_attribute(fid, path): 2068 2139 return ("%s/%s" % (self.repodir, path), "application/binary") … … 2070 2141 return (None, None) 2071 2142 2072 def clean_info_response(self, rv ):2143 def clean_info_response(self, rv, proof): 2073 2144 """ 2074 2145 Remove the information in the experiment's state object that is not in … … 2077 2148 # Remove the owner info (should always be there, but...) 2078 2149 if rv.has_key('owner'): del rv['owner'] 2150 if 'auth' in rv: del rv['auth'] 2079 2151 2080 2152 # Convert the log into the allocationLog parameter and remove the … … 2093 2165 if f.has_key('allocID'): del f['allocID'] 2094 2166 if f.has_key('uri'): del f['uri'] 2167 rv['proof'] = proof.to_dict() 2095 2168 2096 2169 return rv … … 2119 2192 raise service_error(service_error.req, "No request?") 2120 2193 2121 self.check_experiment_access(fid, key)2194 proof = self.check_experiment_access(fid, key) 2122 2195 2123 2196 # The state may be massaged by the service function that called … … 2130 2203 2131 2204 if rv: 2132 return self.clean_info_response(rv )2205 return self.clean_info_response(rv, proof) 2133 2206 else: 2134 2207 raise service_error(service_error.req, "No such experiment") … … 2138 2211 Return all the stored info that this fedid can access 2139 2212 """ 2140 rv = { 'info': [ ] }2213 rv = { 'info': [ ], 'proof': [ ] } 2141 2214 2142 2215 self.state_lock.acquire() 2143 2216 for key in [ k for k in self.state.keys() if isinstance(k, fedid)]: 2144 2217 try: 2145 self.check_experiment_access(fid, key)2218 proof = self.check_experiment_access(fid, key) 2146 2219 except service_error, e: 2147 2220 if e.code == service_error.access: … … 2153 2226 if self.state.has_key(key): 2154 2227 e = copy.deepcopy(self.state[key]) 2155 e = self.clean_info_response(e )2228 e = self.clean_info_response(e, proof) 2156 2229 rv['info'].append(e) 2230 rv['proof'].append(proof.to_dict()) 2157 2231 self.state_lock.release() 2158 2232 return rv … … 2282 2356 if tmpdir: self.remove_dirs(tmpdir) 2283 2357 2284 2285 2358 def terminate_experiment(self, req, fid): 2286 2359 """ … … 2295 2368 2296 2369 key = self.get_experiment_key(req, 'experiment') 2297 self.check_experiment_access(fid, key)2370 proof = self.check_experiment_access(fid, key) 2298 2371 exp = req.get('experiment', False) 2299 2372 force = req.get('force', False) … … 2326 2399 self.state_lock.acquire() 2327 2400 for id in ids: 2401 self.clear_experiment_authorization(id, need_state_lock=False) 2328 2402 if id in self.state: del self.state[id] 2329 2403 … … 2346 2420 if repo: 2347 2421 self.remove_dirs("%s/%s" % (self.repodir, repo)) 2348 2422 2349 2423 return { 2350 2424 'experiment': exp , 2351 2425 'deallocationLog': string.join(dealloc_list, ''), 2426 'proof': [proof.to_dict()], 2352 2427 } 2353 2428 else: … … 2368 2443 rv = { 'name': name } 2369 2444 2370 if name and self.auth.check_attribute(fid, name): 2445 if not name: 2446 raise service_error(service_error.req, "No name?") 2447 2448 access_ok, proof = self.auth.check_attribute(fid, name, with_proof=True) 2449 2450 if access_ok: 2371 2451 self.log.debug("[GetValue] asking for %s " % name) 2372 2452 try: … … 2378 2458 if v is not None: 2379 2459 rv['value'] = v 2460 rv['proof'] = proof.to_dict() 2380 2461 self.log.debug("[GetValue] got %s from %s" % (v, name)) 2381 2462 return rv 2382 2463 else: 2383 raise service_error(service_error.access, "Access Denied") 2464 raise service_error(service_error.access, "Access Denied", 2465 proof=proof) 2384 2466 2385 2467 … … 2396 2478 v = req.get('value', '') 2397 2479 2398 if name and self.auth.check_attribute(fid, name): 2480 if not name: 2481 raise service_error(service_error.req, "No name?") 2482 2483 access_ok, proof = self.auth.check_attribute(fid, name, with_proof=True) 2484 2485 if access_ok: 2399 2486 try: 2400 2487 self.synch_store.set_value(name, v) … … 2409 2496 raise service_error(service_error.federant, 2410 2497 "Synch key %s revoked" % name) 2411 return { 'name': name, 'value': v}2498 return { 'name': name, 'value': v, 'proof': proof.to_dict() } 2412 2499 else: 2413 raise service_error(service_error.access, "Access Denied") 2500 raise service_error(service_error.access, "Access Denied", 2501 proof=proof) -
fedd/federation/ns2topdl.py
rac15159 r0a49bd7 11 11 from remote_service import xmlrpc_handler, soap_handler 12 12 from service_error import * 13 from authorizer import authorizer 13 from authorizer import authorizer, abac_authorizer 14 14 15 15 … … 31 31 self.tcl_splitter = config.get("ns2topdl", "tcl_splitter", 32 32 "/usr/testbed/lib/ns2ir/parse.tcl") 33 self.auth_type = config.get('ns2topdl', 'auth_type') or 'legacy' 33 34 access_db = config.get("ns2topdl", "accessdb", None) 34 allow_any = config.getboolean("ns2topdl", "allow_any", False) 35 self.allow_any = config.getboolean("ns2topdl", "allow_any", False) 36 auth_dir = config.get('ns2topdl', 'auth_dir') 35 37 36 38 self.log = logging.getLogger("fedd.ns2topdl") … … 47 49 "using local one") 48 50 49 if access_db and allow_any: 51 52 if self.auth_type == 'legacy': 53 if access_db and self.allow_any: 54 raise service_error(service_error.internal, 55 "Cannot specify both an access database and " + 56 "allow_any for ns2topdl") 57 58 if access_db: 59 try: 60 read_simple_accessdb(access_db, self.auth, 'ns2topdl') 61 except EnvironmentError, e: 62 raise service_error(service_error.internal, 63 "Error reading accessDB %s: %s" % (access_db, e)) 64 except ValueError: 65 raise service_error(service_error.internal, "%s" % e) 66 elif self.allow_any: 67 auth.set_global_attribute("ns2topdl") 68 elif self.auth_type == 'abac': 69 self.auth = abac_authorizer(load=auth_dir) 70 else: 50 71 raise service_error(service_error.internal, 51 "Cannot specify both an access database and allow_any " +\ 52 "for ns2topdl") 53 54 if access_db: 55 try: 56 read_simple_accessdb(access_db, self.auth, 'ns2topdl') 57 except EnvironmentError, e: 58 raise service_error(service_error.internal, 59 "Error reading accessDB %s: %s" % (access_db, e)) 60 except ValueError: 61 raise service_error(service_error.internal, "%s" % e) 62 elif allow_any: 63 auth.set_global_attribute("ns2topdl") 72 "Unknown auth_type: %s" % self.auth_type) 64 73 65 74 … … 81 90 """ 82 91 83 if not self.auth.check_attribute(fid, 'ns2topdl'): 84 raise service_error(service_error.access, "Access Denied") 92 if self.allow_any: 93 self.auth.set_attribute(fid, 'ns2topdl') 94 95 access_ok, proof = self.auth.check_attribute(fid, 'ns2topdl', 96 with_proof=True) 97 98 if not access_ok: 99 raise service_error(service_error.access, "Access Denied", 100 proof=proof) 85 101 86 102 try: … … 137 153 'experimentdescription': { 138 154 'topdldescription': top.to_dict(), 139 } 155 }, 156 'proof': proof.to_dict(), 140 157 } 141 158 -
fedd/federation/parse_detail.py
rac15159 r0a49bd7 1 1 #!/usr/local/bin/python 2 2 3 from fedd_client import * 3 try: 4 from fedd_services import * 5 except ImportError: 6 from fedd_client import * 4 7 5 8 from ZSI.TC import QName, String, URI, AnyElement, UNBOUNDED, Any -
fedd/federation/protogeni_access.py
rac15159 r0a49bd7 215 215 return (None, None) 216 216 217 def build_access_response(self, alloc_id, services ):217 def build_access_response(self, alloc_id, services, proof): 218 218 """ 219 219 Create the SOAP response. … … 230 230 'fedAttr': [ 231 231 { 'attribute': 'domain', 'value': self.domain } , 232 ] 232 ], 233 'proof': proof.to_dict() 233 234 } 234 235 if self.dragon_endpoint: … … 262 263 263 264 # Request for this fedd 264 found, match, owners = self.lookup_access(req, fid)265 found, match, owners, proof = self.lookup_access(req, fid) 265 266 services, svc_state = self.export_services(req.get('service',[]), 266 267 None, None) … … 275 276 # The list of owner FIDs 276 277 self.allocation[aid]['owners'] = owners 278 self.allocation[aid]['auth'] = set() 279 self.append_allocation_authorization(aid, 280 ((fid, allocID), (allocID, allocID)), state_attr='allocation') 277 281 self.write_state() 278 282 self.state_lock.release() 279 self.auth.set_attribute(fid, allocID)280 self.auth.set_attribute(allocID, allocID)281 self.auth.save()282 283 283 284 try: … … 288 289 raise service_error(service_error.internal, 289 290 "Can't open %s/%s : %s" % (self.certdir, aid, e)) 290 return self.build_access_response({ 'fedid': allocID }, None )291 return self.build_access_response({ 'fedid': allocID }, None, proof) 291 292 292 293 … … 312 313 313 314 self.log.debug("[access] deallocation requested for %s", aid) 314 if not self.auth.check_attribute(fid, auth_attr): 315 access_ok , proof = self.auth.check_attribute(fid, auth_attr, 316 with_proof=True) 317 if not access_ok: 315 318 self.log.debug("[access] deallocation denied for %s", aid) 316 319 raise service_error(service_error.access, "Access Denied") … … 319 322 if self.allocation.has_key(aid): 320 323 self.log.debug("Found allocation for %s" %aid) 324 self.clear_allocation_authorization(aid, state_attr='allocation') 321 325 del self.allocation[aid] 322 326 self.write_state() … … 326 330 self.log.debug("Removing %s" % cf) 327 331 os.remove(cf) 328 return { 'allocID': req['allocID'] }332 return { 'allocID': req['allocID'], 'proof': proof.to_dict() } 329 333 else: 330 334 self.state_lock.release() … … 1250 1254 cpw, alloc_log) 1251 1255 1252 def finalize_experiment(self, topo, nodes, aid, alloc_id ):1256 def finalize_experiment(self, topo, nodes, aid, alloc_id, proof): 1253 1257 # Copy the assigned names into the return topology 1254 1258 rvtopo = topo.clone() … … 1272 1276 'topdldescription': rvtopo.to_dict() }, 1273 1277 'embedding': embedding, 1278 'proof': proof.to_dict(), 1274 1279 } 1275 1280 retval = copy.deepcopy(self.allocation[aid]['started']) … … 1294 1299 aid = "%s" % auth_attr 1295 1300 attrs = req.get('fedAttr', []) 1296 if not self.auth.check_attribute(fid, auth_attr): 1301 access_ok, proof = self.auth.check_attribute(fid, auth_attr, 1302 with_proof=True) 1303 if not access_ok: 1297 1304 raise service_error(service_error.access, "Access denied") 1298 1305 else: … … 1355 1362 1356 1363 if rv: 1357 return self.finalize_experiment(topo, nodes, aid, req['allocID']) 1364 return self.finalize_experiment(topo, nodes, aid, req['allocID'], 1365 proof) 1358 1366 elif err: 1359 1367 raise service_error(service_error.federant, … … 1391 1399 aid = "%s" % auth_attr 1392 1400 attrs = req.get('fedAttr', []) 1393 if not self.auth.check_attribute(fid, auth_attr): 1401 access_ok, proof = self.auth.check_attribute(fid, auth_attr, 1402 with_proof=True) 1403 if not access_ok: 1394 1404 raise service_error(service_error.access, "Access denied") 1395 1405 … … 1418 1428 self.stop_segment(segment_commands, user, staging, slice_cred, 1419 1429 slice_urn, cf, cpw) 1420 return { 'allocID': req['allocID'] }1430 return { 'allocID': req['allocID'], 'proof': proof.to_dict() } 1421 1431 1422 1432 def renew_segment(self, segment_commands, name, scred, slice_urn, interval, -
fedd/federation/remote_service.py
rac15159 r0a49bd7 16 16 import httplib 17 17 18 from proof import proof 18 19 from service_error import service_error 19 20 from xmlrpclib import ServerProxy, dumps, loads, Fault, Error, Binary … … 21 22 import fedd_services 22 23 import fedd_internal_services 24 service_port_name = 'getfeddPortType' 25 internal_service_port_name = 'getfeddInternalPortType' 23 26 except ImportError: 24 import fedd_server25 27 import fedd_client 28 import fedd_internal_client 29 fedd_services = fedd_client 30 fedd_internal_services = fedd_internal_client 31 service_port_name = 'getfeddPort' 32 internal_service_port_name = 'getfedd_internalPort' 26 33 27 34 from util import fedd_ssl_context … … 60 67 # A map used to encapsulate fedids into xmlrpclib.Binary objects 61 68 encap_fedids = (('fedid', to_binary),) 69 70 # fields that are never unicoded, because they represent non strings. 71 do_not_unicode = set(['credential']) 62 72 63 73 @staticmethod … … 166 176 if isinstance(obj, dict): 167 177 for k in obj.keys(): 168 obj[k] = remote_service_base.make_unicode(obj[k]) 178 if k not in remote_service_base.do_not_unicode: 179 obj[k] = remote_service_base.make_unicode(obj[k]) 169 180 return obj 170 181 elif isinstance(obj, basestring) and not isinstance(obj, unicode): … … 283 294 self.service_name = service_name 284 295 296 <<<<<<< HEAD 285 297 try: 286 298 if getattr(fedd_services.feddBindingSOAP, service_name, None): … … 300 312 self.port_name = 'getfedd_internalPort' 301 313 314 ======= 315 if getattr(fedd_services.feddBindingSOAP, service_name, None): 316 self.locator = fedd_services.feddServiceLocator 317 self.port_name = service_port_name 318 elif getattr(fedd_internal_services.feddInternalBindingSOAP, 319 service_name, None): 320 self.locator = fedd_internal_services.feddInternalServiceLocator 321 self.port_name = internal_service_port_name 322 >>>>>>> 944b746d2f97c5803ca28f587dd7100a57e25a69 302 323 303 324 if request_message: self.request_message = request_message 304 325 else: 305 326 request_message_name = "%sRequestMessage" % service_name 327 <<<<<<< HEAD 306 328 try: 307 329 self.request_message = \ … … 314 336 getattr(fedd_internal_client, request_message_name, 315 337 None) 338 ======= 339 self.request_message = \ 340 getattr(fedd_services, request_message_name, None) or \ 341 getattr(fedd_internal_services, request_message_name, 342 None) 343 >>>>>>> 944b746d2f97c5803ca28f587dd7100a57e25a69 316 344 if not self.request_message and strict: 317 345 raise service_error(service_error.internal, … … 523 551 'desc': e.fault.string or "Something Weird" } 524 552 if ee: 553 if 'proof' in ee: 554 pl = [ proof.from_dict(p) for p in ee['proof']] 555 else: 556 pl = None 525 557 raise service_error(ee.get('code', 'no code'), 526 ee.get('desc','no desc') )558 ee.get('desc','no desc'), proof=pl) 527 559 else: 528 560 raise service_error(service_error.internal, -
fedd/federation/server.py
rac15159 r0a49bd7 13 13 14 14 from fedid import fedid 15 from fedd_services import ns0 15 16 # ZSI uses a deprecated multifile interface. This shuts the warning system up. 17 from warnings import filterwarnings 18 filterwarnings("ignore", ".*multifile.*", DeprecationWarning, "ZSI") 19 20 try: 21 from fedd_services import ns0 22 except ImportError: 23 from fedd_server import ns0 24 16 25 from service_error import * 17 26 … … 127 136 self.send_fault(f) 128 137 resp = None 129 138 130 139 if resp != None: 131 140 sw = SoapWriter() … … 192 201 de._errstr=e.code_string() 193 202 de._desc=e.desc 203 for p in e.proof: 204 dp = ns0.proofType_Def(ns0.proofType_Def.schema, 205 "proof").pyclass() 206 dp._prover = p.prover 207 dp._principal = p.principal 208 dp._attribute = p.attribute 209 dp._credential = p.creds_to_certs() 210 if de._proof: de._proof.append(dp) 211 else: de._proof = [dp] 194 212 if e.is_server_error(): 195 213 raise Fault(Fault.Server, e.code_string(), detail=de) -
fedd/federation/service_error.py
rac15159 r0a49bd7 28 28 federant, connect) 29 29 30 def __init__(self, code=None, desc=None, from_string=None ):30 def __init__(self, code=None, desc=None, from_string=None, proof=None): 31 31 self.code = code 32 32 self.desc = desc 33 self.proof = proof or [] 34 if not isinstance (self.proof, list): self.proof = [ proof ] 33 35 if code == None: 34 36 self.set_code_from_string(from_string) -
fedd/federation/skeleton_access.py
rac15159 r0a49bd7 163 163 } 164 164 165 def RequestAccess(self, req, fid): 166 """ 167 Handle an access request. Success here maps the requester into the 168 local access control space and establishes state about that user keyed 169 to a fedid. We also save a copy of the certificate underlying that 170 fedid so this allocation can access configuration information and 171 shared parameters on the experiment controller. 172 """ 173 174 # The dance to get into the request body 175 if req.has_key('RequestAccessRequestBody'): 176 req = req['RequestAccessRequestBody'] 177 else: 178 raise service_error(service_error.req, "No request!?") 179 180 # Base class lookup routine. If this fails, it throws a service 181 # exception denying access that triggers a fault response back to the 182 # caller. 183 found, match, owners = self.lookup_access(req, fid) 184 self.log.info( 185 "[RequestAccess] Access granted to %s with local creds %s" % \ 186 (match, found)) 187 # Make a fedid for this allocation 188 allocID, alloc_cert = generate_fedid(subj="alloc", log=self.log) 189 aid = unicode(allocID) 190 191 # Store the data about this allocation: 192 self.state_lock.acquire() 193 self.state[aid] = { } 194 self.state[aid]['user'] = found 195 self.state[aid]['owners'] = owners 196 self.write_state() 197 self.state_lock.release() 198 # Authorize the creating fedid and the principal representing the 199 # allocation to manipulate it. 200 self.auth.set_attribute(fid, allocID) 201 self.auth.set_attribute(allocID, allocID) 202 self.auth.save() 203 204 # Create a directory to stash the certificate in, ans stash it. 205 try: 206 f = open("%s/%s.pem" % (self.certdir, aid), "w") 207 print >>f, alloc_cert 208 f.close() 209 except EnvironmentError, e: 210 raise service_error(service_error.internal, 211 "Can't open %s/%s : %s" % (self.certdir, aid, e)) 212 self.log.debug('[RequestAccess] Returning allocation ID: %s' % allocID) 213 return { 'allocID': { 'fedid': allocID } } 214 215 def ReleaseAccess(self, req, fid): 216 """ 217 Release the allocation granted earlier. Access to the allocation is 218 checked and if valid, the state and cached certificate are destroyed. 219 """ 220 # The dance to get into the request body 221 if req.has_key('ReleaseAccessRequestBody'): 222 req = req['ReleaseAccessRequestBody'] 223 else: 224 raise service_error(service_error.req, "No request!?") 225 226 # Pull a key out of the request. One can request to delete an 227 # allocation by a local human readable name or by a fedid. This finds 228 # both choices. 229 try: 230 if 'localname' in req['allocID']: 231 auth_attr = aid = req['allocID']['localname'] 232 elif 'fedid' in req['allocID']: 233 aid = unicode(req['allocID']['fedid']) 234 auth_attr = req['allocID']['fedid'] 235 else: 236 raise service_error(service_error.req, 237 "Only localnames and fedids are understood") 238 except KeyError: 239 raise service_error(service_error.req, "Badly formed request") 240 241 self.log.debug("[ReleaseAccess] deallocation requested for %s", aid) 242 # Confirm access 243 if not self.auth.check_attribute(fid, auth_attr): 244 self.log.debug("[ReleaseAccess] deallocation denied for %s", aid) 245 raise service_error(service_error.access, "Access Denied") 246 247 # If there is an allocation in the state, delete it. Note the locking. 248 self.state_lock.acquire() 249 if aid in self.state: 250 self.log.debug("[ReleaseAccess] Found allocation for %s" %aid) 251 del self.state[aid] 252 self.write_state() 253 self.state_lock.release() 254 # And remove the access cert 255 cf = "%s/%s.pem" % (self.certdir, aid) 256 self.log.debug("[ReleaseAccess] Removing %s" % cf) 257 os.remove(cf) 258 return { 'allocID': req['allocID'] } 259 else: 260 self.state_lock.release() 261 raise service_error(service_error.req, "No such allocation") 165 # RequestAccess and ReleaseAccess come from the base class 262 166 263 167 def StartSegment(self, req, fid): … … 279 183 aid = "%s" % auth_attr 280 184 # Authorization check 281 if not self.auth.check_attribute(fid, auth_attr): 282 raise service_error(service_error.access, "Access denied") 185 access_ok, proof = self.auth.check_attribute(fid, auth_attr, 186 with_proof=True) 187 if not access_ok: 188 raise service_error(service_error.access, "Access denied", 189 proof=proof) 283 190 else: 284 191 # See if this is a replay of an earlier succeeded StartSegment - … … 338 245 'allocID': req['allocID'], 339 246 'allocationLog': "Allocatation complete", 340 'segmentdescription': { 'topdldescription': topo.to_dict() } 247 'segmentdescription': { 'topdldescription': topo.to_dict() }, 248 'proof': proof.to_dict(), 341 249 } 342 250 retval = copy.deepcopy(self.state[aid]['started']) … … 362 270 self.log.debug("Terminate request for %s" %aid) 363 271 # Check authorization 364 if not self.auth.check_attribute(fid, auth_attr): 365 raise service_error(service_error.access, "Access denied") 272 access_ok, proof = self.auth.check_attribute(fid, auth_attr, 273 with_proof=True) 274 if not access_ok: 275 raise service_error(service_error.access, "Access denied", 276 proof=proof) 366 277 367 278 # Authorized: remove the integer from the allocation. A more complex … … 377 288 self.state_lock.release() 378 289 379 return { 'allocID': req['allocID'] }290 return { 'allocID': req['allocID'], 'proof': proof.to_dict() } -
fedd/federation/thread_pool.py
rac15159 r0a49bd7 4 4 import time 5 5 from threading import Lock, Thread, Condition 6 from service_error import service_error 6 7 7 8 class thread_pool: -
fedd/federation/util.py
rac15159 r0a49bd7 8 8 9 9 import httplib 10 11 from optparse import OptionParser 10 12 11 13 from socket import sslerror … … 95 97 self.set_allow_unknown_ca(True) 96 98 self.set_verify(SSL.verify_peer, 10, callback=callb) 99 100 class file_expanding_opts(OptionParser): 101 def expand_file(self, option, opt_str, v, p): 102 """ 103 Store the given value to the given destination after expanding home 104 directories. 105 """ 106 setattr(p.values, option.dest, os.path.expanduser(v)) 107 108 def __init__(self, usage=None, version=None): 109 OptionParser.__init__(self) 110 97 111 98 112 def read_simple_accessdb(fn, auth, mask=[]): … … 360 374 # This should be a one-iteration loop 361 375 for c in context.credentials(): 362 ids.add( c.issuer_cert())363 attrs.add( c.attribute_cert())376 ids.add(str(c.issuer_cert())) 377 attrs.add(str(c.attribute_cert())) 364 378 365 379 return list(ids), list(attrs)
Note: See TracChangeset
for help on using the changeset viewer.