added request_hash argumet some more calls
[sfa.git] / sfa / methods / register.py
1 ### $Id$
2 ### $URL$
3
4 from sfa.trust.certificate import Keypair, convert_public_key
5 from sfa.trust.gid import *
6
7 from sfa.util.faults import *
8 from sfa.util.misc import *
9 from sfa.util.method import Method
10 from sfa.util.parameter import Parameter, Mixed
11 from sfa.util.record import GeniRecord
12 from sfa.util.genitable import GeniTable
13 from sfa.util.debug import log
14 from sfa.trust.auth import Auth
15 from sfa.trust.gid import create_uuid
16 from sfa.trust.credential import Credential
17
18 class register(Method):
19     """
20     Register an object with the registry. In addition to being stored in the
21     Geni database, the appropriate records will also be created in the
22     PLC databases
23     
24     @param cred credential string
25     @param record_dict dictionary containing record fields
26     
27     @return gid string representation
28     """
29
30     interfaces = ['registry']
31     
32     accepts = [
33         Parameter(str, "Credential string"),
34         Parameter(dict, "Record dictionary containing record fields"),
35         Parameter(str, "Request hash")
36         ]
37
38     returns = Parameter(int, "String representation of gid object")
39     
40     def call(self, cred, record_dict, request_hash, caller_cred=None):
41         # This cred will be an authority cred, not a user, so we cant use it to 
42         # authenticate the caller's request_hash. Let just get the caller's gid
43         # from the cred and authenticate using that 
44         client_gid = Credential(string=cred).get_gid_caller()
45         client_gid_str = client_gid.save_to_string(save_parents=True)
46         self.api.auth.authenticateGid(client_gid_str, [cred], request_hash)
47         self.api.auth.check(cred, "register")
48         if caller_cred==None:
49                 caller_cred=cred
50         
51         #log the call
52         self.api.logger.info("interface: %s\tcaller-hrn: %s\ttarget-hrn: %s\tmethod-name: %s"%(self.api.interface, Credential(string=caller_cred).get_gid_caller().get_hrn(), None, self.name))
53         record = GeniRecord(dict = record_dict)
54         record['authority'] = get_authority(record['hrn'])
55         type = record['type']
56         hrn = record['hrn']
57         self.api.auth.verify_object_permission(hrn)
58         auth_info = self.api.auth.get_auth_info(record['authority'])
59         pub_key = None  
60         # make sure record has a gid
61         if 'gid' not in record:
62             uuid = create_uuid()
63             pkey = Keypair(create=True)
64             if 'key' in record and record['key']:
65                 if isinstance(record['key'], list):
66                     pub_key = record['key'][0]
67                 else:
68                     pub_key = record['key']
69                 pkey = convert_public_key(pub_key)
70             
71             gid_object = self.api.auth.hierarchy.create_gid(hrn, uuid, pkey)
72             gid = gid_object.save_to_string(save_parents=True)
73             record['gid'] = gid
74             record.set_gid(gid)
75
76         # check if record already exists
77         table = GeniTable()
78         existing_records = table.find({'type': type, 'hrn': hrn})
79         if existing_records:
80             raise ExistingRecord(hrn)
81         else:
82             # We will update the pointer later
83             record['pointer'] = -1 
84             record.set_pointer(-1)
85             record_id = table.insert(record)
86             record['record_id'] = record_id
87  
88         if type in ["authority"]:
89             # update the tree
90             if not self.api.auth.hierarchy.auth_exists(hrn):
91                 self.api.auth.hierarchy.create_auth(hrn)
92
93             # authorities are special since they are managed by the registry
94             # rather than by the caller. We create our own GID for the
95             # authority rather than relying on the caller to supply one.
96
97             # get the GID from the newly created authority
98             gid = auth_info.get_gid_object()
99             record.set_gid(gid.save_to_string(save_parents=True))
100
101             pl_record = self.api.geni_fields_to_pl_fields(type, hrn, record)
102             sites = self.api.plshell.GetSites(self.api.plauth, [pl_record['login_base']])
103             if not sites:    
104                 pointer = self.api.plshell.AddSite(self.api.plauth, pl_record)
105             else:
106                 pointer = sites[0]['site_id']
107
108             record.set_pointer(pointer)
109
110         elif (type == "slice"):
111             pl_record = self.api.geni_fields_to_pl_fields(type, hrn, record)
112             slices = self.api.plshell.GetSlices(self.api.plauth, [pl_record['name']])
113             if not slices: 
114                 pointer = self.api.plshell.AddSlice(self.api.plauth, pl_record)
115             else:
116                 pointer = slices[0]['slice_id']
117             record.set_pointer(pointer)
118
119         elif  (type == "user"):
120             persons = self.api.plshell.GetPersons(self.api.plauth, [record['email']])
121             if not persons:
122                 pointer = self.api.plshell.AddPerson(self.api.plauth, dict(record))
123             else:
124                 pointer = persons[0]['person_id']
125  
126             if 'enabled' in record and record['enabled']:
127                 self.api.plshell.UpdatePerson(self.api.plauth, pointer, {'enabled': record['enabled']})
128             # add this persons to the site only if he is being added for the first
129             # time by sfa and doesont already exist in plc     
130             if not persons or not persons[0]['site_ids']:
131                 login_base = get_leaf(record['authority'])
132                 self.api.plshell.AddPersonToSite(self.api.plauth, pointer, login_base)
133         
134             # What roles should this user have?
135             self.api.plshell.AddRoleToPerson(self.api.plauth, 'user', pointer) 
136             record.set_pointer(pointer)
137             # Add the user's key
138             if pub_key:
139                 self.api.plshell.AddPersonKey(self.api.plauth, pointer, {'key_type' : 'ssh', 'key' : pub_key})
140
141         elif (type == "node"):
142             pl_record = self.api.geni_fields_to_pl_fields(type, hrn, record)
143             login_base = hrn_to_pl_login_base(record['authority'])
144             nodes = self.api.plshell.GetNodes(self.api.plauth, [pl_record['hostname']])
145             if not nodes:
146                 pointer = self.api.plshell.AddNode(self.api.plauth, login_base, pl_record)
147             else:
148                 pointer = nodes[0]['node_id']
149             record.set_pointer(pointer)
150
151         else:
152             raise UnknownGeniType(type)
153
154         table.update(record)
155
156         # update membership for researchers, pis, owners, operators
157         self.api.update_membership(None, record)
158
159         return record.get_gid_object().save_to_string(save_parents=True)