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 logger.debug("Auth.checkCredentials with %d creds"%len(creds))
46 self.check(cred, operation, hrn)
49 cred_obj=Credential(string=cred)
50 logger.debug("failed to validate credential - dump=%s"%cred_obj.dump_string(dump_parents=True))
51 error = sys.exc_info()[:2]
55 raise InsufficientRights('Access denied: %s -- %s' % (error[0],error[1]))
60 def check(self, cred, operation, hrn = None):
62 Check the credential against the peer cert (callerGID included
63 in the credential matches the caller that is connected to the
64 HTTPS connection, check if the credential was signed by a
65 trusted cert and check if the credential is allowed to perform
66 the specified operation.
68 self.client_cred = Credential(string = cred)
69 self.client_gid = self.client_cred.get_gid_caller()
70 self.object_gid = self.client_cred.get_gid_object()
72 # make sure the client_gid is not blank
73 if not self.client_gid:
74 raise MissingCallerGID(self.client_cred.get_subject())
76 # validate the client cert if it exists
78 self.verifyPeerCert(self.peer_cert, self.client_gid)
80 # make sure the client is allowed to perform the operation
82 if not self.client_cred.can_perform(operation):
83 raise InsufficientRights(operation)
85 if self.trusted_cert_list:
86 self.client_cred.verify(self.trusted_cert_file_list, self.config.SFA_CREDENTIAL_SCHEMA)
88 raise MissingTrustedRoots(self.config.get_trustedroots_dir())
90 # Make sure the credential's target matches the specified hrn.
91 # This check does not apply to trusted peers
92 trusted_peers = [gid.get_hrn() for gid in self.trusted_cert_list]
93 if hrn and self.client_gid.get_hrn() not in trusted_peers:
94 target_hrn = self.object_gid.get_hrn()
95 if not hrn == target_hrn:
96 raise PermissionError("Target hrn: %s doesn't match specified hrn: %s " % \
100 def check_ticket(self, ticket):
102 Check if the tickt was signed by a trusted cert
104 if self.trusted_cert_list:
105 client_ticket = SfaTicket(string=ticket)
106 client_ticket.verify_chain(self.trusted_cert_list)
108 raise MissingTrustedRoots(self.config.get_trustedroots_dir())
112 def verifyPeerCert(self, cert, gid):
113 # make sure the client_gid matches client's certificate
114 if not cert.is_pubkey(gid.get_pubkey()):
115 raise ConnectionKeyGIDMismatch(gid.get_subject()+":"+cert.get_subject())
117 def verifyGidRequestHash(self, gid, hash, arglist):
118 key = gid.get_pubkey()
119 if not key.verify_string(str(arglist), hash):
120 raise BadRequestHash(hash)
122 def verifyCredRequestHash(self, cred, hash, arglist):
123 gid = cred.get_gid_caller()
124 self.verifyGidRequestHash(gid, hash, arglist)
126 def validateGid(self, gid):
127 if self.trusted_cert_list:
128 gid.verify_chain(self.trusted_cert_list)
130 def validateCred(self, cred):
131 if self.trusted_cert_list:
132 cred.verify(self.trusted_cert_file_list)
134 def authenticateGid(self, gidStr, argList, requestHash=None):
135 gid = GID(string = gidStr)
136 self.validateGid(gid)
137 # request_hash is optional
139 self.verifyGidRequestHash(gid, requestHash, argList)
142 def authenticateCred(self, credStr, argList, requestHash=None):
143 cred = Credential(string = credStr)
144 self.validateCred(cred)
145 # request hash is optional
147 self.verifyCredRequestHash(cred, requestHash, argList)
150 def authenticateCert(self, certStr, requestHash):
151 cert = Certificate(string=certStr)
152 # xxx should be validateCred ??
153 self.validateCred(cert)
155 def gidNoop(self, gidStr, value, requestHash):
156 self.authenticateGid(gidStr, [gidStr, value], requestHash)
159 def credNoop(self, credStr, value, requestHash):
160 self.authenticateCred(credStr, [credStr, value], requestHash)
163 def verify_cred_is_me(self, credential):
165 cred = Credential(string=credential)
166 caller_gid = cred.get_gid_caller()
167 caller_hrn = caller_gid.get_hrn()
168 if caller_hrn != self.config.SFA_INTERFACE_HRN:
169 raise SfaPermissionDenied(self.config.SFA_INTEFACE_HRN)
173 def get_auth_info(self, auth_hrn):
175 Given an authority name, return the information for that authority.
176 This is basically a stub that calls the hierarchy module.
178 @param auth_hrn human readable name of authority
181 return self.hierarchy.get_auth_info(auth_hrn)
184 def veriry_auth_belongs_to_me(self, name):
186 Verify that an authority belongs to our hierarchy.
187 This is basically left up to the implementation of the hierarchy
188 module. If the specified name does not belong, ane exception is
189 thrown indicating the caller should contact someone else.
191 @param auth_name human readable name of authority
194 # get auth info will throw an exception if the authority doesnt exist
195 self.get_auth_info(name)
198 def verify_object_belongs_to_me(self, name):
200 Verify that an object belongs to our hierarchy. By extension,
201 this implies that the authority that owns the object belongs
202 to our hierarchy. If it does not an exception is thrown.
204 @param name human readable name of object
206 auth_name = self.get_authority(name)
209 if name == self.config.SFA_INTERFACE_HRN:
211 self.verify_auth_belongs_to_me(auth_name)
213 def verify_auth_belongs_to_me(self, name):
214 # get auth info will throw an exception if the authority doesnt exist
215 self.get_auth_info(name)
218 def verify_object_permission(self, name):
220 Verify that the object gid that was specified in the credential
221 allows permission to the object 'name'. This is done by a simple
222 prefix test. For example, an object_gid for plc.arizona would
223 match the objects plc.arizona.slice1 and plc.arizona.
225 @param name human readable name to test
227 object_hrn = self.object_gid.get_hrn()
228 strname = str(name).strip("['']")
230 if object_hrn == strname:
232 if strname.startswith((object_hrn + ".")) is True:
234 #if name.startswith(get_authority(name)):
236 print>>sys.stderr, " \r\n \t AUTH.PY verify_object_permission GROSECHECDELENFER "
237 raise PermissionError(name)
239 def determine_user_rights(self, caller_hrn, record):
241 Given a user credential and a record, determine what set of rights the
242 user should have to that record.
244 This is intended to replace determine_rights() and
245 verify_cancreate_credential()
249 type = record['type']
253 researchers = record.get("researcher", [])
254 pis = record.get("PI", [])
255 if (caller_hrn in researchers + pis):
262 elif type == "authority":
263 pis = record.get("PI", [])
264 operators = record.get("operator", [])
265 if (caller_hrn == self.config.SFA_INTERFACE_HRN):
269 if (caller_hrn in pis):
272 if (caller_hrn in operators):
286 def verify_cancreate_credential(self, src_cred, record):
288 Verify that a user can retrive a particular type of credential.
289 For slices, the user must be on the researcher list. For SA and
290 MA the user must be on the pi and operator lists respectively
293 type = record.get_type()
294 cred_object_hrn = src_cred.get_gid_object().get_hrn()
295 if cred_object_hrn in [self.config.SFA_REGISTRY_ROOT_AUTH]:
298 researchers = record.get("researcher", [])
299 if not (cred_object_hrn in researchers):
300 raise PermissionError(cred_object_hrn + " is not in researcher list for " + record.get_name())
302 pis = record.get("pi", [])
303 if not (cred_object_hrn in pis):
304 raise PermissionError(cred_object_hrn + " is not in pi list for " + record.get_name())
306 operators = record.get("operator", [])
307 if not (cred_object_hrn in operators):
308 raise PermissionError(cred_object_hrn + " is not in operator list for " + record.get_name())
310 def get_authority(self, hrn):
311 return get_authority(hrn)
313 def filter_creds_by_caller(self, creds, caller_hrn_list):
315 Returns a list of creds who's gid caller matches the
318 if not isinstance(creds, list):
321 if not isinstance(caller_hrn_list, list):
322 caller_hrn_list = [caller_hrn_list]
325 tmp_cred = Credential(string=cred)
326 if tmp_cred.get_gid_caller().get_hrn() in [caller_hrn_list]: