blob: dd6df0e0cf82081eee758873af7ccd2ed8a5bfb1 [file] [log] [blame]
Jeremy Mowery3c5277f2016-02-29 21:09:04 -07001import time
2
Jeremy Moweryb31bd9e2016-03-14 23:59:11 -07003from core.admin import ReadOnlyAwareAdmin, SliceInline, TenantPrivilegeInline
Jeremy Mowery3c5277f2016-02-29 21:09:04 -07004from core.middleware import get_request
5from core.models import User
6from django import forms
7from django.contrib import admin
8from services.vpn.models import VPN_KIND, VPNService, VPNTenant
Jeremy Mowery257d591d2016-03-15 20:28:04 -07009from subprocess import Popen, PIPE
Jeremy Mowery3c5277f2016-02-29 21:09:04 -070010
11class VPNServiceAdmin(ReadOnlyAwareAdmin):
12 """Defines the admin for the VPNService."""
13 model = VPNService
14 verbose_name = "VPN Service"
15
16 list_display = ("backend_status_icon", "name", "enabled")
17
18 list_display_links = ('backend_status_icon', 'name', )
19
20 fieldsets = [(None, {'fields': ['backend_status_text', 'name', 'enabled',
21 'versionNumber', 'description', "view_url"],
22 'classes':['suit-tab suit-tab-general']})]
23
24 readonly_fields = ('backend_status_text', )
25
26 inlines = [SliceInline]
27
28 extracontext_registered_admins = True
29
30 user_readonly_fields = ["name", "enabled", "versionNumber", "description"]
31
32 suit_form_tabs = (('general', 'VPN Service Details'),
33 ('administration', 'Tenants'),
34 ('slices', 'Slices'),)
35
36 suit_form_includes = (('vpnserviceadmin.html',
37 'top',
38 'administration'),)
39
40 def queryset(self, request):
41 return VPNService.get_service_objects_by_user(request.user)
42
43
44class VPNTenantForm(forms.ModelForm):
45 """The form used to create and edit a VPNTenant.
46
47 Attributes:
48 creator (forms.ModelChoiceField): The XOS user that created this tenant.
49 client_conf (forms.CharField): The readonly configuration used on the client to connect to this Tenant.
50 server_address (forms.GenericIPAddressField): The ip address on the VPN of this Tenant.
51 client_address (forms.GenericIPAddressField): The ip address on the VPN of the client.
52 is_persistent (forms.BooleanField): Determines if this Tenant keeps this connection alive through failures.
53 can_view_subnet (forms.BooleanField): Determines if this Tenant makes it's subnet available to the client.
Jeremy Moweryb1387d22016-03-01 08:30:30 -070054 port_number (forms.IntegerField): The port to use for this Tenant.
Jeremy Mowery3c5277f2016-02-29 21:09:04 -070055 """
56 creator = forms.ModelChoiceField(queryset=User.objects.all())
57 server_network = forms.GenericIPAddressField(
58 protocol="IPv4", required=True)
59 vpn_subnet = forms.GenericIPAddressField(protocol="IPv4", required=True)
60 is_persistent = forms.BooleanField(required=False)
61 clients_can_see_each_other = forms.BooleanField(required=False)
Jeremy Mowery324caf52016-03-16 11:22:02 -070062 failover_servers = forms.ModelMultipleChoiceField(queryset=VPNTenant.objects.all(), required=False)
Jeremy Mowery3c5277f2016-02-29 21:09:04 -070063
64 def __init__(self, *args, **kwargs):
65 super(VPNTenantForm, self).__init__(*args, **kwargs)
66 self.fields['kind'].widget.attrs['readonly'] = True
67 # self.fields['script_name'].widget.attrs['readonly'] = True
68 self.fields[
69 'provider_service'].queryset = VPNService.get_service_objects().all()
70
71 self.fields['kind'].initial = VPN_KIND
72
73 if self.instance:
74 self.fields['creator'].initial = self.instance.creator
75 self.fields['vpn_subnet'].initial = self.instance.vpn_subnet
76 self.fields[
77 'server_network'].initial = self.instance.server_network
78 self.fields[
79 'clients_can_see_each_other'].initial = self.instance.clients_can_see_each_other
80 self.fields['is_persistent'].initial = self.instance.is_persistent
Jeremy Mowery324caf52016-03-16 11:22:02 -070081 self.fields['failover_servers'].initial = self.instance.failover_servers
Jeremy Mowery3c5277f2016-02-29 21:09:04 -070082
83 if (not self.instance) or (not self.instance.pk):
84 self.fields['creator'].initial = get_request().user
85 self.fields['vpn_subnet'].initial = "255.255.255.0"
86 self.fields['server_network'].initial = "10.66.77.0"
87 self.fields['clients_can_see_each_other'].initial = True
88 self.fields['is_persistent'].initial = True
89 if VPNService.get_service_objects().exists():
90 self.fields["provider_service"].initial = VPNService.get_service_objects().all()[
91 0]
92
93 def save(self, commit=True):
94 self.instance.creator = self.cleaned_data.get("creator")
95 self.instance.is_persistent = self.cleaned_data.get('is_persistent')
96 self.instance.vpn_subnet = self.cleaned_data.get("vpn_subnet")
97 self.instance.server_network = self.cleaned_data.get('server_network')
98 self.instance.clients_can_see_each_other = self.cleaned_data.get(
99 'clients_can_see_each_other')
Jeremy Mowery324caf52016-03-16 11:22:02 -0700100 self.instance.failover_servers = self.cleaned_data.get('failover_servers')
101
102 prev = 1000
103 for (tenant : VPNTenant.objects.order_by('port_number')):
104 if (tenant.port_number != prev):
105 break
106 prev++
107 self.instance.port_number = prev
Jeremy Mowery3c5277f2016-02-29 21:09:04 -0700108
Jeremy Mowery3c5277f2016-02-29 21:09:04 -0700109 if (not self.instance.ca_crt):
110 self.instance.ca_crt = self.generate_ca_crt()
111
112 return super(VPNTenantForm, self).save(commit=commit)
113
114 def generate_ca_crt(self):
115 """str: Generates the ca cert by reading from the ca file"""
116 with open("/opt/openvpn/easyrsa3/pki/ca.crt") as crt:
117 return crt.readlines()
118
119 class Meta:
120 model = VPNTenant
121
122
123class VPNTenantAdmin(ReadOnlyAwareAdmin):
124 verbose_name = "VPN Tenant Admin"
125 list_display = ('id', 'backend_status_icon', 'instance',
126 'server_network', 'vpn_subnet')
127 list_display_links = ('id', 'backend_status_icon',
128 'instance', 'server_network', 'vpn_subnet')
129 fieldsets = [(None, {'fields': ['backend_status_text', 'kind',
130 'provider_service', 'instance', 'creator',
131 'server_network', 'vpn_subnet', 'is_persistent',
Jeremy Mowery324caf52016-03-16 11:22:02 -0700132 'clients_can_see_each_other'],
Jeremy Mowery3c5277f2016-02-29 21:09:04 -0700133 'classes': ['suit-tab suit-tab-general']})]
134 readonly_fields = ('backend_status_text', 'instance')
135 form = VPNTenantForm
Jeremy Moweryb31bd9e2016-03-14 23:59:11 -0700136 inlines = [TenantPrivilegeInline]
Jeremy Mowery3c5277f2016-02-29 21:09:04 -0700137
Jeremy Moweryb31bd9e2016-03-14 23:59:11 -0700138 suit_form_tabs = (('general', 'Details'),
139 ('tenantprivileges','Privileges')
140 )
Jeremy Mowery3c5277f2016-02-29 21:09:04 -0700141
142 def queryset(self, request):
143 return VPNTenant.get_tenant_objects_by_user(request.user)
144
Jeremy Moweryb31bd9e2016-03-14 23:59:11 -0700145 def certificate_name(self, tenant_privilege):
146 return str(tenant_privilege.user.email) + "-" + str(tenant_privilege.tenant.id)
147
148 def save_formset(self, request, form, formset, change):
149 super(VPNTenantAdmin, self).save_formset(request, form, formset, change)
150 for obj in formset.deleted_objects:
151 # If anything deleated was a TenantPrivilege then revoke the certificate
152 if type(obj) is TenantPrivilege:
153 certificate = self.certificate_name(obj)
Jeremy Mowery257d591d2016-03-15 20:28:04 -0700154 Popen("/opt/openvpn/easyrsa3/easyrsa --batch revoke " + certificate, shell=True, stdout=PIPE).communicate()
Jeremy Moweryb31bd9e2016-03-14 23:59:11 -0700155 # TODO(jermowery): determine if this is necessary.
156 # if type(obj) is VPNTenant:
157 # if the tenant was deleted revoke all certs assoicated
158 # pass
159
160 for obj in formset.new_objects:
161 # If there were any new TenantPrivlege objects then create certs
162 if type(obj) is TenantPrivilege:
163 certificate = self.certificate_name(obj)
Jeremy Mowery257d591d2016-03-15 20:28:04 -0700164 Popen("/opt/openvpn/easyrsa3/easyrsa --batch build-client-full " + certificate + " nopass", shell=True, stdout=PIPE).communicate()
Jeremy Moweryb31bd9e2016-03-14 23:59:11 -0700165
166
Jeremy Mowery3c5277f2016-02-29 21:09:04 -0700167# Associate the admin forms with the models.
168admin.site.register(VPNService, VPNServiceAdmin)
169admin.site.register(VPNTenant, VPNTenantAdmin)