only allow authority creds if oject_hrn in pi list
[sfa.git] / sfa / trust / auth.py
1 #
2 # GeniAPI 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.genitable import GeniTable
16 from sfa.util.config import *
17 from sfa.util.misc import *
18 from sfa.trust.gid import GID
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.trusted_cert_list = TrustedRootList(self.config.get_trustedroots_dir()).get_list()
31
32
33     def check(self, cred, operation):
34         """
35         Check the credential against the peer cert (callerGID included 
36         in the credential matches the caller that is connected to the 
37         HTTPS connection, check if the credential was signed by a 
38         trusted cert and check if the credential is allowd to perform 
39         the specified operation.    
40         """
41         self.client_cred = Credential(string = cred)
42         self.client_gid = self.client_cred.get_gid_caller()
43         self.object_gid = self.client_cred.get_gid_object()
44         
45         # make sure the client_gid is not blank
46         if not self.client_gid:
47             raise MissingCallerGID(self.client_cred.get_subject())
48        
49         # validate the client cert if it exists
50         if self.peer_cert:
51             self.verifyPeerCert(self.peer_cert, self.client_gid)                   
52
53         # make sure the client is allowed to perform the operation
54         if operation:
55             if not self.client_cred.can_perform(operation):
56                 raise InsufficientRights(operation)
57
58         if self.trusted_cert_list:
59             self.client_cred.verify_chain(self.trusted_cert_list)
60             if self.client_gid:
61                 self.client_gid.verify_chain(self.trusted_cert_list)
62             if self.object_gid:
63                 self.object_gid.verify_chain(self.trusted_cert_list)
64
65         return True
66
67     def verifyPeerCert(self, cert, gid):
68         # make sure the client_gid matches client's certificate
69         if not cert:
70             peer_cert = self.peer_cert
71         else:
72             peer_cert = cert
73
74         if not gid:
75             peer_gid = self.client_gid
76         else:
77             peer_gid = gid
78         if not peer_cert.is_pubkey(peer_gid.get_pubkey()):
79             raise ConnectionKeyGIDMismatch(peer_gid.get_subject())            
80
81     def verifyGidRequestHash(self, gid, hash, arglist):
82         key = gid.get_pubkey()
83         if not key.verify_string(str(arglist), hash):
84             raise BadRequestHash(hash)
85
86     def verifyCredRequestHash(self, cred, hash, arglist):
87         gid = cred.get_gid_caller()
88         self.verifyGidRequestHash(gid, hash, arglist)
89
90     def validateGid(self, gid):
91         if self.trusted_cert_list:
92             gid.verify_chain(self.trusted_cert_list)
93
94     def validateCred(self, cred):
95         if self.trusted_cert_list:
96             cred.verify_chain(self.trusted_cert_list)
97             caller_gid = cred.get_gid_caller()
98             object_gid = cred.get_gid_object()
99             if caller_gid:
100                 caller_gid.verify_chain(self.trusted_cert_list)
101             if object_gid:
102                 object_gid.verify_chain(self.trusted_cert_list)
103
104     def authenticateGid(self, gidStr, argList, requestHash=None):
105         gid = GID(string = gidStr)
106         self.validateGid(gid)
107         # request_hash is optional
108         if requestHash:
109             self.verifyGidRequestHash(gid, requestHash, argList)
110         return gid
111
112     def authenticateCred(self, credStr, argList, requestHash=None):
113         cred = Credential(string = credStr)
114         self.validateCred(cred)
115         # request hash is optional
116         if requestHash:
117             self.verifyCredRequestHash(cred, requestHash, argList)
118         return cred
119
120     def authenticateCert(self, certStr, requestHash):
121         cert = Certificate(string=certStr)
122         self.validateCert(self, cert)   
123
124     def gidNoop(self, gidStr, value, requestHash):
125         self.authenticateGid(gidStr, [gidStr, value], requestHash)
126         return value
127
128     def credNoop(self, credStr, value, requestHash):
129         self.authenticateCred(credStr, [credStr, value], requestHash)
130         return value
131
132     def verify_cred_is_me(self, credential):
133         is_me = False 
134         cred = Credential(string=credential)
135         caller_gid = cred.get_gid_caller()
136         caller_hrn = caller_gid.get_hrn()
137         if caller_hrn != self.config.SFA_INTERFACE_HRN:
138             raise GeniPermissionError(self.config.SFA_INTEFACE_HRN)
139
140         return   
141         
142     def get_auth_info(self, auth_hrn):
143         """
144         Given an authority name, return the information for that authority.
145         This is basically a stub that calls the hierarchy module.
146         
147         @param auth_hrn human readable name of authority  
148         """
149
150         return self.hierarchy.get_auth_info(auth_hrn)
151
152
153     def veriry_auth_belongs_to_me(self, name):
154         """
155         Verify that an authority belongs to our hierarchy. 
156         This is basically left up to the implementation of the hierarchy
157         module. If the specified name does not belong, ane exception is 
158         thrown indicating the caller should contact someone else.
159
160         @param auth_name human readable name of authority
161         """
162
163         # get auth info will throw an exception if the authority doesnt exist
164         self.get_auth_info(name)
165
166
167     def verify_object_belongs_to_me(self, name):
168         """
169         Verify that an object belongs to our hierarchy. By extension,
170         this implies that the authority that owns the object belongs
171         to our hierarchy. If it does not an exception is thrown.
172     
173         @param name human readable name of object        
174         """
175         auth_name = self.get_authority(name)
176         if not auth_name:
177             auth_name = name 
178         if name == self.config.SFA_INTERFACE_HRN:
179             return
180         self.verify_auth_belongs_to_me(auth_name) 
181              
182     def verify_auth_belongs_to_me(self, name):
183         # get auth info will throw an exception if the authority doesnt exist
184         self.get_auth_info(name) 
185
186
187     def verify_object_permission(self, name):
188         """
189         Verify that the object gid that was specified in the credential
190         allows permission to the object 'name'. This is done by a simple
191         prefix test. For example, an object_gid for plc.arizona would 
192         match the objects plc.arizona.slice1 and plc.arizona.
193     
194         @param name human readable name to test  
195         """
196         object_hrn = self.object_gid.get_hrn()
197         if object_hrn == name:
198             return
199         if name.startswith(object_hrn + "."):
200             return
201         #if name.startswith(get_authority(name)):
202             #return
203     
204         raise PermissionError(name)
205
206     def determine_user_rights(self, src_cred, record):
207         """
208         Given a user credential and a record, determine what set of rights the
209         user should have to that record.
210
211         Src_cred can be None when obtaining a user credential, but should be
212         set to a valid user credential when obtaining a slice or authority
213         credential.
214
215         This is intended to replace determine_rights() and
216         verify_cancreate_credential()
217         """
218
219         type = record['type']
220         if src_cred:
221             cred_object_hrn = src_cred.get_gid_object().get_hrn()
222         else:
223             # supplying src_cred==None is only valid when obtaining user
224             # credentials.
225             #assert(type == "user")
226             
227             cred_object_hrn = None
228
229         rl = RightList()
230
231         if type=="slice":
232             researchers = record.get("researcher", [])
233             if (cred_object_hrn in researchers):
234                 rl.add("refresh")
235                 rl.add("embed")
236                 rl.add("bind")
237                 rl.add("control")
238                 rl.add("info")
239
240         elif type == "authority":
241             pis = record.get("pi", [])
242             operators = record.get("operator", [])
243             if (cred_object_hrn in pis):
244                 rl.add("authority,sa")
245             if (cred_object_hrn in operators):
246                 rl.add("authority,ma")
247
248         elif type == "user":
249             rl.add("refresh")
250             rl.add("resolve")
251             rl.add("info")
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)