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>
ENV DEBIAN_FRONTEND noninteractive
RUN apt-get update \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /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

View File

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

View File

@ -1,6 +1,6 @@
import binascii
import dns.tsigkeyring
from models import BindServer, Key
from binder.models import BindServer, Key
from django.contrib import admin
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
# App Imports
from models import Key
from binder.models import Key
class CustomUnicodeListField(forms.CharField):

View File

@ -170,7 +170,7 @@ def ip_info(host_name):
if s_family == 10 and s_type == 1:
ipv6_count += 1
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)])
return info

View File

@ -2,22 +2,26 @@ from django.conf import settings
from django.contrib.auth import REDIRECT_FIELD_NAME
from django.http import HttpResponseRedirect
class LoginRequiredMiddleware(object):
class LoginRequiredMiddleware:
"""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
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
response = self.get_response(request)
if request.path == settings.LOGIN_URL:
return
return response
# 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,
settings.LOGIN_REDIRECT_URL):
return HttpResponseRedirect('%s?%s=%s' % (settings.LOGIN_URL,
REDIRECT_FIELD_NAME,
request.path))
else:
return HttpResponseRedirect(settings.LOGIN_URL)
return response

View File

@ -1,11 +1,13 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
# Generated by Django 2.1.5 on 2019-02-12 01:12
from django.db import models, migrations
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
]
@ -13,32 +15,30 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='BindServer',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('hostname', models.CharField(help_text=b'Host name or IP address of the BIND server.', unique=True, max_length=255)),
('statistics_port', models.IntegerField(help_text=b'Port where the BIND server is serving statistics on.')),
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('hostname', models.CharField(help_text='Host name or IP address of the BIND server.', max_length=255, unique=True)),
('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={
'ordering': ['hostname'],
},
bases=(models.Model,),
),
migrations.CreateModel(
name='Key',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('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)),
('data', models.CharField(help_text=b'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')])),
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('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='The private part of the TSIG key.', max_length=255)),
('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={
'ordering': ['name'],
},
bases=(models.Model,),
),
migrations.AddField(
model_name='bindserver',
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),
preserve_default=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'),
),
]

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):
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
super(Key, self).save(*args, **kwargs)
@ -59,7 +59,7 @@ class Key(models.Model):
try:
key_data = self.decrypt_keydata()
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))
return keyring
@ -99,6 +99,7 @@ class BindServer(models.Model):
default_transfer_key = models.ForeignKey(Key,
null=True,
blank=True,
on_delete=models.CASCADE,
help_text="The default key to use for all actions "
"with this DNS server as long as no other key is "
"specified explicitly.")
@ -153,7 +154,7 @@ class BindServer(models.Model):
except dns.tsig.PeerBadKey:
# The incorrect TSIG key was selected for transfers.
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).
raise exceptions.TransferException("DNS server did not respond for transfer. Reason: %s" % err)
except dns.exception.FormError:

View File

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

View File

@ -54,7 +54,8 @@ class Model_Key_Tests(TestCase):
key_1.save()
decrypt_key = Fernet(settings.FERNET_KEY)
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=')
def test_FernetKeyDecryptionFailure(self):

View File

@ -1,7 +1,7 @@
from django.test import TestCase
from django.test.client import Client
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
from django.urls import reverse
from binder import models
@ -80,7 +80,7 @@ class PostTests(TestCase):
self.assertContains(response,
'<input type="hidden" id="zone_name" name="zone_name" value="testzone1.test.net" />', html=True)
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)
self.assertContains(response,
'<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.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
admin.autodiscover()
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/logout/$', django.contrib.auth.views.logout_then_login, name='logout'),
url(r'^accounts/login/$', auth_views.LoginView.as_view(), name='login'),
url(r'^accounts/logout/$', logout_then_login, name='logout'),
url(r'^$', binder.views.home_index, name="index"),
url(r'^server_list/$', binder.views.view_server_list, name="server_list"),

View File

@ -1,4 +1,4 @@
#!/bin/bash
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
Django>=1.10
dnspython>=1.11
pybindxml>=0.7
lxml
mysqlclient