oops - wrong identation
[plcapi.git] / PLC / AuthorizeHelpers.py
1 #
2 # Thierry Parmentelat - INRIA
3 #
4 from PLC.Faults import *
5 from PLC.Persons import Persons,Person
6 from PLC.Sites import Sites,Site
7 from PLC.Nodes import Nodes,Node
8
9 class AuthorizeHelpers:
10
11     @staticmethod
12     def person_tag_type_common_roles (api, person, tag_type):
13         return list (set(person['roles']).intersection(set(tag_type['roles'])))
14
15     @staticmethod
16     def caller_may_access_tag_type (api, caller, tag_type):
17         if isinstance(caller,Person):
18             return len(AuthorizeHelpers.person_tag_type_common_roles(api,caller,tag_type))!=0
19         elif isinstance(caller,Node):
20             return 'node' in tag_type['roles']
21         else:
22             raise PLCInvalidArgument, "caller_may_access_tag_type - unexpected arg"
23
24     @staticmethod
25     def person_may_access_person (api, caller_person, subject_person):
26         # keep it simple for now - could be a bit more advanced for PIs maybe
27         try:    return caller_person['person_id'] == subject_person['person_id']
28         except: return False
29
30     @staticmethod
31     def person_in_site (api, person, site):
32         return site['site_id'] in person['site_ids']
33
34     @staticmethod
35     def person_in_slice (api, caller_person, slice):
36         return caller_person['person_id'] in slice['person_ids']
37
38     @staticmethod
39     def slice_in_site (api, slice, site):
40         return slice['site_id']==site['site_id']
41
42     @staticmethod
43     def node_id_in_slice (api, node_id_or_hostname, slice):
44         if isinstance (node_id_or_hostname,int):
45             return node_id_or_hostname in slice['node_ids']
46         else:
47             try:   return Nodes(api,node_id_or_hostname)[0]['node_id'] in slice['node_ids']
48             except:return False
49
50     @staticmethod
51     def node_id_in_site (api, node_id_or_hostname, site):
52         if isinstance (node_id_or_hostname,int):
53             return node_id_or_hostname in site['node_ids']
54         else:
55             try:   return Nodes(api,node_id_or_hostname)[0]['node_id'] in site['node_ids']
56             except:return False
57
58
59     @staticmethod
60     def node_match_id (api, node, node_id_or_hostname):
61         if isinstance (node_id_or_hostname,int):
62             return node['node_id']==node_id_or_hostname
63         else:
64             return node['hostname']==node_id_or_hostname
65
66     @staticmethod
67     def interface_belongs_to_person (api,interface, person):
68         try:
69             node=Nodes(api,[interface['node_id']])[0]
70             return AuthorizeHelpers.node_belongs_to_person (api, node, person)
71         except:
72             return False
73
74     @staticmethod
75     def node_belongs_to_person (api, node, person):
76         try:
77             site=Sites(api,[node['site_id']])[0]
78             return AuthorizeHelpers.person_in_site (api, person, site)
79         except:
80             import traceback
81             return False
82
83     # does the slice belong to the site that the (pi) user is in ?
84     @staticmethod
85     def slice_belongs_to_pi (api, slice, pi):
86         return slice['site_id'] in pi['site_ids']
87
88
89 # authorization methods - check if a given caller can set tag on this object
90 # called in {Add,Update,Delete}<Class>Tags methods, and in the accessors created in factory
91 # attach these as <Class>.caller_may_write_tag so accessors can find it
92
93 def caller_may_write_node_tag (node, api, caller, tag_type):
94     if 'admin' in caller['roles']:
95         pass
96     elif not AuthorizeHelpers.caller_may_access_tag_type (api, caller, tag_type):
97         raise PLCPermissionDenied, "Role mismatch for writing tag %s"%(tag_type['tagname'])
98     elif AuthorizeHelpers.node_belongs_to_person (api, node, caller):
99         pass
100     else:
101         raise PLCPermissionDenied, "Writing node tag: must belong in the same site as %s"%\
102             (node['hostname'])
103
104 setattr(Node,'caller_may_write_tag',caller_may_write_node_tag)
105         
106
107 def caller_may_write_interface_tag (interface, api, caller, tag_type):
108     if 'admin' in caller['roles']:
109         pass
110     elif not AuthorizeHelpers.caller_may_access_tag_type (api, caller, tag_type):
111         raise PLCPermissionDenied, "Role mismatch for writing tag %s"%(tag_type['tagname'])
112     elif AuthorizeHelpers.interface_belongs_to_person (api, interface, caller):
113         pass
114     else:
115         raise PLCPermissionDenied, "Writing interface tag: must belong in the same site as %s"%\
116             (interface['ip'])
117         
118 setattr(Interface,'caller_may_write_tag',caller_may_write_interface_tag)
119         
120
121 def caller_may_write_site_tag (site, api, caller, tag_type):
122     if 'admin' in caller['roles']:
123         pass
124     elif not AuthorizeHelpers.caller_may_access_tag_type (api, caller, tag_type):
125         raise PLCPermissionDenied, "Role mismatch for writing tag %s"%(tag_type['tagname'])
126     elif AuthorizeHelpers.person_in_site (api, caller, site):
127         pass
128     else:
129         raise PLCPermissionDenied, "Writing site tag: must be part of site"%site['login_base']
130
131 setattr(Site,'caller_may_write_tag',caller_may_write_site_tag)
132
133
134 def caller_may_write_person_tag (person, api, caller, tag_type):
135     if 'admin' in caller['roles']:
136         pass
137     # user can change tags on self
138     elif AuthorizeHelpers.person_may_access_person (api, caller, person):
139         pass
140     else:
141         raise PLCPermissionDenied, "Writing person tag: you can only change your own tags"
142
143 setattr(Person,'caller_may_write_tag',caller_may_write_person_tag)
144
145
146 def caller_may_write_slice_tag (slice, api, caller, tag_type, node_id_or_hostname=None, nodegroup_id_or_name=None):
147     granted=False
148     if 'admin' in caller['roles']:
149         granted=True
150     # does caller have right role(s) ? this knows how to deal with caller being a node
151     elif not AuthorizeHelpers.caller_may_access_tag_type (api, caller, tag_type):
152         granted=False
153     # node callers: check the node is in the slice
154     elif isinstance(caller, Node): 
155         # nodes can only set their own sliver tags
156         if node_id_or_hostname is None: 
157             granted=False
158         elif not AuthorizeHelpers.node_match_id (api, caller, node_id_or_hostname):
159             granted=False
160         elif not AuthorizeHelpers.node_in_slice (api, caller, slice):
161             granted=False
162     # caller is a non-admin person
163     else:
164         # only admins can handle slice tags on a nodegroup
165         if nodegroup_id_or_name:
166             raise PLCPermissionDenied, "Cannot set slice tag %s on nodegroup - restricted to admins"%\
167                 (tag_type['tagname'])
168         # if a node is specified it is expected to be in the slice
169         if node_id_or_hostname:
170             if not AuthorizeHelpers.node_id_in_slice (api, node_id_or_hostname, slice):
171                 raise PLCPermissionDenied, "%s, node must be in slice when setting sliver tag"
172         # try all roles to find a match - tech are ignored b/c not in AddSliceTag.roles anyways
173         for role in AuthorizeHelpers.person_tag_type_common_roles(api,caller,tag_type):
174             # regular users need to be in the slice
175             if role=='user':
176                 if AuthorizeHelpers.person_in_slice(api, caller, slice):
177                     granted=True ; break
178             # for convenience, pi's can tweak all the slices in their site
179             elif role=='pi':
180                 if AuthorizeHelpers.slice_belongs_to_pi (api, slice, caller):
181                     granted=True ; break
182     if not granted:
183         raise PLCPermissionDenied, "Cannot write slice tag %s"%(tag_type['tagname'])
184
185 setattr(Slice,'caller_may_write_tag',caller_may_write_slice_tag)
186
187