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
20 Credential based authentication
23 def __init__(self, peer_cert = None, config = None ):
24 self.peer_cert = peer_cert
25 self.hierarchy = Hierarchy()
27 self.config = Config()
28 self.load_trusted_certs()
30 def load_trusted_certs(self):
31 self.trusted_cert_list = TrustedRootList(self.config.get_trustedroots_dir()).get_list()
32 self.trusted_cert_file_list = TrustedRootList(self.config.get_trustedroots_dir()).get_file_list()
35 def check(self, cred, operation, hrn = None):
37 Check the credential against the peer cert (callerGID included
38 in the credential matches the caller that is connected to the
39 HTTPS connection, check if the credential was signed by a
40 trusted cert and check if the credential is allowd to perform
41 the specified operation.
43 self.client_cred = Credential(string = cred)
44 self.client_gid = self.client_cred.get_gid_caller()
45 self.object_gid = self.client_cred.get_gid_object()
47 # make sure the client_gid is not blank
48 if not self.client_gid:
49 raise MissingCallerGID(self.client_cred.get_subject())
51 # validate the client cert if it exists
53 self.verifyPeerCert(self.peer_cert, self.client_gid)
55 # make sure the client is allowed to perform the operation
57 if not self.client_cred.can_perform(operation):
58 raise InsufficientRights(operation)
60 if self.trusted_cert_list:
61 self.client_cred.verify(self.trusted_cert_file_list)
63 raise MissingTrustedRoots(self.config.get_trustedroots_dir())
65 # Make sure the credential's target matches the specified hrn.
66 # This check does not apply to trusted peers
67 trusted_peers = [gid.get_hrn() for gid in self.trusted_cert_list]
68 if hrn and client_gid.get_hrn() not in trusted_peers:
69 if not hrn == object_gid.get_hrn():
70 raise PermissionError("Target hrn: %s doesn't match specified hrn: %s " % \
71 (object_gid.get_hrn(), hrn) )
74 def check_ticket(self, ticket):
76 Check if the tickt was signed by a trusted cert
78 if self.trusted_cert_list:
79 client_ticket = SfaTicket(string=ticket)
80 client_ticket.verify_chain(self.trusted_cert_list)
82 raise MissingTrustedRoots(self.config.get_trustedroots_dir())
86 def verifyPeerCert(self, cert, gid):
87 # make sure the client_gid matches client's certificate
88 if not cert.is_pubkey(gid.get_pubkey()):
89 raise ConnectionKeyGIDMismatch(gid.get_subject()+":"+cert.get_subject())
91 def verifyGidRequestHash(self, gid, hash, arglist):
92 key = gid.get_pubkey()
93 if not key.verify_string(str(arglist), hash):
94 raise BadRequestHash(hash)
96 def verifyCredRequestHash(self, cred, hash, arglist):
97 gid = cred.get_gid_caller()
98 self.verifyGidRequestHash(gid, hash, arglist)
100 def validateGid(self, gid):
101 if self.trusted_cert_list:
102 gid.verify_chain(self.trusted_cert_list)
104 def validateCred(self, cred):
105 if self.trusted_cert_list:
106 cred.verify(self.trusted_cert_file_list)
108 def authenticateGid(self, gidStr, argList, requestHash=None):
109 gid = GID(string = gidStr)
110 self.validateGid(gid)
111 # request_hash is optional
113 self.verifyGidRequestHash(gid, requestHash, argList)
116 def authenticateCred(self, credStr, argList, requestHash=None):
117 cred = Credential(string = credStr)
118 self.validateCred(cred)
119 # request hash is optional
121 self.verifyCredRequestHash(cred, requestHash, argList)
124 def authenticateCert(self, certStr, requestHash):
125 cert = Certificate(string=certStr)
126 self.validateCert(self, cert)
128 def gidNoop(self, gidStr, value, requestHash):
129 self.authenticateGid(gidStr, [gidStr, value], requestHash)
132 def credNoop(self, credStr, value, requestHash):
133 self.authenticateCred(credStr, [credStr, value], requestHash)
136 def verify_cred_is_me(self, credential):
138 cred = Credential(string=credential)
139 caller_gid = cred.get_gid_caller()
140 caller_hrn = caller_gid.get_hrn()
141 if caller_hrn != self.config.SFA_INTERFACE_HRN:
142 raise SfaPermissionDenied(self.config.SFA_INTEFACE_HRN)
146 def get_auth_info(self, auth_hrn):
148 Given an authority name, return the information for that authority.
149 This is basically a stub that calls the hierarchy module.
151 @param auth_hrn human readable name of authority
154 return self.hierarchy.get_auth_info(auth_hrn)
157 def veriry_auth_belongs_to_me(self, name):
159 Verify that an authority belongs to our hierarchy.
160 This is basically left up to the implementation of the hierarchy
161 module. If the specified name does not belong, ane exception is
162 thrown indicating the caller should contact someone else.
164 @param auth_name human readable name of authority
167 # get auth info will throw an exception if the authority doesnt exist
168 self.get_auth_info(name)
171 def verify_object_belongs_to_me(self, name):
173 Verify that an object belongs to our hierarchy. By extension,
174 this implies that the authority that owns the object belongs
175 to our hierarchy. If it does not an exception is thrown.
177 @param name human readable name of object
179 auth_name = self.get_authority(name)
182 if name == self.config.SFA_INTERFACE_HRN:
184 self.verify_auth_belongs_to_me(auth_name)
186 def verify_auth_belongs_to_me(self, name):
187 # get auth info will throw an exception if the authority doesnt exist
188 self.get_auth_info(name)
191 def verify_object_permission(self, name):
193 Verify that the object gid that was specified in the credential
194 allows permission to the object 'name'. This is done by a simple
195 prefix test. For example, an object_gid for plc.arizona would
196 match the objects plc.arizona.slice1 and plc.arizona.
198 @param name human readable name to test
200 object_hrn = self.object_gid.get_hrn()
201 if object_hrn == name:
203 if name.startswith(object_hrn + "."):
205 #if name.startswith(get_authority(name)):
208 raise PermissionError(name)
210 def determine_user_rights(self, caller_hrn, record):
212 Given a user credential and a record, determine what set of rights the
213 user should have to that record.
215 This is intended to replace determine_rights() and
216 verify_cancreate_credential()
220 type = record['type']
223 researchers = record.get("researcher", [])
224 pis = record.get("PI", [])
225 if (caller_hrn in researchers + pis):
232 elif type == "authority":
233 pis = record.get("PI", [])
234 operators = record.get("operator", [])
235 if (caller_hrn == self.config.SFA_INTERFACE_HRN):
239 if (caller_hrn in pis):
242 if (caller_hrn in operators):
256 def verify_cancreate_credential(self, src_cred, record):
258 Verify that a user can retrive a particular type of credential.
259 For slices, the user must be on the researcher list. For SA and
260 MA the user must be on the pi and operator lists respectively
263 type = record.get_type()
264 cred_object_hrn = src_cred.get_gid_object().get_hrn()
265 if cred_object_hrn in [self.config.SFA_REGISTRY_ROOT_AUTH]:
268 researchers = record.get("researcher", [])
269 if not (cred_object_hrn in researchers):
270 raise PermissionError(cred_object_hrn + " is not in researcher list for " + record.get_name())
272 pis = record.get("pi", [])
273 if not (cred_object_hrn in pis):
274 raise PermissionError(cred_object_hrn + " is not in pi list for " + record.get_name())
276 operators = record.get("operator", [])
277 if not (cred_object_hrn in operators):
278 raise PermissionError(cred_object_hrn + " is not in operator list for " + record.get_name())
280 def get_authority(self, hrn):
281 return get_authority(hrn)