3 from sfa.server.registry import Registries
4 from sfa.util.prefixTree import prefixTree
5 from sfa.util.record import GeniRecord
6 from sfa.util.genitable import GeniTable
7 from sfa.util.record import GeniRecord
8 from sfa.util.genitable import GeniTable
9 from sfa.trust.gid import GID
10 from sfa.util.namespace import *
11 from sfa.trust.credential import *
12 from sfa.trust.certificate import *
13 from sfa.util.faults import *
15 def get_credential(api, hrn, type, is_self=False):
16 # Is this a root or sub authority
17 auth_hrn = api.auth.get_authority(hrn)
18 if not auth_hrn or hrn == api.config.SFA_INTERFACE_HRN:
21 auth_info = api.auth.get_auth_info(auth_hrn)
23 records = table.findObjects({'type': type, 'hrn': hrn})
25 raise RecordNotFound(hrn)
28 # verify_cancreate_credential requires that the member lists
29 # (researchers, pis, etc) be filled in
30 api.fill_record_info(record)
33 # if this is a self cred the record's gid is the caller's gid
36 caller_gid = record.get_gid_object()
38 caller_gid = api.auth.client_cred.get_gid_caller()
39 caller_hrn = caller_gid.get_hrn()
41 object_hrn = record.get_gid_object().get_hrn()
42 rights = api.auth.determine_user_rights(caller_hrn, record)
43 # make sure caller has rights to this object
45 raise PermissionError(caller_hrn + " has no rights to " + record['name'])
47 object_gid = GID(string=record['gid'])
48 new_cred = Credential(subject = object_gid.get_subject())
49 new_cred.set_gid_caller(caller_gid)
50 new_cred.set_gid_object(object_gid)
51 new_cred.set_issuer(key=auth_info.get_pkey_object(), subject=auth_hrn)
52 new_cred.set_pubkey(object_gid.get_pubkey())
53 new_cred.set_privileges(rights)
54 new_cred.set_delegate(True)
55 auth_kind = "authority,ma,sa"
56 new_cred.set_parent(api.auth.hierarchy.get_auth_cred(auth_hrn, kind=auth_kind))
60 return new_cred.save_to_string(save_parents=True)
62 def resolve(api, hrns, type=None, origin_hrn=None):
64 # load all know registry names into a prefix tree and attempt to find
65 # the longest matching prefix
66 if not isinstance(hrns, types.ListType):
69 # create a dict whre key is an registry hrn and its value is a
70 # hrns at that registry (determined by the known prefix tree).
72 registries = Registries(api)
74 registry_hrns = registries.keys()
75 tree.load(registry_hrns)
77 registry_hrn = tree.best_match(hrn)
78 if registry_hrn not in hrn_dict:
79 hrn_dict[registry_hrn] = []
80 hrn_dict[registry_hrn].append(hrn)
83 for registry_hrn in hrn_dict:
84 # skip the hrn without a registry hrn
85 # XX should we let the user know the authority is unknown?
89 # if the best match (longest matching hrn) is not the local registry,
91 hrns = hrn_dict[registry_hrn]
92 if registry_hrn != api.hrn:
93 credential = api.getCredential()
94 peer_records = registries[registry_hrn].resolve(credential, hrn, origin_hrn)
95 records.extend([GeniRecord(dict=record).as_dict() for record in peer_records])
97 # try resolving the remaining unfound records at the local registry
98 remaining_hrns = set(hrns).difference([record['hrn'] for record in records])
99 remaining_hrns = [hrn for hrn in remaining_hrns]
101 local_records = table.findObjects({'hrn': remaining_hrns})
102 for record in local_records:
104 api.fill_record_info(record)
105 records.append(dict(record))
106 except PlanetLabRecordDoesNotExist:
107 # silently drop the ones that are missing in PL
108 print >> log, "ignoring geni record ", record['hrn'], \
109 " because pl record does not exist"
113 raise RecordNotFound(str(hrns))
116 records = filter(lambda rec: rec['type'] in [type], records)
121 # load all know registry names into a prefix tree and attempt to find
122 # the longest matching prefix
124 registries = Registries(api)
125 hrns = registries.keys()
128 registry_hrn = tree.best_match(hrn)
130 #if there was no match then this record belongs to an unknow registry
132 raise MissingAuthority(hrn)
134 # if the best match (longest matching hrn) is not the local registry,
135 # forward the request
137 if registry_hrn != api.hrn:
138 credential = api.getCredential()
139 record_list = registries[registry_hrn].list(credential, hrn, origin_hrn)
140 records = [GeniRecord(dict=record).as_dict() for record in record_list]
142 # if we still havnt found the record yet, try the local registry
144 if not api.auth.hierarchy.auth_exists(hrn):
145 raise MissingAuthority(hrn)
148 records = table.find({'authority': hrn})
153 def register(api, record):
155 hrn, type = record['hrn'], record['type']
158 if type not in ['authority', 'slice', 'node', 'user']:
159 raise UnknownGeniType(type)
161 # check if record already exists
163 existing_records = table.find({'type': type, 'hrn': hrn})
165 raise ExistingRecord(hrn)
167 record = GeniRecord(dict = record)
168 record['authority'] = get_authority(record['hrn'])
169 type = record['type']
171 api.auth.verify_object_permission(hrn)
172 auth_info = api.auth.get_auth_info(record['authority'])
174 # make sure record has a gid
175 if 'gid' not in record:
177 pkey = Keypair(create=True)
178 if 'key' in record and record['key']:
179 if isinstance(record['key'], types.ListType):
180 pub_key = record['key'][0]
182 pub_key = record['key']
183 pkey = convert_public_key(pub_key)
185 gid_object = api.auth.hierarchy.create_gid(hrn, uuid, pkey)
186 gid = gid_object.save_to_string(save_parents=True)
190 if type in ["authority"]:
192 if not api.auth.hierarchy.auth_exists(hrn):
193 api.auth.hierarchy.create_auth(hrn)
195 # get the GID from the newly created authority
196 gid = auth_info.get_gid_object()
197 record.set_gid(gid.save_to_string(save_parents=True))
198 pl_record = api.geni_fields_to_pl_fields(type, hrn, record)
199 sites = api.plshell.GetSites(api.plauth, [pl_record['login_base']])
201 pointer = api.plshell.AddSite(api.plauth, pl_record)
203 pointer = sites[0]['site_id']
205 record.set_pointer(pointer)
206 record['pointer'] = pointer
208 elif (type == "slice"):
209 acceptable_fields=['url', 'instantiation', 'name', 'description']
210 pl_record = api.geni_fields_to_pl_fields(type, hrn, record)
211 for key in pl_record.keys():
212 if key not in acceptable_fields:
214 slices = api.plshell.GetSlices(api.plauth, [pl_record['name']])
216 pointer = api.plshell.AddSlice(api.plauth, pl_record)
218 pointer = slices[0]['slice_id']
219 record.set_pointer(pointer)
220 record['pointer'] = pointer
222 elif (type == "user"):
223 persons = api.plshell.GetPersons(api.plauth, [record['email']])
225 pointer = api.plshell.AddPerson(api.plauth, dict(record))
227 pointer = persons[0]['person_id']
229 if 'enabled' in record and record['enabled']:
230 api.plshell.UpdatePerson(api.plauth, pointer, {'enabled': record['enabled']})
231 # add this persons to the site only if he is being added for the first
232 # time by sfa and doesont already exist in plc
233 if not persons or not persons[0]['site_ids']:
234 login_base = get_leaf(record['authority'])
235 api.plshell.AddPersonToSite(api.plauth, pointer, login_base)
237 # What roles should this user have?
238 api.plshell.AddRoleToPerson(api.plauth, 'user', pointer)
241 api.plshell.AddPersonKey(api.plauth, pointer, {'key_type' : 'ssh', 'key' : pub_key})
243 elif (type == "node"):
244 pl_record = api.geni_fields_to_pl_fields(type, hrn, record)
245 login_base = hrn_to_pl_login_base(record['authority'])
246 nodes = api.plshell.GetNodes(api.plauth, [pl_record['hostname']])
248 pointer = api.plshell.AddNode(api.plauth, login_base, pl_record)
250 pointer = nodes[0]['node_id']
252 record['pointer'] = pointer
253 record.set_pointer(pointer)
254 record_id = table.insert(record)
255 record['record_id'] = record_id
257 # update membership for researchers, pis, owners, operators
258 api.update_membership(None, record)
260 return record.get_gid_object().save_to_string(save_parents=True)
262 def update(api, record_dict):
263 new_record = GeniRecord(dict = record_dict)
264 type = new_record['type']
265 hrn = new_record['hrn']
266 api.auth.verify_object_permission(hrn)
268 # make sure the record exists
269 records = table.findObjects({'type': type, 'hrn': hrn})
271 raise RecordNotFound(hrn)
273 record['last_updated'] = time.gmtime()
275 # Update_membership needs the membership lists in the existing record
276 # filled in, so it can see if members were added or removed
277 api.fill_record_info(record)
279 # Use the pointer from the existing record, not the one that the user
280 # gave us. This prevents the user from inserting a forged pointer
281 pointer = record['pointer']
282 # update the PLC information that was specified with the record
284 if (type == "authority"):
285 api.plshell.UpdateSite(api.plauth, pointer, new_record)
287 elif type == "slice":
288 pl_record=api.geni_fields_to_pl_fields(type, hrn, new_record)
289 if 'name' in pl_record:
290 pl_record.pop('name')
291 api.plshell.UpdateSlice(api.plauth, pointer, pl_record)
294 # SMBAKER: UpdatePerson only allows a limited set of fields to be
295 # updated. Ideally we should have a more generic way of doing
296 # this. I copied the field names from UpdatePerson.py...
298 all_fields = new_record
299 for key in all_fields.keys():
300 if key in ['first_name', 'last_name', 'title', 'email',
301 'password', 'phone', 'url', 'bio', 'accepted_aup',
303 update_fields[key] = all_fields[key]
304 api.plshell.UpdatePerson(api.plauth, pointer, update_fields)
306 if 'key' in new_record and new_record['key']:
307 # must check this key against the previous one if it exists
308 persons = api.plshell.GetPersons(api.plauth, [pointer], ['key_ids'])
310 keys = person['key_ids']
311 keys = api.plshell.GetKeys(api.plauth, person['key_ids'])
313 if isinstance(new_record['key'], types.ListType):
314 new_key = new_record['key'][0]
316 new_key = new_record['key']
318 # Delete all stale keys
320 if new_record['key'] != key['key']:
321 api.plshell.DeleteKey(api.plauth, key['key_id'])
325 api.plshell.AddPersonKey(api.plauth, pointer, {'key_type': 'ssh', 'key': new_key})
327 # update the openssl key and gid
328 pkey = convert_public_key(new_key)
330 gid_object = api.auth.hierarchy.create_gid(hrn, uuid, pkey)
331 gid = gid_object.save_to_string(save_parents=True)
333 record = GeniRecord(dict=record)
337 api.plshell.UpdateNode(api.plauth, pointer, new_record)
340 raise UnknownGeniType(type)
342 # update membership for researchers, pis, owners, operators
343 api.update_membership(record, new_record)
347 def remove(api, hrn, type, origin_hrn=None):
349 filter = {'hrn': hrn}
350 if type not in ['all', '*']:
351 filter['type'] = type
352 records = table.find(filter)
354 raise RecordNotFound(hrn)
356 type = record['type']
358 credential = api.getCredential()
359 registries = Registries(api)
361 # Try to remove the object from the PLCDB of federated agg.
362 # This is attempted before removing the object from the local agg's PLCDB and sfa table
363 if hrn.startswith(api.hrn) and type in ['user', 'slice', 'authority']:
364 for registry in registries:
365 if registry not in [api.hrn]:
367 result=registries[registry].remove_peer_object(credential, record, origin_hrn)
371 persons = api.plshell.GetPersons(api.plauth, record['pointer'])
372 # only delete this person if he has site ids. if he doesnt, it probably means
373 # he was just removed from a site, not actually deleted
374 if persons and persons[0]['site_ids']:
375 api.plshell.DeletePerson(api.plauth, record['pointer'])
376 elif type == "slice":
377 if api.plshell.GetSlices(api.plauth, record['pointer']):
378 api.plshell.DeleteSlice(api.plauth, record['pointer'])
380 if api.plshell.GetNodes(api.plauth, record['pointer']):
381 api.plshell.DeleteNode(api.plauth, record['pointer'])
382 elif type == "authority":
383 if api.plshell.GetSites(api.plauth, record['pointer']):
384 api.plshell.DeleteSite(api.plauth, record['pointer'])
386 raise UnknownGeniType(type)
392 def remove_peer_object(api, record, origin_hrn=None):
395 def register_peer_object(api, record, origin_hrn=None):