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