Exemple #1
0
def export_gid(options):
    from sfa.util.table import SfaTable
    # lookup the record for the specified hrn 
    hrn = options.export
    type = options.type
    # check sfa table first
    filter = {'hrn': hrn}
    if type:
        filter['type'] = type                    
    table = SfaTable()
    records = table.find(filter)
    if not records:
        # check the authorities hierarchy 
        hierarchy = Hierarchy()
        try:
            auth_info = hierarchy.get_auth_info()
            gid = auth_info.gid_object 
        except:
            print "Record: %s not found" % hrn
            sys.exit(1)
    else:
        record = records[0]
        gid = GID(string=record['gid'])
        
    # get the outfile
    outfile = options.outfile
    if not outfile:
        outfile = os.path.abspath('./%s.gid' % gid.get_hrn())

    # save it
    if options.verbose:
        print "Writing %s gid to %s" % (gid.get_hrn(), outfile)
    gid.save_to_file(outfile, save_parents=True)
Exemple #2
0
def sign(options):
    """
    Sign the specified gid
    """
    hierarchy = Hierarchy()
    config = Config()
    default_authority = config.SFA_INTERFACE_HRN
    auth_info = hierarchy.get_auth_info(default_authority)

    # load the gid
    gidfile = os.path.abspath(options.sign)
    if not os.path.isfile(gidfile):
        print "no such gid: %s" % gidfile
        sys.exit(1)
    gid = GID(filename=gidfile)

    # extract pub_key and create new gid
    pkey = gid.get_pubkey()
    urn = gid.get_urn()
    gid = hierarchy.create_gid(urn, create_uuid(), pkey)

    # get the outfile
    outfile = options.outfile
    if not outfile:
        outfile = os.path.abspath('./signed-%s.gid' % gid.get_hrn())
   
    # save the signed gid
    if options.verbose:
        print "Writing signed gid %s" % outfile  
    gid.save_to_file(outfile, save_parents=True)
Exemple #3
0
 def server_proxy(self, interface, cred, timeout=30):
     """
     Returns a connection to the specified interface. Use the specified
     credential to determine the caller and look for the caller's key/cert 
     in the registry hierarchy cache. 
     """       
     from sfa.trust.hierarchy import Hierarchy
     if not isinstance(cred, Credential):
         cred_obj = Credential(string=cred)
     else:
         cred_obj = cred
     caller_gid = cred_obj.get_gid_caller()
     hierarchy = Hierarchy()
     auth_info = hierarchy.get_auth_info(caller_gid.get_hrn())
     key_file = auth_info.get_privkey_filename()
     cert_file = auth_info.get_gid_filename()
     server = interface.server_proxy(key_file, cert_file, timeout)
     return server
Exemple #4
0
 def server_proxy(self, interface, cred, timeout=30):
     """
     Returns a connection to the specified interface. Use the specified
     credential to determine the caller and look for the caller's key/cert 
     in the registry hierarchy cache. 
     """
     from sfa.trust.hierarchy import Hierarchy
     if not isinstance(cred, Credential):
         cred_obj = Credential(string=cred)
     else:
         cred_obj = cred
     caller_gid = cred_obj.get_gid_caller()
     hierarchy = Hierarchy()
     auth_info = hierarchy.get_auth_info(caller_gid.get_hrn())
     key_file = auth_info.get_privkey_filename()
     cert_file = auth_info.get_gid_filename()
     server = interface.server_proxy(key_file, cert_file, timeout)
     return server
Exemple #5
0
def import_gid(options):
    """
    Import the specified gid into the registry (db and authorities 
    hierarchy) overwriting any previous gid.
    """
    from sfa.util.table import SfaTable
    from sfa.util.record import SfaRecord
    # load the gid
    gidfile = os.path.abspath(options.importgid)
    if not gidfile or not os.path.isfile(gidfile):
        print "No such gid: %s" % gidfile
        sys.exit(1)
    gid = GID(filename=gidfile)
    
    # check if it exists within the hierarchy
    hierarchy = Hierarchy()
    if not hierarchy.auth_exists(gid.get_hrn()):
        print "%s not found in hierarchy" % gid.get_hrn()
        sys.exit(1)

    # check if record exists in db
    table = SfaTable()
    records = table.find({'hrn': gid.get_hrn(), 'type': 'authority'})
    if not records:
        print "%s not found in record database" % get.get_hrn()  
        sys.exit(1)

    # update the database record
    record = records[0]
    record['gid'] = gid.save_to_string(save_parents=True)
    table.update(record)
    if options.verbose:
        print "Imported %s gid into db" % record['hrn']

    # update the hierarchy
    auth_info = hierarchy.get_auth_info(gid.get_hrn())  
    filename = auth_info.gid_filename
    gid.save_to_file(filename, save_parents=True)
    if options.verbose:
        print "Writing %s gid to %s" % (gid.get_hrn(), filename)

    # ending here
    return
Exemple #6
0
def init_server_cert(hrn, key, server_cert_file, self_signed=False):
    """
    Setup the certificate for this server. Attempt to use gid before 
    creating a self signed cert 
    """
    if self_signed:
        init_self_signed_cert(hrn, key, server_cert_file)
    else:
        try:
            # look for gid file
            logger.debug("generating server cert from gid: %s" % hrn)
            hierarchy = Hierarchy()
            auth_info = hierarchy.get_auth_info(hrn)
            gid = GID(filename=auth_info.gid_filename)
            gid.save_to_file(filename=server_cert_file)
        except:
            # fall back to self signed cert
            logger.debug("gid for %s not found" % hrn)
            init_self_signed_cert(hrn, key, server_cert_file)
Exemple #7
0
 def export(self, xrn, type=None, outfile=None):
     """Fetch an object's GID from the Registry"""  
     from sfa.storage.model import RegRecord
     hrn = Xrn(xrn).get_hrn()
     request=self.api.dbsession().query(RegRecord).filter_by(hrn=hrn)
     if type: request = request.filter_by(type=type)
     record=request.first()
     if record:
         gid = GID(string=record.gid)
     else:
         # check the authorities hierarchy
         hierarchy = Hierarchy()
         try:
             auth_info = hierarchy.get_auth_info(hrn)
             gid = auth_info.gid_object
         except:
             print "Record: %s not found" % hrn
             sys.exit(1)
     # save to file
     if not outfile:
         outfile = os.path.abspath('./%s.gid' % gid.get_hrn())
     gid.save_to_file(outfile, save_parents=True)
Exemple #8
0
 def export(self, xrn, type=None, outfile=None):
     """Fetch an object's GID from the Registry"""
     from sfa.storage.model import RegRecord
     hrn = Xrn(xrn).get_hrn()
     request = self.api.dbsession().query(RegRecord).filter_by(hrn=hrn)
     if type: request = request.filter_by(type=type)
     record = request.first()
     if record:
         gid = GID(string=record.gid)
     else:
         # check the authorities hierarchy
         hierarchy = Hierarchy()
         try:
             auth_info = hierarchy.get_auth_info(hrn)
             gid = auth_info.gid_object
         except:
             print "Record: %s not found" % hrn
             sys.exit(1)
     # save to file
     if not outfile:
         outfile = os.path.abspath('./%s.gid' % gid.get_hrn())
     gid.save_to_file(outfile, save_parents=True)
Exemple #9
0
class Auth:
    """
    Credential based authentication
    """

    def __init__(self, peer_cert = None, config = None ):
        self.peer_cert = peer_cert
        self.hierarchy = Hierarchy()
        if not config:
            self.config = Config()
        self.load_trusted_certs()

    def load_trusted_certs(self):
        self.trusted_cert_list = \
            TrustedRoots(self.config.get_trustedroots_dir()).get_list()
        self.trusted_cert_file_list = \
            TrustedRoots(self.config.get_trustedroots_dir()).get_file_list()

    # this convenience methods extracts speaking_for_xrn
    # from the passed options using 'geni_speaking_for'
    def checkCredentialsSpeaksFor (self, *args, **kwds):
        if 'options' not in kwds:
            logger.error ("checkCredentialsSpeaksFor was not passed options=options")
            return
        # remove the options arg
        options=kwds['options']; del kwds['options']
        # compute the speaking_for_xrn arg and pass it to checkCredentials
        if options is None: speaking_for_xrn=None
        else:               speaking_for_xrn=options.get('geni_speaking_for',None)
        kwds['speaking_for_xrn']=speaking_for_xrn
        return self.checkCredentials (*args, **kwds)

    # do not use mutable as default argument 
    # http://docs.python-guide.org/en/latest/writing/gotchas/#mutable-default-arguments
    def checkCredentials(self, creds, operation, xrns=None, 
                         check_sliver_callback=None, 
                         speaking_for_xrn=None):
        if xrns is None: xrns=[]
        def log_invalid_cred(cred):
            if not isinstance (cred, StringTypes):
                logger.info("cannot validate credential %s - expecting a string"%cred)
                error="checkCredentials: expected a string, received %s"%(type(cred))
            else:
                cred_obj=Credential(string=cred)
                logger.info("failed to validate credential - dump=%s"%\
                            cred_obj.dump_string(dump_parents=True))
                error = sys.exc_info()[:2]
            return error

        # if xrns are specified they cannot be None or empty string
        if xrns:
            for xrn in xrns:
                if not xrn:
                    raise BadArgs("Invalid urn or hrn")

        
        if not isinstance(xrns, list):
            xrns = [xrns]

        slice_xrns  = Xrn.filter_type(xrns, 'slice')
        sliver_xrns = Xrn.filter_type(xrns, 'sliver')

        # we are not able to validate slivers in the traditional way so 
        # we make sure not to include sliver urns/hrns in the core validation loop
        hrns = [Xrn(xrn).hrn for xrn in xrns if xrn not in sliver_xrns] 
        valid = []
        if not isinstance(creds, list):
            creds = [creds]
        logger.debug("Auth.checkCredentials with %d creds on hrns=%s"%(len(creds),hrns))
        # won't work if either creds or hrns is empty - let's make it more explicit
        if not creds: raise Forbidden("no credential provided")
        if not hrns: hrns = [None]
        error=[None,None]

        speaks_for_gid = determine_speaks_for(logger, creds, self.peer_cert,
                                              speaking_for_xrn, self.trusted_cert_list)

        if self.peer_cert and \
           not self.peer_cert.is_pubkey(speaks_for_gid.get_pubkey()):
            valid = creds
        else:
            for cred in creds:
                for hrn in hrns:
                    try:
                        self.check(cred, operation, hrn)
                        valid.append(cred)
                    except:
                        error = log_invalid_cred(cred)
        
        # make sure all sliver xrns are validated against the valid credentials
        if sliver_xrns:
            if not check_sliver_callback:
                msg = "sliver verification callback method not found." 
                msg += " Unable to validate sliver xrns: %s" % sliver_xrns
                raise Forbidden(msg)
            check_sliver_callback(valid, sliver_xrns)
                
        if not len(valid):
            raise Forbidden("Invalid credential %s -- %s"%(error[0],error[1]))
        
        return valid
        
        
    def check(self, credential, operation, hrn = None):
        """
        Check the credential against the peer cert (callerGID) included 
        in the credential matches the caller that is connected to the 
        HTTPS connection, check if the credential was signed by a 
        trusted cert and check if the credential is allowed to perform 
        the specified operation.    
        """
        cred = Credential(cred=credential)    
        self.client_cred = cred
        logger.debug("Auth.check: handling hrn=%s and credential=%s"%\
                         (hrn,cred.pretty_cred()))

        if cred.type not in ['geni_sfa']:
            raise CredentialNotVerifiable(cred.type, "%s not supported" % cred.type)
        self.client_gid = self.client_cred.get_gid_caller()
        self.object_gid = self.client_cred.get_gid_object()
        
        # make sure the client_gid is not blank
        if not self.client_gid:
            raise MissingCallerGID(self.client_cred.pretty_subject())
       
        # validate the client cert if it exists
        if self.peer_cert:
            self.verifyPeerCert(self.peer_cert, self.client_gid)                   

        # make sure the client is allowed to perform the operation
        if operation:
            if not self.client_cred.can_perform(operation):
                raise InsufficientRights(operation)

        if self.trusted_cert_list:
            self.client_cred.verify(self.trusted_cert_file_list,
                                    self.config.SFA_CREDENTIAL_SCHEMA)
        else:
           raise MissingTrustedRoots(self.config.get_trustedroots_dir())
       
        # Make sure the credential's target matches the specified hrn. 
        # This check does not apply to trusted peers 
        trusted_peers = [gid.get_hrn() for gid in self.trusted_cert_list]
        if hrn and self.client_gid.get_hrn() not in trusted_peers:
            target_hrn = self.object_gid.get_hrn()
            if not hrn == target_hrn:
                raise PermissionError("Target hrn: %s doesn't match specified hrn: %s " % \
                                       (target_hrn, hrn) )       
        return True

    def check_ticket(self, ticket):
        """
        Check if the ticket was signed by a trusted cert
        """
        if self.trusted_cert_list:
            client_ticket = SfaTicket(string=ticket)
            client_ticket.verify_chain(self.trusted_cert_list)
        else:
           raise MissingTrustedRoots(self.config.get_trustedroots_dir())

        return True 

    def verifyPeerCert(self, cert, gid):
        # make sure the client_gid matches client's certificate
        if not cert.is_pubkey(gid.get_pubkey()):
            raise ConnectionKeyGIDMismatch(gid.get_subject()+":"+cert.get_subject())            

    def verifyGidRequestHash(self, gid, hash, arglist):
        key = gid.get_pubkey()
        if not key.verify_string(str(arglist), hash):
            raise BadRequestHash(hash)

    def verifyCredRequestHash(self, cred, hash, arglist):
        gid = cred.get_gid_caller()
        self.verifyGidRequestHash(gid, hash, arglist)

    def validateGid(self, gid):
        if self.trusted_cert_list:
            gid.verify_chain(self.trusted_cert_list)

    def validateCred(self, cred):
        if self.trusted_cert_list:
            cred.verify(self.trusted_cert_file_list)

    def authenticateGid(self, gidStr, argList, requestHash=None):
        gid = GID(string = gidStr)
        self.validateGid(gid)
        # request_hash is optional
        if requestHash:
            self.verifyGidRequestHash(gid, requestHash, argList)
        return gid

    def authenticateCred(self, credStr, argList, requestHash=None):
        cred = Credential(string = credStr)
        self.validateCred(cred)
        # request hash is optional
        if requestHash:
            self.verifyCredRequestHash(cred, requestHash, argList)
        return cred

    def authenticateCert(self, certStr, requestHash):
        cert = Certificate(string=certStr)
        # xxx should be validateCred ??
        self.validateCred(cert)   

    def gidNoop(self, gidStr, value, requestHash):
        self.authenticateGid(gidStr, [gidStr, value], requestHash)
        return value

    def credNoop(self, credStr, value, requestHash):
        self.authenticateCred(credStr, [credStr, value], requestHash)
        return value

    def verify_cred_is_me(self, credential):
        is_me = False 
        cred = Credential(string=credential)
        caller_gid = cred.get_gid_caller()
        caller_hrn = caller_gid.get_hrn()
        if caller_hrn != self.config.SFA_INTERFACE_HRN:
            raise SfaPermissionDenied(self.config.SFA_INTEFACE_HRN)

        return   
        
    def get_auth_info(self, auth_hrn):
        """
        Given an authority name, return the information for that authority.
        This is basically a stub that calls the hierarchy module.
        
        @param auth_hrn human readable name of authority  
        """

        return self.hierarchy.get_auth_info(auth_hrn)


    def veriry_auth_belongs_to_me(self, name):
        """
        Verify that an authority belongs to our hierarchy. 
        This is basically left up to the implementation of the hierarchy
        module. If the specified name does not belong, ane exception is 
        thrown indicating the caller should contact someone else.

        @param auth_name human readable name of authority
        """

        # get auth info will throw an exception if the authority doesnt exist
        self.get_auth_info(name)


    def verify_object_belongs_to_me(self, name):
        """
        Verify that an object belongs to our hierarchy. By extension,
        this implies that the authority that owns the object belongs
        to our hierarchy. If it does not an exception is thrown.
    
        @param name human readable name of object        
        """
        auth_name = self.get_authority(name)
        if not auth_name:
            auth_name = name 
        if name == self.config.SFA_INTERFACE_HRN:
            return
        self.verify_auth_belongs_to_me(auth_name) 
             
    def verify_auth_belongs_to_me(self, name):
        # get auth info will throw an exception if the authority doesnt exist
        self.get_auth_info(name) 


    def verify_object_permission(self, name):
        """
        Verify that the object gid that was specified in the credential
        allows permission to the object 'name'. This is done by a simple
        prefix test. For example, an object_gid for plc.arizona would 
        match the objects plc.arizona.slice1 and plc.arizona.
    
        @param name human readable name to test  
        """
        object_hrn = self.object_gid.get_hrn()
        if object_hrn == name:
            return
        if name.startswith(object_hrn + "."):
            return
        #if name.startswith(get_authority(name)):
            #return
    
        raise PermissionError(name)

    def determine_user_rights(self, caller_hrn, reg_record):
        """
        Given a user credential and a record, determine what set of rights the
        user should have to that record.
        
        This is intended to replace determine_user_rights() and
        verify_cancreate_credential()
        """

        rl = Rights()
        type = reg_record.type

        logger.debug("entering determine_user_rights with record %s and caller_hrn %s"%\
                     (reg_record, caller_hrn))

        if type == 'slice':
            # researchers in the slice are in the DB as-is
            researcher_hrns = [ user.hrn for user in reg_record.reg_researchers ]
            # locating PIs attached to that slice
            slice_pis=reg_record.get_pis()
            pi_hrns = [ user.hrn for user in slice_pis ]
            if (caller_hrn in researcher_hrns + pi_hrns):
                rl.add('refresh')
                rl.add('embed')
                rl.add('bind')
                rl.add('control')
                rl.add('info')

        elif type == 'authority':
            pi_hrns = [ user.hrn for user in reg_record.reg_pis ]
            if (caller_hrn == self.config.SFA_INTERFACE_HRN):
                rl.add('authority')
                rl.add('sa')
                rl.add('ma')
            if (caller_hrn in pi_hrns):
                rl.add('authority')
                rl.add('sa')
            # NOTE: for the PL implementation, this 'operators' list 
            # amounted to users with 'tech' role in that site 
            # it seems like this is not needed any longer, so for now I just drop that
            # operator_hrns = reg_record.get('operator',[])
            # if (caller_hrn in operator_hrns):
            #    rl.add('authority')
            #    rl.add('ma')

        elif type == 'user':
            rl.add('refresh')
            rl.add('resolve')
            rl.add('info')

        elif type == 'node':
            rl.add('operator')

        return rl

    def get_authority(self, hrn):
        return get_authority(hrn)

    def filter_creds_by_caller(self, creds, caller_hrn_list):
        """
        Returns a list of creds who's gid caller matches the 
        specified caller hrn
        """
        if not isinstance(creds, list):
            creds = [creds]
        creds = []
        if not isinstance(caller_hrn_list, list):
            caller_hrn_list = [caller_hrn_list]
        for cred in creds:
            try:
                tmp_cred = Credential(string=cred)
                if tmp_cred.get_gid_caller().get_hrn() in [caller_hrn_list]:
                    creds.append(cred)
            except: pass
        return creds
Exemple #10
0
class Auth:
    """
    Credential based authentication
    """
    def __init__(self, peer_cert=None, config=None):
        self.peer_cert = peer_cert
        self.hierarchy = Hierarchy()
        if not config:
            self.config = Config()
        self.load_trusted_certs()

    def load_trusted_certs(self):
        self.trusted_cert_list = TrustedRoots(
            self.config.get_trustedroots_dir()).get_list()
        self.trusted_cert_file_list = TrustedRoots(
            self.config.get_trustedroots_dir()).get_file_list()

    def checkCredentials(self,
                         creds,
                         operation,
                         xrns=[],
                         check_sliver_callback=None,
                         speaking_for_hrn=None):
        def log_invalid_cred(cred):
            cred_obj = Credential(string=cred)
            logger.debug("failed to validate credential - dump=%s" %
                         cred_obj.dump_string(dump_parents=True))
            error = sys.exc_info()[:2]
            return error

        # if xrns are specified they cannot be None or empty string
        if xrns:
            for xrn in xrns:
                if not xrn:
                    raise BadArgs("Invalid urn or hrn")

        if not isinstance(xrns, list):
            xrns = [xrns]

        slice_xrns = Xrn.filter_type(xrns, 'slice')
        sliver_xrns = Xrn.filter_type(xrns, 'sliver')

        # we are not able to validate slivers in the traditional way so
        # we make sure not to include sliver urns/hrns in the core validation loop
        hrns = [Xrn(xrn).hrn for xrn in xrns if xrn not in sliver_xrns]
        valid = []
        speaks_for_cred = None
        if not isinstance(creds, list):
            creds = [creds]
        logger.debug("Auth.checkCredentials with %d creds on hrns=%s" %
                     (len(creds), hrns))
        # won't work if either creds or hrns is empty - let's make it more explicit
        if not creds:
            raise BadArgs(
                "no credential provided")  #Forbidden("no credential provided")
        if not hrns: hrns = [None]
        for cred in creds:
            for hrn in hrns:
                try:
                    self.check(cred, operation, hrn)
                    valid.append(cred)
                except:
                    if speaking_for_hrn:
                        try:
                            self.check(cred, operation, speaking_for_hrn)
                            speaks_for_cred = cred
                            valid.append(cred)
                        except:
                            error = log_invalid_cred(cred)
                    else:
                        error = log_invalid_cred(cred)
                    continue

        # make sure all sliver xrns are validated against the valid credentials
        if sliver_xrns:
            if not check_sliver_callback:
                msg = "sliver verification callback method not found."
                msg += " Unable to validate sliver xrns: %s" % sliver_xrns
                raise Forbidden(msg)
            check_sliver_callback(valid, sliver_xrns)

        if not len(valid):
            raise Forbidden("Invalid credential")

        if speaking_for_hrn and not speaks_for_cred:
            raise InsufficientRights(
                'Access denied: "geni_speaking_for" option specified but no valid speaks for credential found: %s -- %s'
                % (error[0], error[1]))

        return valid

    def check(self, credential, operation, hrn=None):
        """
        Check the credential against the peer cert (callerGID included 
        in the credential matches the caller that is connected to the 
        HTTPS connection, check if the credential was signed by a 
        trusted cert and check if the credential is allowed to perform 
        the specified operation.    
        """
        cred = Credential(cred=credential)
        self.client_cred = cred
        logger.debug("Auth.check: handling hrn=%s and credential=%s"%\
                         (hrn,cred.get_summary_tostring()))

        if cred.type not in ['geni_sfa']:
            raise CredentialNotVerifiable(cred.type,
                                          "%s not supported" % cred.type)
        self.client_gid = self.client_cred.get_gid_caller()
        self.object_gid = self.client_cred.get_gid_object()

        # make sure the client_gid is not blank
        if not self.client_gid:
            raise MissingCallerGID(self.client_cred.get_subject())

        # validate the client cert if it exists
        if self.peer_cert:
            self.verifyPeerCert(self.peer_cert, self.client_gid)

        # make sure the client is allowed to perform the operation
        if operation:
            if not self.client_cred.can_perform(operation):
                raise InsufficientRights(operation)

        if self.trusted_cert_list:
            self.client_cred.verify(self.trusted_cert_file_list,
                                    self.config.SFA_CREDENTIAL_SCHEMA)
        else:
            raise MissingTrustedRoots(self.config.get_trustedroots_dir())

        # Make sure the credential's target matches the specified hrn.
        # This check does not apply to trusted peers
        trusted_peers = [gid.get_hrn() for gid in self.trusted_cert_list]
        if hrn and self.client_gid.get_hrn() not in trusted_peers:
            target_hrn = self.object_gid.get_hrn()
            if not hrn == target_hrn:
                raise PermissionError("Target hrn: %s doesn't match specified hrn: %s " % \
                                       (target_hrn, hrn) )
        return True

    def check_ticket(self, ticket):
        """
        Check if the tickt was signed by a trusted cert
        """
        if self.trusted_cert_list:
            client_ticket = SfaTicket(string=ticket)
            client_ticket.verify_chain(self.trusted_cert_list)
        else:
            raise MissingTrustedRoots(self.config.get_trustedroots_dir())

        return True

    def verifyPeerCert(self, cert, gid):
        # make sure the client_gid matches client's certificate
        if not cert.is_pubkey(gid.get_pubkey()):
            raise ConnectionKeyGIDMismatch(gid.get_subject() + ":" +
                                           cert.get_subject())

    def verifyGidRequestHash(self, gid, hash, arglist):
        key = gid.get_pubkey()
        if not key.verify_string(str(arglist), hash):
            raise BadRequestHash(hash)

    def verifyCredRequestHash(self, cred, hash, arglist):
        gid = cred.get_gid_caller()
        self.verifyGidRequestHash(gid, hash, arglist)

    def validateGid(self, gid):
        if self.trusted_cert_list:
            gid.verify_chain(self.trusted_cert_list)

    def validateCred(self, cred):
        if self.trusted_cert_list:
            cred.verify(self.trusted_cert_file_list)

    def authenticateGid(self, gidStr, argList, requestHash=None):
        gid = GID(string=gidStr)
        self.validateGid(gid)
        # request_hash is optional
        if requestHash:
            self.verifyGidRequestHash(gid, requestHash, argList)
        return gid

    def authenticateCred(self, credStr, argList, requestHash=None):
        cred = Credential(string=credStr)
        self.validateCred(cred)
        # request hash is optional
        if requestHash:
            self.verifyCredRequestHash(cred, requestHash, argList)
        return cred

    def authenticateCert(self, certStr, requestHash):
        cert = Certificate(string=certStr)
        # xxx should be validateCred ??
        self.validateCred(cert)

    def gidNoop(self, gidStr, value, requestHash):
        self.authenticateGid(gidStr, [gidStr, value], requestHash)
        return value

    def credNoop(self, credStr, value, requestHash):
        self.authenticateCred(credStr, [credStr, value], requestHash)
        return value

    def verify_cred_is_me(self, credential):
        is_me = False
        cred = Credential(string=credential)
        caller_gid = cred.get_gid_caller()
        caller_hrn = caller_gid.get_hrn()
        if caller_hrn != self.config.SFA_INTERFACE_HRN:
            raise SfaPermissionDenied(self.config.SFA_INTEFACE_HRN)

        return

    def get_auth_info(self, auth_hrn):
        """
        Given an authority name, return the information for that authority.
        This is basically a stub that calls the hierarchy module.
        
        @param auth_hrn human readable name of authority  
        """

        return self.hierarchy.get_auth_info(auth_hrn)

    def veriry_auth_belongs_to_me(self, name):
        """
        Verify that an authority belongs to our hierarchy. 
        This is basically left up to the implementation of the hierarchy
        module. If the specified name does not belong, ane exception is 
        thrown indicating the caller should contact someone else.

        @param auth_name human readable name of authority
        """

        # get auth info will throw an exception if the authority doesnt exist
        self.get_auth_info(name)

    def verify_object_belongs_to_me(self, name):
        """
        Verify that an object belongs to our hierarchy. By extension,
        this implies that the authority that owns the object belongs
        to our hierarchy. If it does not an exception is thrown.
    
        @param name human readable name of object        
        """
        auth_name = self.get_authority(name)
        if not auth_name:
            auth_name = name
        if name == self.config.SFA_INTERFACE_HRN:
            return
        self.verify_auth_belongs_to_me(auth_name)

    def verify_auth_belongs_to_me(self, name):
        # get auth info will throw an exception if the authority doesnt exist
        self.get_auth_info(name)

    def verify_object_permission(self, name):
        """
        Verify that the object gid that was specified in the credential
        allows permission to the object 'name'. This is done by a simple
        prefix test. For example, an object_gid for plc.arizona would 
        match the objects plc.arizona.slice1 and plc.arizona.
    
        @param name human readable name to test  
        """
        object_hrn = self.object_gid.get_hrn()
        logger.debug(
            "VERIFY OBJECT PERMISSION. \n\n object_hrn: %s \n name: %s \n get_authority(name): %s"
            % (object_hrn, name, get_authority(name)))
        if object_hrn == name:
            return
        if name.startswith(object_hrn + "."):
            return
        #if name.startswith(get_authority(name)):
        #return

        raise PermissionError(name)

    def determine_user_rights(self, caller_hrn, reg_record):
        """
        Given a user credential and a record, determine what set of rights the
        user should have to that record.
        
        This is intended to replace determine_user_rights() and
        verify_cancreate_credential()
        """

        rl = Rights()
        type = reg_record.type

        logger.debug(
            "entering determine_user_rights with record %s and caller_hrn %s" %
            (reg_record, caller_hrn))

        if type == 'slice':
            # researchers in the slice are in the DB as-is
            researcher_hrns = [user.hrn for user in reg_record.reg_researchers]
            # locating PIs attached to that slice
            slice_pis = reg_record.get_pis()
            pi_hrns = [user.hrn for user in slice_pis]
            if (caller_hrn in researcher_hrns + pi_hrns):
                rl.add('refresh')
                rl.add('embed')
                rl.add('bind')
                rl.add('control')
                rl.add('info')

        elif type == 'authority':
            pi_hrns = [user.hrn for user in reg_record.reg_pis]
            if (caller_hrn == self.config.SFA_INTERFACE_HRN):
                rl.add('authority')
                rl.add('sa')
                rl.add('ma')
            if (caller_hrn in pi_hrns):
                rl.add('authority')
                rl.add('sa')
            # NOTE: for the PL implementation, this 'operators' list
            # amounted to users with 'tech' role in that site
            # it seems like this is not needed any longer, so for now I just drop that
            # operator_hrns = reg_record.get('operator',[])
            # if (caller_hrn in operator_hrns):
            #    rl.add('authority')
            #    rl.add('ma')

        elif type == 'user':
            rl.add('refresh')
            rl.add('resolve')
            rl.add('info')

        elif type == 'node':
            rl.add('operator')

        return rl

    def get_authority(self, hrn):
        return get_authority(hrn)

    def filter_creds_by_caller(self, creds, caller_hrn_list):
        """
        Returns a list of creds who's gid caller matches the 
        specified caller hrn
        """
        if not isinstance(creds, list):
            creds = [creds]
        creds = []
        if not isinstance(caller_hrn_list, list):
            caller_hrn_list = [caller_hrn_list]
        for cred in creds:
            try:
                tmp_cred = Credential(string=cred)
                if tmp_cred.get_gid_caller().get_hrn() in [caller_hrn_list]:
                    creds.append(cred)
            except:
                pass
        return creds
Exemple #11
0
class Auth:
    """
    Credential based authentication
    """

    def __init__(self, peer_cert = None, config = None ):
        self.peer_cert = peer_cert
        self.hierarchy = Hierarchy()
        if not config:
            self.config = Config()
        self.load_trusted_certs()

    def load_trusted_certs(self):
        self.trusted_cert_list = TrustedRoots(self.config.get_trustedroots_dir()).get_list()
        self.trusted_cert_file_list = TrustedRoots(self.config.get_trustedroots_dir()).get_file_list()

        
        
    def checkCredentials(self, creds, operation, hrn = None):
        valid = []
        if not isinstance(creds, list):
            creds = [creds]
        logger.debug("Auth.checkCredentials with %d creds"%len(creds))
        for cred in creds:
            try:
                self.check(cred, operation, hrn)
                valid.append(cred)
            except:
                cred_obj=Credential(string=cred)
                logger.debug("failed to validate credential - dump=%s"%cred_obj.dump_string(dump_parents=True))
                error = sys.exc_info()[:2]
                continue
            
        if not len(valid):
            raise InsufficientRights('Access denied: %s -- %s' % (error[0],error[1]))
        
        return valid
        
        
    def check(self, cred, operation, hrn = None):
        """
        Check the credential against the peer cert (callerGID included 
        in the credential matches the caller that is connected to the 
        HTTPS connection, check if the credential was signed by a 
        trusted cert and check if the credential is allowed to perform 
        the specified operation.    
        """
        self.client_cred = Credential(string = cred)
        self.client_gid = self.client_cred.get_gid_caller()
        self.object_gid = self.client_cred.get_gid_object()
        
        # make sure the client_gid is not blank
        if not self.client_gid:
            raise MissingCallerGID(self.client_cred.get_subject())
       
        # validate the client cert if it exists
        if self.peer_cert:
            self.verifyPeerCert(self.peer_cert, self.client_gid)                   

        # make sure the client is allowed to perform the operation
        if operation:
            if not self.client_cred.can_perform(operation):
                raise InsufficientRights(operation)

        if self.trusted_cert_list:
            self.client_cred.verify(self.trusted_cert_file_list, self.config.SFA_CREDENTIAL_SCHEMA)
        else:
           raise MissingTrustedRoots(self.config.get_trustedroots_dir())
       
        # Make sure the credential's target matches the specified hrn. 
        # This check does not apply to trusted peers 
        trusted_peers = [gid.get_hrn() for gid in self.trusted_cert_list]
        if hrn and self.client_gid.get_hrn() not in trusted_peers:
            target_hrn = self.object_gid.get_hrn()
            if not hrn == target_hrn:
                raise PermissionError("Target hrn: %s doesn't match specified hrn: %s " % \
                                       (target_hrn, hrn) )       
        return True

    def check_ticket(self, ticket):
        """
        Check if the tickt was signed by a trusted cert
        """
        if self.trusted_cert_list:
            client_ticket = SfaTicket(string=ticket)
            client_ticket.verify_chain(self.trusted_cert_list)
        else:
           raise MissingTrustedRoots(self.config.get_trustedroots_dir())

        return True 

    def verifyPeerCert(self, cert, gid):
        # make sure the client_gid matches client's certificate
        if not cert.is_pubkey(gid.get_pubkey()):
            raise ConnectionKeyGIDMismatch(gid.get_subject()+":"+cert.get_subject())            

    def verifyGidRequestHash(self, gid, hash, arglist):
        key = gid.get_pubkey()
        if not key.verify_string(str(arglist), hash):
            raise BadRequestHash(hash)

    def verifyCredRequestHash(self, cred, hash, arglist):
        gid = cred.get_gid_caller()
        self.verifyGidRequestHash(gid, hash, arglist)

    def validateGid(self, gid):
        if self.trusted_cert_list:
            gid.verify_chain(self.trusted_cert_list)

    def validateCred(self, cred):
        if self.trusted_cert_list:
            cred.verify(self.trusted_cert_file_list)

    def authenticateGid(self, gidStr, argList, requestHash=None):
        gid = GID(string = gidStr)
        self.validateGid(gid)
        # request_hash is optional
        if requestHash:
            self.verifyGidRequestHash(gid, requestHash, argList)
        return gid

    def authenticateCred(self, credStr, argList, requestHash=None):
        cred = Credential(string = credStr)
        self.validateCred(cred)
        # request hash is optional
        if requestHash:
            self.verifyCredRequestHash(cred, requestHash, argList)
        return cred

    def authenticateCert(self, certStr, requestHash):
        cert = Certificate(string=certStr)
        # xxx should be validateCred ??
        self.validateCred(cert)   

    def gidNoop(self, gidStr, value, requestHash):
        self.authenticateGid(gidStr, [gidStr, value], requestHash)
        return value

    def credNoop(self, credStr, value, requestHash):
        self.authenticateCred(credStr, [credStr, value], requestHash)
        return value

    def verify_cred_is_me(self, credential):
        is_me = False 
        cred = Credential(string=credential)
        caller_gid = cred.get_gid_caller()
        caller_hrn = caller_gid.get_hrn()
        if caller_hrn != self.config.SFA_INTERFACE_HRN:
            raise SfaPermissionDenied(self.config.SFA_INTEFACE_HRN)

        return   
        
    def get_auth_info(self, auth_hrn):
        """
        Given an authority name, return the information for that authority.
        This is basically a stub that calls the hierarchy module.
        
        @param auth_hrn human readable name of authority  
        """

        return self.hierarchy.get_auth_info(auth_hrn)


    def veriry_auth_belongs_to_me(self, name):
        """
        Verify that an authority belongs to our hierarchy. 
        This is basically left up to the implementation of the hierarchy
        module. If the specified name does not belong, ane exception is 
        thrown indicating the caller should contact someone else.

        @param auth_name human readable name of authority
        """

        # get auth info will throw an exception if the authority doesnt exist
        self.get_auth_info(name)


    def verify_object_belongs_to_me(self, name):
        """
        Verify that an object belongs to our hierarchy. By extension,
        this implies that the authority that owns the object belongs
        to our hierarchy. If it does not an exception is thrown.
    
        @param name human readable name of object        
        """
        auth_name = self.get_authority(name)
        if not auth_name:
            auth_name = name 
        if name == self.config.SFA_INTERFACE_HRN:
            return
        self.verify_auth_belongs_to_me(auth_name) 
             
    def verify_auth_belongs_to_me(self, name):
        # get auth info will throw an exception if the authority doesnt exist
        self.get_auth_info(name) 


    def verify_object_permission(self, name):
        """
        Verify that the object gid that was specified in the credential
        allows permission to the object 'name'. This is done by a simple
        prefix test. For example, an object_gid for plc.arizona would 
        match the objects plc.arizona.slice1 and plc.arizona.
    
        @param name human readable name to test  
        """
        object_hrn = self.object_gid.get_hrn()
        if object_hrn == name:
            return
        if name.startswith(object_hrn + "."):
            return
        #if name.startswith(get_authority(name)):
            #return
    
        raise PermissionError(name)

    def determine_user_rights(self, caller_hrn, reg_record):
        """
        Given a user credential and a record, determine what set of rights the
        user should have to that record.
        
        This is intended to replace determine_user_rights() and
        verify_cancreate_credential()
        """

        rl = Rights()
        type = reg_record.type

        logger.debug("entering determine_user_rights with record %s and caller_hrn %s"%(reg_record, caller_hrn))

        if type == 'slice':
            # researchers in the slice are in the DB as-is
            researcher_hrns = [ user.hrn for user in reg_record.reg_researchers ]
            # locating PIs attached to that slice
            slice_pis=reg_record.get_pis()
            pi_hrns = [ user.hrn for user in slice_pis ]
            if (caller_hrn in researcher_hrns + pi_hrns):
                rl.add('refresh')
                rl.add('embed')
                rl.add('bind')
                rl.add('control')
                rl.add('info')

        elif type == 'authority':
            pi_hrns = [ user.hrn for user in reg_record.reg_pis ]
            if (caller_hrn == self.config.SFA_INTERFACE_HRN):
                rl.add('authority')
                rl.add('sa')
                rl.add('ma')
            if (caller_hrn in pi_hrns):
                rl.add('authority')
                rl.add('sa')
            # NOTE: for the PL implementation, this 'operators' list 
            # amounted to users with 'tech' role in that site 
            # it seems like this is not needed any longer, so for now I just drop that
            # operator_hrns = reg_record.get('operator',[])
            # if (caller_hrn in operator_hrns):
            #    rl.add('authority')
            #    rl.add('ma')

        elif type == 'user':
            rl.add('refresh')
            rl.add('resolve')
            rl.add('info')

        elif type == 'node':
            rl.add('operator')

        return rl

    def get_authority(self, hrn):
        return get_authority(hrn)

    def filter_creds_by_caller(self, creds, caller_hrn_list):
        """
        Returns a list of creds who's gid caller matches the 
        specified caller hrn
        """
        if not isinstance(creds, list):
            creds = [creds]
        creds = []
        if not isinstance(caller_hrn_list, list):
            caller_hrn_list = [caller_hrn_list]
        for cred in creds:
            try:
                tmp_cred = Credential(string=cred)
                if tmp_cred.get_gid_caller().get_hrn() in [caller_hrn_list]:
                    creds.append(cred)
            except: pass
        return creds
Exemple #12
0
class Importer:

    def __init__(self,auth_hierarchy=None,logger=None):
        self.config = Config()
        if auth_hierarchy is not None:
            self.auth_hierarchy=auth_hierarchy
        else:
            self.auth_hierarchy = Hierarchy ()
        if logger is not None:
            self.logger=logger
        else:
            self.logger = _SfaLogger(logfile='/var/log/sfa_import.log', loggername='importlog')
            self.logger.setLevelFromOptVerbose(self.config.SFA_API_LOGLEVEL)
# ugly side effect so that other modules get it right
        import sfa.util.sfalogging
        sfa.util.sfalogging.logger=logger
#        self.TrustedRoots = TrustedRoots(self.config.get_trustedroots_dir())    
   
    # check before creating a RegRecord entry as we run this over and over
    def record_exists (self, type, hrn):
       return dbsession.query(RegRecord).filter_by(hrn=hrn,type=type).count()!=0 

    def create_top_level_auth_records(self, hrn):
        """
        Create top level db records (includes root and sub authorities (local/remote)
        """
        # make sure parent exists
        parent_hrn = get_authority(hrn)
        if not parent_hrn:
            parent_hrn = hrn
        if not parent_hrn == hrn:
            self.create_top_level_auth_records(parent_hrn)

        # ensure key and cert exists:
        self.auth_hierarchy.create_top_level_auth(hrn)
        # create the db record if it doesnt already exist
        if not self.record_exists ('authority',hrn):
            auth_info = self.auth_hierarchy.get_auth_info(hrn)
            auth_record = RegAuthority(hrn=hrn, gid=auth_info.get_gid_object(),
                                       authority=get_authority(hrn))
            auth_record.just_created()
            dbsession.add (auth_record)
            dbsession.commit()
            self.logger.info("SfaImporter: imported authority (parent) %s " % auth_record)     
   

    def create_sm_client_record(self):
        """
        Create a user record for the Slicemanager service.
        """
        hrn = self.interface_hrn + '.slicemanager'
        urn = hrn_to_urn(hrn, 'user')
        if not self.auth_hierarchy.auth_exists(urn):
            self.logger.info("SfaImporter: creating Slice Manager user")
            self.auth_hierarchy.create_auth(urn)

        if self.record_exists ('user',hrn): return
        auth_info = self.auth_hierarchy.get_auth_info(hrn)
        user_record = RegUser(hrn=hrn, gid=auth_info.get_gid_object(),
                              authority=get_authority(hrn))
        user_record.just_created()
        dbsession.add (user_record)
        dbsession.commit()
        self.logger.info("SfaImporter: importing user (slicemanager) %s " % user_record)


    def create_interface_records(self):
        """
        Create a record for each SFA interface
        """
        # just create certs for all sfa interfaces even if they
        # aren't enabled
        auth_info = self.auth_hierarchy.get_auth_info(self.config.SFA_INTERFACE_HRN)
        pkey = auth_info.get_pkey_object()
        hrn=self.config.SFA_INTERFACE_HRN
        for type in  [ 'authority+sa', 'authority+am', 'authority+sm', ]:
            urn = hrn_to_urn(hrn, type)
            gid = self.auth_hierarchy.create_gid(urn, create_uuid(), pkey)
            # for now we have to preserve the authority+<> stuff
            if self.record_exists (type,hrn): continue
            interface_record = RegAuthority(type=type, hrn=hrn, gid=gid,
                                            authority=get_authority(hrn))
            interface_record.just_created()
            dbsession.add (interface_record)
            dbsession.commit()
            self.logger.info("SfaImporter: imported authority (%s) %s " % (type,interface_record))
 
    def run(self, options=None):
        if not self.config.SFA_REGISTRY_ENABLED:
            self.logger.critical("Importer: need SFA_REGISTRY_ENABLED to run import")

        # testbed-neutral : create local certificates and the like
        auth_hierarchy = Hierarchy ()
        self.create_top_level_auth_records(self.config.SFA_INTERFACE_HRN)
        self.create_interface_records()
 
        # testbed-specific
        testbed_importer = None
        generic=Generic.the_flavour()
        importer_class = generic.importer_class()
        if importer_class:
            begin_time=datetime.now()
            self.logger.info ("Starting import on %s, using class %s from flavour %s"%\
                         (begin_time,importer_class.__name__,generic.flavour))
            testbed_importer = importer_class (auth_hierarchy, self.logger)
            if testbed_importer:
                testbed_importer.add_options(options)
                testbed_importer.run (options)
            end_time=datetime.now()
            duration=end_time-begin_time
            self.logger.info("Import took %s"%duration)
Exemple #13
0
class Importer:
    def __init__(self, auth_hierarchy=None, logger=None):
        self.config = Config()
        if auth_hierarchy is not None:
            self.auth_hierarchy = auth_hierarchy
        else:
            self.auth_hierarchy = Hierarchy()
        if logger is not None:
            self.logger = logger
        else:
            self.logger = _SfaLogger(logfile='/var/log/sfa_import.log',
                                     loggername='importlog')
            self.logger.setLevelFromOptVerbose(self.config.SFA_API_LOGLEVEL)
# ugly side effect so that other modules get it right
        import sfa.util.sfalogging
        sfa.util.sfalogging.logger = logger
#        self.TrustedRoots = TrustedRoots(self.config.get_trustedroots_dir())

# check before creating a RegRecord entry as we run this over and over

    def record_exists(self, type, hrn):
        return global_dbsession.query(RegRecord).filter_by(
            hrn=hrn, type=type).count() != 0

    def create_top_level_auth_records(self, hrn):
        """
        Create top level db records (includes root and sub authorities (local/remote)
        """
        # make sure parent exists
        parent_hrn = get_authority(hrn)
        if not parent_hrn:
            parent_hrn = hrn
        if not parent_hrn == hrn:
            self.create_top_level_auth_records(parent_hrn)

        # ensure key and cert exists:
        self.auth_hierarchy.create_top_level_auth(hrn)
        # create the db record if it doesnt already exist
        if not self.record_exists('authority', hrn):
            auth_info = self.auth_hierarchy.get_auth_info(hrn)
            auth_record = RegAuthority(hrn=hrn,
                                       gid=auth_info.get_gid_object(),
                                       authority=get_authority(hrn))
            auth_record.just_created()
            global_dbsession.add(auth_record)
            global_dbsession.commit()
            self.logger.info("SfaImporter: imported authority (parent) %s " %
                             auth_record)

    def create_sm_client_record(self):
        """
        Create a user record for the Slicemanager service.
        """
        hrn = self.interface_hrn + '.slicemanager'
        urn = hrn_to_urn(hrn, 'user')
        if not self.auth_hierarchy.auth_exists(urn):
            self.logger.info("SfaImporter: creating Slice Manager user")
            self.auth_hierarchy.create_auth(urn)

        if self.record_exists('user', hrn): return
        auth_info = self.auth_hierarchy.get_auth_info(hrn)
        user_record = RegUser(hrn=hrn,
                              gid=auth_info.get_gid_object(),
                              authority=get_authority(hrn))
        user_record.just_created()
        global_dbsession.add(user_record)
        global_dbsession.commit()
        self.logger.info("SfaImporter: importing user (slicemanager) %s " %
                         user_record)

    def create_interface_records(self):
        """
        Create a record for each SFA interface
        """
        # just create certs for all sfa interfaces even if they
        # aren't enabled
        auth_info = self.auth_hierarchy.get_auth_info(
            self.config.SFA_INTERFACE_HRN)
        pkey = auth_info.get_pkey_object()
        hrn = self.config.SFA_INTERFACE_HRN
        for type in [
                'authority+sa',
                'authority+am',
                'authority+sm',
        ]:
            urn = hrn_to_urn(hrn, type)
            gid = self.auth_hierarchy.create_gid(urn, create_uuid(), pkey)
            # for now we have to preserve the authority+<> stuff
            if self.record_exists(type, hrn): continue
            interface_record = RegAuthority(type=type,
                                            hrn=hrn,
                                            gid=gid,
                                            authority=get_authority(hrn))
            interface_record.just_created()
            global_dbsession.add(interface_record)
            global_dbsession.commit()
            self.logger.info("SfaImporter: imported authority (%s) %s " %
                             (type, interface_record))

    def run(self, options=None):
        if not self.config.SFA_REGISTRY_ENABLED:
            self.logger.critical(
                "Importer: need SFA_REGISTRY_ENABLED to run import")

        # testbed-neutral : create local certificates and the like
        auth_hierarchy = Hierarchy()
        self.create_top_level_auth_records(self.config.SFA_INTERFACE_HRN)
        self.create_interface_records()

        # testbed-specific
        testbed_importer = None
        generic = Generic.the_flavour()
        importer_class = generic.importer_class()
        if importer_class:
            begin_time = datetime.now()
            self.logger.info ("Starting import on %s, using class %s from flavour %s"%\
                         (begin_time,importer_class.__name__,generic.flavour))
            testbed_importer = importer_class(auth_hierarchy, self.logger)
            if testbed_importer:
                testbed_importer.add_options(options)
                testbed_importer.run(options)
            end_time = datetime.now()
            duration = end_time - begin_time
            self.logger.info("Import took %s" % duration)