2 # SfaAPI authentication
6 from sfa.util.faults import *
7 from sfa.util.sfalogging import logger
8 from sfa.util.config import Config
9 from sfa.util.xrn import get_authority
11 from sfa.trust.gid import GID
12 from sfa.trust.rights import Rights
13 from sfa.trust.certificate import Keypair, Certificate
14 from sfa.trust.credential import Credential
15 from sfa.trust.trustedroots import TrustedRoots
16 from sfa.trust.hierarchy import Hierarchy
17 from sfa.trust.sfaticket import SfaTicket
22 Credential based authentication
25 def __init__(self, peer_cert = None, config = None ):
26 self.peer_cert = peer_cert
27 self.hierarchy = Hierarchy()
29 self.config = Config()
30 self.load_trusted_certs()
32 def load_trusted_certs(self):
33 self.trusted_cert_list = TrustedRoots(self.config.get_trustedroots_dir()).get_list()
34 self.trusted_cert_file_list = TrustedRoots(self.config.get_trustedroots_dir()).get_file_list()
38 def checkCredentials(self, creds, operation, hrn = None):
40 if not isinstance(creds, list):
42 logger.debug("Auth.checkCredentials with %d creds"%len(creds))
45 self.check(cred, operation, hrn)
48 cred_obj=Credential(string=cred)
49 logger.debug("failed to validate credential - dump=%s"%cred_obj.dump_string(dump_parents=True))
50 error = sys.exc_info()[:2]
54 raise InsufficientRights('Access denied: %s -- %s' % (error[0],error[1]))
59 def check(self, cred, operation, hrn = None):
61 Check the credential against the peer cert (callerGID included
62 in the credential matches the caller that is connected to the
63 HTTPS connection, check if the credential was signed by a
64 trusted cert and check if the credential is allowed to perform
65 the specified operation.
67 self.client_cred = Credential(string = cred)
68 self.client_gid = self.client_cred.get_gid_caller()
69 self.object_gid = self.client_cred.get_gid_object()
71 # make sure the client_gid is not blank
72 if not self.client_gid:
73 raise MissingCallerGID(self.client_cred.get_subject())
75 # validate the client cert if it exists
77 self.verifyPeerCert(self.peer_cert, self.client_gid)
79 # make sure the client is allowed to perform the operation
81 if not self.client_cred.can_perform(operation):
82 raise InsufficientRights(operation)
84 if self.trusted_cert_list:
85 self.client_cred.verify(self.trusted_cert_file_list, self.config.SFA_CREDENTIAL_SCHEMA)
87 raise MissingTrustedRoots(self.config.get_trustedroots_dir())
89 # Make sure the credential's target matches the specified hrn.
90 # This check does not apply to trusted peers
91 trusted_peers = [gid.get_hrn() for gid in self.trusted_cert_list]
92 if hrn and self.client_gid.get_hrn() not in trusted_peers:
93 target_hrn = self.object_gid.get_hrn()
94 if not hrn == target_hrn:
95 raise PermissionError("Target hrn: %s doesn't match specified hrn: %s " % \
99 def check_ticket(self, ticket):
101 Check if the tickt was signed by a trusted cert
103 if self.trusted_cert_list:
104 client_ticket = SfaTicket(string=ticket)
105 client_ticket.verify_chain(self.trusted_cert_list)
107 raise MissingTrustedRoots(self.config.get_trustedroots_dir())
111 def verifyPeerCert(self, cert, gid):
112 # make sure the client_gid matches client's certificate
113 if not cert.is_pubkey(gid.get_pubkey()):
114 raise ConnectionKeyGIDMismatch(gid.get_subject()+":"+cert.get_subject())
116 def verifyGidRequestHash(self, gid, hash, arglist):
117 key = gid.get_pubkey()
118 if not key.verify_string(str(arglist), hash):
119 raise BadRequestHash(hash)
121 def verifyCredRequestHash(self, cred, hash, arglist):
122 gid = cred.get_gid_caller()
123 self.verifyGidRequestHash(gid, hash, arglist)
125 def validateGid(self, gid):
126 if self.trusted_cert_list:
127 gid.verify_chain(self.trusted_cert_list)
129 def validateCred(self, cred):
130 if self.trusted_cert_list:
131 cred.verify(self.trusted_cert_file_list)
133 def authenticateGid(self, gidStr, argList, requestHash=None):
134 gid = GID(string = gidStr)
135 self.validateGid(gid)
136 # request_hash is optional
138 self.verifyGidRequestHash(gid, requestHash, argList)
141 def authenticateCred(self, credStr, argList, requestHash=None):
142 cred = Credential(string = credStr)
143 self.validateCred(cred)
144 # request hash is optional
146 self.verifyCredRequestHash(cred, requestHash, argList)
149 def authenticateCert(self, certStr, requestHash):
150 cert = Certificate(string=certStr)
151 self.validateCert(self, cert)
153 def gidNoop(self, gidStr, value, requestHash):
154 self.authenticateGid(gidStr, [gidStr, value], requestHash)
157 def credNoop(self, credStr, value, requestHash):
158 self.authenticateCred(credStr, [credStr, value], requestHash)
161 def verify_cred_is_me(self, credential):
163 cred = Credential(string=credential)
164 caller_gid = cred.get_gid_caller()
165 caller_hrn = caller_gid.get_hrn()
166 if caller_hrn != self.config.SFA_INTERFACE_HRN:
167 raise SfaPermissionDenied(self.config.SFA_INTEFACE_HRN)
171 def get_auth_info(self, auth_hrn):
173 Given an authority name, return the information for that authority.
174 This is basically a stub that calls the hierarchy module.
176 @param auth_hrn human readable name of authority
179 return self.hierarchy.get_auth_info(auth_hrn)
182 def veriry_auth_belongs_to_me(self, name):
184 Verify that an authority belongs to our hierarchy.
185 This is basically left up to the implementation of the hierarchy
186 module. If the specified name does not belong, ane exception is
187 thrown indicating the caller should contact someone else.
189 @param auth_name human readable name of authority
192 # get auth info will throw an exception if the authority doesnt exist
193 self.get_auth_info(name)
196 def verify_object_belongs_to_me(self, name):
198 Verify that an object belongs to our hierarchy. By extension,
199 this implies that the authority that owns the object belongs
200 to our hierarchy. If it does not an exception is thrown.
202 @param name human readable name of object
204 auth_name = self.get_authority(name)
207 if name == self.config.SFA_INTERFACE_HRN:
209 self.verify_auth_belongs_to_me(auth_name)
211 def verify_auth_belongs_to_me(self, name):
212 # get auth info will throw an exception if the authority doesnt exist
213 self.get_auth_info(name)
216 def verify_object_permission(self, name):
218 Verify that the object gid that was specified in the credential
219 allows permission to the object 'name'. This is done by a simple
220 prefix test. For example, an object_gid for plc.arizona would
221 match the objects plc.arizona.slice1 and plc.arizona.
223 @param name human readable name to test
225 object_hrn = self.object_gid.get_hrn()
226 if object_hrn == name:
228 if name.startswith(object_hrn + "."):
230 #if name.startswith(get_authority(name)):
233 raise PermissionError(name)
235 def determine_user_rights(self, caller_hrn, record):
237 Given a user credential and a record, determine what set of rights the
238 user should have to that record.
240 This is intended to replace determine_rights() and
241 verify_cancreate_credential()
245 type = record['type']
249 researchers = record.get("researcher", [])
250 pis = record.get("PI", [])
251 if (caller_hrn in researchers + pis):
258 elif type == "authority":
259 pis = record.get("PI", [])
260 operators = record.get("operator", [])
261 if (caller_hrn == self.config.SFA_INTERFACE_HRN):
265 if (caller_hrn in pis):
268 if (caller_hrn in operators):
282 def verify_cancreate_credential(self, src_cred, record):
284 Verify that a user can retrive a particular type of credential.
285 For slices, the user must be on the researcher list. For SA and
286 MA the user must be on the pi and operator lists respectively
289 type = record.get_type()
290 cred_object_hrn = src_cred.get_gid_object().get_hrn()
291 if cred_object_hrn in [self.config.SFA_REGISTRY_ROOT_AUTH]:
294 researchers = record.get("researcher", [])
295 if not (cred_object_hrn in researchers):
296 raise PermissionError(cred_object_hrn + " is not in researcher list for " + record.get_name())
298 pis = record.get("pi", [])
299 if not (cred_object_hrn in pis):
300 raise PermissionError(cred_object_hrn + " is not in pi list for " + record.get_name())
302 operators = record.get("operator", [])
303 if not (cred_object_hrn in operators):
304 raise PermissionError(cred_object_hrn + " is not in operator list for " + record.get_name())
306 def get_authority(self, hrn):
307 return get_authority(hrn)
309 def filter_creds_by_caller(self, creds, caller_hrn_list):
311 Returns a list of creds who's gid caller matches the
314 if not isinstance(creds, list):
317 if not isinistance(caller_hrn_list, list):
318 caller_hrn_list = [caller_hrn_list]
321 tmp_cred = Credential(string=cred)
322 if tmp_cred.get_gid_caller().get_hrn() in [caller_hrn_list]: