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)
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)
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
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
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
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)
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)
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)
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
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
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
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)
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)