Statistics
| Branch: | Tag: | Revision:

root / flowspec / views.py @ d60db93b

History | View | Annotate | Download (18.4 kB)

1
# Create your views here.
2
import urllib2
3
import socket
4
import json
5
from django import forms
6
from django.views.decorators.csrf import csrf_exempt
7
from django.core import urlresolvers
8
from django.core import serializers
9
from django.contrib.auth.decorators import login_required
10
from django.contrib.auth import logout
11
from django.contrib.sites.models import Site
12
from django.contrib.auth.models import User
13
from django.http import HttpResponseRedirect, HttpResponseForbidden, HttpResponse
14
from django.shortcuts import get_object_or_404, render_to_response
15
from django.core.context_processors import request
16
from django.template.context import RequestContext
17
from django.template.loader import get_template, render_to_string
18
from django.core.urlresolvers import reverse
19
from django.contrib import messages
20
from flowspy.accounts.models import *
21
from ipaddr import *
22

    
23
from django.contrib.auth import authenticate, login
24

    
25
from django.forms.models import model_to_dict
26

    
27
from flowspy.flowspec.forms import * 
28
from flowspy.flowspec.models import *
29
from flowspy.peers.models import *
30

    
31
from registration.models import RegistrationProfile
32

    
33
from copy import deepcopy
34
from flowspy.utils.decorators import shib_required
35

    
36
from django.views.decorators.cache import never_cache
37
from django.conf import settings
38
from django.core.mail.message import EmailMessage
39
import datetime
40
import os
41

    
42
LOG_FILENAME = os.path.join(settings.LOG_FILE_LOCATION, 'celery_jobs.log')
43
#FORMAT = '%(asctime)s %(levelname)s: %(message)s'
44
#logging.basicConfig(format=FORMAT)
45
formatter = logging.Formatter('%(asctime)s %(levelname)s %(clientip)s %(user)s: %(message)s')
46

    
47
logger = logging.getLogger(__name__)
48
logger.setLevel(logging.DEBUG)
49
handler = logging.FileHandler(LOG_FILENAME)
50
handler.setFormatter(formatter)
51
logger.addHandler(handler)
52

    
53
@login_required
54
def user_routes(request):
55
    user_routes = Route.objects.filter(applier=request.user)
56
    return render_to_response('user_routes.html', {'routes': user_routes},
57
                              context_instance=RequestContext(request))
58

    
59
def welcome(request):
60
    return render_to_response('welcome.html', context_instance=RequestContext(request))
61

    
62
@login_required
63
@never_cache
64
def group_routes(request):
65
    group_routes = []
66
    try:
67
        peer = request.user.get_profile().peer
68
    except UserProfile.DoesNotExist:
69
        error = "User <strong>%s</strong> does not belong to any peer or organization. It is not possible to create new firewall rules.<br>Please contact Helpdesk to resolve this issue" % request.user.username
70
        return render_to_response('error.html', {'error': error})
71
    if peer:
72
       peer_members = UserProfile.objects.filter(peer=peer)
73
       users = [prof.user for prof in peer_members]
74
       group_routes = Route.objects.filter(applier__in=users)
75
       return render_to_response('user_routes.html', {'routes': group_routes},
76
                              context_instance=RequestContext(request))
77

    
78

    
79
@login_required
80
@never_cache
81
def add_route(request):
82
    applier = request.user.pk
83
    applier_peer_networks = request.user.get_profile().peer.networks.all()
84
    if not applier_peer_networks:
85
         messages.add_message(request, messages.WARNING,
86
                             "Insufficient rights on administrative networks. Cannot add rule. Contact your administrator")
87
         return HttpResponseRedirect(reverse("group-routes"))
88
    if request.method == "GET":
89
        form = RouteForm()
90
        if not request.user.is_superuser:
91
            form.fields['then'] = forms.ModelMultipleChoiceField(queryset=ThenAction.objects.filter(action__in=settings.UI_USER_THEN_ACTIONS).order_by('action'), required=True)
92
            form.fields['protocol'] = forms.ModelMultipleChoiceField(queryset=MatchProtocol.objects.filter(protocol__in=settings.UI_USER_PROTOCOLS).order_by('protocol'), required=False)
93
        return render_to_response('apply.html', {'form': form, 'applier': applier},
94
                                  context_instance=RequestContext(request))
95

    
96
    else:
97
        form = RouteForm(request.POST)
98
        if form.is_valid():
99
            route=form.save(commit=False)
100
            route.applier = request.user
101
            route.status = "PENDING"
102
            route.source = IPNetwork("%s/%s" %(IPNetwork(route.source).network.compressed, IPNetwork(route.source).prefixlen)).compressed
103
            route.destination = IPNetwork("%s/%s" %(IPNetwork(route.destination).network.compressed, IPNetwork(route.destination).prefixlen)).compressed
104
            route.save()
105
            form.save_m2m()
106
            route.commit_add()
107
            requesters_address = request.META['HTTP_X_FORWARDED_FOR']
108
            mail_body = render_to_string("rule_add_mail.txt",
109
                                             {"route": route, "address": requesters_address})
110
            user_mail = "%s" %route.applier.email
111
            user_mail = user_mail.split(';')
112
            send_new_mail(settings.EMAIL_SUBJECT_PREFIX + "Rule %s creation request submitted by %s" %(route.name, route.applier.username),
113
                              mail_body, settings.SERVER_EMAIL, user_mail,
114
                              get_peer_techc_mails(route.applier))
115
            d = { 'clientip' : "%s"%requesters_address, 'user' : route.applier.username }
116
            logger.info(mail_body, extra=d)
117
            return HttpResponseRedirect(reverse("group-routes"))
118
        else:
119
            return render_to_response('apply.html', {'form': form, 'applier':applier},
120
                                      context_instance=RequestContext(request))
121

    
122
@login_required
123
@never_cache
124
def edit_route(request, route_slug):
125
    applier = request.user.pk
126
    applier_peer = request.user.get_profile().peer
127
    route_edit = get_object_or_404(Route, name=route_slug)
128
    route_edit_applier_peer = route_edit.applier.get_profile().peer
129
    if applier_peer != route_edit_applier_peer:
130
        messages.add_message(request, messages.WARNING,
131
                             "Insufficient rights to edit rule %s" %(route_slug))
132
        return HttpResponseRedirect(reverse("group-routes"))
133
#    if route_edit.status == "ADMININACTIVE" :
134
#        messages.add_message(request, messages.WARNING,
135
#                             "Administrator has disabled editing of rule %s" %(route_slug))
136
#        return HttpResponseRedirect(reverse("group-routes"))
137
#    if route_edit.status == "EXPIRED" :
138
#        messages.add_message(request, messages.WARNING,
139
#                             "Cannot edit the expired rule %s. Contact helpdesk to enable it" %(route_slug))
140
#        return HttpResponseRedirect(reverse("group-routes"))
141
    if route_edit.status == "PENDING" :
142
        messages.add_message(request, messages.WARNING,
143
                             "Cannot edit a pending rule: %s." %(route_slug))
144
        return HttpResponseRedirect(reverse("group-routes"))
145
    route_original = deepcopy(route_edit)
146
    if request.POST:
147
        form = RouteForm(request.POST, instance = route_edit)
148
        if form.is_valid():
149
            route=form.save(commit=False)
150
            route.name = route_original.name
151
            route.applier = request.user
152
            route.status = "PENDING"
153
            route.source = IPNetwork("%s/%s" %(IPNetwork(route.source).network.compressed, IPNetwork(route.source).prefixlen)).compressed
154
            route.destination = IPNetwork("%s/%s" %(IPNetwork(route.destination).network.compressed, IPNetwork(route.destination).prefixlen)).compressed
155
            route.save()
156
            form.save_m2m()
157
            route.commit_edit()
158
            requesters_address = request.META['HTTP_X_FORWARDED_FOR']
159
            mail_body = render_to_string("rule_edit_mail.txt",
160
                                             {"route": route, "address": requesters_address})
161
            user_mail = "%s" %route.applier.email
162
            user_mail = user_mail.split(';')
163
            send_new_mail(settings.EMAIL_SUBJECT_PREFIX + "Rule %s edit request submitted by %s" %(route.name, route.applier.username),
164
                              mail_body, settings.SERVER_EMAIL, user_mail,
165
                              get_peer_techc_mails(route.applier))
166
            d = { 'clientip' : requesters_address, 'user' : route.applier.username }
167
            logger.info(mail_body, extra=d)
168
            return HttpResponseRedirect(reverse("group-routes"))
169
        else:
170
            return render_to_response('apply.html', {'form': form, 'edit':True, 'applier': applier},
171
                                      context_instance=RequestContext(request))
172
    else:
173
        dictionary = model_to_dict(route_edit, fields=[], exclude=[])
174
        #form = RouteForm(instance=route_edit)
175
        form = RouteForm(dictionary)
176
        if not request.user.is_superuser:
177
            form.fields['then'] = forms.ModelMultipleChoiceField(queryset=ThenAction.objects.filter(action__in=settings.UI_USER_THEN_ACTIONS).order_by('action'), required=True)
178
            form.fields['protocol'] = forms.ModelMultipleChoiceField(queryset=MatchProtocol.objects.filter(protocol__in=settings.UI_USER_PROTOCOLS).order_by('protocol'), required=False)
179
        return render_to_response('apply.html', {'form': form, 'edit':True, 'applier': applier},
180
                                  context_instance=RequestContext(request))
181

    
182
@login_required
183
@never_cache
184
def delete_route(request, route_slug):
185
    if request.is_ajax():
186
        route = get_object_or_404(Route, name=route_slug)
187
        applier_peer = route.applier.get_profile().peer
188
        requester_peer = request.user.get_profile().peer
189
        if applier_peer == requester_peer:
190
            route.status = "PENDING"
191
            route.expires = datetime.date.today()
192
            route.applier = request.user
193
            route.save()
194
            route.commit_delete()
195
            requesters_address = request.META['HTTP_X_FORWARDED_FOR']
196
            mail_body = render_to_string("rule_delete_mail.txt",
197
                                             {"route": route, "address": requesters_address})
198
            user_mail = "%s" %route.applier.email
199
            user_mail = user_mail.split(';')
200
            send_new_mail(settings.EMAIL_SUBJECT_PREFIX + "Rule %s removal request submitted by %s" %(route.name, route.applier.username), 
201
                              mail_body, settings.SERVER_EMAIL, user_mail,
202
                             get_peer_techc_mails(route.applier))
203
            d = { 'clientip' : requesters_address, 'user' : route.applier.username }
204
            logger.info(mail_body, extra=d)            
205
        html = "<html><body>Done</body></html>"
206
        return HttpResponse(html)
207
    else:
208
        return HttpResponseRedirect(reverse("group-routes"))
209

    
210
@login_required
211
@never_cache
212
def user_profile(request):
213
    user = request.user
214
    try:
215
        peer = request.user.get_profile().peer
216
    except UserProfile.DoesNotExist:
217
        error = "User <strong>%s</strong> does not belong to any peer or organization. It is not possible to create new firewall rules.<br>Please contact Helpdesk to resolve this issue" % user.username
218
        return render_to_response('error.html', {'error': error})
219
    return render_to_response('profile.html', {'user': user, 'peer':peer},
220
                                  context_instance=RequestContext(request))
221

    
222
@never_cache
223
def user_login(request):
224
    try:
225
        error_username = False
226
        error_orgname = False
227
        error_entitlement = False
228
        error_mail = False
229
        has_entitlement = False
230
        error = ''
231
        username = request.META['HTTP_EPPN']
232
        if not username:
233
            error_username = True
234
        firstname = request.META['HTTP_SHIB_INETORGPERSON_GIVENNAME']
235
        lastname = request.META['HTTP_SHIB_PERSON_SURNAME']
236
        mail = request.META['HTTP_SHIB_INETORGPERSON_MAIL']
237
        organization = request.META['HTTP_SHIB_HOMEORGANIZATION']
238
        entitlement = request.META['HTTP_SHIB_EP_ENTITLEMENT']
239
        if settings.SHIB_AUTH_ENTITLEMENT in entitlement.split(";"):
240
            has_entitlement = True
241
        if not has_entitlement:
242
            error_entitlement = True
243
        if not organization:
244
            error_orgname = True
245
        if not mail:
246
            error_mail = True
247
        if error_username:
248
            error = "Your idP should release the HTTP_EPPN attribute towards this service<br>"
249
        if error_orgname:
250
            error = error + "Your idP should release the HTTP_SHIB_HOMEORGANIZATION attribute towards this service<br>"
251
        if error_entitlement:
252
            error = error + "Your idP should release an appropriate HTTP_SHIB_EP_ENTITLEMENT attribute towards this service<br>"
253
        if error_mail:
254
            error = error + "Your idP should release the HTTP_SHIB_INETORGPERSON_MAIL attribute towards this service"
255
        if error_username or error_orgname or error_entitlement or error_mail:
256
            return render_to_response('error.html', {'error': error, "missing_attributes": True},
257
                                  context_instance=RequestContext(request))
258
        try:
259
            user = User.objects.get(username__exact=username)
260
            user.email = mail
261
            user.first_name = firstname
262
            user.last_name = lastname
263
            user.save()
264
            user_exists = True
265
        except:
266
            user_exists = False
267
        user = authenticate(username=username, firstname=firstname, lastname=lastname, mail=mail, authsource='shibboleth')
268
        if user is not None:
269
            try:
270
                peer = Peer.objects.get(domain_name=organization)
271
                up = UserProfile.objects.get_or_create(user=user,peer=peer)
272
            except:
273
                error = "Your organization's domain name does not match our peers' domain names<br>Please contact Helpdesk to resolve this issue"
274
                return render_to_response('error.html', {'error': error})
275
            if not user_exists:
276
                user_activation_notify(user)
277
            if user.is_active:
278
               login(request, user)
279
               return HttpResponseRedirect(reverse("group-routes"))
280
            else:
281
                error = "User account <strong>%s</strong> is pending activation. Administrators have been notified and will activate this account within the next days. <br>If this account has remained inactive for a long time contact your technical coordinator or GRNET Helpdesk" %user.username
282
                return render_to_response('error.html', {'error': error, 'inactive': True},
283
                                  context_instance=RequestContext(request))
284
        else:
285
            error = "Something went wrong during user authentication. Contact your administrator"
286
            return render_to_response('error.html', {'error': error,},
287
                                  context_instance=RequestContext(request))
288
    except Exception:
289
        error = "Invalid login procedure"
290
        return render_to_response('error.html', {'error': error,},
291
                                  context_instance=RequestContext(request))
292
        # Return an 'invalid login' error message.
293
#    return HttpResponseRedirect(reverse("user-routes"))
294

    
295
def user_activation_notify(user):
296
    current_site = Site.objects.get_current()
297
    subject = render_to_string('registration/activation_email_subject.txt',
298
                                   { 'site': current_site })
299
    # Email subject *must not* contain newlines
300
    subject = ''.join(subject.splitlines())
301
    registration_profile = RegistrationProfile.objects.create_profile(user)
302
    message = render_to_string('registration/activation_email.txt',
303
                                   { 'activation_key': registration_profile.activation_key,
304
                                     'expiration_days': settings.ACCOUNT_ACTIVATION_DAYS,
305
                                     'site': current_site,
306
                                     'user': user })
307
    send_new_mail(settings.EMAIL_SUBJECT_PREFIX + subject, 
308
                              message, settings.SERVER_EMAIL,
309
                             get_peer_techc_mails(user), [])
310

    
311
@login_required
312
@never_cache
313
def add_rate_limit(request):
314
    if request.method == "GET":
315
        form = ThenPlainForm()
316
        return render_to_response('add_rate_limit.html', {'form': form,},
317
                                  context_instance=RequestContext(request))
318

    
319
    else:
320
        form = ThenPlainForm(request.POST)
321
        if form.is_valid():
322
            then=form.save(commit=False)
323
            then.action_value = "%sk"%then.action_value
324
            then.save()
325
            response_data = {}
326
            response_data['pk'] = "%s" %then.pk
327
            response_data['value'] = "%s:%s" %(then.action, then.action_value)
328
            return HttpResponse(json.dumps(response_data), mimetype='application/json')
329
        else:
330
            return render_to_response('add_rate_limit.html', {'form': form,},
331
                                      context_instance=RequestContext(request))
332

    
333
@login_required
334
@never_cache
335
def add_port(request):
336
    if request.method == "GET":
337
        form = PortPlainForm()
338
        return render_to_response('add_port.html', {'form': form,},
339
                                  context_instance=RequestContext(request))
340

    
341
    else:
342
        form = PortPlainForm(request.POST)
343
        if form.is_valid():
344
            port=form.save()
345
            response_data = {}
346
            response_data['value'] = "%s" %port.pk
347
            response_data['text'] = "%s" %port.port
348
            return HttpResponse(json.dumps(response_data), mimetype='application/json')
349
        else:
350
            return render_to_response('add_port.html', {'form': form,},
351
                                      context_instance=RequestContext(request))
352

    
353
@login_required
354
@never_cache
355
def user_logout(request):
356
    logout(request)
357
    return HttpResponseRedirect(reverse('group-routes'))
358
    
359
@never_cache
360
def load_jscript(request, file):
361
    long_polling_timeout = int(settings.POLL_SESSION_UPDATE)*1000 + 10000
362
    return render_to_response('%s.js' % file, {'timeout': long_polling_timeout}, context_instance=RequestContext(request), mimetype="text/javascript")
363

    
364

    
365
def get_peer_techc_mails(user):
366
    mail = []
367
    additional_mail = []
368
    techmails_list = []
369
    user_mail = "%s" %user.email
370
    user_mail = user_mail.split(';')
371
    techmails = user.get_profile().peer.techc_emails.all()
372
    if techmails:
373
        for techmail in techmails:
374
            techmails_list.append(techmail.email)
375
    if settings.NOTIFY_ADMIN_MAILS:
376
        additional_mail = settings.NOTIFY_ADMIN_MAILS
377
#    mail.extend(user_mail)
378
    mail.extend(additional_mail)
379
    mail.extend(techmails_list)
380
    return mail
381

    
382

    
383
def send_new_mail(subject, message, from_email, recipient_list, bcc_list):
384
    return EmailMessage(subject, message, from_email, recipient_list, bcc_list).send()
385