48c39221e5be8e49723311f8407ac18d7a9fe7a0
[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 verify_cancreate_credential(self, src_cred, record):
146         """
147         Verify that a user can retrive a particular type of credential. 
148         For slices, the user must be on the researcher list. For SA and
149         MA the user must be on the pi and operator lists respectively 
150         """
151
152         type = record.get_type()
153         cred_object_hrn = src_cred.get_gid_object().get_hrn()
154         if cred_object_hrn in [self.config.GENI_REGISTRY_ROOT_AUTH]:
155             return
156         if type=="slice":
157             researchers = record.get_geni_info().get("researcher", [])
158             if not (cred_object_hrn in researchers):
159                 raise PermissionError(cred_object_hrn + " is not in researcher list for " + record.get_name())
160         elif type == "sa":
161             pis = record.get_geni_info().get("pi", [])
162             if not (cred_object_hrn in pis):
163                 raise PermissionError(cred_object_hrn + " is not in pi list for " + record.get_name())
164         elif type == "ma":
165             operators = record.get_geni_info().get("operator", [])
166             if not (cred_object_hrn in operators):
167                 raise PermissionError(cred_object_hrn + " is not in operator list for " + record.get_name())
168
169     def get_leaf(self, hrn):
170         parts = hrn.split(".")
171         return ".".join(parts[-1:])
172
173     def get_authority(self, hrn):
174
175         parts = hrn.split(".")
176         return ".".join(parts[:-1])
177
178     def get_auth_type(self, type):
179         if (type=="slice") or (type=="user") or (type=="sa"):
180             return "sa"
181         elif (type=="component") or (type=="ma"):
182             return "ma"
183         else:
184             raise UnknownGeniType(type)
185
186     def hrn_to_pl_slicename(self, hrn):
187         parts = hrn.split(".")
188         return parts[-2] + "_" + parts[-1]
189
190     # assuming hrn is the hrn of an authority, return the plc authority name
191     def hrn_to_pl_authname(self, hrn):
192         parts = hrn.split(".")
193         return parts[-1]
194
195     # assuming hrn is the hrn of an authority, return the plc login_base
196     def hrn_to_pl_login_base(self, hrn):
197         return self.hrn_to_pl_authname(hrn)
198