fix bug
[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()                   
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):
68         # make sure the client_gid matches client's certificate
69         peer_cert = self.peer_cert
70         if not peer_cert.is_pubkey(self.client_gid.get_pubkey()):
71             raise ConnectionKeyGIDMismatch(self.client_gid.get_subject())            
72
73     def verifyGidRequestHash(self, gid, hash, arglist):
74         key = gid.get_pubkey()
75         if not key.verify_string(str(arglist), hash):
76             raise BadRequestHash(hash)
77
78     def verifyCredRequestHash(self, cred, hash, arglist):
79         gid = cred.get_gid_caller()
80         self.verifyGidRequestHash(gid, hash, arglist)
81
82     def validateGid(self, gid):
83         if self.trusted_cert_list:
84             gid.verify_chain(self.trusted_cert_list)
85
86     def validateCred(self, cred):
87         if self.trusted_cert_list:
88             cred.verify_chain(self.trusted_cert_list)
89             caller_gid = cred.get_gid_caller()
90             object_gid = cred.get_gid_object()
91             if caller_gid:
92                 caller_gid.verify_chain(self.trusted_cert_list)
93             if object_gid:
94                 object_gid.verify_chain(self.trusted_cert_list)
95
96     def authenticateGid(self, gidStr, argList, requestHash):
97         gid = GID(string = gidStr)
98         self.validateGid(gid)
99         self.verifyGidRequestHash(gid, requestHash, argList)
100         return gid
101
102     def authenticateCred(self, credStr, argList, requestHash):
103         cred = Credential(string = credStr)
104         self.validateCred(cred)
105         self.verifyCredRequestHash(cred, requestHash, argList)
106         return cred
107
108     def authenticateCert(self, certStr, requestHash):
109         cert = Certificate(string=certStr)
110         self.validateCert(self, cert)   
111
112     def gidNoop(self, gidStr, value, requestHash):
113         self.authenticateGid(gidStr, [gidStr, value], requestHash)
114         return value
115
116     def credNoop(self, credStr, value, requestHash):
117         self.authenticateCred(credStr, [credStr, value], requestHash)
118         return value
119
120     def verify_cred_is_me(self, credential):
121         is_me = False 
122         cred = Credential(string=credential)
123         caller_gid = cred.get_gid_caller()
124         caller_hrn = caller_gid.get_hrn()
125         if caller_hrn != self.config.SFA_INTERFACE_HRN:
126             raise GeniPermissionError(self.config.SFA_INTEFACE_HRN)
127
128         return   
129         
130     def get_auth_info(self, auth_hrn):
131         """
132         Given an authority name, return the information for that authority.
133         This is basically a stub that calls the hierarchy module.
134         
135         @param auth_hrn human readable name of authority  
136         """
137
138         return self.hierarchy.get_auth_info(auth_hrn)
139
140
141     def veriry_auth_belongs_to_me(self, name):
142         """
143         Verify that an authority belongs to our hierarchy. 
144         This is basically left up to the implementation of the hierarchy
145         module. If the specified name does not belong, ane exception is 
146         thrown indicating the caller should contact someone else.
147
148         @param auth_name human readable name of authority
149         """
150
151         # get auth info will throw an exception if the authority doesnt exist
152         self.get_auth_info(name)
153
154
155     def verify_object_belongs_to_me(self, name):
156         """
157         Verify that an object belongs to our hierarchy. By extension,
158         this implies that the authority that owns the object belongs
159         to our hierarchy. If it does not an exception is thrown.
160     
161         @param name human readable name of object        
162         """
163         auth_name = self.get_authority(name)
164         if not auth_name:
165             auth_name = name 
166         if name == self.config.SFA_INTERFACE_HRN:
167             return
168         self.verify_auth_belongs_to_me(auth_name) 
169              
170     def verify_auth_belongs_to_me(self, name):
171         # get auth info will throw an exception if the authority doesnt exist
172         self.get_auth_info(name) 
173
174
175     def verify_object_permission(self, name):
176         """
177         Verify that the object gid that was specified in the credential
178         allows permission to the object 'name'. This is done by a simple
179         prefix test. For example, an object_gid for plc.arizona would 
180         match the objects plc.arizona.slice1 and plc.arizona.
181     
182         @param name human readable name to test  
183         """
184         object_hrn = self.object_gid.get_hrn()
185         if object_hrn == name:
186             return
187         if name.startswith(object_hrn + "."):
188             return
189         #if name.startswith(get_authority(name)):
190             #return
191     
192         raise PermissionError(name)
193
194     def determine_user_rights(self, src_cred, record):
195         """
196         Given a user credential and a record, determine what set of rights the
197         user should have to that record.
198
199         Src_cred can be None when obtaining a user credential, but should be
200         set to a valid user credential when obtaining a slice or authority
201         credential.
202
203         This is intended to replace determine_rights() and
204         verify_cancreate_credential()
205         """
206
207         type = record['type']
208         if src_cred:
209             cred_object_hrn = src_cred.get_gid_object().get_hrn()
210         else:
211             # supplying src_cred==None is only valid when obtaining user
212             # credentials.
213             #assert(type == "user")
214             
215             cred_object_hrn = None
216
217         rl = RightList()
218
219         if type=="slice":
220             researchers = record.get("researcher", [])
221             if (cred_object_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             rl.add("authority,sa,ma")
232             if (cred_object_hrn in pis):
233                 rl.add("sa")
234             if (cred_object_hrn in operators):
235                 rl.add("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)