X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=geni%2Fregistry.py;h=c39c243eeac2d2e64841f4310d21d19b510bc9b9;hb=fcd66c68854a7c43522d7002e465b3e6178217e5;hp=5184e99464c0598e64a0c9dd8446c9d2c095a3c0;hpb=01443db1ec49db8612171aa86d0a88f5a4984b7c;p=sfa.git diff --git a/geni/registry.py b/geni/registry.py index 5184e994..c39c243e 100644 --- a/geni/registry.py +++ b/geni/registry.py @@ -122,6 +122,7 @@ class Registry(GeniServer): self.server.register_function(self.get_self_credential) self.server.register_function(self.get_credential) self.server.register_function(self.get_gid) + self.server.register_function(self.get_ticket) self.server.register_function(self.register) self.server.register_function(self.remove) self.server.register_function(self.update) @@ -319,6 +320,62 @@ class Registry(GeniServer): self.fill_record_pl_info(record) self.fill_record_geni_info(record) + def update_membership_list(self, oldRecord, record, listName, addFunc, delFunc): + # get a list of the HRNs tht are members of the old and new records + if oldRecord: + if oldRecord.pl_info == None: + oldRecord.pl_info = {} + oldList = oldRecord.get_geni_info().get(listName, []) + else: + oldList = [] + newList = record.get_geni_info().get(listName, []) + + # if the lists are the same, then we don't have to update anything + if (oldList == newList): + return + + # build a list of the new person ids, by looking up each person to get + # their pointer + newIdList = [] + for hrn in newList: + userRecord = self.resolve_raw("user", hrn)[0] + newIdList.append(userRecord.get_pointer()) + + # build a list of the old person ids from the person_ids field of the + # pl_info + if oldRecord: + oldIdList = oldRecord.pl_info.get("person_ids", []) + containerId = oldRecord.get_pointer() + else: + # if oldRecord==None, then we are doing a Register, instead of an + # update. + oldIdList = [] + containerId = record.get_pointer() + + # add people who are in the new list, but not the oldList + for personId in newIdList: + if not (personId in oldIdList): + print "adding id", personId, "to", record.get_name() + addFunc(self.pl_auth, personId, containerId) + + # remove people who are in the old list, but not the new list + for personId in oldIdList: + if not (personId in newIdList): + print "removing id", personId, "from", record.get_name() + delFunc(self.pl_auth, personId, containerId) + + def update_membership(self, oldRecord, record): + if record.type == "slice": + self.update_membership_list(oldRecord, record, 'researcher', + self.shell.AddPersonToSlice, + self.shell.DeletePersonFromSlice) + elif record.type == "sa": + # TODO + pass + elif record.type == "ma": + # TODO + pass + ## # GENI API: register # @@ -417,6 +474,9 @@ class Registry(GeniServer): table.insert(record) + # update membership for researchers, pis, owners, operators + self.update_membership(None, record) + return record.get_gid_object().save_to_string(save_parents=True) ## @@ -473,7 +533,7 @@ class Registry(GeniServer): return True ## - # GENI API: Register + # GENI API: Update # # Update an object in the registry. Currently, this only updates the # PLC information associated with the record. The Geni fields (name, type, @@ -503,8 +563,14 @@ class Registry(GeniServer): existing_record_list = table.resolve(type, record.get_name()) if not existing_record_list: raise RecordNotFound(record.get_name()) - existing_record = existing_record_list[0] + + # Update_membership needs the membership lists in the existing record + # filled in, so it can see if members were added or removed + self.fill_record_info(existing_record) + + # Use the pointer from the existing record, not the one that the user + # gave us. This prevents the user from inserting a forged pointer pointer = existing_record.get_pointer() # update the PLC information that was specified with the record @@ -534,6 +600,9 @@ class Registry(GeniServer): else: raise UnknownGeniType(type) + # update membership for researchers, pis, owners, operators + self.update_membership(existing_record, record) + ## # List the records in an authority. The objectGID in the supplied credential # should name the authority that will be listed. @@ -745,6 +814,29 @@ class Registry(GeniServer): return cred.save_to_string(save_parents=True) + ## + # verify_cancreate_credential + # + # Verify that a user can retrieve a particular type of credential. For + # slices, the user must be on the researcher list. For SA and MA the user + # must be on the pi and operator lists respectively. + + def verify_cancreate_credential(self, src_cred, record): + type = record.get_type() + cred_object_hrn = src_cred.get_gid_object().get_hrn() + if type=="slice": + researchers = record.get_geni_info().get("researcher", []) + if not (cred_object_hrn in researchers): + raise PermissionError(cred_object_hrn + " is not in researcher list for " + record.get_name()) + elif type == "sa": + pis = record.get_geni_info().get("pi", []) + if not (cred_object_hrn in pis): + raise PermissionError(cred_object_hrn + " is not in pi list for " + record.get_name()) + elif type == "ma": + operators = record.get_geni_info().get("operator", []) + if not (cred_object_hrn in operators): + raise PermissionError(cred_object_hrn + " is not in operator list for " + record.get_name()) + ## # GENI API: Get_credential # @@ -772,6 +864,12 @@ class Registry(GeniServer): records = self.resolve_raw(type, name, must_exist=True) record = records[0] + # verify_cancreate_credential requires that the member lists + # (researchers, pis, etc) be filled in + self.fill_record_info(record) + + self.verify_cancreate_credential(self.client_cred, record) + # TODO: Check permission that self.client_cred can access the object object_gid = record.get_gid_object() @@ -799,6 +897,60 @@ class Registry(GeniServer): return new_cred.save_to_string(save_parents=True) + ## + # GENI API: get_ticket + # + # Retrieve a ticket. This operation is currently implemented on PLC + # only (see SFA, engineering decisions); it is not implemented on + # components. + # + # The ticket is filled in with information from the PLC database. This + # information includes resources, and attributes such as user keys and + # initscripts. + # + # @param cred credential string + # @param name name of the slice to retrieve a ticket for + # @param rspec resource specification dictionary + # + # @return the string representation of a ticket object + + def get_ticket(self, cred, name, rspec): + self.decode_authentication(cred, "getticket") + + self.verify_object_belongs_to_me(name) + + self.verify_object_permission(name) + + # XXX much of this code looks like get_credential... are they so similar + # that they should be combined? + + auth_hrn = get_authority(name) + auth_info = self.get_auth_info(auth_hrn) + + records = self.resolve_raw("slice", name, must_exist=True) + record = records[0] + + object_gid = record.get_gid_object() + new_ticket = Ticket(subject = object_gid.get_subject()) + new_ticket.set_gid_caller(self.client_gid) + new_ticket.set_gid_object(object_gid) + new_ticket.set_issuer(key=auth_info.get_pkey_object(), subject=auth_hrn) + new_ticket.set_pubkey(object_gid.get_pubkey()) + + self.fill_record_info(record) + + (attributes, rspec) = self.record_to_slice_info(record) + + new_ticket.set_attributes(attributes) + new_ticket.set_rspec(rspec) + + new_ticket.set_parent(AuthHierarchy.get_auth_ticket(auth_hrn)) + + new_ticket.encode() + new_ticket.sign() + + return new_ticket.save_to_string(save_parents=True) + ## # GENI_API: Create_gid #