2 # SfaAPI authentication
9 from sfa.trust.certificate import Keypair, Certificate
10 from sfa.trust.credential import Credential
11 from sfa.trust.trustedroot import TrustedRootList
12 from sfa.util.faults import *
13 from sfa.trust.hierarchy import Hierarchy
14 from sfa.util.config import *
15 from sfa.util.namespace import *
16 from sfa.util.sfaticket import *
17 from sfa.util.sfalogging import logger
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 = TrustedRootList(self.config.get_trustedroots_dir()).get_list()
35 self.trusted_cert_file_list = TrustedRootList(self.config.get_trustedroots_dir()).get_file_list()
39 def checkCredentials(self, creds, operation, hrn = None):
41 if not isinstance(creds, list):
45 self.check(cred, operation, hrn)
48 error = sys.exc_info()[:2]
52 raise InsufficientRights('Access denied: %s -- %s' % (error[0],error[1]))
57 def check(self, cred, operation, hrn = None):
59 Check the credential against the peer cert (callerGID included
60 in the credential matches the caller that is connected to the
61 HTTPS connection, check if the credential was signed by a
62 trusted cert and check if the credential is allowd to perform
63 the specified operation.
65 self.client_cred = Credential(string = cred)
66 self.client_gid = self.client_cred.get_gid_caller()
67 self.object_gid = self.client_cred.get_gid_object()
69 # make sure the client_gid is not blank
70 if not self.client_gid:
71 raise MissingCallerGID(self.client_cred.get_subject())
73 # validate the client cert if it exists
75 self.verifyPeerCert(self.peer_cert, self.client_gid)
77 # make sure the client is allowed to perform the operation
79 if not self.client_cred.can_perform(operation):
80 raise InsufficientRights(operation)
82 if self.trusted_cert_list:
83 self.client_cred.verify(self.trusted_cert_file_list)
85 raise MissingTrustedRoots(self.config.get_trustedroots_dir())
87 # Make sure the credential's target matches the specified hrn.
88 # This check does not apply to trusted peers
89 trusted_peers = [gid.get_hrn() for gid in self.trusted_cert_list]
90 if hrn and self.client_gid.get_hrn() not in trusted_peers:
91 target_hrn = self.object_gid.get_hrn()
92 if not hrn == target_hrn:
93 raise PermissionError("Target hrn: %s doesn't match specified hrn: %s " % \
97 def check_ticket(self, ticket):
99 Check if the tickt was signed by a trusted cert
101 if self.trusted_cert_list:
102 client_ticket = SfaTicket(string=ticket)
103 client_ticket.verify_chain(self.trusted_cert_list)
105 raise MissingTrustedRoots(self.config.get_trustedroots_dir())
109 def verifyPeerCert(self, cert, gid):
110 # make sure the client_gid matches client's certificate
111 if not cert.is_pubkey(gid.get_pubkey()):
112 raise ConnectionKeyGIDMismatch(gid.get_subject()+":"+cert.get_subject())
114 def verifyGidRequestHash(self, gid, hash, arglist):
115 key = gid.get_pubkey()
116 if not key.verify_string(str(arglist), hash):
117 raise BadRequestHash(hash)
119 def verifyCredRequestHash(self, cred, hash, arglist):
120 gid = cred.get_gid_caller()
121 self.verifyGidRequestHash(gid, hash, arglist)
123 def validateGid(self, gid):
124 if self.trusted_cert_list:
125 gid.verify_chain(self.trusted_cert_list)
127 def validateCred(self, cred):
128 if self.trusted_cert_list:
129 cred.verify(self.trusted_cert_file_list)
131 def authenticateGid(self, gidStr, argList, requestHash=None):
132 gid = GID(string = gidStr)
133 self.validateGid(gid)
134 # request_hash is optional
136 self.verifyGidRequestHash(gid, requestHash, argList)
139 def authenticateCred(self, credStr, argList, requestHash=None):
140 cred = Credential(string = credStr)
141 self.validateCred(cred)
142 # request hash is optional
144 self.verifyCredRequestHash(cred, requestHash, argList)
147 def authenticateCert(self, certStr, requestHash):
148 cert = Certificate(string=certStr)
149 self.validateCert(self, cert)
151 def gidNoop(self, gidStr, value, requestHash):
152 self.authenticateGid(gidStr, [gidStr, value], requestHash)
155 def credNoop(self, credStr, value, requestHash):
156 self.authenticateCred(credStr, [credStr, value], requestHash)
159 def verify_cred_is_me(self, credential):
161 cred = Credential(string=credential)
162 caller_gid = cred.get_gid_caller()
163 caller_hrn = caller_gid.get_hrn()
164 if caller_hrn != self.config.SFA_INTERFACE_HRN:
165 raise SfaPermissionDenied(self.config.SFA_INTEFACE_HRN)
169 def get_auth_info(self, auth_hrn):
171 Given an authority name, return the information for that authority.
172 This is basically a stub that calls the hierarchy module.
174 @param auth_hrn human readable name of authority
177 return self.hierarchy.get_auth_info(auth_hrn)
180 def veriry_auth_belongs_to_me(self, name):
182 Verify that an authority belongs to our hierarchy.
183 This is basically left up to the implementation of the hierarchy
184 module. If the specified name does not belong, ane exception is
185 thrown indicating the caller should contact someone else.
187 @param auth_name human readable name of authority
190 # get auth info will throw an exception if the authority doesnt exist
191 self.get_auth_info(name)
194 def verify_object_belongs_to_me(self, name):
196 Verify that an object belongs to our hierarchy. By extension,
197 this implies that the authority that owns the object belongs
198 to our hierarchy. If it does not an exception is thrown.
200 @param name human readable name of object
202 auth_name = self.get_authority(name)
205 if name == self.config.SFA_INTERFACE_HRN:
207 self.verify_auth_belongs_to_me(auth_name)
209 def verify_auth_belongs_to_me(self, name):
210 # get auth info will throw an exception if the authority doesnt exist
211 self.get_auth_info(name)
214 def verify_object_permission(self, name):
216 Verify that the object gid that was specified in the credential
217 allows permission to the object 'name'. This is done by a simple
218 prefix test. For example, an object_gid for plc.arizona would
219 match the objects plc.arizona.slice1 and plc.arizona.
221 @param name human readable name to test
223 object_hrn = self.object_gid.get_hrn()
224 if object_hrn == name:
226 if name.startswith(object_hrn + "."):
228 #if name.startswith(get_authority(name)):
231 raise PermissionError(name)
233 def determine_user_rights(self, caller_hrn, record):
235 Given a user credential and a record, determine what set of rights the
236 user should have to that record.
238 This is intended to replace determine_rights() and
239 verify_cancreate_credential()
243 type = record['type']
247 researchers = record.get("researcher", [])
248 pis = record.get("PI", [])
249 if (caller_hrn in researchers + pis):
256 elif type == "authority":
257 pis = record.get("PI", [])
258 operators = record.get("operator", [])
259 if (caller_hrn == self.config.SFA_INTERFACE_HRN):
263 if (caller_hrn in pis):
266 if (caller_hrn in operators):
280 def verify_cancreate_credential(self, src_cred, record):
282 Verify that a user can retrive a particular type of credential.
283 For slices, the user must be on the researcher list. For SA and
284 MA the user must be on the pi and operator lists respectively
287 type = record.get_type()
288 cred_object_hrn = src_cred.get_gid_object().get_hrn()
289 if cred_object_hrn in [self.config.SFA_REGISTRY_ROOT_AUTH]:
292 researchers = record.get("researcher", [])
293 if not (cred_object_hrn in researchers):
294 raise PermissionError(cred_object_hrn + " is not in researcher list for " + record.get_name())
296 pis = record.get("pi", [])
297 if not (cred_object_hrn in pis):
298 raise PermissionError(cred_object_hrn + " is not in pi list for " + record.get_name())
300 operators = record.get("operator", [])
301 if not (cred_object_hrn in operators):
302 raise PermissionError(cred_object_hrn + " is not in operator list for " + record.get_name())
304 def get_authority(self, hrn):
305 return get_authority(hrn)