update to django-2, python3, and based on an alpine container

This commit is contained in:
jeffrey forman 2019-02-13 20:17:05 -05:00
parent dac54a5ad7
commit f9176387ac
16 changed files with 53 additions and 69 deletions

View File

@ -1,16 +1,13 @@
FROM python:2.7 FROM python:3-alpine
MAINTAINER Jeffrey Forman <code@jeffreyforman.net> MAINTAINER Jeffrey Forman <code@jeffreyforman.net>
ENV DEBIAN_FRONTEND noninteractive
RUN apt-get update \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /code WORKDIR /code
COPY . /code/ COPY . /code/
RUN pip install -r requirements.txt RUN apk add --no-cache nsd build-base python3-dev libffi-dev openssl-dev libc-dev libxslt-dev \
&& pip install --upgrade pip \
&& pip install --no-cache-dir -r requirements.txt
EXPOSE 8000 EXPOSE 8000

View File

@ -86,7 +86,6 @@ bootstrapping.
``` ```
python manage.py migrate python manage.py migrate
python manage.py createsuperuser python manage.py createsuperuser
...
python manage.py dumpdata -o binder/fixtures/initial_data.json python manage.py dumpdata -o binder/fixtures/initial_data.json
``` ```

View File

@ -1,6 +1,6 @@
import binascii import binascii
import dns.tsigkeyring import dns.tsigkeyring
from models import BindServer, Key from binder.models import BindServer, Key
from django.contrib import admin from django.contrib import admin
from django.forms import ModelForm, ValidationError from django.forms import ModelForm, ValidationError

File diff suppressed because one or more lines are too long

View File

@ -8,7 +8,7 @@ from django.core import validators
from django.forms import ValidationError from django.forms import ValidationError
# App Imports # App Imports
from models import Key from binder.models import Key
class CustomUnicodeListField(forms.CharField): class CustomUnicodeListField(forms.CharField):

View File

@ -170,7 +170,7 @@ def ip_info(host_name):
if s_family == 10 and s_type == 1: if s_family == 10 and s_type == 1:
ipv6_count += 1 ipv6_count += 1
info.append(["IPv6 (%d)" % ipv6_count, s_sockaddr[0]]) info.append(["IPv6 (%d)" % ipv6_count, s_sockaddr[0]])
except socket.gaierror, err: except (socket.gaierror, err):
info.append(["Error", "Unable to resolve %s: %s" % (host_name, err)]) info.append(["Error", "Unable to resolve %s: %s" % (host_name, err)])
return info return info

View File

@ -2,22 +2,26 @@ from django.conf import settings
from django.contrib.auth import REDIRECT_FIELD_NAME from django.contrib.auth import REDIRECT_FIELD_NAME
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
class LoginRequiredMiddleware(object): class LoginRequiredMiddleware:
"""Middleware to redirect to the login page if the user isn't authenticated """Middleware to redirect to the login page if the user isn't authenticated
After successful authentication the user is redirected back to the page he After successful authentication the user is redirected back to the page he
initially wanted to access. initially wanted to access.
""" """
def process_request(self, request): def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
# allow access to the login url # allow access to the login url
response = self.get_response(request)
if request.path == settings.LOGIN_URL: if request.path == settings.LOGIN_URL:
return return response
# redirect to the login url if the user isn't authenticated # redirect to the login url if the user isn't authenticated
if not request.user.is_authenticated(): if not request.user.is_authenticated:
if request.path not in (settings.LOGIN_URL, if request.path not in (settings.LOGIN_URL,
settings.LOGIN_REDIRECT_URL): settings.LOGIN_REDIRECT_URL):
return HttpResponseRedirect('%s?%s=%s' % (settings.LOGIN_URL, return HttpResponseRedirect('%s?%s=%s' % (settings.LOGIN_URL,
REDIRECT_FIELD_NAME, REDIRECT_FIELD_NAME,
request.path)) request.path))
else: return HttpResponseRedirect(settings.LOGIN_URL)
return HttpResponseRedirect(settings.LOGIN_URL) return response

View File

@ -1,11 +1,13 @@
# -*- coding: utf-8 -*- # Generated by Django 2.1.5 on 2019-02-12 01:12
from __future__ import unicode_literals
from django.db import models, migrations from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration): class Migration(migrations.Migration):
initial = True
dependencies = [ dependencies = [
] ]
@ -13,32 +15,30 @@ class Migration(migrations.Migration):
migrations.CreateModel( migrations.CreateModel(
name='BindServer', name='BindServer',
fields=[ fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('hostname', models.CharField(help_text=b'Host name or IP address of the BIND server.', unique=True, max_length=255)), ('hostname', models.CharField(help_text='Host name or IP address of the BIND server.', max_length=255, unique=True)),
('statistics_port', models.IntegerField(help_text=b'Port where the BIND server is serving statistics on.')), ('dns_port', models.IntegerField(default=53, help_text='The port where the BIND server is listening for DNS requests. binder especially uses that port for the dynamic zone updates. In most cases you should always leave it at the default port 53.', verbose_name='DNS port')),
('statistics_port', models.IntegerField(help_text='Port where the BIND server is serving statistics on.')),
], ],
options={ options={
'ordering': ['hostname'], 'ordering': ['hostname'],
}, },
bases=(models.Model,),
), ),
migrations.CreateModel( migrations.CreateModel(
name='Key', name='Key',
fields=[ fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(help_text=b'A human readable name for the key to store, used for further references to the key.', unique=True, max_length=255)), ('name', models.CharField(help_text='A human readable name for the key to store, used for further references to the key.', max_length=255, unique=True)),
('data', models.CharField(help_text=b'The private part of the TSIG key.', max_length=255)), ('data', models.CharField(help_text='The private part of the TSIG key.', max_length=255)),
('algorithm', models.CharField(help_text=b'The algorithm which has been used for the key.', max_length=255, choices=[(b'HMAC-MD5.SIG-ALG.REG.INT', b'MD5'), (b'hmac-sha1', b'SHA1'), (b'hmac-sha256', b'SHA256'), (b'hmac-sha384', b'SHA384'), (b'hmac-sha512', b'SHA512')])), ('algorithm', models.CharField(choices=[('HMAC-MD5.SIG-ALG.REG.INT', 'MD5'), ('hmac-sha1', 'SHA1'), ('hmac-sha256', 'SHA256'), ('hmac-sha384', 'SHA384'), ('hmac-sha512', 'SHA512')], help_text='The algorithm which has been used for the key.', max_length=255)),
], ],
options={ options={
'ordering': ['name'], 'ordering': ['name'],
}, },
bases=(models.Model,),
), ),
migrations.AddField( migrations.AddField(
model_name='bindserver', model_name='bindserver',
name='default_transfer_key', name='default_transfer_key',
field=models.ForeignKey(blank=True, to='binder.Key', help_text=b'The default key to use for all actions with this DNS server as long as no other key is specified explicitly.', null=True), field=models.ForeignKey(blank=True, help_text='The default key to use for all actions with this DNS server as long as no other key is specified explicitly.', null=True, on_delete=django.db.models.deletion.CASCADE, to='binder.Key'),
preserve_default=True,
), ),
] ]

View File

@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('binder', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='bindserver',
name='dns_port',
field=models.IntegerField(default=53, verbose_name='DNS port', help_text=b'The port where the BIND server is listening for DNSrequests. binder especially uses that port for the dynamic zone updates. In most cases you should always leave it at the default port 53.'),
preserve_default=True,
),
]

View File

@ -48,7 +48,7 @@ class Key(models.Model):
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
f = Fernet(settings.FERNET_KEY) f = Fernet(settings.FERNET_KEY)
crypted_key = f.encrypt(bytes(self.data)) crypted_key = f.encrypt(bytes(self.data, encoding="utf8"))
self.data = crypted_key self.data = crypted_key
super(Key, self).save(*args, **kwargs) super(Key, self).save(*args, **kwargs)
@ -59,7 +59,7 @@ class Key(models.Model):
try: try:
key_data = self.decrypt_keydata() key_data = self.decrypt_keydata()
keyring = dns.tsigkeyring.from_text({self.name: key_data}) keyring = dns.tsigkeyring.from_text({self.name: key_data})
except binascii.Error, err: except (binascii.Error, err):
raise exceptions.KeyringException("Incorrect key data. Verify key: %s. Reason: %s" % (self.name, err)) raise exceptions.KeyringException("Incorrect key data. Verify key: %s. Reason: %s" % (self.name, err))
return keyring return keyring
@ -99,6 +99,7 @@ class BindServer(models.Model):
default_transfer_key = models.ForeignKey(Key, default_transfer_key = models.ForeignKey(Key,
null=True, null=True,
blank=True, blank=True,
on_delete=models.CASCADE,
help_text="The default key to use for all actions " help_text="The default key to use for all actions "
"with this DNS server as long as no other key is " "with this DNS server as long as no other key is "
"specified explicitly.") "specified explicitly.")
@ -153,7 +154,7 @@ class BindServer(models.Model):
except dns.tsig.PeerBadKey: except dns.tsig.PeerBadKey:
# The incorrect TSIG key was selected for transfers. # The incorrect TSIG key was selected for transfers.
raise exceptions.TransferException("Unable to list zone records because of a TSIG key mismatch.") raise exceptions.TransferException("Unable to list zone records because of a TSIG key mismatch.")
except socket.error, err: except socket.error as err:
# Thrown when the DNS server does not respond for a zone transfer (XFR). # Thrown when the DNS server does not respond for a zone transfer (XFR).
raise exceptions.TransferException("DNS server did not respond for transfer. Reason: %s" % err) raise exceptions.TransferException("DNS server did not respond for transfer. Reason: %s" % err)
except dns.exception.FormError: except dns.exception.FormError:

View File

@ -97,13 +97,14 @@ TEMPLATES = [
} }
] ]
MIDDLEWARE_CLASSES = ( MIDDLEWARE = (
'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.security.SecurityMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware', 'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'binder.middlewares.LoginRequiredMiddleware', 'binder.middlewares.LoginRequiredMiddleware',
) )

View File

@ -54,7 +54,8 @@ class Model_Key_Tests(TestCase):
key_1.save() key_1.save()
decrypt_key = Fernet(settings.FERNET_KEY) decrypt_key = Fernet(settings.FERNET_KEY)
decrypted_tsig_key = decrypt_key.decrypt(bytes(key_1.data)) decrypted_tsig_key = decrypt_key.decrypt(bytes(key_1.data))
self.assertEqual(original_tsig_key, decrypted_tsig_key) self.assertEqual(bytes(original_tsig_key, encoding="utf8"),
decrypted_tsig_key)
@override_settings(FERNET_KEY='yfE1kyYLNlpR-2ybdB-Mvs_k1ZoDMFFVtE_PpWYxVgs=') @override_settings(FERNET_KEY='yfE1kyYLNlpR-2ybdB-Mvs_k1ZoDMFFVtE_PpWYxVgs=')
def test_FernetKeyDecryptionFailure(self): def test_FernetKeyDecryptionFailure(self):

View File

@ -1,7 +1,7 @@
from django.test import TestCase from django.test import TestCase
from django.test.client import Client from django.test.client import Client
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.urlresolvers import reverse from django.urls import reverse
from binder import models from binder import models
@ -80,7 +80,7 @@ class PostTests(TestCase):
self.assertContains(response, self.assertContains(response,
'<input type="hidden" id="zone_name" name="zone_name" value="testzone1.test.net" />', html=True) '<input type="hidden" id="zone_name" name="zone_name" value="testzone1.test.net" />', html=True)
self.assertContains(response, self.assertContains(response,
'<input type="hidden" id="rr_list" name="rr_list" value="[u&#39;testrecord1.testzone1.test.net&#39;, u&#39;testrecord2.testzone1.test.net&#39;]"/>', '<input type="hidden" id="rr_list" name="rr_list" value="[&#39;testrecord1.testzone1.test.net&#39;, &#39;testrecord2.testzone1.test.net&#39;]"/>',
html=True) html=True)
self.assertContains(response, self.assertContains(response,
'<input type="hidden" id="dns_server" name="dns_server" value="testserver.test.net" />', '<input type="hidden" id="dns_server" name="dns_server" value="testserver.test.net" />',

View File

@ -1,14 +1,16 @@
from django.conf.urls import include, url from django.conf.urls import include, url
from django.contrib import admin from django.contrib import admin
import django.contrib.auth.views from django.contrib.auth import login
from django.contrib.auth.views import logout_then_login
from django.contrib.auth import views as auth_views
import binder.views import binder.views
admin.autodiscover() admin.autodiscover()
urlpatterns = [ urlpatterns = [
url(r'^admin/', include(admin.site.urls)), url(r'^admin/', admin.site.urls),
url(r'^accounts/login/$', django.contrib.auth.views.login, name='login'), url(r'^accounts/login/$', auth_views.LoginView.as_view(), name='login'),
url(r'^accounts/logout/$', django.contrib.auth.views.logout_then_login, name='logout'), url(r'^accounts/logout/$', logout_then_login, name='logout'),
url(r'^$', binder.views.home_index, name="index"), url(r'^$', binder.views.home_index, name="index"),
url(r'^server_list/$', binder.views.view_server_list, name="server_list"), url(r'^server_list/$', binder.views.view_server_list, name="server_list"),

View File

@ -1,4 +1,4 @@
#!/bin/bash #!/bin/bash
docker build -t jforman/binder:latest . docker build -t jforman/binder:latest .
docker run -it --rm -v `pwd`:/code/ -w /code/ jforman/binder:latest /bin/bash docker run -it --rm -v `pwd`:/code/ -w /code/ jforman/binder:latest /bin/ash

View File

@ -1,6 +1,5 @@
Django
cryptography cryptography
Django>=1.10
dnspython>=1.11 dnspython>=1.11
pybindxml>=0.7 pybindxml>=0.7
lxml lxml
mysqlclient