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