Ignore:
Timestamp:
Jan 15, 2011 5:52:15 PM (14 years ago)
Author:
Ted Faber <faber@…>
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)
Message:

merge from current

File:
1 edited

Legend:

Unmodified
Added
Removed
  • fedd/federation/access.py

    rac15159 r0a49bd7  
    234234                        "Unpickling failed: %s") % e)
    235235
     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
    236276    def lookup_access(self, req, fid, filter=None, compare=None):
    237277        """
     
    261301        # Check every attribute that we know how to map and take the first
    262302        # success.
     303        fail_proofs = [ ]
    263304        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:
    265308                self.log.debug("Access succeeded for %s %s" % (attr.attr, fid))
    266309                # XXX: needs to deal with dynamics
    267310                return copy.copy(attr.value), (False, False, False), \
    268                         [ fid ]
     311                        [ fid ], proof
    269312            else:
     313                fail_proofs.append(proof)
    270314                self.log.debug("Access failed for %s %s" % (attr.attr, fid))
    271315        else:
    272             raise service_error(service_error.access, "Access denied")
     316            raise service_error(service_error.access, "Access denied",
     317                    proof=fail_proofs)
    273318
    274319
     
    408453        return (exp, state)
    409454
    410     def build_access_response(self, alloc_id, ap, services):
     455    def build_access_response(self, alloc_id, ap, services, proof):
    411456        """
    412457        Create the SOAP response.
     
    421466        msg = {
    422467                'allocID': alloc_id,
     468                'proof': proof.to_dict(),
    423469                'fedAttr': [
    424470                    { 'attribute': 'domain', 'value': self.domain } ,
     
    730776        except EnvironmentError, e:
    731777            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")
Note: See TracChangeset for help on using the changeset viewer.