2 # SfaAPI authentication
6 from sfa.trust.certificate import Keypair, Certificate
7 from sfa.trust.credential import Credential
8 from sfa.trust.trustedroots import TrustedRoots
9 from sfa.util.faults import *
10 from sfa.trust.hierarchy import Hierarchy
11 from sfa.util.config import *
12 from sfa.util.xrn import get_authority
13 from sfa.util.sfaticket import *
15 from sfa.util.sfalogging import logger
19 Credential based authentication
22 def __init__(self, peer_cert = None, config = None ):
23 self.peer_cert = peer_cert
24 self.hierarchy = Hierarchy()
26 self.config = Config()
27 self.load_trusted_certs()
29 def load_trusted_certs(self):
30 self.trusted_cert_list = TrustedRoots(self.config.get_trustedroots_dir()).get_list()
31 self.trusted_cert_file_list = TrustedRoots(self.config.get_trustedroots_dir()).get_file_list()
35 def checkCredentials(self, creds, operation, hrn = None):
37 if not isinstance(creds, list):
39 logger.debug("Auth.checkCredentials with %d creds"%len(creds))
42 self.check(cred, operation, hrn)
45 cred_obj=Credential(string=cred)
46 logger.debug("failed to validate credential - dump=%s"%cred_obj.dump_string(dump_parents=True))
47 error = sys.exc_info()[:2]
51 raise InsufficientRights('Access denied: %s -- %s' % (error[0],error[1]))
56 def check(self, cred, operation, hrn = None):
58 Check the credential against the peer cert (callerGID included
59 in the credential matches the caller that is connected to the
60 HTTPS connection, check if the credential was signed by a
61 trusted cert and check if the credential is allowed to perform
62 the specified operation.
64 self.client_cred = Credential(string = cred)
65 self.client_gid = self.client_cred.get_gid_caller()
66 self.object_gid = self.client_cred.get_gid_object()
68 # make sure the client_gid is not blank
69 if not self.client_gid:
70 raise MissingCallerGID(self.client_cred.get_subject())
72 # validate the client cert if it exists
74 self.verifyPeerCert(self.peer_cert, self.client_gid)
76 # make sure the client is allowed to perform the operation
78 if not self.client_cred.can_perform(operation):
79 raise InsufficientRights(operation)
81 if self.trusted_cert_list:
82 self.client_cred.verify(self.trusted_cert_file_list, self.config.SFA_CREDENTIAL_SCHEMA)
84 raise MissingTrustedRoots(self.config.get_trustedroots_dir())
86 # Make sure the credential's target matches the specified hrn.
87 # This check does not apply to trusted peers
88 trusted_peers = [gid.get_hrn() for gid in self.trusted_cert_list]
89 if hrn and self.client_gid.get_hrn() not in trusted_peers:
90 target_hrn = self.object_gid.get_hrn()
91 if not hrn == target_hrn:
92 raise PermissionError("Target hrn: %s doesn't match specified hrn: %s " % \
96 def check_ticket(self, ticket):
98 Check if the tickt was signed by a trusted cert
100 if self.trusted_cert_list:
101 client_ticket = SfaTicket(string=ticket)
102 client_ticket.verify_chain(self.trusted_cert_list)
104 raise MissingTrustedRoots(self.config.get_trustedroots_dir())
108 def verifyPeerCert(self, cert, gid):
109 # make sure the client_gid matches client's certificate
110 if not cert.is_pubkey(gid.get_pubkey()):
111 raise ConnectionKeyGIDMismatch(gid.get_subject()+":"+cert.get_subject())
113 def verifyGidRequestHash(self, gid, hash, arglist):
114 key = gid.get_pubkey()
115 if not key.verify_string(str(arglist), hash):
116 raise BadRequestHash(hash)
118 def verifyCredRequestHash(self, cred, hash, arglist):
119 gid = cred.get_gid_caller()
120 self.verifyGidRequestHash(gid, hash, arglist)
122 def validateGid(self, gid):
123 if self.trusted_cert_list:
124 gid.verify_chain(self.trusted_cert_list)
126 def validateCred(self, cred):
127 if self.trusted_cert_list:
128 cred.verify(self.trusted_cert_file_list)
130 def authenticateGid(self, gidStr, argList, requestHash=None):
131 gid = GID(string = gidStr)
132 self.validateGid(gid)
133 # request_hash is optional
135 self.verifyGidRequestHash(gid, requestHash, argList)
138 def authenticateCred(self, credStr, argList, requestHash=None):
139 cred = Credential(string = credStr)
140 self.validateCred(cred)
141 # request hash is optional
143 self.verifyCredRequestHash(cred, requestHash, argList)
146 def authenticateCert(self, certStr, requestHash):
147 cert = Certificate(string=certStr)
148 self.validateCert(self, cert)
150 def gidNoop(self, gidStr, value, requestHash):
151 self.authenticateGid(gidStr, [gidStr, value], requestHash)
154 def credNoop(self, credStr, value, requestHash):
155 self.authenticateCred(credStr, [credStr, value], requestHash)
158 def verify_cred_is_me(self, credential):
160 cred = Credential(string=credential)
161 caller_gid = cred.get_gid_caller()
162 caller_hrn = caller_gid.get_hrn()
163 if caller_hrn != self.config.SFA_INTERFACE_HRN:
164 raise SfaPermissionDenied(self.config.SFA_INTEFACE_HRN)
168 def get_auth_info(self, auth_hrn):
170 Given an authority name, return the information for that authority.
171 This is basically a stub that calls the hierarchy module.
173 @param auth_hrn human readable name of authority
176 return self.hierarchy.get_auth_info(auth_hrn)
179 def veriry_auth_belongs_to_me(self, name):
181 Verify that an authority belongs to our hierarchy.
182 This is basically left up to the implementation of the hierarchy
183 module. If the specified name does not belong, ane exception is
184 thrown indicating the caller should contact someone else.
186 @param auth_name human readable name of authority
189 # get auth info will throw an exception if the authority doesnt exist
190 self.get_auth_info(name)
193 def verify_object_belongs_to_me(self, name):
195 Verify that an object belongs to our hierarchy. By extension,
196 this implies that the authority that owns the object belongs
197 to our hierarchy. If it does not an exception is thrown.
199 @param name human readable name of object
201 auth_name = self.get_authority(name)
204 if name == self.config.SFA_INTERFACE_HRN:
206 self.verify_auth_belongs_to_me(auth_name)
208 def verify_auth_belongs_to_me(self, name):
209 # get auth info will throw an exception if the authority doesnt exist
210 self.get_auth_info(name)
213 def verify_object_permission(self, name):
215 Verify that the object gid that was specified in the credential
216 allows permission to the object 'name'. This is done by a simple
217 prefix test. For example, an object_gid for plc.arizona would
218 match the objects plc.arizona.slice1 and plc.arizona.
220 @param name human readable name to test
222 object_hrn = self.object_gid.get_hrn()
223 if object_hrn == name:
225 if name.startswith(object_hrn + "."):
227 #if name.startswith(get_authority(name)):
230 raise PermissionError(name)
232 def determine_user_rights(self, caller_hrn, record):
234 Given a user credential and a record, determine what set of rights the
235 user should have to that record.
237 This is intended to replace determine_rights() and
238 verify_cancreate_credential()
242 type = record['type']
246 researchers = record.get("researcher", [])
247 pis = record.get("PI", [])
248 if (caller_hrn in researchers + pis):
255 elif type == "authority":
256 pis = record.get("PI", [])
257 operators = record.get("operator", [])
258 if (caller_hrn == self.config.SFA_INTERFACE_HRN):
262 if (caller_hrn in pis):
265 if (caller_hrn in operators):
279 def verify_cancreate_credential(self, src_cred, record):
281 Verify that a user can retrive a particular type of credential.
282 For slices, the user must be on the researcher list. For SA and
283 MA the user must be on the pi and operator lists respectively
286 type = record.get_type()
287 cred_object_hrn = src_cred.get_gid_object().get_hrn()
288 if cred_object_hrn in [self.config.SFA_REGISTRY_ROOT_AUTH]:
291 researchers = record.get("researcher", [])
292 if not (cred_object_hrn in researchers):
293 raise PermissionError(cred_object_hrn + " is not in researcher list for " + record.get_name())
295 pis = record.get("pi", [])
296 if not (cred_object_hrn in pis):
297 raise PermissionError(cred_object_hrn + " is not in pi list for " + record.get_name())
299 operators = record.get("operator", [])
300 if not (cred_object_hrn in operators):
301 raise PermissionError(cred_object_hrn + " is not in operator list for " + record.get_name())
303 def get_authority(self, hrn):
304 return get_authority(hrn)
306 def filter_creds_by_caller(self, creds, caller_hrn):
308 Returns a list of creds who's gid caller matches the
311 if not isinstance(creds, list):
316 tmp_cred = Credential(string=cred)
317 if tmp_cred.get_gid_caller().get_hrn() == caller_hrn: