Skip to content

Commit

Permalink
Add the ability to whitelist views
Browse files Browse the repository at this point in the history
Fixes #17
  • Loading branch information
Dunedan committed Mar 24, 2019
1 parent 83cab3f commit 9cc4c14
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 4 deletions.
3 changes: 3 additions & 0 deletions CHANGES.rst
Expand Up @@ -6,6 +6,9 @@ tip (unreleased)

- Added support for proxies when using IP-address based lockdown exceptions.

- Added the ability to whitelist views when locking down a whole site using
the middleware.

1.6.0 (2018-11-25)
------------------

Expand Down
18 changes: 18 additions & 0 deletions README.rst
Expand Up @@ -156,6 +156,24 @@ locked. For example::
r'\.json$', # unlock JSON API
)

LOCKDOWN_VIEW_EXCEPTIONS
------------------------

An optional list of regular expressions to be matched against the
resolved views of incoming requests. If the URL of an incoming request
resolves to one of the views in the list, it will not be locked.
That's useful if you want to lock down a whole site using the middleware,
but want to whitelist some localized URLs.

For example:

from yourapp import one_view_to_unlock, another_view_to_unlock

LOCKDOWN_VIEW_EXCEPTIONS = [
one_view_to_unlock,
another_view_to_unlock
]

LOCKDOWN_REMOTE_ADDR_EXCEPTIONS
-------------------------------

Expand Down
15 changes: 13 additions & 2 deletions lockdown/middleware.py
Expand Up @@ -5,6 +5,7 @@
from django.core.exceptions import ImproperlyConfigured
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.urls import Resolver404, resolve

from lockdown import settings

Expand Down Expand Up @@ -46,8 +47,9 @@ class LockdownMiddleware(object):
# pylint: disable=too-many-arguments
def __init__(self, get_response=None, form=None, until_date=None,
after_date=None, logout_key=None, session_key=None,
url_exceptions=None, remote_addr_exceptions=None,
trusted_proxies=None, extra_context=None, **form_kwargs):
url_exceptions=None, view_exceptions=None,
remote_addr_exceptions=None, trusted_proxies=None,
extra_context=None, **form_kwargs):
"""Initialize the middleware, by setting the configuration values."""
if logout_key is None:
logout_key = settings.LOGOUT_KEY
Expand Down Expand Up @@ -119,6 +121,15 @@ def process_request(self, request):
if pattern.search(request.path):
return None

# Don't lock down if the URL resolves to a whitelisted view.
try:
resolved_path = resolve(request.path)
except Resolver404:
pass
else:
if resolved_path.func in settings.VIEW_EXCEPTIONS:
return None

# Don't lock down if outside of the lockdown dates.
if self.until_date:
until_date = self.until_date
Expand Down
1 change: 1 addition & 0 deletions lockdown/settings.py
Expand Up @@ -2,6 +2,7 @@

ENABLED = getattr(settings, 'LOCKDOWN_ENABLED', True)
URL_EXCEPTIONS = getattr(settings, 'LOCKDOWN_URL_EXCEPTIONS', ())
VIEW_EXCEPTIONS = getattr(settings, 'LOCKDOWN_VIEW_EXCEPTIONS', [])
REMOTE_ADDR_EXCEPTIONS = getattr(settings, 'LOCKDOWN_REMOTE_ADDR_EXCEPTIONS',
[])
TRUSTED_PROXIES = getattr(settings, 'LOCKDOWN_TRUSTED_PROXIES', [])
Expand Down
16 changes: 14 additions & 2 deletions lockdown/tests/tests.py
Expand Up @@ -6,6 +6,7 @@

from lockdown import middleware
from lockdown.forms import AuthForm
from lockdown.tests.views import a_view

try:
from unittest.mock import patch
Expand Down Expand Up @@ -49,8 +50,8 @@ def test_global_disable(self):
def test_url_exceptions(self):
"""Test that a page isn't locked when its URL is in the exception list.
The excepted URLs are determinated by the
LOCKDOWN_URL_EXCEPTIONS setting.
The excepted URLs are determined by the LOCKDOWN_URL_EXCEPTIONS
setting.
"""
response = self.client.get(self.locked_url)
self.assertEqual(response.content, self.locked_contents)
Expand Down Expand Up @@ -320,6 +321,17 @@ def setUp(self):
'lockdown.middleware.LockdownMiddleware',
)

@patch('lockdown.tests.tests.middleware.settings.VIEW_EXCEPTIONS',
[a_view])
def test_view_exceptions(self):
"""Test that a page isn't locked when its view whitelisted.
The excepted URLs are determined by the
LOCKDOWN_VIEW_EXCEPTIONS setting.
"""
response = self.client.get(self.locked_url)
self.assertEqual(response.content, self.locked_contents)

def tearDown(self):
"""Additional tear down for middleware tests."""
django_settings.MIDDLEWARE = self._old_middleware_classes
Expand Down

0 comments on commit 9cc4c14

Please sign in to comment.