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/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