2 # SfaAPI authentication
9 from sfa.trust.certificate import Keypair, Certificate
10 from sfa.trust.credential import Credential
11 from sfa.trust.trustedroot import TrustedRootList
12 from sfa.util.faults import *
13 from sfa.trust.hierarchy import Hierarchy
14 from sfa.util.config import *
15 from sfa.util.namespace import *
16 from sfa.util.sfaticket import *
21 Credential based authentication
24 def __init__(self, peer_cert = None, config = None ):
25 self.peer_cert = peer_cert
26 self.hierarchy = Hierarchy()
28 self.config = Config()
29 self.load_trusted_certs()
31 def load_trusted_certs(self):
32 self.trusted_cert_list = TrustedRootList(self.config.get_trustedroots_dir()).get_list()
33 self.trusted_cert_file_list = TrustedRootList(self.config.get_trustedroots_dir()).get_file_list()
37 def checkCredentials(self, creds, operation, hrn = None):
39 if not isinstance(creds, list):
43 self.check(cred, operation, hrn)
46 error = sys.exc_info()[:2]
50 raise InsufficientRights('Access denied: %s -- %s' % (error[0],error[1]))
55 def check(self, cred, operation, hrn = None):
57 Check the credential against the peer cert (callerGID included
58 in the credential matches the caller that is connected to the
59 HTTPS connection, check if the credential was signed by a
60 trusted cert and check if the credential is allowd to perform
61 the specified operation.
63 self.client_cred = Credential(string = cred)
64 self.client_gid = self.client_cred.get_gid_caller()
65 self.object_gid = self.client_cred.get_gid_object()
67 # make sure the client_gid is not blank
68 if not self.client_gid:
69 raise MissingCallerGID(self.client_cred.get_subject())
71 # validate the client cert if it exists
73 self.verifyPeerCert(self.peer_cert, self.client_gid)
75 # make sure the client is allowed to perform the operation
77 if not self.client_cred.can_perform(operation):
78 raise InsufficientRights(operation)
80 if self.trusted_cert_list:
81 self.client_cred.verify(self.trusted_cert_file_list)
83 raise MissingTrustedRoots(self.config.get_trustedroots_dir())
85 # Make sure the credential's target matches the specified hrn.
86 # This check does not apply to trusted peers
87 trusted_peers = [gid.get_hrn() for gid in self.trusted_cert_list]
88 if hrn and self.client_gid.get_hrn() not in trusted_peers:
89 target_hrn = self.object_gid.get_hrn()
90 if not hrn == target_hrn:
91 raise PermissionError("Target hrn: %s doesn't match specified hrn: %s " % \
95 def check_ticket(self, ticket):
97 Check if the tickt was signed by a trusted cert
99 if self.trusted_cert_list:
100 client_ticket = SfaTicket(string=ticket)
101 client_ticket.verify_chain(self.trusted_cert_list)
103 raise MissingTrustedRoots(self.config.get_trustedroots_dir())
107 def verifyPeerCert(self, cert, gid):
108 # make sure the client_gid matches client's certificate
109 if not cert.is_pubkey(gid.get_pubkey()):
110 raise ConnectionKeyGIDMismatch(gid.get_subject()+":"+cert.get_subject())
112 def verifyGidRequestHash(self, gid, hash, arglist):
113 key = gid.get_pubkey()
114 if not key.verify_string(str(arglist), hash):
115 raise BadRequestHash(hash)
117 def verifyCredRequestHash(self, cred, hash, arglist):
118 gid = cred.get_gid_caller()
119 self.verifyGidRequestHash(gid, hash, arglist)
121 def validateGid(self, gid):
122 if self.trusted_cert_list:
123 gid.verify_chain(self.trusted_cert_list)
125 def validateCred(self, cred):
126 if self.trusted_cert_list:
127 cred.verify(self.trusted_cert_file_list)
129 def authenticateGid(self, gidStr, argList, requestHash=None):
130 gid = GID(string = gidStr)
131 self.validateGid(gid)
132 # request_hash is optional
134 self.verifyGidRequestHash(gid, requestHash, argList)
137 def authenticateCred(self, credStr, argList, requestHash=None):
138 cred = Credential(string = credStr)
139 self.validateCred(cred)
140 # request hash is optional
142 self.verifyCredRequestHash(cred, requestHash, argList)
145 def authenticateCert(self, certStr, requestHash):
146 cert = Certificate(string=certStr)
147 self.validateCert(self, cert)
149 def gidNoop(self, gidStr, value, requestHash):
150 self.authenticateGid(gidStr, [gidStr, value], requestHash)
153 def credNoop(self, credStr, value, requestHash):
154 self.authenticateCred(credStr, [credStr, value], requestHash)
157 def verify_cred_is_me(self, credential):
159 cred = Credential(string=credential)
160 caller_gid = cred.get_gid_caller()
161 caller_hrn = caller_gid.get_hrn()
162 if caller_hrn != self.config.SFA_INTERFACE_HRN:
163 raise SfaPermissionDenied(self.config.SFA_INTEFACE_HRN)
167 def get_auth_info(self, auth_hrn):
169 Given an authority name, return the information for that authority.
170 This is basically a stub that calls the hierarchy module.
172 @param auth_hrn human readable name of authority
175 return self.hierarchy.get_auth_info(auth_hrn)
178 def veriry_auth_belongs_to_me(self, name):
180 Verify that an authority belongs to our hierarchy.
181 This is basically left up to the implementation of the hierarchy
182 module. If the specified name does not belong, ane exception is
183 thrown indicating the caller should contact someone else.
185 @param auth_name human readable name of authority
188 # get auth info will throw an exception if the authority doesnt exist
189 self.get_auth_info(name)
192 def verify_object_belongs_to_me(self, name):
194 Verify that an object belongs to our hierarchy. By extension,
195 this implies that the authority that owns the object belongs
196 to our hierarchy. If it does not an exception is thrown.
198 @param name human readable name of object
200 auth_name = self.get_authority(name)
203 if name == self.config.SFA_INTERFACE_HRN:
205 self.verify_auth_belongs_to_me(auth_name)
207 def verify_auth_belongs_to_me(self, name):
208 # get auth info will throw an exception if the authority doesnt exist
209 self.get_auth_info(name)
212 def verify_object_permission(self, name):
214 Verify that the object gid that was specified in the credential
215 allows permission to the object 'name'. This is done by a simple
216 prefix test. For example, an object_gid for plc.arizona would
217 match the objects plc.arizona.slice1 and plc.arizona.
219 @param name human readable name to test
221 object_hrn = self.object_gid.get_hrn()
222 if object_hrn == name:
224 if name.startswith(object_hrn + "."):
226 #if name.startswith(get_authority(name)):
229 raise PermissionError(name)
231 def determine_user_rights(self, caller_hrn, record):
233 Given a user credential and a record, determine what set of rights the
234 user should have to that record.
236 This is intended to replace determine_rights() and
237 verify_cancreate_credential()
241 type = record['type']
245 researchers = record.get("researcher", [])
246 pis = record.get("PI", [])
247 if (caller_hrn in researchers + pis):
254 elif type == "authority":
255 pis = record.get("PI", [])
256 operators = record.get("operator", [])
257 if (caller_hrn == self.config.SFA_INTERFACE_HRN):
261 if (caller_hrn in pis):
264 if (caller_hrn in operators):
278 def verify_cancreate_credential(self, src_cred, record):
280 Verify that a user can retrive a particular type of credential.
281 For slices, the user must be on the researcher list. For SA and
282 MA the user must be on the pi and operator lists respectively
285 type = record.get_type()
286 cred_object_hrn = src_cred.get_gid_object().get_hrn()
287 if cred_object_hrn in [self.config.SFA_REGISTRY_ROOT_AUTH]:
290 researchers = record.get("researcher", [])
291 if not (cred_object_hrn in researchers):
292 raise PermissionError(cred_object_hrn + " is not in researcher list for " + record.get_name())
294 pis = record.get("pi", [])
295 if not (cred_object_hrn in pis):
296 raise PermissionError(cred_object_hrn + " is not in pi list for " + record.get_name())
298 operators = record.get("operator", [])
299 if not (cred_object_hrn in operators):
300 raise PermissionError(cred_object_hrn + " is not in operator list for " + record.get_name())
302 def get_authority(self, hrn):
303 return get_authority(hrn)
305 def filter_creds_by_caller(self, creds, caller_hrn):
307 Returns a list of creds who's gid caller matches the
310 if not isinstance(creds, list):
315 tmp_cred = Credential(string=cred)
316 if tmp_cred.get_gid_caller().get_hrn() == caller_hrn: