get caller's hrn from the credentials gid_origin_caller object
[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         Mixed(Parameter(str, "Request hash"),
36               Parameter(None, "Request hash not specified"))
37         ]
38
39     returns = Parameter(int, "String representation of gid object")
40     
41     def call(self, cred, record_dict, request_hash=None):
42         user_cred = Credential(string=cred)
43
44         #log the call
45         gid_origin_caller = user_cred.get_gid_origin_caller()
46         origin_hrn = gid_origin_caller.get_hrn()
47         self.api.logger.info("interface: %s\tcaller-hrn: %s\ttarget-hrn: %s\tmethod-name: %s"%(self.api.interface, origin_hrn, hrn, self.name))
48         
49         # This cred will be an authority cred, not a user, so we cant use it to 
50         # authenticate the caller's request_hash. Let just get the caller's gid
51         # from the cred and authenticate using that 
52         client_gid = Credential(string=cred).get_gid_caller()
53         client_gid_str = client_gid.save_to_string(save_parents=True)
54         self.api.auth.authenticateGid(client_gid_str, [cred], request_hash)
55         self.api.auth.check(cred, "register")
56         
57         record = GeniRecord(dict = record_dict)
58         record['authority'] = get_authority(record['hrn'])
59         type = record['type']
60         hrn = record['hrn']
61         self.api.auth.verify_object_permission(hrn)
62         auth_info = self.api.auth.get_auth_info(record['authority'])
63         pub_key = None  
64         # make sure record has a gid
65         if 'gid' not in record:
66             uuid = create_uuid()
67             pkey = Keypair(create=True)
68             if 'key' in record and record['key']:
69                 if isinstance(record['key'], list):
70                     pub_key = record['key'][0]
71                 else:
72                     pub_key = record['key']
73                 pkey = convert_public_key(pub_key)
74             
75             gid_object = self.api.auth.hierarchy.create_gid(hrn, uuid, pkey)
76             gid = gid_object.save_to_string(save_parents=True)
77             record['gid'] = gid
78             record.set_gid(gid)
79
80         # check if record already exists
81         table = GeniTable()
82         existing_records = table.find({'type': type, 'hrn': hrn})
83         if existing_records:
84             raise ExistingRecord(hrn)
85  
86         if type in ["authority"]:
87             # update the tree
88             if not self.api.auth.hierarchy.auth_exists(hrn):
89                 self.api.auth.hierarchy.create_auth(hrn)
90
91             # authorities are special since they are managed by the registry
92             # rather than by the caller. We create our own GID for the
93             # authority rather than relying on the caller to supply one.
94
95             # get the GID from the newly created authority
96             gid = auth_info.get_gid_object()
97             record.set_gid(gid.save_to_string(save_parents=True))
98
99             pl_record = self.api.geni_fields_to_pl_fields(type, hrn, record)
100             sites = self.api.plshell.GetSites(self.api.plauth, [pl_record['login_base']])
101             if not sites:    
102                 pointer = self.api.plshell.AddSite(self.api.plauth, pl_record)
103             else:
104                 pointer = sites[0]['site_id']
105
106             record.set_pointer(pointer)
107             record['pointer'] = pointer
108
109         elif (type == "slice"):
110             acceptable_fields=['url', 'instantiation', 'name', 'description']
111             pl_record = self.api.geni_fields_to_pl_fields(type, hrn, record)
112             for key in pl_record.keys():
113                 if key not in acceptable_fields:
114                    pl_record.pop(key)
115             slices = self.api.plshell.GetSlices(self.api.plauth, [pl_record['name']])
116             if not slices: 
117                 pointer = self.api.plshell.AddSlice(self.api.plauth, pl_record)
118             else:
119                 pointer = slices[0]['slice_id']
120             record.set_pointer(pointer)
121             record['pointer'] = pointer
122
123         elif  (type == "user"):
124             persons = self.api.plshell.GetPersons(self.api.plauth, [record['email']])
125             if not persons:
126                 pointer = self.api.plshell.AddPerson(self.api.plauth, dict(record))
127             else:
128                 raise ExistingRecord(record['email'])
129  
130             if 'enabled' in record and record['enabled']:
131                 self.api.plshell.UpdatePerson(self.api.plauth, pointer, {'enabled': record['enabled']})
132             # add this persons to the site only if he is being added for the first
133             # time by sfa and doesont already exist in plc     
134             if not persons or not persons[0]['site_ids']:
135                 login_base = get_leaf(record['authority'])
136                 self.api.plshell.AddPersonToSite(self.api.plauth, pointer, login_base)
137         
138             # What roles should this user have?
139             self.api.plshell.AddRoleToPerson(self.api.plauth, 'user', pointer) 
140             record.set_pointer(pointer)
141             record['pointer'] = pointer
142             # Add the user's key
143             if pub_key:
144                 self.api.plshell.AddPersonKey(self.api.plauth, pointer, {'key_type' : 'ssh', 'key' : pub_key})
145
146         elif (type == "node"):
147             pl_record = self.api.geni_fields_to_pl_fields(type, hrn, record)
148             login_base = hrn_to_pl_login_base(record['authority'])
149             nodes = self.api.plshell.GetNodes(self.api.plauth, [pl_record['hostname']])
150             if not nodes:
151                 pointer = self.api.plshell.AddNode(self.api.plauth, login_base, pl_record)
152             else:
153                 pointer = nodes[0]['node_id']
154             record['pointer'] = pointer
155             record.set_pointer(pointer)
156
157         else:
158             raise UnknownGeniType(type)
159
160         record_id = table.insert(record)
161         record['record_id'] = record_id
162
163         # update membership for researchers, pis, owners, operators
164         self.api.update_membership(None, record)
165
166         return record.get_gid_object().save_to_string(save_parents=True)