Add global authentication

This commit adds global authentication to binder to ensure that only valid
users are able to use it. This should enable binder to be used in
environemts where it's webfrontend is reachable for unauthenticated users as
well.

For setups where such a global authentication isn't desired it can be disabled
by simply removing the LoginRequiredMiddleware from the list of active
middlewares.
This commit is contained in:
Daniel Roschka 2015-04-05 21:06:01 +02:00
parent dc15440a98
commit 7882ee9121
6 changed files with 89 additions and 0 deletions

23
binder/middlewares.py Normal file
View File

@ -0,0 +1,23 @@
from django.conf import settings
from django.contrib.auth import REDIRECT_FIELD_NAME
from django.http import HttpResponseRedirect
class LoginRequiredMiddleware(object):
"""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):
# allow access to the login url
if request.path == settings.LOGIN_URL:
return
# redirect to the login url if the user isn't 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)

View File

@ -67,6 +67,7 @@ MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'binder.middlewares.LoginRequiredMiddleware',
)
ROOT_URLCONF = 'binder.urls'
@ -86,3 +87,5 @@ INSTALLED_APPS = (
)
TEST_RUNNER = 'django.test.runner.DiscoverRunner'
LOGIN_REDIRECT_URL = '/'

View File

@ -20,6 +20,9 @@
<li role="presentation" class="active">Actions</li>
<li role="presentation"><a href="/">Home</a></li>
<li role="presentation"><a href="{% url "server_list" %}">Server List</a></li>
{% if user.is_authenticated %}
<li role="presentation"><a href="{% url "logout" %}">Logout</a></li>
{% endif %}
</ul>
{% endblock navigation %}
</div>

View File

@ -0,0 +1,44 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Binder DNS Admin Login</title>
<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}bootstrap/css/bootstrap.css" />
</head>
<body>
<div class="container">
<div class="page-header text-center">
<h1>Binder DNS Admin</h1>
</div>
{% if form.errors %}
<div class="row">
<div class="col-md-4"></div>
<div class="col-md-4 alert alert-danger text-center" role="alert">Wrong username or password! Please try again.</div>
</div>
{% endif %}
<form method="post" action="{% url 'django.contrib.auth.views.login' %}{% if next %}?next={{ next }}{% endif %}" class="form-horizontal" >
{% csrf_token %}
<div class="form-group">
<label for="{{ form.username.id_for_label }}" class="control-label col-md-5">Username</label>
<div class="controls col-md-3">
<input type="text" id="{{ form.username.id_for_label }}" name="username" class="form-control" value="{{ form.username.value|default_if_none:"" }}">
</div>
</div>
<div class="form-group">
<label for="{{ form.password.id_for_label }}" class="control-label col-md-5">Password</label>
<div class="controls col-md-3">
<input type="password" id="{{ form.password.id_for_label }}" name="password" class="form-control">
</div>
</div>
<div class="form-group">
<div class="col-md-5"></div>
<div class="col-md-3">
<button type="submit" class="btn btn-default">Login</button>
</div>
</div>
</form>
</div>
</body>
</html>

View File

@ -1,5 +1,6 @@
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 binder import models, helpers
@ -9,6 +10,12 @@ class GetTests(TestCase):
""" Unit Tests that exercise HTTP GET. """
def setUp(self):
self.client = Client()
user = User.objects.create_user('testuser',
'testuser@example.com',
'testpassword')
response = self.client.login(username='testuser',
password='testpassword')
def test_GetIndex(self):
response = self.client.get(reverse("index"))
@ -44,6 +51,11 @@ class PostTests(TestCase):
models.BindServer(hostname="testserver.test.net",
statistics_port=1234).save()
user = User.objects.create_user('testuser',
'testuser@example.com',
'testpassword')
response = self.client.login(username='testuser',
password='testpassword')
def test_DeleteRecordInitial_Empty(self):
""" Ensure the initial deletion form works as expected with no RR list. """

View File

@ -6,6 +6,10 @@ admin.autodiscover()
urlpatterns = patterns('',
url(r'^admin/', include(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'^$', 'binder.views.home_index', name="index"),
url(r'^server_list/$', 'binder.views.view_server_list', name="server_list"),