From ff1c68ec543e2e8db1f5980c3e7888dd9a25c8f6 Mon Sep 17 00:00:00 2001 From: Michael Elkins Date: Tue, 7 Feb 2012 04:56:23 +0000 Subject: split roa creation double confirmation into separate functions and forms svn path=/branches/tk161/; revision=4300 --- rpkid/rpki/gui/app/forms.py | 45 ++++++-- .../templates/app/roa_request_confirm_delete.html | 50 ++++----- .../app/templates/app/roarequest_confirm_form.html | 58 ++++++++++ .../gui/app/templates/app/roarequest_form.html | 40 ++----- rpkid/rpki/gui/app/urls.py | 1 + rpkid/rpki/gui/app/views.py | 121 ++++++++++++--------- 6 files changed, 191 insertions(+), 124 deletions(-) create mode 100644 rpkid/rpki/gui/app/templates/app/roarequest_confirm_form.html (limited to 'rpkid') diff --git a/rpkid/rpki/gui/app/forms.py b/rpkid/rpki/gui/app/forms.py index 2ddd1dbd..2fcceda2 100644 --- a/rpkid/rpki/gui/app/forms.py +++ b/rpkid/rpki/gui/app/forms.py @@ -22,6 +22,7 @@ from rpki.resource_set import (resource_range_as, resource_range_ipv4, resource_range_ipv6) from rpki.gui.app import models from rpki.exceptions import BadIPResource +from rpki.gui.app.glue import str_to_resource_range class AddConfForm(forms.Form): @@ -153,23 +154,19 @@ class ROARequest(forms.Form): def _as_resource_range(self): prefix = self.cleaned_data.get('prefix') - try: - r = resource_range_ipv4.parse_str(prefix) - except BadIPResource: - r = resource_range_ipv6.parse_str(prefix) - return r + return str_to_resource_range(prefix) def clean_asn(self): value = self.cleaned_data.get('asn') if value < 0: - raise forms.ValidationError, 'AS must be a positive value or 0' + raise forms.ValidationError('AS must be a positive value or 0') return value def clean_prefix(self): try: r = self._as_resource_range() except: - raise forms.ValidationError, 'invalid IP address' + raise forms.ValidationError('invalid IP address') return str(r) def clean_max_prefixlen(self): @@ -178,8 +175,7 @@ class ROARequest(forms.Form): if v[0] == '/': v = v[1:] # allow user to specify /24 if int(v) < 0: - raise forms.ValidationError, \ - 'max prefix length must be positive or 0' + raise forms.ValidationError('max prefix length must be positive or 0') return v def clean(self): @@ -188,8 +184,7 @@ class ROARequest(forms.Form): max_prefixlen = self.cleaned_data.get('max_prefixlen') max_prefixlen = int(max_prefixlen) if max_prefixlen else r.prefixlen() if max_prefixlen < r.prefixlen(): - raise forms.ValidationError, \ - 'max prefix length must be greater than or equal to the prefix length' + raise forms.ValidationError('max prefix length must be greater than or equal to the prefix length') if max_prefixlen > r.datum_type.bits: raise forms.ValidationError, \ 'max prefix length (%d) is out of range for IP version (%d)' % (max_prefixlen, r.datum_type.bits) @@ -198,6 +193,34 @@ class ROARequest(forms.Form): return self.cleaned_data +class ROARequestConfirm(forms.Form): + asn = forms.IntegerField(widget=forms.HiddenInput) + prefix = forms.CharField(widget=forms.HiddenInput) + max_prefixlen = forms.IntegerField(widget=forms.HiddenInput) + + def clean_asn(self): + value = self.cleaned_data.get('asn') + if value < 0: + raise forms.ValidationError('AS must be a positive value or 0') + return value + + def clean_prefix(self): + try: + r = str_to_resource_range(self.cleaned_data.get('prefix')) + except BadIPResource: + raise forms.ValidationError('invalid prefix') + return str(r) + + def clean(self): + try: + r =str_to_resource_range(self.cleaned_data.get('prefix')) + if r.prefixlen() > self.cleaned_data.get('max_prefixlen'): + raise forms.ValidationError('max length is smaller than mask') + except BadIPResource: + pass + return self.cleaned_data + + def AddASNForm(qs): """ Generate a form class which only allows specification of ASNs contained diff --git a/rpkid/rpki/gui/app/templates/app/roa_request_confirm_delete.html b/rpkid/rpki/gui/app/templates/app/roa_request_confirm_delete.html index a0e4b54d..4c8228b6 100644 --- a/rpkid/rpki/gui/app/templates/app/roa_request_confirm_delete.html +++ b/rpkid/rpki/gui/app/templates/app/roa_request_confirm_delete.html @@ -1,20 +1,19 @@ {% extends "app/app_base.html" %} {% block content %} -
-
-

Please confirm that you would like to delete the following ROA Request: +

+

Please confirm that you would like to delete the following ROA Request. The table to the right indicates how validation status for matching routes may change. - + @@ -30,31 +29,26 @@ Cancel - -
-

This table indicates what the validation status for the routing entries -that are covered by this ROA request will be if this ROA request is deleted: - -

PrefixMax LenMax Length AS
{{ object.prefix }}/{{ object.prefixlen }}
- - - - - - {% for r in routes %} - - - - - - {% endfor %} -
PrefixOrigin ASValidation Status
{{ r.get_prefix_display }}{{ r.asn }}{{ r.status }}
-

+
+

Matching Routes

+ + + + + + + + {% for r in routes %} + + + + + + {% endfor %} +
PrefixOrigin ASValidation Status
{{ r.get_prefix_display }}{{ r.asn }}{{ r.status }}
+
- -{% endblock %} - - +{% endblock content %} diff --git a/rpkid/rpki/gui/app/templates/app/roarequest_confirm_form.html b/rpkid/rpki/gui/app/templates/app/roarequest_confirm_form.html new file mode 100644 index 00000000..99428875 --- /dev/null +++ b/rpkid/rpki/gui/app/templates/app/roarequest_confirm_form.html @@ -0,0 +1,58 @@ +{% extends "app/app_base.html" %} + +{% block content %} +
+

Create ROA

+
+ +
+
+
+

Please confirm that you would like to create the following ROA. + The table on the right shows how the validation status may change as a result. + + + + + + + + + + + + +
ASPrefixMax Length
{{ asn }}{{ prefix }}{{ max_prefixlen }}
+ +

+ {% csrf_token %} + {% include "app/bootstrap_form.html" %} +
+ + Cancel +
+
+
+
+ +
+

Matched Routes

+ + + + + + + + {% for r in routes %} + + + + + + {% endfor %} +
PrefixOrigin ASValidation Status
{{ r.get_prefix_display }}{{ r.asn }}{{ r.status }}
+
+ +
+{% endblock content %} diff --git a/rpkid/rpki/gui/app/templates/app/roarequest_form.html b/rpkid/rpki/gui/app/templates/app/roarequest_form.html index 83759120..5385cab0 100644 --- a/rpkid/rpki/gui/app/templates/app/roarequest_form.html +++ b/rpkid/rpki/gui/app/templates/app/roarequest_form.html @@ -1,42 +1,16 @@ {% extends "app/app_base.html" %} {% block content %} -

Create ROA

-
-
-
- {% csrf_token %} - {% include "app/bootstrap_form.html" %} -
- - Cancel -
-
-
-
-

Matched Routes - - - - - - - - {% for r in routes %} - - - - - - {% endfor %} -
PrefixOrigin ASValidation Status
{{ r.get_prefix_display }}{{ r.asn }}{{ r.status }}
+

+ {% csrf_token %} + {% include "app/bootstrap_form.html" %} +
+ + Cancel
-
- + {% endblock content %} - -{# vim:set sw=2: #} diff --git a/rpkid/rpki/gui/app/urls.py b/rpkid/rpki/gui/app/urls.py index b2e30b12..cfe82777 100644 --- a/rpkid/rpki/gui/app/urls.py +++ b/rpkid/rpki/gui/app/urls.py @@ -54,6 +54,7 @@ urlpatterns = patterns('', (r'^repo/(?P\d+)/delete$', views.repository_delete), (r'^roa/$', views.roa_list), (r'^roa/create$', views.roa_create), + (r'^roa/confirm$', views.roa_create_confirm), (r'^roa/(?P\d+)$', views.roa_detail), (r'^roa/(?P\d+)/delete$', views.roa_delete), (r'^routes/$', views.route_view), diff --git a/rpkid/rpki/gui/app/views.py b/rpkid/rpki/gui/app/views.py index 795080fc..b76495c0 100644 --- a/rpkid/rpki/gui/app/views.py +++ b/rpkid/rpki/gui/app/views.py @@ -428,7 +428,6 @@ def roa_create(request): """ - routes = [] if request.method == 'POST': form = forms.ROARequest(request.POST, request.FILES) if form.is_valid(): @@ -437,61 +436,79 @@ def roa_create(request): rng = form._as_resource_range() # FIXME calling "private" method max_prefixlen = int(form.cleaned_data.get('max_prefixlen')) - if form.cleaned_data.get('confirmed'): - roarequests = models.ROARequest.objects.filter(issuer=conf, - asn=asn) - if roarequests: - # FIXME need to handle the case where there are - # multiple ROAs for the same AS due to prefixes - # delegated from different resource certs. - roa = roarequests[0] - else: - roa = models.ROARequest.objects.create(issuer=conf, - asn=asn) - version = 'IPv4' if isinstance(rng, - resource_range_ipv4) else 'IPv6' - roa.prefixes.create(version=version, prefix=str(rng.min), - prefixlen=rng.prefixlen(), max_prefixlen=max_prefixlen) - return http.HttpResponseRedirect(reverse(roa_list)) - else: - form = forms.ROARequest(initial={ - 'asn': form.cleaned_data.get('asn'), - 'prefix': form.cleaned_data.get('prefix'), - 'max_prefixlen': form.cleaned_data.get('max_prefixlen'), - 'confirmed': True}) - - # find list of matching routes - match = roa_match(rng) - for route, roas in match: - validate_route(route, roas) - # tweak the validation status due to the presence of the - # new ROA. Don't need to check the prefix bounds here - # because all the matches routes will be covered by this - # new ROA - if route.status == 'unknown': - # if the route was previously unknown (no covering - # ROAs), then: - # if the AS matches, it is valid, otherwise invalid - if (route.asn != 0 and route.asn == asn and route.prefixlen() <= max_prefixlen): - route.status = 'valid' - route.status_label = 'success' - else: - route.status = 'invalid' - route.status_label = 'important' - elif route.status == 'invalid': - # if the route was previously invalid, but this new ROA - # matches the ASN, it is now valid - if route.asn != 0 and route.asn == asn and route.prefixlen() <= max_prefixlen: - route.status = 'valid' - route.status_label = 'success' - - routes.append(route) + # find list of matching routes + routes = [] + match = roa_match(rng) + for route, roas in match: + validate_route(route, roas) + # tweak the validation status due to the presence of the + # new ROA. Don't need to check the prefix bounds here + # because all the matches routes will be covered by this + # new ROA + if route.status == 'unknown': + # if the route was previously unknown (no covering + # ROAs), then: + # if the AS matches, it is valid, otherwise invalid + if (route.asn != 0 and route.asn == asn and route.prefixlen() <= max_prefixlen): + route.status = 'valid' + route.status_label = 'success' + else: + route.status = 'invalid' + route.status_label = 'important' + elif route.status == 'invalid': + # if the route was previously invalid, but this new ROA + # matches the ASN, it is now valid + if route.asn != 0 and route.asn == asn and route.prefixlen() <= max_prefixlen: + route.status = 'valid' + route.status_label = 'success' + + routes.append(route) + + prefix = str(rng) + form = forms.ROARequestConfirm(initial={'asn': asn, + 'prefix': prefix, + 'max_prefixlen': max_prefixlen}) + return render(request, 'app/roarequest_confirm_form.html', + {'form': form, + 'asn': asn, + 'prefix': prefix, + 'max_prefixlen': max_prefixlen, + 'routes': routes}) else: form = forms.ROARequest() - return render(request, 'app/roarequest_form.html', - {'form': form, 'routes': routes}) + return render(request, 'app/roarequest_form.html', {'form': form}) + + +@handle_required +def roa_create_confirm(request): + conf = request.session['handle'] + + if request.method == 'POST': + form = forms.ROARequestConfirm(request.POST, request.FILES) + if form.is_valid(): + asn = form.cleaned_data.get('asn') + prefix = form.cleaned_data.get('prefix') + rng = glue.str_to_resource_range(prefix) + max_prefixlen = form.cleaned_data.get('max_prefixlen') + roarequests = models.ROARequest.objects.filter(issuer=conf, + asn=asn) + if roarequests: + # FIXME need to handle the case where there are + # multiple ROAs for the same AS due to prefixes + # delegated from different resource certs. + roa = roarequests[0] + else: + roa = models.ROARequest.objects.create(issuer=conf, + asn=asn) + v = 'IPv4' if isinstance(rng, resource_range_ipv4) else 'IPv6' + roa.prefixes.create(version=v, prefix=str(rng.min), + prefixlen=rng.prefixlen(), + max_prefixlen=max_prefixlen) + return http.HttpResponseRedirect(reverse(roa_list)) + else: + return http.HttpResponseRedirect(reverse(roa_create)) @handle_required def roa_list(request): -- cgit v1.2.3