2 # SfaAPI authentication
6 from sfa.util.faults import InsufficientRights, MissingCallerGID, MissingTrustedRoots, PermissionError, \
7 BadRequestHash, ConnectionKeyGIDMismatch, SfaPermissionDenied
8 from sfa.util.sfalogging import logger
9 from sfa.util.config import Config
10 from sfa.util.xrn import get_authority
12 from sfa.trust.gid import GID
13 from sfa.trust.rights import Rights
14 from sfa.trust.certificate import Keypair, Certificate
15 from sfa.trust.credential import Credential
16 from sfa.trust.trustedroots import TrustedRoots
17 from sfa.trust.hierarchy import Hierarchy
18 from sfa.trust.sfaticket import SfaTicket
23 Credential based authentication
26 def __init__(self, peer_cert = None, config = None ):
27 self.peer_cert = peer_cert
28 self.hierarchy = Hierarchy()
30 self.config = Config()
31 self.load_trusted_certs()
33 def load_trusted_certs(self):
34 self.trusted_cert_list = TrustedRoots(self.config.get_trustedroots_dir()).get_list()
35 self.trusted_cert_file_list = TrustedRoots(self.config.get_trustedroots_dir()).get_file_list()
39 def checkCredentials(self, creds, operation, hrn = None):
41 if not isinstance(creds, list):
43 #print>>sys.stderr, "\r\n \r\n \t AUTH.PY checkCredentials hrn %s" %(hrn)
44 logger.debug("Auth.checkCredentials with %d creds"%len(creds))
47 self.check(cred, operation, hrn)
50 cred_obj=Credential(string=cred)
51 logger.debug("failed to validate credential - dump=%s"%cred_obj.dump_string(dump_parents=True))
52 error = sys.exc_info()[:2]
56 raise InsufficientRights('Access denied: %s -- %s' % (error[0],error[1]))
61 def check(self, cred, operation, hrn = None):
63 Check the credential against the peer cert (callerGID included
64 in the credential matches the caller that is connected to the
65 HTTPS connection, check if the credential was signed by a
66 trusted cert and check if the credential is allowed to perform
67 the specified operation.
69 self.client_cred = Credential(string = cred)
70 self.client_gid = self.client_cred.get_gid_caller()
71 self.object_gid = self.client_cred.get_gid_object()
72 #print>>sys.stderr, " \r\n \r\n \t AUTH.PY check client_gid %s hrn %s object_gid %s" %(self.client_gid.get_hrn(),hrn, self.object_gid.get_hrn())
73 # make sure the client_gid is not blank
74 if not self.client_gid:
75 raise MissingCallerGID(self.client_cred.get_subject())
77 # validate the client cert if it exists
79 self.verifyPeerCert(self.peer_cert, self.client_gid)
81 # make sure the client is allowed to perform the operation
83 #print>>sys.stderr, " \r\n \r\n \t AUTH.PY check operation %s trusted_cert_list %s " %(operation,self.trusted_cert_list)
84 if not self.client_cred.can_perform(operation):
85 #print>>sys.stderr, " \r\n \r\n \t AUTH.PY InsufficientRights(operation)"
86 raise InsufficientRights(operation)
88 if self.trusted_cert_list:
89 self.client_cred.verify(self.trusted_cert_file_list, self.config.SFA_CREDENTIAL_SCHEMA)
90 #print>>sys.stderr, " \r\n \r\n \t AUTH.PY check trusted_cert_file_list %s self.config.SFA_CREDENTIAL_SCHEMA %s" %(self.trusted_cert_file_list, self.config.SFA_CREDENTIAL_SCHEMA)
93 raise MissingTrustedRoots(self.config.get_trustedroots_dir())
95 # Make sure the credential's target matches the specified hrn.
96 # This check does not apply to trusted peers
97 trusted_peers = [gid.get_hrn() for gid in self.trusted_cert_list]
98 #print>>sys.stderr, " \r\n \r\n \t AUTH.PY check trusted_peers ", trusted_peers
99 if hrn and self.client_gid.get_hrn() not in trusted_peers:
101 target_hrn = self.object_gid.get_hrn()
102 if not hrn == target_hrn:
103 raise PermissionError("Target hrn: %s doesn't match specified hrn: %s " % \
107 def check_ticket(self, ticket):
109 Check if the tickt was signed by a trusted cert
111 if self.trusted_cert_list:
112 client_ticket = SfaTicket(string=ticket)
113 client_ticket.verify_chain(self.trusted_cert_list)
115 raise MissingTrustedRoots(self.config.get_trustedroots_dir())
119 def verifyPeerCert(self, cert, gid):
120 # make sure the client_gid matches client's certificate
121 if not cert.is_pubkey(gid.get_pubkey()):
122 raise ConnectionKeyGIDMismatch(gid.get_subject()+":"+cert.get_subject())
124 def verifyGidRequestHash(self, gid, hash, arglist):
125 key = gid.get_pubkey()
126 if not key.verify_string(str(arglist), hash):
127 raise BadRequestHash(hash)
129 def verifyCredRequestHash(self, cred, hash, arglist):
130 gid = cred.get_gid_caller()
131 self.verifyGidRequestHash(gid, hash, arglist)
133 def validateGid(self, gid):
134 if self.trusted_cert_list:
135 gid.verify_chain(self.trusted_cert_list)
137 def validateCred(self, cred):
138 if self.trusted_cert_list:
139 cred.verify(self.trusted_cert_file_list)
141 def authenticateGid(self, gidStr, argList, requestHash=None):
142 gid = GID(string = gidStr)
143 self.validateGid(gid)
144 # request_hash is optional
146 self.verifyGidRequestHash(gid, requestHash, argList)
149 def authenticateCred(self, credStr, argList, requestHash=None):
150 cred = Credential(string = credStr)
151 self.validateCred(cred)
152 # request hash is optional
154 self.verifyCredRequestHash(cred, requestHash, argList)
157 def authenticateCert(self, certStr, requestHash):
158 cert = Certificate(string=certStr)
159 # xxx should be validateCred ??
160 self.validateCred(cert)
162 def gidNoop(self, gidStr, value, requestHash):
163 self.authenticateGid(gidStr, [gidStr, value], requestHash)
166 def credNoop(self, credStr, value, requestHash):
167 self.authenticateCred(credStr, [credStr, value], requestHash)
170 def verify_cred_is_me(self, credential):
172 cred = Credential(string=credential)
173 caller_gid = cred.get_gid_caller()
174 caller_hrn = caller_gid.get_hrn()
175 if caller_hrn != self.config.SFA_INTERFACE_HRN:
176 raise SfaPermissionDenied(self.config.SFA_INTEFACE_HRN)
180 def get_auth_info(self, auth_hrn):
182 Given an authority name, return the information for that authority.
183 This is basically a stub that calls the hierarchy module.
185 @param auth_hrn human readable name of authority
188 return self.hierarchy.get_auth_info(auth_hrn)
191 def veriry_auth_belongs_to_me(self, name):
193 Verify that an authority belongs to our hierarchy.
194 This is basically left up to the implementation of the hierarchy
195 module. If the specified name does not belong, ane exception is
196 thrown indicating the caller should contact someone else.
198 @param auth_name human readable name of authority
201 # get auth info will throw an exception if the authority doesnt exist
202 self.get_auth_info(name)
205 def verify_object_belongs_to_me(self, name):
207 Verify that an object belongs to our hierarchy. By extension,
208 this implies that the authority that owns the object belongs
209 to our hierarchy. If it does not an exception is thrown.
211 @param name human readable name of object
213 auth_name = self.get_authority(name)
216 if name == self.config.SFA_INTERFACE_HRN:
218 self.verify_auth_belongs_to_me(auth_name)
220 def verify_auth_belongs_to_me(self, name):
221 # get auth info will throw an exception if the authority doesnt exist
222 self.get_auth_info(name)
225 def verify_object_permission(self, name):
227 Verify that the object gid that was specified in the credential
228 allows permission to the object 'name'. This is done by a simple
229 prefix test. For example, an object_gid for plc.arizona would
230 match the objects plc.arizona.slice1 and plc.arizona.
232 @param name human readable name to test
234 object_hrn = self.object_gid.get_hrn()
235 #strname = str(name).strip("['']")
236 if object_hrn == name:
237 #if object_hrn == strname:
239 if name.startswith(object_hrn + ".") :
240 #if strname.startswith((object_hrn + ".")) is True:
242 #if name.startswith(get_authority(name)):
245 raise PermissionError(name)
247 def determine_user_rights(self, caller_hrn, record):
249 Given a user credential and a record, determine what set of rights the
250 user should have to that record.
252 This is intended to replace determine_rights() and
253 verify_cancreate_credential()
257 type = record['type']
261 researchers = record.get("researcher", [])
262 pis = record.get("PI", [])
263 if (caller_hrn in researchers + pis):
270 elif type == "authority":
271 pis = record.get("PI", [])
272 operators = record.get("operator", [])
273 if (caller_hrn == self.config.SFA_INTERFACE_HRN):
277 if (caller_hrn in pis):
280 if (caller_hrn in operators):
294 def verify_cancreate_credential(self, src_cred, record):
296 Verify that a user can retrive a particular type of credential.
297 For slices, the user must be on the researcher list. For SA and
298 MA the user must be on the pi and operator lists respectively
301 type = record.get_type()
302 cred_object_hrn = src_cred.get_gid_object().get_hrn()
303 if cred_object_hrn in [self.config.SFA_REGISTRY_ROOT_AUTH]:
306 researchers = record.get("researcher", [])
307 if not (cred_object_hrn in researchers):
308 raise PermissionError(cred_object_hrn + " is not in researcher list for " + record.get_name())
310 pis = record.get("pi", [])
311 if not (cred_object_hrn in pis):
312 raise PermissionError(cred_object_hrn + " is not in pi list for " + record.get_name())
314 operators = record.get("operator", [])
315 if not (cred_object_hrn in operators):
316 raise PermissionError(cred_object_hrn + " is not in operator list for " + record.get_name())
318 def get_authority(self, hrn):
319 return get_authority(hrn)
321 def filter_creds_by_caller(self, creds, caller_hrn_list):
323 Returns a list of creds who's gid caller matches the
326 if not isinstance(creds, list):
329 if not isinstance(caller_hrn_list, list):
330 caller_hrn_list = [caller_hrn_list]
333 tmp_cred = Credential(string=cred)
334 if tmp_cred.get_gid_caller().get_hrn() in [caller_hrn_list]: