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