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