2 # SfaAPI authentication
9 from sfa.trust.credential import Credential
10 from sfa.trust.trustedroot import TrustedRootList
11 from sfa.util.faults import *
12 from sfa.trust.hierarchy import Hierarchy
13 from sfa.util.config import *
14 from sfa.util.namespace import *
15 from sfa.util.sfaticket import *
16 from sfa.util.sfalogging import logger
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 = TrustedRootList(self.config.get_trustedroots_dir()).get_list()
34 self.trusted_cert_file_list = TrustedRootList(self.config.get_trustedroots_dir()).get_file_list()
38 def checkCredentials(self, creds, operation, hrn = None):
42 self.check(cred, operation, hrn)
45 error = sys.exc_info()[:2]
49 raise InsufficientRights('Access denied: %s -- %s' % (error[0],error[1]))
54 def check(self, cred, operation, hrn = None):
56 Check the credential against the peer cert (callerGID included
57 in the credential matches the caller that is connected to the
58 HTTPS connection, check if the credential was signed by a
59 trusted cert and check if the credential is allowd to perform
60 the specified operation.
62 self.client_cred = Credential(string = cred)
63 self.client_gid = self.client_cred.get_gid_caller()
64 self.object_gid = self.client_cred.get_gid_object()
66 # make sure the client_gid is not blank
67 if not self.client_gid:
68 raise MissingCallerGID(self.client_cred.get_subject())
70 # validate the client cert if it exists
72 self.verifyPeerCert(self.peer_cert, self.client_gid)
74 # make sure the client is allowed to perform the operation
76 if not self.client_cred.can_perform(operation):
77 raise InsufficientRights(operation)
79 if self.trusted_cert_list:
80 self.client_cred.verify(self.trusted_cert_file_list)
82 raise MissingTrustedRoots(self.config.get_trustedroots_dir())
84 # Make sure the credential's target matches the specified hrn.
85 # This check does not apply to trusted peers
86 trusted_peers = [gid.get_hrn() for gid in self.trusted_cert_list]
87 if hrn and self.client_gid.get_hrn() not in trusted_peers:
88 if not hrn == self.object_gid.get_hrn():
89 raise PermissionError("Target hrn: %s doesn't match specified hrn: %s " % \
90 (self.object_gid.get_hrn(), hrn) )
93 def check_ticket(self, ticket):
95 Check if the tickt was signed by a trusted cert
97 if self.trusted_cert_list:
98 client_ticket = SfaTicket(string=ticket)
99 client_ticket.verify_chain(self.trusted_cert_list)
101 raise MissingTrustedRoots(self.config.get_trustedroots_dir())
105 def verifyPeerCert(self, cert, gid):
106 # make sure the client_gid matches client's certificate
107 if not cert.is_pubkey(gid.get_pubkey()):
108 raise ConnectionKeyGIDMismatch(gid.get_subject()+":"+cert.get_subject())
110 def verifyGidRequestHash(self, gid, hash, arglist):
111 key = gid.get_pubkey()
112 if not key.verify_string(str(arglist), hash):
113 raise BadRequestHash(hash)
115 def verifyCredRequestHash(self, cred, hash, arglist):
116 gid = cred.get_gid_caller()
117 self.verifyGidRequestHash(gid, hash, arglist)
119 def validateGid(self, gid):
120 if self.trusted_cert_list:
121 gid.verify_chain(self.trusted_cert_list)
123 def validateCred(self, cred):
124 if self.trusted_cert_list:
125 cred.verify(self.trusted_cert_file_list)
127 def authenticateGid(self, gidStr, argList, requestHash=None):
128 gid = GID(string = gidStr)
129 self.validateGid(gid)
130 # request_hash is optional
132 self.verifyGidRequestHash(gid, requestHash, argList)
135 def authenticateCred(self, credStr, argList, requestHash=None):
136 cred = Credential(string = credStr)
137 self.validateCred(cred)
138 # request hash is optional
140 self.verifyCredRequestHash(cred, requestHash, argList)
143 def authenticateCert(self, certStr, requestHash):
144 cert = Certificate(string=certStr)
145 self.validateCert(self, cert)
147 def gidNoop(self, gidStr, value, requestHash):
148 self.authenticateGid(gidStr, [gidStr, value], requestHash)
151 def credNoop(self, credStr, value, requestHash):
152 self.authenticateCred(credStr, [credStr, value], requestHash)
155 def verify_cred_is_me(self, credential):
157 cred = Credential(string=credential)
158 caller_gid = cred.get_gid_caller()
159 caller_hrn = caller_gid.get_hrn()
160 if caller_hrn != self.config.SFA_INTERFACE_HRN:
161 raise SfaPermissionDenied(self.config.SFA_INTEFACE_HRN)
165 def get_auth_info(self, auth_hrn):
167 Given an authority name, return the information for that authority.
168 This is basically a stub that calls the hierarchy module.
170 @param auth_hrn human readable name of authority
173 return self.hierarchy.get_auth_info(auth_hrn)
176 def veriry_auth_belongs_to_me(self, name):
178 Verify that an authority belongs to our hierarchy.
179 This is basically left up to the implementation of the hierarchy
180 module. If the specified name does not belong, ane exception is
181 thrown indicating the caller should contact someone else.
183 @param auth_name human readable name of authority
186 # get auth info will throw an exception if the authority doesnt exist
187 self.get_auth_info(name)
190 def verify_object_belongs_to_me(self, name):
192 Verify that an object belongs to our hierarchy. By extension,
193 this implies that the authority that owns the object belongs
194 to our hierarchy. If it does not an exception is thrown.
196 @param name human readable name of object
198 auth_name = self.get_authority(name)
201 if name == self.config.SFA_INTERFACE_HRN:
203 self.verify_auth_belongs_to_me(auth_name)
205 def verify_auth_belongs_to_me(self, name):
206 # get auth info will throw an exception if the authority doesnt exist
207 self.get_auth_info(name)
210 def verify_object_permission(self, name):
212 Verify that the object gid that was specified in the credential
213 allows permission to the object 'name'. This is done by a simple
214 prefix test. For example, an object_gid for plc.arizona would
215 match the objects plc.arizona.slice1 and plc.arizona.
217 @param name human readable name to test
219 object_hrn = self.object_gid.get_hrn()
220 if object_hrn == name:
222 if name.startswith(object_hrn + "."):
224 #if name.startswith(get_authority(name)):
227 raise PermissionError(name)
229 def determine_user_rights(self, caller_hrn, record):
231 Given a user credential and a record, determine what set of rights the
232 user should have to that record.
234 This is intended to replace determine_rights() and
235 verify_cancreate_credential()
239 type = record['type']
243 researchers = record.get("researcher", [])
244 pis = record.get("PI", [])
245 if (caller_hrn in researchers + pis):
252 elif type == "authority":
253 pis = record.get("PI", [])
254 operators = record.get("operator", [])
255 if (caller_hrn == self.config.SFA_INTERFACE_HRN):
259 if (caller_hrn in pis):
262 if (caller_hrn in operators):
276 def verify_cancreate_credential(self, src_cred, record):
278 Verify that a user can retrive a particular type of credential.
279 For slices, the user must be on the researcher list. For SA and
280 MA the user must be on the pi and operator lists respectively
283 type = record.get_type()
284 cred_object_hrn = src_cred.get_gid_object().get_hrn()
285 if cred_object_hrn in [self.config.SFA_REGISTRY_ROOT_AUTH]:
288 researchers = record.get("researcher", [])
289 if not (cred_object_hrn in researchers):
290 raise PermissionError(cred_object_hrn + " is not in researcher list for " + record.get_name())
292 pis = record.get("pi", [])
293 if not (cred_object_hrn in pis):
294 raise PermissionError(cred_object_hrn + " is not in pi list for " + record.get_name())
296 operators = record.get("operator", [])
297 if not (cred_object_hrn in operators):
298 raise PermissionError(cred_object_hrn + " is not in operator list for " + record.get_name())
300 def get_authority(self, hrn):
301 return get_authority(hrn)