these two lines, if enabled, allow a credential to operate on all target hrn. tony...
[sfa.git] / sfa / trust / auth.py
1 #
2 # GeniAPI authentication 
3 #
4 ### $Id$
5 ### $URL$
6 #
7
8 import time
9
10 from sfa.trust.credential import Credential
11 from sfa.trust.trustedroot import TrustedRootList
12 from sfa.trust.rights import RightList
13 from sfa.util.faults import *
14 from sfa.trust.hierarchy import Hierarchy
15 from sfa.util.genitable import GeniTable
16 from sfa.util.config import *
17 from sfa.util.misc import *
18
19 class Auth:
20     """
21     Credential based authentication
22     """
23
24     def __init__(self, peer_cert = None, config = None ):
25         self.peer_cert = peer_cert
26         self.hierarchy = Hierarchy()
27         self.trusted_cert_list = TrustedRootList().get_list() 
28         if not config:
29             self.config = Config() 
30     
31
32     def check(self, cred, operation):
33         """
34         Check the credential against the peer cert (callerGID included 
35         in the credential matches the caller that is connected to the 
36         HTTPS connection, check if the credential was signed by a 
37         trusted cert and check if the credential is allowd to perform 
38         the specified operation.    
39         """
40         self.client_cred = Credential(string = cred)
41         self.client_gid = self.client_cred.get_gid_caller()
42         self.object_gid = self.client_cred.get_gid_object()
43         
44         # make sure the client_gid is not blank
45         if not self.client_gid:
46             raise MissingCallerGID(self.client_cred.get_subject())
47
48         # make sure the client_gid matches client's certificate
49         peer_cert = self.peer_cert
50         if not peer_cert.is_pubkey(self.client_gid.get_pubkey()):
51             raise ConnectionKeyGIDMismatch(self.client_gid.get_subject())
52
53         # make sure the client is allowed to perform the operation
54         if operation:
55             if not self.client_cred.can_perform(operation):
56                 raise InsufficientRights(operation)
57
58         if self.trusted_cert_list:
59             self.client_cred.verify_chain(self.trusted_cert_list)
60             if self.client_gid:
61                 self.client_gid.verify_chain(self.trusted_cert_list)
62             if self.object_gid:
63                 self.object_gid.verify_chain(self.trusted_cert_list)
64
65         return True
66
67         
68     def get_auth_info(self, auth_hrn):
69         """
70         Given an authority name, return the information for that authority.
71         This is basically a stub that calls the hierarchy module.
72         
73         @param auth_hrn human readable name of authority  
74         """
75
76         return self.hierarchy.get_auth_info(auth_hrn)
77
78
79     def veriry_auth_belongs_to_me(self, name):
80         """
81         Verify that an authority belongs to our hierarchy. 
82         This is basically left up to the implementation of the hierarchy
83         module. If the specified name does not belong, ane exception is 
84         thrown indicating the caller should contact someone else.
85
86         @param auth_name human readable name of authority
87         """
88
89         self.get_auth_info(name)
90
91
92     def verify_object_belongs_to_me(self, name):
93         """
94         Verify that an object belongs to our hierarchy. By extension,
95         this implies that the authority that owns the object belongs
96         to our hierarchy. If it does not an exception is thrown.
97     
98         @param name human readable name of object        
99         """
100         auth_name = self.get_authority(name)
101         if not auth_name or name == self.config.SFA_INTERFACE_HRN:
102             # the root authority belongs to the registry by default?
103             # TODO: is this true?
104             return
105         self.verify_auth_belongs_to_me(auth_name) 
106              
107     def verify_auth_belongs_to_me(self, name):
108         # get auth info will throw an exception if the authority doesnt exist
109         self.get_auth_info(name) 
110
111
112     def verify_object_permission(self, name):
113         """
114         Verify that the object gid that was specified in the credential
115         allows permission to the object 'name'. This is done by a simple
116         prefix test. For example, an object_gid for plc.arizona would 
117         match the objects plc.arizona.slice1 and plc.arizona.
118     
119         @param name human readable name to test  
120         """
121         object_hrn = self.object_gid.get_hrn()
122         if object_hrn == name:
123             return
124         if name.startswith(object_hrn + "."):
125             return
126         #if name.startswith(get_authority(name)):
127             #return
128     
129         raise PermissionError(name)
130
131     def determine_user_rights(self, src_cred, record):
132         """
133         Given a user credential and a record, determine what set of rights the
134         user should have to that record.
135
136         Src_cred can be None when obtaining a user credential, but should be
137         set to a valid user credential when obtaining a slice or authority
138         credential.
139
140         This is intended to replace determine_rights() and
141         verify_cancreate_credential()
142         """
143
144         type = record['type']
145         if src_cred:
146             cred_object_hrn = src_cred.get_gid_object().get_hrn()
147         else:
148             # supplying src_cred==None is only valid when obtaining user
149             # credentials.
150             #assert(type == "user")
151             
152             cred_object_hrn = None
153
154         rl = RightList()
155
156         if type=="slice":
157             researchers = record.get("researcher", [])
158             if (cred_object_hrn in researchers):
159                 rl.add("refresh")
160                 rl.add("embed")
161                 rl.add("bind")
162                 rl.add("control")
163                 rl.add("info")
164
165         elif type == "authority":
166             pis = record.get("pi", [])
167             operators = record.get("operator", [])
168             rl.add("authority,sa,ma")
169             if (cred_object_hrn in pis):
170                 rl.add("sa")
171             if (cred_object_hrn in operators):
172                 rl.add("ma")
173
174         elif type == "user":
175             rl.add("refresh")
176             rl.add("resolve")
177             rl.add("info")
178
179         return rl
180
181     def verify_cancreate_credential(self, src_cred, record):
182         """
183         Verify that a user can retrive a particular type of credential.
184         For slices, the user must be on the researcher list. For SA and
185         MA the user must be on the pi and operator lists respectively
186         """
187
188         type = record.get_type()
189         cred_object_hrn = src_cred.get_gid_object().get_hrn()
190         if cred_object_hrn in [self.config.SFA_REGISTRY_ROOT_AUTH]:
191             return
192         if type=="slice":
193             researchers = record.get("researcher", [])
194             if not (cred_object_hrn in researchers):
195                 raise PermissionError(cred_object_hrn + " is not in researcher list for " + record.get_name())
196         elif type == "sa":
197             pis = record.get("pi", [])
198             if not (cred_object_hrn in pis):
199                 raise PermissionError(cred_object_hrn + " is not in pi list for " + record.get_name())
200         elif type == "ma":
201             operators = record.get("operator", [])
202             if not (cred_object_hrn in operators):
203                 raise PermissionError(cred_object_hrn + " is not in operator list for " + record.get_name())
204
205     def get_authority(self, hrn):
206         return get_authority(hrn)