root / rapi / api.py @ 534c4a37
History | View | Annotate | Download (13.8 kB)
1 |
from tastypie.resources import ModelResource |
---|---|
2 |
from flowspy.flowspec.models import * |
3 |
from tastypie import fields |
4 |
from django.contrib.auth.models import User |
5 |
from flowspy.accounts.models import * |
6 |
from tastypie.authentication import BasicAuthentication |
7 |
from tastypie.authorization import Authorization |
8 |
from flowspy.djangobackends.restauthBackend import restauthBackend |
9 |
from django.template.loader import render_to_string |
10 |
from django import forms |
11 |
from flowspy.flowspec.forms import * |
12 |
from ipaddr import * |
13 |
from flowspy.flowspec.views import send_new_mail as new_mail |
14 |
from flowspy.flowspec.views import get_peer_techc_mails as get_peer_techcs_contact |
15 |
from django.conf import settings |
16 |
from django.core.exceptions import ObjectDoesNotExist |
17 |
from tastypie.exceptions import * |
18 |
from tastypie import http |
19 |
import logging |
20 |
import datetime |
21 |
from django.shortcuts import get_object_or_404 |
22 |
from copy import deepcopy |
23 |
|
24 |
|
25 |
LOG_FILENAME = os.path.join(settings.LOG_FILE_LOCATION, 'celery_jobs.log')
|
26 |
#FORMAT = '%(asctime)s %(levelname)s: %(message)s'
|
27 |
#logging.basicConfig(format=FORMAT)
|
28 |
formatter = logging.Formatter('%(asctime)s %(levelname)s %(clientip)s %(user)s: %(message)s')
|
29 |
|
30 |
logger = logging.getLogger(__name__) |
31 |
logger.setLevel(logging.DEBUG) |
32 |
handler = logging.FileHandler(LOG_FILENAME) |
33 |
handler.setFormatter(formatter) |
34 |
logger.addHandler(handler) |
35 |
|
36 |
class SourcePortRes(ModelResource): |
37 |
class Meta: |
38 |
queryset = MatchPort.objects.all() |
39 |
resource_name = 'sourceport'
|
40 |
fields = ['port']
|
41 |
allowed_methods = ['get']
|
42 |
|
43 |
class DestPortRes(ModelResource): |
44 |
class Meta: |
45 |
queryset = MatchPort.objects.all() |
46 |
resource_name = 'destinationport'
|
47 |
fields = ['port']
|
48 |
allowed_methods = ['get']
|
49 |
|
50 |
class PortRes(ModelResource): |
51 |
class Meta: |
52 |
queryset = MatchPort.objects.all() |
53 |
resource_name = 'port'
|
54 |
fields = ['port']
|
55 |
allowed_methods = ['get']
|
56 |
|
57 |
class ThenResource(ModelResource): |
58 |
class Meta: |
59 |
queryset = ThenAction.objects.all() |
60 |
resource_name = 'then'
|
61 |
allowed_methods = ['get']
|
62 |
fields = ['action', 'action_value'] |
63 |
|
64 |
class RuleResource(ModelResource): |
65 |
name = fields.CharField(attribute='name')
|
66 |
sourceport = fields.ManyToManyField(SourcePortRes, 'sourceport', full=True, null=True) |
67 |
destinationport = fields.ManyToManyField(DestPortRes, 'destinationport', full=True, null=True) |
68 |
then = fields.ManyToManyField(ThenResource, 'then', full=True, null=True) |
69 |
port = fields.ManyToManyField(PortRes, 'port', full=True, null=True) |
70 |
|
71 |
def get_object_list(self, request): |
72 |
group_routes = [] |
73 |
user = request.user |
74 |
peer = user.get_profile().peer |
75 |
if peer:
|
76 |
peer_members = UserProfile.objects.filter(peer=peer) |
77 |
users = [prof.user for prof in peer_members] |
78 |
return super(RuleResource, self).get_object_list(request).filter(applier__in=users) |
79 |
|
80 |
def obj_create(self, bundle, request=None, **kwargs): |
81 |
then_list = [] |
82 |
sourceport_list = [] |
83 |
destport_list = [] |
84 |
port_list = [] |
85 |
bundle.obj = self._meta.object_class()
|
86 |
|
87 |
for key, value in kwargs.items(): |
88 |
setattr(bundle.obj, key, value)
|
89 |
|
90 |
bundle = self.full_hydrate(bundle)
|
91 |
m2m_bundle = self.hydrate_m2m(bundle)
|
92 |
|
93 |
then_action_dict = m2m_bundle.data['then'][0].obj.__dict__ |
94 |
then_action_pk = ThenAction.objects.get(action=then_action_dict['action'], action_value=then_action_dict['action_value']).pk |
95 |
then_list.append(then_action_pk) |
96 |
try:
|
97 |
sourceport_dict = m2m_bundle.data['sourceport']
|
98 |
except:
|
99 |
sourceport_dict = None
|
100 |
if sourceport_dict:
|
101 |
for sp in sourceport_dict: |
102 |
sourceport_pk = get_port_pk_or_create(sp) |
103 |
sourceport_list.append(sourceport_pk) |
104 |
|
105 |
try:
|
106 |
destport_dict = m2m_bundle.data['destinationport']
|
107 |
except:
|
108 |
destport_dict = None
|
109 |
if destport_dict:
|
110 |
for dp in destport_dict: |
111 |
destport_pk = get_port_pk_or_create(dp) |
112 |
destport_list.append(destport_pk) |
113 |
|
114 |
try:
|
115 |
port_dict = m2m_bundle.data['port']
|
116 |
except:
|
117 |
port_dict = None
|
118 |
if port_dict:
|
119 |
for prt in port_dict: |
120 |
port_pk = get_port_pk_or_create(prt) |
121 |
port_list.append(port_pk) |
122 |
|
123 |
datadict = bundle.obj.__dict__ |
124 |
datadict['applier'] = request.user.pk
|
125 |
datadict['comments'] = "%s: %s" %("Submitted via REST API", datadict['comments']) |
126 |
datadict['then'] = then_list
|
127 |
datadict['sourceport'] = sourceport_list
|
128 |
datadict['destinationport'] = destport_list
|
129 |
datadict['port'] = port_list
|
130 |
form = RouteForm(data=datadict) |
131 |
|
132 |
if form.is_valid():
|
133 |
route=form.save(commit=False)
|
134 |
route.applier = request.user |
135 |
route.status = "PENDING"
|
136 |
route.source = IPNetwork("%s/%s" %(IPNetwork(route.source).network.compressed, IPNetwork(route.source).prefixlen)).compressed
|
137 |
route.destination = IPNetwork("%s/%s" %(IPNetwork(route.destination).network.compressed, IPNetwork(route.destination).prefixlen)).compressed
|
138 |
route.save() |
139 |
form.save_m2m() |
140 |
route.commit_add() |
141 |
requesters_address = request.META['HTTP_X_FORWARDED_FOR']
|
142 |
mail_body = render_to_string("rule_add_mail.txt",
|
143 |
{"route": route, "address": requesters_address}) |
144 |
user_mail = "%s" %route.applier.email
|
145 |
user_mail = user_mail.split(';')
|
146 |
new_mail(settings.EMAIL_SUBJECT_PREFIX + "Rule %s creation request submitted by %s via REST api" %(route.name, route.applier.username),
|
147 |
mail_body, settings.SERVER_EMAIL, user_mail, |
148 |
get_peer_techcs_contact(route.applier)) |
149 |
d = { 'clientip' : "REST_API: %s" %requesters_address, 'user' : route.applier.username } |
150 |
logger.info(mail_body, extra=d) |
151 |
else:
|
152 |
raise ApiFieldError("ERRORS %s %s" %(form.errors, form.__dict__)) |
153 |
|
154 |
return bundle
|
155 |
|
156 |
def obj_delete(self, request=None, **kwargs): |
157 |
obj = kwargs.pop('pk', None) |
158 |
if obj:
|
159 |
try:
|
160 |
route = Route.objects.get(pk=obj) |
161 |
except:
|
162 |
raise NotFound("A model instance matching the provided arguments could not be found.") |
163 |
applier_peer = route.applier.get_profile().peer |
164 |
requester_peer = request.user.get_profile().peer |
165 |
if applier_peer == requester_peer:
|
166 |
route.status = "PENDING"
|
167 |
route.expires = datetime.date.today() |
168 |
route.save() |
169 |
route.commit_delete() |
170 |
requesters_address = request.META['HTTP_X_FORWARDED_FOR']
|
171 |
mail_body = render_to_string("rule_delete_mail.txt",
|
172 |
{"route": route, "address": requesters_address}) |
173 |
user_mail = "%s" %route.applier.email
|
174 |
user_mail = user_mail.split(';')
|
175 |
new_mail(settings.EMAIL_SUBJECT_PREFIX + "Rule %s removal request submitted by %s" %(route.name, route.applier.username),
|
176 |
mail_body, settings.SERVER_EMAIL, user_mail, |
177 |
get_peer_techcs_contact(route.applier)) |
178 |
d = { 'clientip' : "REST_API: %s" %requesters_address, 'user' : route.applier.username } |
179 |
logger.info(mail_body, extra=d) |
180 |
else:
|
181 |
raise NotFound("A model instance matching the provided arguments could not be found.") |
182 |
else:
|
183 |
raise NotFound("A model instance matching the provided arguments could not be found.") |
184 |
|
185 |
def delete_list(self, request, **kwargs): |
186 |
return http.HttpForbidden()
|
187 |
|
188 |
def obj_update(self, bundle, request=None, **kwargs): |
189 |
then_list = [] |
190 |
sourceport_list = [] |
191 |
destport_list = [] |
192 |
port_list = [] |
193 |
applier = request.user.pk |
194 |
applier_peer = request.user.get_profile().peer |
195 |
route_edit = get_object_or_404(Route, pk=kwargs['pk'])
|
196 |
route_edit_applier_peer = route_edit.applier.get_profile().peer |
197 |
if applier_peer != route_edit_applier_peer:
|
198 |
return http.HttpForbidden()
|
199 |
|
200 |
route_original = deepcopy(route_edit) |
201 |
if not bundle.obj or not bundle.obj.pk: |
202 |
|
203 |
try:
|
204 |
bundle.obj = self.get_object_list(request).model()
|
205 |
bundle.data.update(kwargs) |
206 |
bundle = self.full_hydrate(bundle)
|
207 |
lookup_kwargs = kwargs.copy() |
208 |
|
209 |
for key in kwargs.keys(): |
210 |
if key == 'pk': |
211 |
continue
|
212 |
elif getattr(bundle.obj, key, NOT_AVAILABLE) is not NOT_AVAILABLE: |
213 |
lookup_kwargs[key] = getattr(bundle.obj, key)
|
214 |
else:
|
215 |
del lookup_kwargs[key]
|
216 |
except:
|
217 |
# if there is trouble hydrating the data, fall back to just
|
218 |
# using kwargs by itself (usually it only contains a "pk" key
|
219 |
# and this will work fine.
|
220 |
lookup_kwargs = kwargs |
221 |
|
222 |
try:
|
223 |
bundle.obj = self.obj_get(request, **lookup_kwargs)
|
224 |
except ObjectDoesNotExist:
|
225 |
raise NotFound("A model instance matching the provided arguments could not be found.") |
226 |
|
227 |
bundle = self.full_hydrate(bundle)
|
228 |
m2m_bundle = self.hydrate_m2m(bundle)
|
229 |
try:
|
230 |
then_action_dict = m2m_bundle.data['then'][0].obj.__dict__ |
231 |
then_action_pk = ThenAction.objects.get(action=then_action_dict['action'], action_value=then_action_dict['action_value']).pk |
232 |
then_list.append(then_action_pk) |
233 |
except:
|
234 |
then_list.extend([x.pk for x in route_edit.then.all() if x]) |
235 |
|
236 |
try:
|
237 |
sourceport_dict = m2m_bundle.data['sourceport']
|
238 |
except:
|
239 |
sourceport_dict = None
|
240 |
if sourceport_dict:
|
241 |
for sp in sourceport_dict: |
242 |
sourceport_pk = get_port_pk_or_create(sp) |
243 |
sourceport_list.append(sourceport_pk) |
244 |
else:
|
245 |
sourceport_list.extend([x.pk for x in route_edit.sourceport.all() if x]) |
246 |
|
247 |
try:
|
248 |
destport_dict = m2m_bundle.data['destinationport']
|
249 |
except:
|
250 |
destport_dict = None
|
251 |
if destport_dict:
|
252 |
for dp in destport_dict: |
253 |
destport_pk = get_port_pk_or_create(dp) |
254 |
destport_list.append(destport_pk) |
255 |
else:
|
256 |
destport_list.extend([x.pk for x in route_edit.destinationport.all() if x]) |
257 |
try:
|
258 |
port_dict = m2m_bundle.data['port']
|
259 |
except:
|
260 |
port_dict = None
|
261 |
if port_dict:
|
262 |
for prt in port_dict: |
263 |
port_pk = get_port_pk_or_create(prt) |
264 |
port_list.append(port_pk) |
265 |
else:
|
266 |
port_list.extend([x.pk for x in route_edit.port.all() if x]) |
267 |
|
268 |
|
269 |
datadict = bundle.obj.__dict__ |
270 |
datadict['applier'] = request.user.pk
|
271 |
comment_text = "Submitted via REST API"
|
272 |
if comment_text not in datadict['comments']: |
273 |
datadict['comments'] = "%s: %s" %("Submitted via REST API", datadict['comments']) |
274 |
datadict['then'] = then_list
|
275 |
datadict['sourceport'] = sourceport_list
|
276 |
datadict['destinationport'] = destport_list
|
277 |
datadict['port'] = port_list
|
278 |
datadict['name'] = route_edit.name
|
279 |
datadict['expires'] = datetime.date.today() + datetime.timedelta(days = settings.EXPIRATION_DAYS_OFFSET)
|
280 |
form = RouteForm(data=datadict, instance = route_edit) |
281 |
|
282 |
if form.is_valid():
|
283 |
route=form.save(commit=False)
|
284 |
route.name = route_original.name |
285 |
route.applier = request.user |
286 |
route.status = "PENDING"
|
287 |
route.source = IPNetwork("%s/%s" %(IPNetwork(route.source).network.compressed, IPNetwork(route.source).prefixlen)).compressed
|
288 |
route.destination = IPNetwork("%s/%s" %(IPNetwork(route.destination).network.compressed, IPNetwork(route.destination).prefixlen)).compressed
|
289 |
route.save() |
290 |
form.save_m2m() |
291 |
route.commit_edit() |
292 |
requesters_address = request.META['HTTP_X_FORWARDED_FOR']
|
293 |
mail_body = render_to_string("rule_edit_mail.txt",
|
294 |
{"route": route, "address": requesters_address}) |
295 |
user_mail = "%s" %route.applier.email
|
296 |
user_mail = user_mail.split(';')
|
297 |
new_mail(settings.EMAIL_SUBJECT_PREFIX + "Rule %s edit request submitted by %s via REST api" %(route.name, route.applier.username),
|
298 |
mail_body, settings.SERVER_EMAIL, user_mail, |
299 |
get_peer_techcs_contact(route.applier)) |
300 |
d = { 'clientip' : "REST_API: %s" %requesters_address, 'user' : route.applier.username } |
301 |
logger.info(mail_body, extra=d) |
302 |
else:
|
303 |
raise ApiFieldError("ERRORS %s %s" %(form.errors, form.__dict__)) |
304 |
return bundle
|
305 |
|
306 |
|
307 |
class Meta: |
308 |
queryset = Route.objects.all() |
309 |
default_format = "application/json"
|
310 |
resource_name = 'rule'
|
311 |
allowed_methods = ['get', 'post', 'delete', 'put'] |
312 |
fields = ['comments', 'source', 'destination', 'expires', 'status', 'id', 'sourceport', 'destinationport', 'then'] |
313 |
authentication = BasicAuthentication(restauthBackend()) |
314 |
authorization= Authorization() |
315 |
|
316 |
def get_port_pk_or_create(prt): |
317 |
try:
|
318 |
port_pk = MatchPort.objects.get(port=prt.obj.__dict__['port']).pk
|
319 |
except:
|
320 |
try:
|
321 |
assert (int(prt.obj.__dict__['port'])) |
322 |
mp = MatchPort(port=int(int(prt.obj.__dict__['port']))) |
323 |
mp.save() |
324 |
port_pk=mp.pk |
325 |
except:
|
326 |
raise ApiFieldError("Port should be an integer") |
327 |
return port_pk
|