2 # Registry is a GeniServer that implements the Registry interface
9 from geni.util.credential import Credential
10 from geni.util.hierarchy import Hierarchy
11 from geni.util.trustedroot import TrustedRootList
12 from geni.util.cert import Keypair, Certificate
13 from geni.util.gid import GID, create_uuid
14 from geni.util.geniserver import GeniServer
15 from geni.util.record import GeniRecord
16 from geni.util.rights import RightList
17 from geni.util.genitable import GeniTable
18 from geni.util.geniticket import Ticket
19 from geni.util.excep import *
20 from geni.util.misc import *
21 from geni.util.config import *
24 # Convert geni fields to PLC fields for use when registering up updating
25 # registry record in the PLC database
27 # @param type type of record (user, slice, ...)
28 # @param hrn human readable name
29 # @param geni_fields dictionary of geni fields
30 # @param pl_fields dictionary of PLC fields (output)
32 def geni_fields_to_pl_fields(type, hrn, geni_fields, pl_fields):
34 if not "email" in pl_fields:
35 if not "email" in geni_fields:
36 raise MissingGeniInfo("email")
37 pl_fields["email"] = geni_fields["email"]
39 if not "first_name" in pl_fields:
40 pl_fields["first_name"] = "geni"
42 if not "last_name" in pl_fields:
43 pl_fields["last_name"] = hrn
46 if not "instantiation" in pl_fields:
47 pl_fields["instantiation"] = "delegated" # "plc-instantiated"
48 if not "name" in pl_fields:
49 pl_fields["name"] = hrn_to_pl_slicename(hrn)
50 if not "max_nodes" in pl_fields:
51 pl_fields["max_nodes"] = 10
54 if not "hostname" in pl_fields:
55 if not "dns" in geni_fields:
56 raise MissingGeniInfo("dns")
57 pl_fields["hostname"] = geni_fields["dns"]
59 if not "model" in pl_fields:
60 pl_fields["model"] = "geni"
63 pl_fields["login_base"] = hrn_to_pl_login_base(hrn)
65 if not "name" in pl_fields:
66 pl_fields["name"] = hrn
68 if not "abbreviated_name" in pl_fields:
69 pl_fields["abbreviated_name"] = hrn
71 if not "enabled" in pl_fields:
72 pl_fields["enabled"] = True
74 if not "is_public" in pl_fields:
75 pl_fields["is_public"] = True
78 # Registry is a GeniServer that serves registry and slice operations at PLC.
80 class Registry(GeniServer):
82 # Create a new registry object.
84 # @param ip the ip address to listen on
85 # @param port the port to listen on
86 # @param key_file private key filename of registry
87 # @param cert_file certificate filename containing public key (could be a GID file)
89 def __init__(self, ip, port, key_file, cert_file):
90 GeniServer.__init__(self, ip, port, key_file, cert_file)
92 # get PL account settings from config module
93 self.pl_auth = get_pl_auth()
95 # connect to planetlab
96 if "Url" in self.pl_auth:
97 self.connect_remote_shell()
99 self.connect_local_shell()
102 # Connect to a remote shell via XMLRPC
104 def connect_remote_shell(self):
105 from geni.util import remoteshell
106 self.shell = remoteshell.RemoteShell()
109 # Connect to a local shell via local API functions
111 def connect_local_shell(self):
113 self.shell = PLC.Shell.Shell(globals = globals())
116 # Register the server RPCs for the registry
118 def register_functions(self):
119 GeniServer.register_functions(self)
121 self.server.register_function(self.create_gid)
122 self.server.register_function(self.get_self_credential)
123 self.server.register_function(self.get_credential)
124 self.server.register_function(self.get_gid)
125 self.server.register_function(self.get_ticket)
126 self.server.register_function(self.register)
127 self.server.register_function(self.remove)
128 self.server.register_function(self.update)
129 self.server.register_function(self.list)
130 self.server.register_function(self.resolve)
133 # Given an authority name, return the information for that authority. This
134 # is basically a stub that calls the hierarchy module.
136 # @param auth_hrn human readable name of authority
138 def get_auth_info(self, auth_hrn):
139 return self.hierarchy.get_auth_info(auth_hrn)
142 # Given an authority name, return the database table for that authority. If
143 # the database table does not exist, then one will be automatically
146 # @param auth_name human readable name of authority
148 def get_auth_table(self, auth_name):
149 auth_info = self.get_auth_info(auth_name)
151 table = GeniTable(hrn=auth_name,
152 cninfo=auth_info.get_dbinfo())
154 # if the table doesn't exist, then it means we haven't put any records
155 # into this authority yet.
157 if not table.exists():
158 print "Registry: creating table for authority", auth_name
164 # Verify that an authority belongs to this registry. This is basically left
165 # up to the implementation of the hierarchy module. If the specified name
166 # does not belong to this registry, an exception is thrown indicating the
167 # caller should contact someone else.
169 # @param auth_name human readable name of authority
171 def verify_auth_belongs_to_me(self, name):
172 # get_auth_info will throw an exception if the authority does not
174 self.get_auth_info(name)
177 # Verify that an object belongs to this registry. By extension, this implies
178 # that the authority that owns the object belongs to this registry. If the
179 # object does not belong to this registry, then an exception is thrown.
181 # @param name human readable name of object
183 def verify_object_belongs_to_me(self, name):
184 auth_name = get_authority(name)
186 # the root authority belongs to the registry by default?
187 # TODO: is this true?
189 self.verify_auth_belongs_to_me(auth_name)
192 # Verify that the object_gid that was specified in the credential allows
193 # permission to the object 'name'. This is done by a simple prefix test.
194 # For example, an object_gid for planetlab.us.arizona would match the
195 # objects planetlab.us.arizona.slice1 and planetlab.us.arizona.
197 # @param name human readable name to test
199 def verify_object_permission(self, name):
200 object_hrn = self.object_gid.get_hrn()
201 if object_hrn == name:
203 if name.startswith(object_hrn + "."):
205 raise PermissionError(name)
208 # Fill in the planetlab-specific fields of a Geni record. This involves
209 # calling the appropriate PLC methods to retrieve the database record for
212 # PLC data is filled into the pl_info field of the record.
214 # @param record record to fill in fields (in/out param)
216 def fill_record_pl_info(self, record):
217 type = record.get_type()
218 pointer = record.get_pointer()
220 # records with pointer==-1 do not have plc info associated with them.
221 # for example, the top level authority records which are
222 # authorities, but not PL "sites"
224 record.set_pl_info({})
227 if (type == "sa") or (type == "ma"):
228 pl_res = self.shell.GetSites(self.pl_auth, [pointer])
229 elif (type == "slice"):
230 pl_res = self.shell.GetSlices(self.pl_auth, [pointer])
231 elif (type == "user"):
232 pl_res = self.shell.GetPersons(self.pl_auth, [pointer])
233 elif (type == "node"):
234 pl_res = self.shell.GetNodes(self.pl_auth, [pointer])
236 raise UnknownGeniType(type)
239 # the planetlab record no longer exists
240 # TODO: delete the geni record ?
241 raise PlanetLabRecordDoesNotExist(record.get_name())
243 record.set_pl_info(pl_res[0])
246 # Look up user records given PLC user-ids. This is used as part of the
247 # process for reverse-mapping PLC records into Geni records.
249 # @param auth_table database table for the authority that holds the user records
250 # @param user_id_list list of user ids
251 # @param role either "*" or a string describing the role to look for ("pi", "user", ...)
253 # TODO: This function currently only searches one authority because it would
254 # be inefficient to brute-force search all authorities for a user id. The
255 # solution would likely be to implement a reverse mapping of user-id to
258 def lookup_users(self, auth_table, user_id_list, role="*"):
260 for person_id in user_id_list:
261 user_records = auth_table.find("user", person_id, "pointer")
262 for user_record in user_records:
263 self.fill_record_info(user_record)
265 user_roles = user_record.get_pl_info().get("roles")
266 if (role=="*") or (role in user_roles):
267 record_list.append(user_record.get_name())
271 # Fill in the geni-specific fields of the record.
273 # Note: It is assumed the fill_record_pl_info() has already been performed
276 def fill_record_geni_info(self, record):
278 type = record.get_type()
280 if (type == "slice"):
281 auth_table = self.get_auth_table(get_authority(record.get_name()))
282 person_ids = record.pl_info.get("person_ids", [])
283 researchers = self.lookup_users(auth_table, person_ids)
284 geni_info['researcher'] = researchers
287 auth_table = self.get_auth_table(record.get_name())
288 person_ids = record.pl_info.get("person_ids", [])
289 pis = self.lookup_users(auth_table, person_ids, "pi")
290 geni_info['pi'] = pis
291 # TODO: OrganizationName
294 auth_table = self.get_auth_table(record.get_name())
295 person_ids = record.pl_info.get("person_ids", [])
296 operators = self.lookup_users(auth_table, person_ids, "tech")
297 geni_info['operator'] = operators
298 # TODO: OrganizationName
300 auth_table = self.get_auth_table(record.get_name())
301 person_ids = record.pl_info.get("person_ids", [])
302 owners = self.lookup_users(auth_table, person_ids, "admin")
303 geni_info['owner'] = owners
305 elif (type == "node"):
306 geni_info['dns'] = record.pl_info.get("hostname", "")
307 # TODO: URI, LatLong, IP, DNS
309 elif (type == "user"):
310 geni_info['email'] = record.pl_info.get("email", "")
311 # TODO: PostalAddress, Phone
313 record.set_geni_info(geni_info)
316 # Given a Geni record, fill in the PLC-specific and Geni-specific fields
319 def fill_record_info(self, record):
320 self.fill_record_pl_info(record)
321 self.fill_record_geni_info(record)
323 def update_membership_list(self, oldRecord, record, listName, addFunc, delFunc):
324 # get a list of the HRNs tht are members of the old and new records
\r
326 if oldRecord.pl_info == None:
\r
327 oldRecord.pl_info = {}
\r
328 oldList = oldRecord.get_geni_info().get(listName, [])
\r
331 newList = record.get_geni_info().get(listName, [])
\r
333 # if the lists are the same, then we don't have to update anything
\r
334 if (oldList == newList):
\r
337 # build a list of the new person ids, by looking up each person to get
\r
340 for hrn in newList:
\r
341 userRecord = self.resolve_raw("user", hrn)[0]
\r
342 newIdList.append(userRecord.get_pointer())
\r
344 # build a list of the old person ids from the person_ids field of the
\r
347 oldIdList = oldRecord.pl_info.get("person_ids", [])
\r
348 containerId = oldRecord.get_pointer()
\r
350 # if oldRecord==None, then we are doing a Register, instead of an
\r
353 containerId = record.get_pointer()
\r
355 # add people who are in the new list, but not the oldList
\r
356 for personId in newIdList:
\r
357 if not (personId in oldIdList):
\r
358 print "adding id", personId, "to", record.get_name()
\r
359 addFunc(self.pl_auth, personId, containerId)
\r
361 # remove people who are in the old list, but not the new list
\r
362 for personId in oldIdList:
\r
363 if not (personId in newIdList):
\r
364 print "removing id", personId, "from", record.get_name()
\r
365 delFunc(self.pl_auth, personId, containerId)
\r
367 def update_membership(self, oldRecord, record):
\r
368 if record.type == "slice":
\r
369 self.update_membership_list(oldRecord, record, 'researcher',
\r
370 self.shell.AddPersonToSlice,
\r
371 self.shell.DeletePersonFromSlice)
\r
372 elif record.type == "sa":
\r
375 elif record.type == "ma":
\r
382 # Register an object with the registry. In addition to being stored in the
383 # Geni database, the appropriate records will also be created in the
386 # @param cred credential string
387 # @param record_dict dictionary containing record fields
389 def register(self, cred, record_dict):
390 self.decode_authentication(cred, "register")
392 record = GeniRecord(dict = record_dict)
393 type = record.get_type()
394 name = record.get_name()
396 auth_name = get_authority(name)
397 self.verify_object_permission(auth_name)
398 auth_info = self.get_auth_info(auth_name)
399 table = self.get_auth_table(auth_name)
403 # check if record already exists
404 existing_records = table.resolve(type, name)
406 raise ExistingRecord(name)
408 if (type == "sa") or (type=="ma"):
410 if not self.hierarchy.auth_exists(name):
411 self.hierarchy.create_auth(name)
413 # authorities are special since they are managed by the registry
414 # rather than by the caller. We create our own GID for the
415 # authority rather than relying on the caller to supply one.
417 # get the GID from the newly created authority
418 child_auth_info = self.get_auth_info(name)
419 gid = auth_info.get_gid_object()
420 record.set_gid(gid.save_to_string(save_parents=True))
422 geni_fields = record.get_geni_info()
423 site_fields = record.get_pl_info()
425 # if registering a sa, see if a ma already exists
426 # if registering a ma, see if a sa already exists
428 other_rec = table.resolve("ma", record.get_name())
430 other_rec = table.resolve("sa", record.get_name())
433 print "linking ma and sa to the same plc site"
434 pointer = other_rec[0].get_pointer()
436 geni_fields_to_pl_fields(type, name, geni_fields, site_fields)
437 print "adding site with fields", site_fields
438 pointer = self.shell.AddSite(self.pl_auth, site_fields)
440 record.set_pointer(pointer)
442 elif (type == "slice"):
443 geni_fields = record.get_geni_info()
444 slice_fields = record.get_pl_info()
446 geni_fields_to_pl_fields(type, name, geni_fields, slice_fields)
448 pointer = self.shell.AddSlice(self.pl_auth, slice_fields)
449 record.set_pointer(pointer)
451 elif (type == "user"):
452 geni_fields = record.get_geni_info()
453 user_fields = record.get_pl_info()
455 geni_fields_to_pl_fields(type, name, geni_fields, user_fields)
457 pointer = self.shell.AddPerson(self.pl_auth, user_fields)
458 record.set_pointer(pointer)
460 elif (type == "node"):
461 geni_fields = record.get_geni_info()
462 node_fields = record.get_pl_info()
464 geni_fields_to_pl_fields(type, name, geni_fields, node_fields)
466 login_base = hrn_to_pl_login_base(auth_name)
468 print "calling addnode with", login_base, node_fields
469 pointer = self.shell.AddNode(self.pl_auth, login_base, node_fields)
470 record.set_pointer(pointer)
473 raise UnknownGeniType(type)
477 # update membership for researchers, pis, owners, operators
478 self.update_membership(None, record)
480 return record.get_gid_object().save_to_string(save_parents=True)
485 # Remove an object from the registry. If the object represents a PLC object,
486 # then the PLC records will also be removed.
488 # @param cred credential string
489 # @param record_dict dictionary containing record fields. The only relevant
490 # fields of the record are 'name' and 'type', which are used to lookup
491 # the current copy of the record in the Geni database, to make sure
492 # that the appopriate record is removed.
494 def remove(self, cred, type, hrn):
495 self.decode_authentication(cred, "remove")
497 self.verify_object_permission(hrn)
499 auth_name = get_authority(hrn)
500 table = self.get_auth_table(auth_name)
502 record_list = table.resolve(type, hrn)
504 raise RecordNotFound(hrn)
505 record = record_list[0]
509 self.shell.DeletePerson(self.pl_auth, record.get_pointer())
510 elif type == "slice":
511 self.shell.DeleteSlice(self.pl_auth, record.get_pointer())
513 self.shell.DeleteNode(self.pl_auth, record.get_pointer())
514 elif (type == "sa") or (type == "ma"):
516 other_rec = table.resolve("ma", record.get_name())
518 other_rec = table.resolve("sa", record.get_name())
521 # sa and ma both map to a site, so if we are deleting one
522 # but the other still exists, then do not delete the site
523 print "not removing site", record.get_name(), "because either sa or ma still exists"
526 print "removing site", record.get_name()
527 self.shell.DeleteSite(self.pl_auth, record.get_pointer())
529 raise UnknownGeniType(type)
538 # Update an object in the registry. Currently, this only updates the
539 # PLC information associated with the record. The Geni fields (name, type,
542 # The record is expected to have the pl_info field filled in with the data
543 # that should be updated.
545 # TODO: The geni_info member of the record should be parsed and the pl_info
546 # adjusted as necessary (add/remove users from a slice, etc)
548 # @param cred credential string specifying rights of the caller
549 # @param record a record dictionary to be updated
551 def update(self, cred, record_dict):
552 self.decode_authentication(cred, "update")
554 record = GeniRecord(dict = record_dict)
555 type = record.get_type()
557 self.verify_object_permission(record.get_name())
559 auth_name = get_authority(record.get_name())
561 auth_name = record.get_name()
562 table = self.get_auth_table(auth_name)
564 # make sure the record exists
565 existing_record_list = table.resolve(type, record.get_name())
566 if not existing_record_list:
567 raise RecordNotFound(record.get_name())
568 existing_record = existing_record_list[0]
570 # Update_membership needs the membership lists in the existing record
571 # filled in, so it can see if members were added or removed
572 self.fill_record_info(existing_record)
574 # Use the pointer from the existing record, not the one that the user
575 # gave us. This prevents the user from inserting a forged pointer
576 pointer = existing_record.get_pointer()
578 # update the PLC information that was specified with the record
580 if (type == "sa") or (type == "ma"):
581 self.shell.UpdateSite(self.pl_auth, pointer, record.get_pl_info())
583 elif type == "slice":
584 self.shell.UpdateSlice(self.pl_auth, pointer, record.get_pl_info())
587 # SMBAKER: UpdatePerson only allows a limited set of fields to be
588 # updated. Ideally we should have a more generic way of doing
589 # this. I copied the field names from UpdatePerson.py...
591 all_fields = record.get_pl_info()
592 for key in all_fields.keys():
593 if key in ['first_name', 'last_name', 'title', 'email',
594 'password', 'phone', 'url', 'bio', 'accepted_aup',
\r
596 update_fields[key] = all_fields[key]
597 self.shell.UpdatePerson(self.pl_auth, pointer, update_fields)
600 self.shell.UpdateNode(self.pl_auth, pointer, record.get_pl_info())
603 raise UnknownGeniType(type)
605 # update membership for researchers, pis, owners, operators
\r
606 self.update_membership(existing_record, record)
609 # List the records in an authority. The objectGID in the supplied credential
610 # should name the authority that will be listed.
612 # TODO: List doesn't take an hrn and uses the hrn contained in the
613 # objectGid of the credential. Does this mean the only way to list an
614 # authority is by having a credential for that authority?
616 # @param cred credential string specifying rights of the caller
618 # @return list of record dictionaries
619 def list(self, cred, auth_hrn):
620 self.decode_authentication(cred, "list")
622 if not self.hierarchy.auth_exists(auth_hrn):
623 raise MissingAuthority(auth_hrn)
625 table = self.get_auth_table(auth_hrn)
627 records = table.list()
630 for record in records:
632 self.fill_record_info(record)
633 good_records.append(record)
634 except PlanetLabRecordDoesNotExist:
635 # silently drop the ones that are missing in PL.
636 # is this the right thing to do?
637 print "ignoring geni record ", record.get_name(), " because pl record does not exist"
641 for record in good_records:
642 dicts.append(record.as_dict())
649 # Resolve a record. This is an internal version of the Resolve API call
650 # and returns records in record object format rather than dictionaries
651 # that may be sent over XMLRPC.
653 # @param type type of record to resolve (user | sa | ma | slice | node)
654 # @param name human readable name of object
655 # @param must_exist if True, throw an exception if no records are found
657 # @return a list of record objects, or an empty list []
659 def resolve_raw(self, type, name, must_exist=True):
660 auth_name = get_authority(name)
663 table = self.get_auth_table(auth_name)
664 records = table.resolve(type, name)
665 if (not records) and must_exist:
666 raise RecordNotFound(name)
669 for record in records:
671 self.fill_record_info(record)
672 good_records.append(record)
673 except PlanetLabRecordDoesNotExist:
674 # silently drop the ones that are missing in PL.
675 # is this the right thing to do?
676 print "ignoring geni record ", record.get_name(), "because pl record does not exist"
684 # This is a wrapper around resolve_raw that converts records objects into
685 # dictionaries before returning them to the user.
687 # @param cred credential string authorizing the caller
688 # @param name human readable name to resolve
690 # @return a list of record dictionaries, or an empty list
692 def resolve(self, cred, name):
693 self.decode_authentication(cred, "resolve")
695 records = self.resolve_raw("*", name)
697 for record in records:
698 dicts.append(record.as_dict())
705 # Retrieve the GID for an object. This function looks up a record in the
706 # registry and returns the GID of the record if it exists.
707 # TODO: Is this function needed? It's a shortcut for Resolve()
709 # @param name hrn to look up
711 # @return the string representation of a GID object
713 def get_gid(self, name):
714 self.verify_object_belongs_to_me(name)
715 records = self.resolve_raw("*", name)
717 for record in records:
718 gid = record.get_gid()
719 gid_string_list.append(gid.save_to_string(save_parents=True))
720 return gid_string_list
723 # Determine tje rights that an object should have. The rights are entirely
724 # dependent on the type of the object. For example, users automatically
725 # get "refresh", "resolve", and "info".
727 # @param type the type of the object (user | sa | ma | slice | node)
728 # @param name human readable name of the object (not used at this time)
730 # @return RightList object containing rights
732 def determine_rights(self, type, name):
735 # rights seem to be somewhat redundant with the type of the credential.
736 # For example, a "sa" credential implies the authority right, because
737 # a sa credential cannot be issued to a user who is not an owner of
745 rl.add("authority,sa")
747 rl.add("authority,ma")
748 elif type == "slice":
754 elif type == "component":
760 # GENI API: Get_self_credential
762 # Get_self_credential a degenerate version of get_credential used by a
763 # client to get his initial credential when he doesn't have one. This is
764 # the same as get_credential(..., cred=None,...).
766 # The registry ensures that the client is the principal that is named by
767 # (type, name) by comparing the public key in the record's GID to the
768 # private key used to encrypt the client-side of the HTTPS connection. Thus
769 # it is impossible for one principal to retrieve another principal's
770 # credential without having the appropriate private key.
772 # @param type type of object (user | slice | sa | ma | node
773 # @param name human readable name of object
775 # @return the string representation of a credential object
777 def get_self_credential(self, type, name):
778 self.verify_object_belongs_to_me(name)
780 auth_hrn = get_authority(name)
783 auth_info = self.get_auth_info(auth_hrn)
784 # find a record that matches
785 records = self.resolve_raw(type, name, must_exist=True)
788 gid = record.get_gid_object()
789 peer_cert = self.server.peer_cert
790 if not peer_cert.is_pubkey(gid.get_pubkey()):
791 raise ConnectionKeyGIDMismatch(gid.get_subject())
793 # create the credential
794 gid = record.get_gid_object()
795 cred = Credential(subject = gid.get_subject())
796 cred.set_gid_caller(gid)
797 cred.set_gid_object(gid)
798 cred.set_issuer(key=auth_info.get_pkey_object(), subject=auth_hrn)
799 cred.set_pubkey(gid.get_pubkey())
801 rl = self.determine_rights(type, name)
802 cred.set_privileges(rl)
804 # determine the type of credential that we want to use as a parent for
807 if (type == "ma") or (type == "node"):
808 auth_kind = "authority,ma"
809 else: # user, slice, sa
810 auth_kind = "authority,sa"
812 cred.set_parent(self.hierarchy.get_auth_cred(auth_hrn, kind=auth_kind))
817 return cred.save_to_string(save_parents=True)
820 # verify_cancreate_credential
822 # Verify that a user can retrieve a particular type of credential. For
823 # slices, the user must be on the researcher list. For SA and MA the user
824 # must be on the pi and operator lists respectively.
826 def verify_cancreate_credential(self, src_cred, record):
827 type = record.get_type()
828 cred_object_hrn = src_cred.get_gid_object().get_hrn()
830 if cred_object_hrn in [config.GENI_REGISTRY_ROOT_AUTH]:
833 researchers = record.get_geni_info().get("researcher", [])
834 if not (cred_object_hrn in researchers):
835 raise PermissionError(cred_object_hrn + " is not in researcher list for " + record.get_name())
837 pis = record.get_geni_info().get("pi", [])
838 if not (cred_object_hrn in pis):
839 raise PermissionError(cred_object_hrn + " is not in pi list for " + record.get_name())
841 operators = record.get_geni_info().get("operator", [])
842 if not (cred_object_hrn in operators):
843 raise PermissionError(cred_object_hrn + " is not in operator list for " + record.get_name())
846 # GENI API: Get_credential
848 # Retrieve a credential for an object.
850 # If cred==None, then the behavior reverts to get_self_credential()
852 # @param cred credential object specifying rights of the caller
853 # @param type type of object (user | slice | sa | ma | node)
854 # @param name human readable name of object
856 # @return the string representation of a credental object
858 def get_credential(self, cred, type, name):
860 return get_self_credential(self, type, name)
862 self.decode_authentication(cred, "getcredential")
864 self.verify_object_belongs_to_me(name)
866 auth_hrn = get_authority(name)
869 auth_info = self.get_auth_info(auth_hrn)
871 records = self.resolve_raw(type, name, must_exist=True)
874 # verify_cancreate_credential requires that the member lists
875 # (researchers, pis, etc) be filled in
876 self.fill_record_info(record)
878 self.verify_cancreate_credential(self.client_cred, record)
880 # TODO: Check permission that self.client_cred can access the object
882 object_gid = record.get_gid_object()
883 new_cred = Credential(subject = object_gid.get_subject())
884 new_cred.set_gid_caller(self.client_gid)
885 new_cred.set_gid_object(object_gid)
886 new_cred.set_issuer(key=auth_info.get_pkey_object(), subject=auth_hrn)
887 new_cred.set_pubkey(object_gid.get_pubkey())
889 rl = self.determine_rights(type, name)
890 new_cred.set_privileges(rl)
892 # determine the type of credential that we want to use as a parent for
895 if (type == "ma") or (type == "node"):
896 auth_kind = "authority,ma"
897 else: # user, slice, sa
898 auth_kind = "authority,sa"
900 new_cred.set_parent(self.hierarchy.get_auth_cred(auth_hrn, kind=auth_kind))
905 return new_cred.save_to_string(save_parents=True)
908 # GENI API: get_ticket
910 # Retrieve a ticket. This operation is currently implemented on PLC
911 # only (see SFA, engineering decisions); it is not implemented on
914 # The ticket is filled in with information from the PLC database. This
915 # information includes resources, and attributes such as user keys and
918 # @param cred credential string
919 # @param name name of the slice to retrieve a ticket for
920 # @param rspec resource specification dictionary
922 # @return the string representation of a ticket object
924 def get_ticket(self, cred, name, rspec):
925 self.decode_authentication(cred, "getticket")
927 self.verify_object_belongs_to_me(name)
929 self.verify_object_permission(name)
931 # XXX much of this code looks like get_credential... are they so similar
932 # that they should be combined?
934 auth_hrn = get_authority(name)
937 auth_info = self.get_auth_info(auth_hrn)
939 records = self.resolve_raw("slice", name, must_exist=True)
942 object_gid = record.get_gid_object()
943 new_ticket = Ticket(subject = object_gid.get_subject())
944 new_ticket.set_gid_caller(self.client_gid)
945 new_ticket.set_gid_object(object_gid)
946 new_ticket.set_issuer(key=auth_info.get_pkey_object(), subject=auth_hrn)
947 new_ticket.set_pubkey(object_gid.get_pubkey())
949 self.fill_record_info(record)
951 (attributes, rspec) = self.record_to_slice_info(record)
953 new_ticket.set_attributes(attributes)
954 new_ticket.set_rspec(rspec)
956 new_ticket.set_parent(AuthHierarchy.get_auth_ticket(auth_hrn))
961 return new_ticket.save_to_string(save_parents=True)
964 # GENI_API: Create_gid
966 # Create a new GID. For MAs and SAs that are physically located on the
967 # registry, this allows a owner/operator/PI to create a new GID and have it
968 # signed by his respective authority.
970 # @param cred credential of caller
971 # @param name hrn for new GID
972 # @param uuid unique identifier for new GID
973 # @param pkey_string public-key string (TODO: why is this a string and not a keypair object?)
975 # @return the string representation of a GID object
977 def create_gid(self, cred, name, uuid, pubkey_str):
978 self.decode_authentication(cred, "getcredential")
980 self.verify_object_belongs_to_me(name)
982 self.verify_object_permission(name)
988 pkey.load_pubkey_from_string(pubkey_str)
989 gid = self.hierarchy.create_gid(name, uuid, pkey)
991 return gid.save_to_string(save_parents=True)