From f9176387acd78903154942a30d634f09c55a4d55 Mon Sep 17 00:00:00 2001 From: jeffrey forman Date: Wed, 13 Feb 2019 20:17:05 -0500 Subject: [PATCH] update to django-2, python3, and based on an alpine container --- Dockerfile | 11 +++----- README.markdown | 1 - binder/admin.py | 2 +- binder/fixtures/initial_data.json | 2 +- binder/forms.py | 2 +- binder/helpers.py | 2 +- binder/middlewares.py | 16 +++++++---- binder/migrations/0001_initial.py | 28 +++++++++---------- binder/migrations/0002_bindserver_dns_port.py | 20 ------------- binder/models.py | 7 +++-- binder/settings.py | 9 +++--- binder/tests/testModels.py | 3 +- binder/tests/testViews.py | 4 +-- binder/urls.py | 10 ++++--- develop.sh | 2 +- requirements.txt | 3 +- 16 files changed, 53 insertions(+), 69 deletions(-) delete mode 100644 binder/migrations/0002_bindserver_dns_port.py diff --git a/Dockerfile b/Dockerfile index 11626f1..ead9a7a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,16 +1,13 @@ -FROM python:2.7 +FROM python:3-alpine MAINTAINER Jeffrey Forman -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 diff --git a/README.markdown b/README.markdown index 69312a5..6e38c69 100644 --- a/README.markdown +++ b/README.markdown @@ -86,7 +86,6 @@ bootstrapping. ``` python manage.py migrate python manage.py createsuperuser -... python manage.py dumpdata -o binder/fixtures/initial_data.json ``` diff --git a/binder/admin.py b/binder/admin.py index 90404d4..51c2b2a 100644 --- a/binder/admin.py +++ b/binder/admin.py @@ -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 diff --git a/binder/fixtures/initial_data.json b/binder/fixtures/initial_data.json index d3a527f..d1a7e41 100644 --- a/binder/fixtures/initial_data.json +++ b/binder/fixtures/initial_data.json @@ -1 +1 @@ -[{"model": "contenttypes.contenttype", "pk": 1, "fields": {"app_label": "contenttypes", "model": "contenttype"}}, {"model": "contenttypes.contenttype", "pk": 2, "fields": {"app_label": "auth", "model": "group"}}, {"model": "contenttypes.contenttype", "pk": 3, "fields": {"app_label": "auth", "model": "user"}}, {"model": "contenttypes.contenttype", "pk": 4, "fields": {"app_label": "auth", "model": "permission"}}, {"model": "contenttypes.contenttype", "pk": 5, "fields": {"app_label": "sessions", "model": "session"}}, {"model": "contenttypes.contenttype", "pk": 6, "fields": {"app_label": "admin", "model": "logentry"}}, {"model": "contenttypes.contenttype", "pk": 7, "fields": {"app_label": "binder", "model": "bindserver"}}, {"model": "contenttypes.contenttype", "pk": 8, "fields": {"app_label": "binder", "model": "key"}}, {"model": "auth.permission", "pk": 1, "fields": {"name": "Can add content type", "content_type": 1, "codename": "add_contenttype"}}, {"model": "auth.permission", "pk": 2, "fields": {"name": "Can change content type", "content_type": 1, "codename": "change_contenttype"}}, {"model": "auth.permission", "pk": 3, "fields": {"name": "Can delete content type", "content_type": 1, "codename": "delete_contenttype"}}, {"model": "auth.permission", "pk": 4, "fields": {"name": "Can add group", "content_type": 2, "codename": "add_group"}}, {"model": "auth.permission", "pk": 5, "fields": {"name": "Can change group", "content_type": 2, "codename": "change_group"}}, {"model": "auth.permission", "pk": 6, "fields": {"name": "Can delete group", "content_type": 2, "codename": "delete_group"}}, {"model": "auth.permission", "pk": 7, "fields": {"name": "Can add permission", "content_type": 4, "codename": "add_permission"}}, {"model": "auth.permission", "pk": 8, "fields": {"name": "Can change permission", "content_type": 4, "codename": "change_permission"}}, {"model": "auth.permission", "pk": 9, "fields": {"name": "Can delete permission", "content_type": 4, "codename": "delete_permission"}}, {"model": "auth.permission", "pk": 10, "fields": {"name": "Can add user", "content_type": 3, "codename": "add_user"}}, {"model": "auth.permission", "pk": 11, "fields": {"name": "Can change user", "content_type": 3, "codename": "change_user"}}, {"model": "auth.permission", "pk": 12, "fields": {"name": "Can delete user", "content_type": 3, "codename": "delete_user"}}, {"model": "auth.permission", "pk": 13, "fields": {"name": "Can add session", "content_type": 5, "codename": "add_session"}}, {"model": "auth.permission", "pk": 14, "fields": {"name": "Can change session", "content_type": 5, "codename": "change_session"}}, {"model": "auth.permission", "pk": 15, "fields": {"name": "Can delete session", "content_type": 5, "codename": "delete_session"}}, {"model": "auth.permission", "pk": 16, "fields": {"name": "Can add log entry", "content_type": 6, "codename": "add_logentry"}}, {"model": "auth.permission", "pk": 17, "fields": {"name": "Can change log entry", "content_type": 6, "codename": "change_logentry"}}, {"model": "auth.permission", "pk": 18, "fields": {"name": "Can delete log entry", "content_type": 6, "codename": "delete_logentry"}}, {"model": "auth.permission", "pk": 19, "fields": {"name": "Can add key", "content_type": 8, "codename": "add_key"}}, {"model": "auth.permission", "pk": 20, "fields": {"name": "Can change key", "content_type": 8, "codename": "change_key"}}, {"model": "auth.permission", "pk": 21, "fields": {"name": "Can delete key", "content_type": 8, "codename": "delete_key"}}, {"model": "auth.permission", "pk": 22, "fields": {"name": "Can add bind server", "content_type": 7, "codename": "add_bindserver"}}, {"model": "auth.permission", "pk": 23, "fields": {"name": "Can change bind server", "content_type": 7, "codename": "change_bindserver"}}, {"model": "auth.permission", "pk": 24, "fields": {"name": "Can delete bind server", "content_type": 7, "codename": "delete_bindserver"}}, {"model": "auth.user", "pk": 1, "fields": {"password": "pbkdf2_sha256$36000$JgyPNL3vdRfm$BQRq2ISXUB3P39cCT9MueN5Gs+Su6jymeCps3QQKyPo=", "last_login": null, "is_superuser": true, "username": "admin", "first_name": "", "last_name": "", "email": "a@a.com", "is_staff": true, "is_active": true, "date_joined": "2017-04-17T22:04:31.773", "groups": [], "user_permissions": []}}] \ No newline at end of file +[{"model": "contenttypes.contenttype", "pk": 1, "fields": {"app_label": "contenttypes", "model": "contenttype"}}, {"model": "contenttypes.contenttype", "pk": 2, "fields": {"app_label": "auth", "model": "permission"}}, {"model": "contenttypes.contenttype", "pk": 3, "fields": {"app_label": "auth", "model": "group"}}, {"model": "contenttypes.contenttype", "pk": 4, "fields": {"app_label": "auth", "model": "user"}}, {"model": "contenttypes.contenttype", "pk": 5, "fields": {"app_label": "sessions", "model": "session"}}, {"model": "contenttypes.contenttype", "pk": 6, "fields": {"app_label": "admin", "model": "logentry"}}, {"model": "contenttypes.contenttype", "pk": 7, "fields": {"app_label": "binder", "model": "bindserver"}}, {"model": "contenttypes.contenttype", "pk": 8, "fields": {"app_label": "binder", "model": "key"}}, {"model": "auth.permission", "pk": 1, "fields": {"name": "Can add content type", "content_type": 1, "codename": "add_contenttype"}}, {"model": "auth.permission", "pk": 2, "fields": {"name": "Can change content type", "content_type": 1, "codename": "change_contenttype"}}, {"model": "auth.permission", "pk": 3, "fields": {"name": "Can delete content type", "content_type": 1, "codename": "delete_contenttype"}}, {"model": "auth.permission", "pk": 4, "fields": {"name": "Can view content type", "content_type": 1, "codename": "view_contenttype"}}, {"model": "auth.permission", "pk": 5, "fields": {"name": "Can add permission", "content_type": 2, "codename": "add_permission"}}, {"model": "auth.permission", "pk": 6, "fields": {"name": "Can change permission", "content_type": 2, "codename": "change_permission"}}, {"model": "auth.permission", "pk": 7, "fields": {"name": "Can delete permission", "content_type": 2, "codename": "delete_permission"}}, {"model": "auth.permission", "pk": 8, "fields": {"name": "Can view permission", "content_type": 2, "codename": "view_permission"}}, {"model": "auth.permission", "pk": 9, "fields": {"name": "Can add group", "content_type": 3, "codename": "add_group"}}, {"model": "auth.permission", "pk": 10, "fields": {"name": "Can change group", "content_type": 3, "codename": "change_group"}}, {"model": "auth.permission", "pk": 11, "fields": {"name": "Can delete group", "content_type": 3, "codename": "delete_group"}}, {"model": "auth.permission", "pk": 12, "fields": {"name": "Can view group", "content_type": 3, "codename": "view_group"}}, {"model": "auth.permission", "pk": 13, "fields": {"name": "Can add user", "content_type": 4, "codename": "add_user"}}, {"model": "auth.permission", "pk": 14, "fields": {"name": "Can change user", "content_type": 4, "codename": "change_user"}}, {"model": "auth.permission", "pk": 15, "fields": {"name": "Can delete user", "content_type": 4, "codename": "delete_user"}}, {"model": "auth.permission", "pk": 16, "fields": {"name": "Can view user", "content_type": 4, "codename": "view_user"}}, {"model": "auth.permission", "pk": 17, "fields": {"name": "Can add session", "content_type": 5, "codename": "add_session"}}, {"model": "auth.permission", "pk": 18, "fields": {"name": "Can change session", "content_type": 5, "codename": "change_session"}}, {"model": "auth.permission", "pk": 19, "fields": {"name": "Can delete session", "content_type": 5, "codename": "delete_session"}}, {"model": "auth.permission", "pk": 20, "fields": {"name": "Can view session", "content_type": 5, "codename": "view_session"}}, {"model": "auth.permission", "pk": 21, "fields": {"name": "Can add log entry", "content_type": 6, "codename": "add_logentry"}}, {"model": "auth.permission", "pk": 22, "fields": {"name": "Can change log entry", "content_type": 6, "codename": "change_logentry"}}, {"model": "auth.permission", "pk": 23, "fields": {"name": "Can delete log entry", "content_type": 6, "codename": "delete_logentry"}}, {"model": "auth.permission", "pk": 24, "fields": {"name": "Can view log entry", "content_type": 6, "codename": "view_logentry"}}, {"model": "auth.permission", "pk": 25, "fields": {"name": "Can add bind server", "content_type": 7, "codename": "add_bindserver"}}, {"model": "auth.permission", "pk": 26, "fields": {"name": "Can change bind server", "content_type": 7, "codename": "change_bindserver"}}, {"model": "auth.permission", "pk": 27, "fields": {"name": "Can delete bind server", "content_type": 7, "codename": "delete_bindserver"}}, {"model": "auth.permission", "pk": 28, "fields": {"name": "Can view bind server", "content_type": 7, "codename": "view_bindserver"}}, {"model": "auth.permission", "pk": 29, "fields": {"name": "Can add key", "content_type": 8, "codename": "add_key"}}, {"model": "auth.permission", "pk": 30, "fields": {"name": "Can change key", "content_type": 8, "codename": "change_key"}}, {"model": "auth.permission", "pk": 31, "fields": {"name": "Can delete key", "content_type": 8, "codename": "delete_key"}}, {"model": "auth.permission", "pk": 32, "fields": {"name": "Can view key", "content_type": 8, "codename": "view_key"}}, {"model": "auth.user", "pk": 1, "fields": {"password": "pbkdf2_sha256$120000$A1LpLIPjMxKO$HiNlt4OPI7RGxC1JkMNH4sunCY60cIbxZjIbJBxckgA=", "last_login": null, "is_superuser": true, "username": "admin", "first_name": "", "last_name": "", "email": "example@example.com", "is_staff": true, "is_active": true, "date_joined": "2019-02-13T01:52:05.671", "groups": [], "user_permissions": []}}] \ No newline at end of file diff --git a/binder/forms.py b/binder/forms.py index f100702..9860b56 100644 --- a/binder/forms.py +++ b/binder/forms.py @@ -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): diff --git a/binder/helpers.py b/binder/helpers.py index 8c8114b..18f0439 100644 --- a/binder/helpers.py +++ b/binder/helpers.py @@ -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 diff --git a/binder/middlewares.py b/binder/middlewares.py index f7a0a6f..1d6b90c 100644 --- a/binder/middlewares.py +++ b/binder/middlewares.py @@ -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 HttpResponseRedirect(settings.LOGIN_URL) + return response diff --git a/binder/migrations/0001_initial.py b/binder/migrations/0001_initial.py index 9a7999e..e6ff618 100644 --- a/binder/migrations/0001_initial.py +++ b/binder/migrations/0001_initial.py @@ -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'), ), ] diff --git a/binder/migrations/0002_bindserver_dns_port.py b/binder/migrations/0002_bindserver_dns_port.py deleted file mode 100644 index ffec852..0000000 --- a/binder/migrations/0002_bindserver_dns_port.py +++ /dev/null @@ -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, - ), - ] diff --git a/binder/models.py b/binder/models.py index de9cc9a..38d63f8 100644 --- a/binder/models.py +++ b/binder/models.py @@ -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: diff --git a/binder/settings.py b/binder/settings.py index df65b62..2547521 100644 --- a/binder/settings.py +++ b/binder/settings.py @@ -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', ) diff --git a/binder/tests/testModels.py b/binder/tests/testModels.py index 1787231..3a8167e 100644 --- a/binder/tests/testModels.py +++ b/binder/tests/testModels.py @@ -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): diff --git a/binder/tests/testViews.py b/binder/tests/testViews.py index 5aa6267..7c6f0f9 100644 --- a/binder/tests/testViews.py +++ b/binder/tests/testViews.py @@ -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, '', html=True) self.assertContains(response, - '', + '', html=True) self.assertContains(response, '', diff --git a/binder/urls.py b/binder/urls.py index f258af7..b76be03 100644 --- a/binder/urls.py +++ b/binder/urls.py @@ -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"), diff --git a/develop.sh b/develop.sh index 7751176..8cc323b 100755 --- a/develop.sh +++ b/develop.sh @@ -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 diff --git a/requirements.txt b/requirements.txt index c77c772..5f078f9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,5 @@ +Django cryptography -Django>=1.10 dnspython>=1.11 pybindxml>=0.7 lxml -mysqlclient