move process of loading trusted cert files into its own method
[sfa.git] / sfa / trust / auth.py
1 #
2 # SfaAPI authentication 
3 #
4 ### $Id$
5 ### $URL$
6 #
7
8 import time
9
10 from sfa.trust.credential import Credential
11 from sfa.trust.trustedroot import TrustedRootList
12 from sfa.trust.rights import RightList
13 from sfa.util.faults import *
14 from sfa.trust.hierarchy import Hierarchy
15 from sfa.util.config import *
16 from sfa.util.namespace import *
17 from sfa.trust.gid import GID
18 from sfa.util.sfaticket import *
19
20 class Auth:
21     """
22     Credential based authentication
23     """
24
25     def __init__(self, peer_cert = None, config = None ):
26         self.peer_cert = peer_cert
27         self.hierarchy = Hierarchy()
28         if not config:
29             self.config = Config()
30         self.load_trusted_certs()
31
32     def load_trusted_certs(self):
33         self.trusted_cert_list = TrustedRootList(self.config.get_trustedroots_dir()).get_list()
34         
35     def check(self, cred, operation):
36         """
37         Check the credential against the peer cert (callerGID included 
38         in the credential matches the caller that is connected to the 
39         HTTPS connection, check if the credential was signed by a 
40         trusted cert and check if the credential is allowd to perform 
41         the specified operation.    
42         """
43         self.client_cred = Credential(string = cred)
44         self.client_gid = self.client_cred.get_gid_caller()
45         self.object_gid = self.client_cred.get_gid_object()
46         
47         # make sure the client_gid is not blank
48         if not self.client_gid:
49             raise MissingCallerGID(self.client_cred.get_subject())
50        
51         # validate the client cert if it exists
52         if self.peer_cert:
53             self.verifyPeerCert(self.peer_cert, self.client_gid)                   
54
55         # make sure the client is allowed to perform the operation
56         if operation:
57             if not self.client_cred.can_perform(operation):
58                 raise InsufficientRights(operation)
59
60         if self.trusted_cert_list:
61             self.client_cred.verify_chain(self.trusted_cert_list)
62             if self.client_gid:
63                 self.client_gid.verify_chain(self.trusted_cert_list)
64             if self.object_gid:
65                 self.object_gid.verify_chain(self.trusted_cert_list)
66         else:
67            raise MissingTrustedRoots(self.config.get_trustedroots_dir())
68
69         return True
70
71     def check_ticket(self, ticket):
72         """
73         Check if the tickt was signed by a trusted cert
74         """
75         if self.trusted_cert_list:
76             client_ticket = SfaTicket(string=ticket)
77             client_ticket.verify_chain(self.trusted_cert_list)
78         else:
79            raise MissingTrustedRoots(self.config.get_trustedroots_dir())
80
81         return True 
82
83     def verifyPeerCert(self, cert, gid):
84         # make sure the client_gid matches client's certificate
85         if not cert.is_pubkey(gid.get_pubkey()):
86             raise ConnectionKeyGIDMismatch(gid.get_subject()+":"+cert.get_subject())            
87
88     def verifyGidRequestHash(self, gid, hash, arglist):
89         key = gid.get_pubkey()
90         if not key.verify_string(str(arglist), hash):
91             raise BadRequestHash(hash)
92
93     def verifyCredRequestHash(self, cred, hash, arglist):
94         gid = cred.get_gid_caller()
95         self.verifyGidRequestHash(gid, hash, arglist)
96
97     def validateGid(self, gid):
98         if self.trusted_cert_list:
99             gid.verify_chain(self.trusted_cert_list)
100
101     def validateCred(self, cred):
102         if self.trusted_cert_list:
103             cred.verify_chain(self.trusted_cert_list)
104             caller_gid = cred.get_gid_caller()
105             object_gid = cred.get_gid_object()
106             if caller_gid:
107                 caller_gid.verify_chain(self.trusted_cert_list)
108             if object_gid:
109                 object_gid.verify_chain(self.trusted_cert_list)
110
111     def authenticateGid(self, gidStr, argList, requestHash=None):
112         gid = GID(string = gidStr)
113         self.validateGid(gid)
114         # request_hash is optional
115         if requestHash:
116             self.verifyGidRequestHash(gid, requestHash, argList)
117         return gid
118
119     def authenticateCred(self, credStr, argList, requestHash=None):
120         cred = Credential(string = credStr)
121         self.validateCred(cred)
122         # request hash is optional
123         if requestHash:
124             self.verifyCredRequestHash(cred, requestHash, argList)
125         return cred
126
127     def authenticateCert(self, certStr, requestHash):
128         cert = Certificate(string=certStr)
129         self.validateCert(self, cert)   
130
131     def gidNoop(self, gidStr, value, requestHash):
132         self.authenticateGid(gidStr, [gidStr, value], requestHash)
133         return value
134
135     def credNoop(self, credStr, value, requestHash):
136         self.authenticateCred(credStr, [credStr, value], requestHash)
137         return value
138
139     def verify_cred_is_me(self, credential):
140         is_me = False 
141         cred = Credential(string=credential)
142         caller_gid = cred.get_gid_caller()
143         caller_hrn = caller_gid.get_hrn()
144         if caller_hrn != self.config.SFA_INTERFACE_HRN:
145             raise SfaPermissionDenied(self.config.SFA_INTEFACE_HRN)
146
147         return   
148         
149     def get_auth_info(self, auth_hrn):
150         """
151         Given an authority name, return the information for that authority.
152         This is basically a stub that calls the hierarchy module.
153         
154         @param auth_hrn human readable name of authority  
155         """
156
157         return self.hierarchy.get_auth_info(auth_hrn)
158
159
160     def veriry_auth_belongs_to_me(self, name):
161         """
162         Verify that an authority belongs to our hierarchy. 
163         This is basically left up to the implementation of the hierarchy
164         module. If the specified name does not belong, ane exception is 
165         thrown indicating the caller should contact someone else.
166
167         @param auth_name human readable name of authority
168         """
169
170         # get auth info will throw an exception if the authority doesnt exist
171         self.get_auth_info(name)
172
173
174     def verify_object_belongs_to_me(self, name):
175         """
176         Verify that an object belongs to our hierarchy. By extension,
177         this implies that the authority that owns the object belongs
178         to our hierarchy. If it does not an exception is thrown.
179     
180         @param name human readable name of object        
181         """
182         auth_name = self.get_authority(name)
183         if not auth_name:
184             auth_name = name 
185         if name == self.config.SFA_INTERFACE_HRN:
186             return
187         self.verify_auth_belongs_to_me(auth_name) 
188              
189     def verify_auth_belongs_to_me(self, name):
190         # get auth info will throw an exception if the authority doesnt exist
191         self.get_auth_info(name) 
192
193
194     def verify_object_permission(self, name):
195         """
196         Verify that the object gid that was specified in the credential
197         allows permission to the object 'name'. This is done by a simple
198         prefix test. For example, an object_gid for plc.arizona would 
199         match the objects plc.arizona.slice1 and plc.arizona.
200     
201         @param name human readable name to test  
202         """
203         object_hrn = self.object_gid.get_hrn()
204         if object_hrn == name:
205             return
206         if name.startswith(object_hrn + "."):
207             return
208         #if name.startswith(get_authority(name)):
209             #return
210     
211         raise PermissionError(name)
212
213     def determine_user_rights(self, caller_hrn, record):
214         """
215         Given a user credential and a record, determine what set of rights the
216         user should have to that record.
217         
218         This is intended to replace determine_rights() and
219         verify_cancreate_credential()
220         """
221
222         rl = RightList()
223         type = record['type']
224
225         if type=="slice":
226             researchers = record.get("researcher", [])
227             pis = record.get("PI", [])
228             if (caller_hrn in researchers + pis):
229                 rl.add("refresh")
230                 rl.add("embed")
231                 rl.add("bind")
232                 rl.add("control")
233                 rl.add("info")
234
235         elif type == "authority":
236             pis = record.get("PI", [])
237             operators = record.get("operator", [])
238             if (caller_hrn == self.config.SFA_INTERFACE_HRN):
239                 rl.add("authority,sa,ma",)
240             if (caller_hrn in pis):
241                 rl.add("authority,sa")
242             if (caller_hrn in operators):
243                 rl.add("authority,ma")
244
245         elif type == "user":
246             rl.add("refresh")
247             rl.add("resolve")
248             rl.add("info")
249
250         elif type == "node":
251             rl.add("operator")
252
253         return rl
254
255     def verify_cancreate_credential(self, src_cred, record):
256         """
257         Verify that a user can retrive a particular type of credential.
258         For slices, the user must be on the researcher list. For SA and
259         MA the user must be on the pi and operator lists respectively
260         """
261
262         type = record.get_type()
263         cred_object_hrn = src_cred.get_gid_object().get_hrn()
264         if cred_object_hrn in [self.config.SFA_REGISTRY_ROOT_AUTH]:
265             return
266         if type=="slice":
267             researchers = record.get("researcher", [])
268             if not (cred_object_hrn in researchers):
269                 raise PermissionError(cred_object_hrn + " is not in researcher list for " + record.get_name())
270         elif type == "sa":
271             pis = record.get("pi", [])
272             if not (cred_object_hrn in pis):
273                 raise PermissionError(cred_object_hrn + " is not in pi list for " + record.get_name())
274         elif type == "ma":
275             operators = record.get("operator", [])
276             if not (cred_object_hrn in operators):
277                 raise PermissionError(cred_object_hrn + " is not in operator list for " + record.get_name())
278
279     def get_authority(self, hrn):
280         return get_authority(hrn)