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