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