4 from sfa.util.faults import *
5 from sfa.util.prefixTree import prefixTree
6 from sfa.util.record import SfaRecord
7 from sfa.util.table import SfaTable
8 from sfa.util.record import SfaRecord
9 from sfa.trust.gid import GID
10 from sfa.util.xrn import Xrn, get_leaf, get_authority, hrn_to_urn, urn_to_hrn
11 from sfa.util.plxrn import hrn_to_pl_login_base
12 from sfa.trust.credential import Credential
13 from sfa.trust.certificate import Certificate, Keypair
14 from sfa.trust.gid import create_uuid
15 from sfa.util.version import version_core
17 # The GENI GetVersion call
19 peers =dict ([ (peername,v._ServerProxy__host) for (peername,v) in api.registries.items()
20 if peername != api.hrn])
21 return version_core({'interface':'registry',
25 def get_credential(api, xrn, type, is_self=False):
28 hrn = urn_to_hrn(xrn)[0]
30 hrn, type = urn_to_hrn(xrn)
32 # Is this a root or sub authority
33 auth_hrn = api.auth.get_authority(hrn)
34 if not auth_hrn or hrn == api.config.SFA_INTERFACE_HRN:
37 auth_info = api.auth.get_auth_info(auth_hrn)
39 records = table.findObjects({'type': type, 'hrn': hrn})
41 raise RecordNotFound(hrn)
44 # verify_cancreate_credential requires that the member lists
45 # (researchers, pis, etc) be filled in
46 api.fill_record_info(record)
47 if record['type']=='user':
48 if not record['enabled']:
49 raise AccountNotEnabled(": PlanetLab account %s is not enabled. Please contact your site PI" %(record['email']))
52 # if this is a self cred the record's gid is the caller's gid
55 caller_gid = record.get_gid_object()
57 caller_gid = api.auth.client_cred.get_gid_caller()
58 caller_hrn = caller_gid.get_hrn()
60 object_hrn = record.get_gid_object().get_hrn()
61 rights = api.auth.determine_user_rights(caller_hrn, record)
62 # make sure caller has rights to this object
64 raise PermissionError(caller_hrn + " has no rights to " + record['name'])
66 object_gid = GID(string=record['gid'])
67 new_cred = Credential(subject = object_gid.get_subject())
68 new_cred.set_gid_caller(caller_gid)
69 new_cred.set_gid_object(object_gid)
70 new_cred.set_issuer_keys(auth_info.get_privkey_filename(), auth_info.get_gid_filename())
71 #new_cred.set_pubkey(object_gid.get_pubkey())
72 new_cred.set_privileges(rights)
73 new_cred.get_privileges().delegate_all_privileges(True)
74 if 'expires' in record:
75 new_cred.set_expiration(int(record['expires']))
76 auth_kind = "authority,ma,sa"
77 # Parent not necessary, verify with certs
78 #new_cred.set_parent(api.auth.hierarchy.get_auth_cred(auth_hrn, kind=auth_kind))
82 return new_cred.save_to_string(save_parents=True)
85 def resolve(api, xrns, type=None, full=True):
87 # load all know registry names into a prefix tree and attempt to find
88 # the longest matching prefix
89 if not isinstance(xrns, types.ListType):
91 hrns = [urn_to_hrn(xrn)[0] for xrn in xrns]
92 # create a dict whre key is an registry hrn and its value is a
93 # hrns at that registry (determined by the known prefix tree).
95 registries = api.registries
97 registry_hrns = registries.keys()
98 tree.load(registry_hrns)
100 registry_hrn = tree.best_match(urn_to_hrn(xrn)[0])
101 if registry_hrn not in xrn_dict:
102 xrn_dict[registry_hrn] = []
103 xrn_dict[registry_hrn].append(xrn)
106 for registry_hrn in xrn_dict:
107 # skip the hrn without a registry hrn
108 # XX should we let the user know the authority is unknown?
112 # if the best match (longest matching hrn) is not the local registry,
113 # forward the request
114 xrns = xrn_dict[registry_hrn]
115 if registry_hrn != api.hrn:
116 credential = api.getCredential()
117 peer_records = registries[registry_hrn].Resolve(xrns, credential)
118 records.extend([SfaRecord(dict=record).as_dict() for record in peer_records])
120 # try resolving the remaining unfound records at the local registry
121 remaining_hrns = set(hrns).difference([record['hrn'] for record in records])
122 # convert set to list
123 remaining_hrns = [hrn for hrn in remaining_hrns]
125 local_records = table.findObjects({'hrn': remaining_hrns})
127 api.fill_record_info(local_records)
129 # convert local record objects to dicts
130 records.extend([dict(record) for record in local_records])
132 raise RecordNotFound(str(hrns))
135 records = filter(lambda rec: rec['type'] in [type], records)
139 def list(api, xrn, origin_hrn=None):
140 hrn, type = urn_to_hrn(xrn)
141 # load all know registry names into a prefix tree and attempt to find
142 # the longest matching prefix
144 registries = api.registries
145 registry_hrns = registries.keys()
147 tree.load(registry_hrns)
148 registry_hrn = tree.best_match(hrn)
150 #if there was no match then this record belongs to an unknow registry
152 raise MissingAuthority(xrn)
154 # if the best match (longest matching hrn) is not the local registry,
155 # forward the request
157 if registry_hrn != api.hrn:
158 credential = api.getCredential()
159 record_list = registries[registry_hrn].List(xrn, credential)
160 records = [SfaRecord(dict=record).as_dict() for record in record_list]
162 # if we still have not found the record yet, try the local registry
164 if not api.auth.hierarchy.auth_exists(hrn):
165 raise MissingAuthority(hrn)
168 records = table.find({'authority': hrn})
173 def register(api, record):
175 hrn, type = record['hrn'], record['type']
176 urn = hrn_to_urn(hrn,type)
178 if type not in ['authority', 'slice', 'node', 'user']:
179 raise UnknownSfaType(type)
181 # check if record already exists
183 existing_records = table.find({'type': type, 'hrn': hrn})
185 raise ExistingRecord(hrn)
187 record = SfaRecord(dict = record)
188 record['authority'] = get_authority(record['hrn'])
189 type = record['type']
191 api.auth.verify_object_permission(hrn)
192 auth_info = api.auth.get_auth_info(record['authority'])
194 # make sure record has a gid
195 if 'gid' not in record:
197 pkey = Keypair(create=True)
198 if 'key' in record and record['key']:
199 if isinstance(record['key'], types.ListType):
200 pub_key = record['key'][0]
202 pub_key = record['key']
203 pkey = convert_public_key(pub_key)
205 gid_object = api.auth.hierarchy.create_gid(urn, uuid, pkey)
206 gid = gid_object.save_to_string(save_parents=True)
210 if type in ["authority"]:
212 if not api.auth.hierarchy.auth_exists(hrn):
213 api.auth.hierarchy.create_auth(hrn_to_urn(hrn,'authority'))
215 # get the GID from the newly created authority
216 gid = auth_info.get_gid_object()
217 record.set_gid(gid.save_to_string(save_parents=True))
218 pl_record = api.sfa_fields_to_pl_fields(type, hrn, record)
219 sites = api.plshell.GetSites(api.plauth, [pl_record['login_base']])
221 pointer = api.plshell.AddSite(api.plauth, pl_record)
223 pointer = sites[0]['site_id']
225 record.set_pointer(pointer)
226 record['pointer'] = pointer
228 elif (type == "slice"):
229 acceptable_fields=['url', 'instantiation', 'name', 'description']
230 pl_record = api.sfa_fields_to_pl_fields(type, hrn, record)
231 for key in pl_record.keys():
232 if key not in acceptable_fields:
234 slices = api.plshell.GetSlices(api.plauth, [pl_record['name']])
236 pointer = api.plshell.AddSlice(api.plauth, pl_record)
238 pointer = slices[0]['slice_id']
239 record.set_pointer(pointer)
240 record['pointer'] = pointer
242 elif (type == "user"):
243 persons = api.plshell.GetPersons(api.plauth, [record['email']])
245 pointer = api.plshell.AddPerson(api.plauth, dict(record))
247 pointer = persons[0]['person_id']
249 if 'enabled' in record and record['enabled']:
250 api.plshell.UpdatePerson(api.plauth, pointer, {'enabled': record['enabled']})
251 # add this persons to the site only if he is being added for the first
252 # time by sfa and doesont already exist in plc
253 if not persons or not persons[0]['site_ids']:
254 login_base = get_leaf(record['authority'])
255 api.plshell.AddPersonToSite(api.plauth, pointer, login_base)
257 # What roles should this user have?
258 api.plshell.AddRoleToPerson(api.plauth, 'user', pointer)
261 api.plshell.AddPersonKey(api.plauth, pointer, {'key_type' : 'ssh', 'key' : pub_key})
263 elif (type == "node"):
264 pl_record = api.sfa_fields_to_pl_fields(type, hrn, record)
265 login_base = hrn_to_pl_login_base(record['authority'])
266 nodes = api.plshell.GetNodes(api.plauth, [pl_record['hostname']])
268 pointer = api.plshell.AddNode(api.plauth, login_base, pl_record)
270 pointer = nodes[0]['node_id']
272 record['pointer'] = pointer
273 record.set_pointer(pointer)
274 record_id = table.insert(record)
275 record['record_id'] = record_id
277 # update membership for researchers, pis, owners, operators
278 api.update_membership(None, record)
280 return record.get_gid_object().save_to_string(save_parents=True)
282 def update(api, record_dict):
283 new_record = SfaRecord(dict = record_dict)
284 type = new_record['type']
285 hrn = new_record['hrn']
286 urn = hrn_to_urn(hrn,type)
287 api.auth.verify_object_permission(hrn)
289 # make sure the record exists
290 records = table.findObjects({'type': type, 'hrn': hrn})
292 raise RecordNotFound(hrn)
294 record['last_updated'] = time.gmtime()
296 # Update_membership needs the membership lists in the existing record
297 # filled in, so it can see if members were added or removed
298 api.fill_record_info(record)
300 # Use the pointer from the existing record, not the one that the user
301 # gave us. This prevents the user from inserting a forged pointer
302 pointer = record['pointer']
303 # update the PLC information that was specified with the record
305 if (type == "authority"):
306 api.plshell.UpdateSite(api.plauth, pointer, new_record)
308 elif type == "slice":
309 pl_record=api.sfa_fields_to_pl_fields(type, hrn, new_record)
310 if 'name' in pl_record:
311 pl_record.pop('name')
312 api.plshell.UpdateSlice(api.plauth, pointer, pl_record)
315 # SMBAKER: UpdatePerson only allows a limited set of fields to be
316 # updated. Ideally we should have a more generic way of doing
317 # this. I copied the field names from UpdatePerson.py...
319 all_fields = new_record
320 for key in all_fields.keys():
321 if key in ['first_name', 'last_name', 'title', 'email',
322 'password', 'phone', 'url', 'bio', 'accepted_aup',
324 update_fields[key] = all_fields[key]
325 api.plshell.UpdatePerson(api.plauth, pointer, update_fields)
327 if 'key' in new_record and new_record['key']:
328 # must check this key against the previous one if it exists
329 persons = api.plshell.GetPersons(api.plauth, [pointer], ['key_ids'])
331 keys = person['key_ids']
332 keys = api.plshell.GetKeys(api.plauth, person['key_ids'])
334 if isinstance(new_record['key'], types.ListType):
335 new_key = new_record['key'][0]
337 new_key = new_record['key']
339 # Delete all stale keys
341 if new_record['key'] != key['key']:
342 api.plshell.DeleteKey(api.plauth, key['key_id'])
346 api.plshell.AddPersonKey(api.plauth, pointer, {'key_type': 'ssh', 'key': new_key})
348 # update the openssl key and gid
349 pkey = convert_public_key(new_key)
351 gid_object = api.auth.hierarchy.create_gid(urn, uuid, pkey)
352 gid = gid_object.save_to_string(save_parents=True)
354 record = SfaRecord(dict=record)
358 api.plshell.UpdateNode(api.plauth, pointer, new_record)
361 raise UnknownSfaType(type)
363 # update membership for researchers, pis, owners, operators
364 api.update_membership(record, new_record)
368 # expecting an Xrn instance
369 def remove(api, xrn, origin_hrn=None):
372 filter = {'hrn': xrn.get_hrn()}
375 if type and type not in ['all', '*']:
376 filter['type'] = type
378 records = table.find(filter)
379 if not records: raise RecordNotFound(hrn)
381 type = record['type']
383 credential = api.getCredential()
384 registries = api.registries
386 # Try to remove the object from the PLCDB of federated agg.
387 # This is attempted before removing the object from the local agg's PLCDB and sfa table
388 if hrn.startswith(api.hrn) and type in ['user', 'slice', 'authority']:
389 for registry in registries:
390 if registry not in [api.hrn]:
392 result=registries[registry].remove_peer_object(credential, record, origin_hrn)
396 persons = api.plshell.GetPersons(api.plauth, record['pointer'])
397 # only delete this person if he has site ids. if he doesnt, it probably means
398 # he was just removed from a site, not actually deleted
399 if persons and persons[0]['site_ids']:
400 api.plshell.DeletePerson(api.plauth, record['pointer'])
401 elif type == "slice":
402 if api.plshell.GetSlices(api.plauth, record['pointer']):
403 api.plshell.DeleteSlice(api.plauth, record['pointer'])
405 if api.plshell.GetNodes(api.plauth, record['pointer']):
406 api.plshell.DeleteNode(api.plauth, record['pointer'])
407 elif type == "authority":
408 if api.plshell.GetSites(api.plauth, record['pointer']):
409 api.plshell.DeleteSite(api.plauth, record['pointer'])
411 raise UnknownSfaType(type)
417 def remove_peer_object(api, record, origin_hrn=None):
420 def register_peer_object(api, record, origin_hrn=None):