switch from sa/ma to authority, fix update_membership_list
[sfa.git] / geni / util / auth.py
1 #
2 # GeniAPI authentication 
3 #
4 #
5
6 import time
7 from geni.util.faults import *
8 from geni.util.excep import *
9 from geni.util.credential import Credential
10 from geni.util.trustedroot import TrustedRootList
11 from geni.util.hierarchy import Hierarchy
12 from geni.util.rights import RightList
13 from geni.util.genitable import *
14 from geni.util.config import *
15
16 class Auth:
17     """
18     Credential based authentication
19     """
20
21     def __init__(self, peer_cert = None, config = None ):
22         self.peer_cert = peer_cert
23         self.hierarchy = Hierarchy()
24         self.trusted_cert_list = TrustedRootList().get_list() 
25         if not config:
26             self.config = Config() 
27     
28
29     def check(self, cred, operation):
30         """
31         Check the credential against the peer cert (callerGID included 
32         in the credential matches the caller that is connected to the 
33         HTTPS connection, check if the credential was signed by a 
34         trusted cert and check if the credential is allowd to perform 
35         the specified operation.    
36         """
37         self.client_cred = Credential(string = cred)
38         self.client_gid = self.client_cred.get_gid_caller()
39         self.object_gid = self.client_cred.get_gid_object()
40         
41         # make sure the client_gid is not blank
42         if not self.client_gid:
43             raise MissingCallerGID(self.client_cred.get_subject())
44
45         # make sure the client_gid matches client's certificate
46         peer_cert = self.peer_cert
47         if not peer_cert.is_pubkey(self.client_gid.get_pubkey()):
48             raise ConnectionKeyGIDMismatch(self.client_gid.get_subject())
49
50         # make sure the client is allowed to perform the operation
51         if operation:
52             if not self.client_cred.can_perform(operation):
53                 raise InsufficientRights(operation)
54
55         if self.trusted_cert_list:
56             self.client_cred.verify_chain(self.trusted_cert_list)
57             if self.client_gid:
58                 self.client_gid.verify_chain(self.trusted_cert_list)
59             if self.object_gid:
60                 self.object_gid.verify_chain(self.trusted_cert_list)
61
62         return True
63
64         
65     def get_auth_info(self, auth_hrn):
66         """
67         Given an authority name, return the information for that authority.
68         This is basically a stub that calls the hierarchy module.
69         
70         @param auth_hrn human readable name of authority  
71         """
72
73         return self.hierarchy.get_auth_info(auth_hrn)
74
75
76     def get_auth_table(self, auth_name):
77         """
78         Given an authority name, return the database table for that authority.
79         If the databse table does not exist, then one will be automatically
80         created.
81
82         @param auth_name human readable name of authority
83         """
84         auth_info = self.get_auth_info(auth_name)
85         table = GeniTable(hrn=auth_name,
86                           cninfo=auth_info.get_dbinfo())
87         # if the table doesn't exist, then it means we haven't put any records
88         # into this authority yet.
89
90         if not table.exists():
91             print >> log, "Registry: creating table for authority", auth_name
92             table.create()
93     
94         return table
95
96     def veriry_auth_belongs_to_me(self, name):
97         """
98         Verify that an authority belongs to our hierarchy. 
99         This is basically left up to the implementation of the hierarchy
100         module. If the specified name does not belong, ane exception is 
101         thrown indicating the caller should contact someone else.
102
103         @param auth_name human readable name of authority
104         """
105
106         self.get_auth_info(name)
107
108
109     def verify_object_belongs_to_me(self, name):
110         """
111         Verify that an object belongs to our hierarchy. By extension,
112         this implies that the authority that owns the object belongs
113         to our hierarchy. If it does not an exception is thrown.
114     
115         @param name human readable name of object        
116         """
117         auth_name = self.get_authority(name)
118         if not auth_name:
119             # the root authority belongs to the registry by default?
120             # TODO: is this true?
121             return
122         self.verify_auth_belongs_to_me(auth_name) 
123              
124     def verify_auth_belongs_to_me(self, name):
125         # get auth info will throw an exception if the authority doesnt exist
126         self.get_auth_info(name) 
127
128
129     def verify_object_permission(self, name):
130         """
131         Verify that the object gid that was specified in the credential
132         allows permission to the object 'name'. This is done by a simple
133         prefix test. For example, an object_gid for plc.arizona would 
134         match the objects plc.arizona.slice1 and plc.arizona.
135     
136         @param name human readable name to test  
137         """
138         object_hrn = self.object_gid.get_hrn()
139         if object_hrn == name:
140             return
141         if name.startswith(object_hrn + "."):
142             return
143         raise PermissionError(name)
144
145     def determine_user_rights(self, src_cred, record):
146         """
147         Given a user credential and a record, determine what set of rights the
148         user should have to that record.
149
150         This is intended to replace determine_rights() and
151         verify_cancreate_credential()
152         """
153
154         type = record.get_type()
155         cred_object_hrn = src_cred.get_gid_object().get_hrn()
156
157         rl = RightList()
158
159         if type=="slice":
160             researchers = record.get_geni_info().get("researcher", [])
161             if (cred_object_hrn in researchers):
162                 rl.add("refresh")
163                 rl.add("embed")
164                 rl.add("bind")
165                 rl.add("control")
166                 rl.add("info")
167
168         elif type == "authority":
169             pis = record.get_geni_info().get("pi", [])
170             operators = record.get_geni_info().get("operator", [])
171             if (cred_object_hrn in pis):
172                 rl.add("sa")
173             if (cred_object_hrn in operators):
174                 rl.add("ma")
175             if (cred_object_hrn in pis) or (cred_object_hrn in operators):
176                 rl.add("authority")
177
178         elif type == "user":
179             rl.add("refresh")
180             rl.add("resolve")
181             rl.add("info")
182
183         return rl
184
185     def verify_cancreate_credential(self, src_cred, record):
186         """
187         Verify that a user can retrive a particular type of credential.
188         For slices, the user must be on the researcher list. For SA and
189         MA the user must be on the pi and operator lists respectively
190         """
191
192         type = record.get_type()
193         cred_object_hrn = src_cred.get_gid_object().get_hrn()
194         if cred_object_hrn in [self.config.GENI_REGISTRY_ROOT_AUTH]:
195             return
196         if type=="slice":
197             researchers = record.get_geni_info().get("researcher", [])
198             if not (cred_object_hrn in researchers):
199                 raise PermissionError(cred_object_hrn + " is not in researcher list for " + record.get_name())
200         elif type == "sa":
201             pis = record.get_geni_info().get("pi", [])
202             if not (cred_object_hrn in pis):
203                 raise PermissionError(cred_object_hrn + " is not in pi list for " + record.get_name())
204         elif type == "ma":
205             operators = record.get_geni_info().get("operator", [])
206             if not (cred_object_hrn in operators):
207                 raise PermissionError(cred_object_hrn + " is not in operator list for " + record.get_name())
208
209     def get_leaf(self, hrn):
210         parts = hrn.split(".")
211         return ".".join(parts[-1:])
212
213     def get_authority(self, hrn):
214         parts = hrn.split(".")
215         return ".".join(parts[:-1])
216
217     def hrn_to_pl_slicename(self, hrn):
218         parts = hrn.split(".")
219         return parts[-2] + "_" + parts[-1]
220
221     # assuming hrn is the hrn of an authority, return the plc authority name
222     def hrn_to_pl_authname(self, hrn):
223         parts = hrn.split(".")
224         return parts[-1]
225
226     # assuming hrn is the hrn of an authority, return the plc login_base
227     def hrn_to_pl_login_base(self, hrn):
228         return self.hrn_to_pl_authname(hrn)
229