determine user rights reqires the hrn of the caller instead of a cred (which may...
[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, caller_hrn, 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         This is intended to replace determine_rights() and
212         verify_cancreate_credential()
213         """
214
215         rl = RightList()
216         type = record['type']
217
218         if type=="slice":
219             researchers = record.get("researcher", [])
220             if (caller_hrn in researchers):
221                 rl.add("refresh")
222                 rl.add("embed")
223                 rl.add("bind")
224                 rl.add("control")
225                 rl.add("info")
226
227         elif type == "authority":
228             pis = record.get("pi", [])
229             operators = record.get("operator", [])
230             if (caller_hrn == config.SFA_INTERFACE_HRN):
231                 rl.add("authority")
232             if (caller_hrn in pis):
233                 rl.add("authority,sa")
234             if (caller_hrn in operators):
235                 rl.add("authority,ma")
236
237         elif type == "user":
238             rl.add("refresh")
239             rl.add("resolve")
240             rl.add("info")
241
242         return rl
243
244     def verify_cancreate_credential(self, src_cred, record):
245         """
246         Verify that a user can retrive a particular type of credential.
247         For slices, the user must be on the researcher list. For SA and
248         MA the user must be on the pi and operator lists respectively
249         """
250
251         type = record.get_type()
252         cred_object_hrn = src_cred.get_gid_object().get_hrn()
253         if cred_object_hrn in [self.config.SFA_REGISTRY_ROOT_AUTH]:
254             return
255         if type=="slice":
256             researchers = record.get("researcher", [])
257             if not (cred_object_hrn in researchers):
258                 raise PermissionError(cred_object_hrn + " is not in researcher list for " + record.get_name())
259         elif type == "sa":
260             pis = record.get("pi", [])
261             if not (cred_object_hrn in pis):
262                 raise PermissionError(cred_object_hrn + " is not in pi list for " + record.get_name())
263         elif type == "ma":
264             operators = record.get("operator", [])
265             if not (cred_object_hrn in operators):
266                 raise PermissionError(cred_object_hrn + " is not in operator list for " + record.get_name())
267
268     def get_authority(self, hrn):
269         return get_authority(hrn)