8 from geniserver import *
10 from trustedroot import *
11 from hierarchy import *
15 def geni_fields_to_pl_fields(type, hrn, geni_fields, pl_fields):
17 if not "email" in pl_fields:
18 if not "email" in geni_fields:
19 raise MissingGeniInfo("email")
20 pl_fields["email"] = geni_fields["email"]
22 if not "first_name" in pl_fields:
23 pl_fields["first_name"] = "geni"
25 if not "last_name" in pl_fields:
26 pl_fields["last_name"] = hrn
29 if not "instantiation" in pl_fields:
30 pl_fields["instantiation"] = "plc-instantiated"
31 if not "name" in pl_fields:
32 pl_fields["name"] = hrn_to_pl_slicename(hrn)
33 if not "max_nodes" in pl_fields:
34 pl_fields["max_nodes"] = 10
37 if not "hostname" in pl_fields:
38 if not "dns" in geni_fields:
39 raise MissingGeniInfo("dns")
40 pl_fields["hostname"] = geni_fields["dns"]
42 if not "model" in pl_fields:
43 pl_fields["model"] = "geni"
46 pl_fields["login_base"] = hrn_to_pl_login_base(hrn)
48 if not "name" in pl_fields:
49 pl_fields["name"] = hrn
51 if not "abbreviated_name" in pl_fields:
52 pl_fields["abbreviated_name"] = hrn
54 if not "enabled" in pl_fields:
55 pl_fields["enabled"] = True
57 if not "is_public" in pl_fields:
58 pl_fields["is_public"] = True
60 class Registry(GeniServer):
61 def __init__(self, ip, port, key_file, cert_file):
62 GeniServer.__init__(self, ip, port, key_file, cert_file)
64 # get PL account settings from config module
65 self.pl_auth = get_pl_auth()
67 # connect to planetlab
68 if "Url" in self.pl_auth:
69 self.connect_remote_shell()
71 self.connect_local_shell()
73 def connect_remote_shell(self):
75 self.shell = remoteshell.RemoteShell()
77 def connect_local_shell(self):
79 self.shell = PLC.Shell.Shell(globals = globals())
81 def register_functions(self):
82 GeniServer.register_functions(self)
83 self.server.register_function(self.create_gid)
84 self.server.register_function(self.get_self_credential)
85 self.server.register_function(self.get_credential)
86 self.server.register_function(self.get_gid)
87 self.server.register_function(self.register)
88 self.server.register_function(self.remove)
89 self.server.register_function(self.update)
90 self.server.register_function(self.list)
91 self.server.register_function(self.resolve)
93 def get_auth_info(self, name):
94 return AuthHierarchy.get_auth_info(name)
96 def get_auth_table(self, auth_name):
97 auth_info = self.get_auth_info(auth_name)
99 table = GeniTable(hrn=auth_name,
100 cninfo=auth_info.get_dbinfo())
102 # if the table doesn't exist, then it means we haven't put any records
103 # into this authority yet.
105 if not table.exists():
106 report.trace("Registry: creating table for authority " + auth_name)
111 def verify_auth_belongs_to_me(self, name):
112 # get_auth_info will throw an exception if the authority does not
114 self.get_auth_info(name)
116 def verify_object_belongs_to_me(self, name):
117 auth_name = get_authority(name)
119 # the root authority belongs to the registry by default?
120 # TODO: is this true?
122 self.verify_auth_belongs_to_me(auth_name)
124 def verify_object_permission(self, name):
125 object_hrn = self.object_gid.get_hrn()
126 if object_hrn == name:
128 if name.startswith(object_hrn + "."):
130 raise PermissionError(name)
132 def fill_record_pl_info(self, record):
133 type = record.get_type()
134 pointer = record.get_pointer()
136 # records with pointer==-1 do not have plc info associated with them.
137 # for example, the top level authority records which are
138 # authorities, but not PL "sites"
142 if (type == "sa") or (type == "ma"):
143 pl_res = self.shell.GetSites(self.pl_auth, [pointer])
144 elif (type == "slice"):
145 pl_res = self.shell.GetSlices(self.pl_auth, [pointer])
146 elif (type == "user"):
147 pl_res = self.shell.GetPersons(self.pl_auth, [pointer])
148 elif (type == "node"):
149 pl_res = self.shell.GetNodes(self.pl_auth, [pointer])
151 raise UnknownGeniType(type)
154 # the planetlab record no longer exists
155 # TODO: delete the geni record ?
156 raise PlanetLabRecordDoesNotExist(record.get_name())
158 record.set_pl_info(pl_res[0])
160 def fill_record_geni_info(self, record):
163 def fill_record_info(self, record):
164 self.fill_record_pl_info(record)
165 self.fill_record_geni_info(record)
167 def register(self, cred, record_dict):
168 self.decode_authentication(cred, "register")
170 record = GeniRecord(dict = record_dict)
171 type = record.get_type()
172 name = record.get_name()
174 auth_name = get_authority(name)
175 self.verify_object_permission(auth_name)
176 auth_info = self.get_auth_info(auth_name)
177 table = self.get_auth_table(auth_name)
181 # check if record already exists
182 existing_records = table.resolve(type, name)
184 raise ExistingRecord(name)
186 if (type == "sa") or (type=="ma"):
188 if not AuthHierarchy.auth_exists(name):
189 AuthHierarchy.create_auth(name)
191 # authorities are special since they are managed by the registry
192 # rather than by the caller. We create our own GID for the
193 # authority rather than relying on the caller to supply one.
195 # get the GID from the newly created authority
196 child_auth_info = self.get_auth_info(name)
197 gid = auth_info.get_gid_object()
198 record.set_gid(gid.save_to_string(save_parents=True))
200 geni_fields = record.get_geni_info()
201 site_fields = record.get_pl_info()
203 # if registering a sa, see if a ma already exists
204 # if registering a ma, see if a sa already exists
206 other_rec = table.resolve("ma", record.get_name())
208 other_rec = table.resolve("sa", record.get_name())
211 print "linking ma and sa to the same plc site"
212 pointer = other_rec[0].get_pointer()
214 geni_fields_to_pl_fields(type, name, geni_fields, site_fields)
215 print "adding site with fields", site_fields
216 pointer = self.shell.AddSite(self.pl_auth, site_fields)
218 record.set_pointer(pointer)
220 elif (type == "slice"):
221 geni_fields = record.get_geni_info()
222 slice_fields = record.get_pl_info()
224 geni_fields_to_pl_fields(type, name, geni_fields, slice_fields)
226 pointer = self.shell.AddSlice(self.pl_auth, slice_fields)
227 record.set_pointer(pointer)
229 elif (type == "user"):
230 geni_fields = record.get_geni_info()
231 user_fields = record.get_pl_info()
233 geni_fields_to_pl_fields(type, name, geni_fields, user_fields)
235 pointer = self.shell.AddPerson(self.pl_auth, user_fields)
236 record.set_pointer(pointer)
238 elif (type == "node"):
239 geni_fields = record.get_geni_info()
240 node_fields = record.get_pl_info()
242 geni_fields_to_pl_fields(type, name, geni_fields, node_fields)
244 login_base = hrn_to_pl_login_base(auth_name)
246 print "calling addnode with", login_base, node_fields
247 pointer = self.shell.AddNode(self.pl_auth, login_base, node_fields)
248 record.set_pointer(pointer)
251 raise UnknownGeniType(type)
255 return record.get_gid_object().save_to_string(save_parents=True)
257 def remove(self, cred, record_dict):
258 self.decode_authentication(cred, "remove")
260 record = GeniRecord(dict = record_dict)
261 type = record.get_type()
263 self.verify_object_permission(record.get_name())
265 auth_name = get_authority(record.get_name())
266 table = self.get_auth_table(auth_name)
268 # let's not trust that the caller has a well-formed record (a forged
269 # pointer field could be a disaster), so look it up ourselves
270 record_list = table.resolve(type, record.get_name())
272 raise RecordNotFound(name)
273 record = record_list[0]
277 self.shell.DeletePerson(self.pl_auth, record.get_pointer())
278 elif type == "slice":
279 self.shell.DeleteSlice(self.pl_auth, record.get_pointer())
281 self.shell.DeleteNode(self.pl_auth, record.get_pointer())
282 elif (type == "sa") or (type == "ma"):
284 other_rec = table.resolve("ma", record.get_name())
286 other_rec = table.resolve("sa", record.get_name())
289 # sa and ma both map to a site, so if we are deleting one
290 # but the other still exists, then do not delete the site
291 print "not removing site", record.get_name(), "because either sa or ma still exists"
294 print "removing site", record.get_name()
295 self.shell.DeleteSite(self.pl_auth, record.get_pointer())
297 raise UnknownGeniType(type)
303 def update(self, cred, record_dict):
304 self.decode_authentication(cred, "update")
306 record = GeniRecord(dict = record_dict)
307 type = record.get_type()
309 self.verify_object_permission(record.get_name())
311 auth_name = get_authority(record.get_name())
312 table = self.get_auth_table(auth_name)
314 # make sure the record exists
315 existing_record_list = table.resolve(type, record.get_name())
316 if not existing_record_list:
317 raise RecordNotFound(record.get_name())
319 existing_record = existing_record_list[0]
320 pointer = existing_record.get_pointer()
322 if (type == "sa") or (type == "ma"):
323 self.shell.UpdateSite(self.pl_auth, pointer, record.get_pl_info())
325 elif type == "slice":
326 self.shell.UpdateSlice(self.pl_auth, pointer, record.get_pl_info())
329 self.shell.UpdatePerson(self.pl_auth, pointer, record.get_pl_info())
332 self.shell.UpdateNode(self.pl_auth, pointer, record.get_pl_info())
335 raise UnknownGeniType(type)
337 # TODO: List doesn't take an hrn and uses the hrn contained in the
338 # objectGid of the credential. Does this mean the only way to list an
339 # authority is by having a credential for that authority?
340 def list(self, cred):
341 self.decode_authentication(cred, "list")
343 auth_name = self.object_gid.get_hrn()
344 table = self.get_auth_table(auth_name)
346 records = table.list()
349 for record in records:
351 self.fill_record_info(record)
352 good_records.append(record)
353 except PlanetLabRecordDoesNotExist:
354 # silently drop the ones that are missing in PL.
355 # is this the right thing to do?
356 report.error("ignoring geni record " + record.get_name() + " because pl record does not exist")
360 for record in good_records:
361 dicts.append(record.as_dict())
367 def resolve_raw(self, type, name, must_exist=True):
368 auth_name = get_authority(name)
370 table = self.get_auth_table(auth_name)
372 records = table.resolve(type, name)
374 if (not records) and must_exist:
375 raise RecordNotFound(name)
378 for record in records:
380 self.fill_record_info(record)
381 good_records.append(record)
382 except PlanetLabRecordDoesNotExist:
383 # silently drop the ones that are missing in PL.
384 # is this the right thing to do?
385 report.error("ignoring geni record " + record.get_name() + " because pl record does not exist")
390 def resolve(self, cred, name):
391 self.decode_authentication(cred, "resolve")
393 records = self.resolve_raw("*", name)
395 for record in records:
396 dicts.append(record.as_dict())
400 def get_gid(self, name):
401 self.verify_object_belongs_to_me(name)
402 records = self.resolve_raw("*", name)
404 for record in records:
405 gid = record.get_gid()
406 gid_string_list.append(gid.save_to_string(save_parents=True))
407 return gid_string_list
409 def determine_rights(self, type, name):
412 # rights seem to be somewhat redundant with the type of the credential.
413 # For example, a "sa" credential implies the authority right, because
414 # a sa credential cannot be issued to a user who is not an owner of
424 elif type == "slice":
428 elif type == "component":
434 def get_self_credential(self, type, name):
435 self.verify_object_belongs_to_me(name)
437 auth_hrn = get_authority(name)
438 auth_info = self.get_auth_info(auth_hrn)
440 # find a record that matches
441 records = self.resolve_raw(type, name, must_exist=True)
444 gid = record.get_gid_object()
445 peer_cert = self.server.peer_cert
446 if not peer_cert.is_pubkey(gid.get_pubkey()):
447 raise ConnectionKeyGIDMismatch(gid.get_subject())
449 # create the credential
450 gid = record.get_gid_object()
451 cred = Credential(subject = gid.get_subject())
452 cred.set_gid_caller(gid)
453 cred.set_gid_object(gid)
454 cred.set_issuer(key=auth_info.get_pkey_object(), subject=auth_hrn)
455 cred.set_pubkey(gid.get_pubkey())
457 rl = self.determine_rights(type, name)
458 cred.set_privileges(rl)
460 cred.set_parent(AuthHierarchy.get_auth_cred(auth_hrn))
465 return cred.save_to_string(save_parents=True)
467 def get_credential(self, cred, type, name):
469 return get_self_credential(self, type, name)
471 self.decode_authentication(cred, "getcredential")
473 self.verify_object_belongs_to_me(name)
475 auth_hrn = get_authority(name)
476 auth_info = self.get_auth_info(auth_hrn)
478 records = self.resolve_raw(type, name, must_exist=True)
481 # TODO: Check permission that self.client_cred can access the object
483 object_gid = record.get_gid_object()
484 new_cred = Credential(subject = object_gid.get_subject())
485 new_cred.set_gid_caller(self.client_gid)
486 new_cred.set_gid_object(object_gid)
487 new_cred.set_issuer(key=auth_info.get_pkey_object(), subject=auth_hrn)
488 new_cred.set_pubkey(object_gid.get_pubkey())
490 rl = self.determine_rights(type, name)
491 new_cred.set_privileges(rl)
493 new_cred.set_parent(AuthHierarchy.get_auth_cred(auth_hrn))
498 return new_cred.save_to_string(save_parents=True)
500 def create_gid(self, cred, name, uuid, pubkey_str):
501 self.decode_authentication(cred, "getcredential")
503 self.verify_object_belongs_to_me(name)
505 self.verify_object_permission(name)
511 pkey.load_pubkey_from_string(pubkey_str)
512 gid = AuthHierarchy.create_gid(name, uuid, pkey)
514 return gid.save_to_string(save_parents=True)
517 if __name__ == "__main__":
521 key_file = "server.key"
522 cert_file = "server.cert"
524 # if no key is specified, then make one up
525 if (not os.path.exists(key_file)) or (not os.path.exists(cert_file)):
526 key = Keypair(create=True)
527 key.save_to_file(key_file)
529 cert = Certificate(subject="registry")
530 cert.set_issuer(key=key, subject="registry")
533 cert.save_to_file(cert_file)
535 AuthHierarchy = Hierarchy()
537 TrustedRoots = TrustedRootList()
539 s = Registry("localhost", 12345, key_file, cert_file)
540 s.trusted_cert_list = TrustedRoots.get_list()