PKTFlockdown/__init__.pyPKF\lockdown/decorators.pyfrom django.utils.decorators import decorator_from_middleware_with_args from lockdown.middleware import LockdownMiddleware def lockdown(*args, **kwargs): """Define a decorator based on the LockdownMiddleware. This decorator takes the same arguments as the middleware, but allows a more granular locking than the middleware. """ return decorator_from_middleware_with_args(LockdownMiddleware)(*args, **kwargs) PK=hG[Hlockdown/forms.pyfrom django import forms from django.contrib import auth from django.contrib.auth.forms import AuthenticationForm from lockdown import settings class LockdownForm(forms.Form): """Defines a form to enter a password for accessing locked down content.""" password = forms.CharField(widget=forms.PasswordInput(render_value=False)) def __init__(self, passwords=None, *args, **kwargs): """Initialize the form by setting the valid passwords.""" super(LockdownForm, self).__init__(*args, **kwargs) if passwords is None: passwords = settings.PASSWORDS self.valid_passwords = passwords def clean_password(self): """Check that the password is valid.""" value = self.cleaned_data.get('password') if value not in self.valid_passwords: raise forms.ValidationError('Incorrect password.') return value def generate_token(self): """Save the password as the authentication token. It's acceptable to store the password raw, as it is stored server-side in the user's session. """ return self.cleaned_data['password'] def authenticate(self, token_value): """Check that the password is valid. This allows for revoking of a user's preview rights by changing the valid passwords. """ return token_value in self.valid_passwords def show_form(self): """Show the form if there are any valid passwords.""" return bool(self.valid_passwords) class AuthForm(AuthenticationForm): """Defines a form using Djangos authentication to access locked content. This form is a sample implementation of how to use a custom form to provide access to locked down content. """ def __init__(self, staff_only=None, superusers_only=None, *args, **kwargs): """Initialize the form by setting permissions needed for access.""" from django.conf import settings as django_settings super(AuthForm, self).__init__(*args, **kwargs) if staff_only is None: staff_only = getattr(django_settings, 'LOCKDOWN_AUTHFORM_STAFF_ONLY', True) if superusers_only is None: superusers_only = getattr(django_settings, 'LOCKDOWN_AUTHFORM_SUPERUSERS_ONLY', False) self.staff_only = staff_only self.superusers_only = superusers_only def clean(self): """When receiving the filled out form, check for valid access.""" cleaned_data = super(AuthForm, self).clean() user = self.get_user() if self.staff_only and (not user or not user.is_staff): raise forms.ValidationError('Sorry, only staff are allowed.') if self.superusers_only and (not user or not user.is_superuser): raise forms.ValidationError('Sorry, only superusers are allowed.') return cleaned_data def generate_token(self): """Save the password as the authentication token. It's acceptable to store the password raw, as it is stored server-side in the user's session. """ user = self.get_user() return '%s:%s' % (user.backend, user.pk) def authenticate(self, token_value): """Check that the password is valid. This allows for revoking of a user's preview rights by changing the valid passwords. """ try: backend_path, user_id = token_value.split(':', 1) except (ValueError, AttributeError): return False backend = auth.load_backend(backend_path) return bool(backend.get_user(user_id)) def show_form(self): """Determine if the form should be shown on locked pages.""" return True PK=hGbzzlockdown/settings.pyfrom django.conf import settings ENABLED = getattr(settings, 'LOCKDOWN_ENABLED', True) URL_EXCEPTIONS = getattr(settings, 'LOCKDOWN_URL_EXCEPTIONS', ()) PASSWORDS = getattr(settings, 'LOCKDOWN_PASSWORDS', ()) FORM = getattr(settings, 'LOCKDOWN_FORM', 'lockdown.forms.LockdownForm') SESSION_KEY = getattr(settings, 'LOCKDOWN_SESSION_KEY', 'lockdown-allow') LOGOUT_KEY = getattr(settings, 'LOCKDOWN_LOGOUT_KEY', 'preview-logout') UNTIL_DATE = getattr(settings, 'LOCKDOWN_UNTIL', None) AFTER_DATE = getattr(settings, 'LOCKDOWN_AFTER', None) if not isinstance(PASSWORDS, (tuple, list)): PASSWORDS = PASSWORDS and (PASSWORDS,) or () PKDhG5lockdown/middleware.pyimport datetime import re from django.core.exceptions import ImproperlyConfigured from django.http import HttpResponseRedirect from django.shortcuts import render_to_response from django.template import RequestContext from importlib import import_module from lockdown import settings def compile_url_exceptions(url_exceptions): """Return a list of compiled regex objects, containing the url exceptions. All URLs in that list returned won't be considered as locked. """ return [re.compile(p) for p in url_exceptions] _default_url_exceptions = compile_url_exceptions(settings.URL_EXCEPTIONS) def get_lockdown_form(form_path): """Return a form class for a given string pointing to a lockdown form.""" if not form_path: raise ImproperlyConfigured('No LOCKDOWN_FORM specified.') form_path_list = form_path.split(".") module = ".".join(form_path_list[:-1]) attr = form_path_list[-1] try: mod = import_module(module) except (ImportError, ValueError): raise ImproperlyConfigured('Module configured in LOCKDOWN_FORM (%s) to' ' contain the form class couldn\'t be ' 'found.' % module) try: form = getattr(mod, attr) except AttributeError: raise ImproperlyConfigured('The module configured in LOCKDOWN_FORM ' ' (%s) doesn\'t define a "%s" form.' % (module, attr)) return form _default_form = get_lockdown_form(settings.FORM) class LockdownMiddleware(object): """Middleware to lock down a whole Django site.""" def __init__(self, form=None, until_date=None, after_date=None, logout_key=None, session_key=None, url_exceptions=None, **form_kwargs): """Initialize the middleware, by setting the configuration values.""" if logout_key is None: logout_key = settings.LOGOUT_KEY if session_key is None: session_key = settings.SESSION_KEY self.form = form self.form_kwargs = form_kwargs self.until_date = until_date self.after_date = after_date self.logout_key = logout_key self.session_key = session_key self.url_exceptions = url_exceptions def process_request(self, request): """Check if each request is allowed to access the current resource.""" try: session = request.session except AttributeError: raise ImproperlyConfigured('django-lockdown requires the Django ' 'sessions framework') # Don't lock down if django-lockdown is disabled altogether. if settings.ENABLED is False: return None # Don't lock down if the URL matches an exception pattern. if self.url_exceptions is None: url_exceptions = _default_url_exceptions else: url_exceptions = compile_url_exceptions(self.url_exceptions) for pattern in url_exceptions: if pattern.search(request.path): return None # Don't lock down if outside of the lockdown dates. if self.until_date is None: until_date = settings.UNTIL_DATE else: until_date = self.until_date if self.after_date is None: after_date = settings.AFTER_DATE else: after_date = self.after_date if until_date or after_date: locked_date = False if until_date and datetime.datetime.now() < until_date: locked_date = True if after_date and datetime.datetime.now() > after_date: locked_date = True if not locked_date: return None form_data = request.method == 'POST' and request.POST or None if self.form is None: form_class = _default_form else: form_class = self.form form = form_class(data=form_data, **self.form_kwargs) authorized = False token = session.get(self.session_key) if hasattr(form, 'authenticate'): if form.authenticate(token): authorized = True elif token is True: authorized = True if authorized and self.logout_key and self.logout_key in request.GET: if self.session_key in session: del session[self.session_key] url = request.path querystring = request.GET.copy() del querystring[self.logout_key] if querystring: url = '%s?%s' % (url, querystring.urlencode()) return self.redirect(request) # Don't lock down if the user is already authorized for previewing. if authorized: return None if form.is_valid(): if hasattr(form, 'generate_token'): token = form.generate_token() else: token = True session[self.session_key] = token return self.redirect(request) page_data = {'until_date': until_date, 'after_date': after_date} if not hasattr(form, 'show_form') or form.show_form(): page_data['form'] = form return render_to_response('lockdown/form.html', page_data, context_instance=RequestContext(request)) def redirect(self, request): """Utility method to handle redirects.""" url = request.path querystring = request.GET.copy() if self.logout_key and self.logout_key in request.GET: del querystring[self.logout_key] if querystring: url = '%s?%s' % (url, querystring.urlencode()) return HttpResponseRedirect(url) PKFokulockdown/tests/urls.pyfrom django.conf.urls import url from . import views urlpatterns = [ url(r'^a/view/$', views.a_view), url(r'^locked/view/$', views.locked_view), url(r'^overridden/locked/view/$', views.overridden_locked_view), url(r'^locked/view/with/exception1/', views.locked_view_with_exception), url(r'^locked/view/with/exception2/', views.locked_view_with_exception), url(r'^locked/view/until/yesterday/', views.locked_view_until_yesterday), url(r'^locked/view/until/tomorrow/', views.locked_view_until_tomorrow), url(r'^locked/view/after/yesterday/', views.locked_view_after_yesterday), url(r'^locked/view/after/tomorrow/', views.locked_view_after_tomorrow), url(r'^locked/view/until/and/after/', views.locked_view_until_and_after), url(r'^auth/user/locked/view/$', views.user_locked_view), url(r'^auth/staff/locked/view/$', views.staff_locked_view), url(r'^auth/superuser/locked/view/$', views.superuser_locked_view), ] PKFlockdown/tests/forms.pyfrom django import forms class CustomLockdownForm(forms.Form): """A form to test the behavior of using custom forms for authentication.""" answer = forms.IntegerField() def clean_answer(self): """Cleaning of the answer field, by checking it's value.""" if self.cleaned_data['answer'] == 42: return 42 raise forms.ValidationError('Wrong answer.') PK;FxNlockdown/tests/views.pyimport datetime from django.http import HttpResponse from lockdown.decorators import lockdown from lockdown.forms import AuthForm YESTERDAY = datetime.datetime.now() - datetime.timedelta(days=1) TOMORROW = datetime.datetime.now() + datetime.timedelta(days=1) def a_view(request): """Regular unlocked view.""" return HttpResponse('A view.') @lockdown() def locked_view(request): """View, locked by the default lockdown decorator.""" return HttpResponse('A locked view.') @lockdown(passwords=('squirrel',)) def overridden_locked_view(request): """View, locked by the decorator with a custom password.""" return HttpResponse('A locked view.') @lockdown(url_exceptions=(r'^/locked/view/with/exception2/',)) def locked_view_with_exception(request): """View, locked by the decorator with url exceptions.""" return HttpResponse('A locked view.') @lockdown(until_date=YESTERDAY) def locked_view_until_yesterday(request): """View, locked till yesterday.""" return HttpResponse('A locked view.') @lockdown(until_date=TOMORROW) def locked_view_until_tomorrow(request): """View, locked till tomorrow.""" return HttpResponse('A locked view.') @lockdown(after_date=YESTERDAY) def locked_view_after_yesterday(request): """View, locked since yesterday.""" return HttpResponse('A locked view.') @lockdown(after_date=TOMORROW) def locked_view_after_tomorrow(request): """View, locked starting from tomorrow.""" return HttpResponse('A locked view.') @lockdown(until_date=YESTERDAY, after_date=TOMORROW) def locked_view_until_and_after(request): """View, only not looked between yesterday and tomorrow.""" return HttpResponse('A locked view.') @lockdown(form=AuthForm, staff_only=False) def user_locked_view(request): """View, locked by the decorator with access for known users only.""" return HttpResponse('A locked view.') @lockdown(form=AuthForm) def staff_locked_view(request): """View, locked by the decorator with access for staff users only.""" return HttpResponse('A locked view.') @lockdown(form=AuthForm, superusers_only=True) def superuser_locked_view(request): """View, locked by the decorator with access for superusers only.""" return HttpResponse('A locked view.') PKKF!:hlockdown/tests/test_settings.pyfrom random import choice DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3' } } SECRET_KEY = ''.join([choice('abcdefghijklmnopqrstuvwxyz' '0123456789!@#$%^&*(-_=+)') for i in range(64)]) MIDDLEWARE_CLASSES = ('django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware' ) INSTALLED_APPS = ( 'django.contrib.sessions', 'django.contrib.contenttypes', 'django.contrib.auth', 'lockdown' ) ROOT_URLCONF = 'lockdown.tests.urls' PKܸGlockdown/tests/__init__.pyPKܸGq99lockdown/tests/tests.pyimport datetime from django.conf import settings as django_settings from django.core.exceptions import ImproperlyConfigured from django.test import TestCase from lockdown import middleware, settings from lockdown.forms import AuthForm class LockdownTestCase(TestCase): """Base class for the other tests, setting up a proper test environment.""" urls = 'lockdown.tests.urls' def setUp(self): """Basic setup for all tests.""" self._old_pw = settings.PASSWORDS settings.PASSWORDS = ('letmein',) self._old_form = settings.FORM settings.FORM = 'lockdown.forms.LockdownForm' middleware._default_form = middleware.get_lockdown_form(settings.FORM) def tearDown(self): """Tearing down all settings made for the tests after running them.""" settings.PASSWORDS = self._old_pw settings.FORM = self._old_form middleware._default_form = middleware.get_lockdown_form(settings.FORM) class BaseTests(LockdownTestCase): """Base tests for lockdown functionality. These base tests are used for testing lockdowns decorator and middleware functionality. Subclasses should provide ``locked_url`` and ``locked_contents`` attributes. """ def test_lockdown_template_used(self): """Test if the login form template is used on locked pages.""" response = self.client.get(self.locked_url) self.assertTemplateUsed(response, 'lockdown/form.html') def test_form_in_context(self): """Test if the login form contains a proper password field.""" response = self.client.get(self.locked_url) form = response.context['form'] self.failUnless('password' in form.fields) def test_global_disable(self): """Test that a page isn't locked when LOCKDOWN_ENABLED=False.""" _old_enabled = settings.ENABLED settings.ENABLED = False try: response = self.client.get(self.locked_url) self.assertEqual(response.content, self.locked_contents) finally: settings.ENABLED = _old_enabled 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. """ _old_url_exceptions = settings.URL_EXCEPTIONS settings.URL_EXCEPTIONS = (r'/view/$',) middleware._default_url_exceptions = \ middleware.compile_url_exceptions(settings.URL_EXCEPTIONS) try: response = self.client.get(self.locked_url) self.assertEqual(response.content, self.locked_contents) finally: settings.URL_EXCEPTIONS = _old_url_exceptions middleware._default_url_exceptions = \ middleware.compile_url_exceptions(settings.URL_EXCEPTIONS) def test_submit_password(self): """Test that access to locked content works with a correct password.""" response = self.client.post(self.locked_url, {'password': 'letmein'}, follow=True) self.assertEqual(response.content, self.locked_contents) def test_submit_wrong_password(self): """Test access to locked content is denied for wrong passwords.""" response = self.client.post(self.locked_url, {'password': 'imacrook'}) self.assertContains(response, 'Incorrect password.') def test_custom_form(self): """Test if access using a custom lockdown form works.""" _old_form = settings.FORM settings.FORM = 'lockdown.tests.forms.CustomLockdownForm' middleware._default_form = middleware.get_lockdown_form(settings.FORM) try: response = self.client.post(self.locked_url, {'answer': '42'}, follow=True) self.assertEqual(response.content, self.locked_contents) finally: settings.FORM = _old_form middleware._default_form = middleware.get_lockdown_form( settings.FORM) def test_invalid_custom_form(self): """Test that pointing to an invalid form properly produces an error.""" # no form configured at all self.assertRaises(ImproperlyConfigured, middleware.get_lockdown_form, None) # invalid module name in the configured form self.assertRaises(ImproperlyConfigured, middleware.get_lockdown_form, 'invalidform') # not existing module for form self.assertRaises(ImproperlyConfigured, middleware.get_lockdown_form, 'invalid.form') # existing module, but no form with that name in the module self.assertRaises(ImproperlyConfigured, middleware.get_lockdown_form, 'lockdown.forms.foo') def test_locked_until(self): """Test locking until a certain date.""" _old_until_date = settings.UNTIL_DATE yesterday = datetime.datetime.now() - datetime.timedelta(days=1) tomorrow = datetime.datetime.now() + datetime.timedelta(days=1) try: settings.UNTIL_DATE = tomorrow response = self.client.get(self.locked_url) self.assertTemplateUsed(response, 'lockdown/form.html') settings.UNTIL_DATE = yesterday response = self.client.get(self.locked_url) self.assertEqual(response.content, self.locked_contents) finally: settings.UNTIL_DATE = _old_until_date def test_locked_after(self): """Test locking starting at a certain date.""" _old_after_date = settings.AFTER_DATE yesterday = datetime.datetime.now() - datetime.timedelta(days=1) tomorrow = datetime.datetime.now() + datetime.timedelta(days=1) try: settings.AFTER_DATE = yesterday response = self.client.get(self.locked_url) self.assertTemplateUsed(response, 'lockdown/form.html') settings.AFTER_DATE = tomorrow response = self.client.get(self.locked_url) self.assertEqual(response.content, self.locked_contents) finally: settings.AFTER_DATE = _old_after_date def test_locked_until_and_after(self): """Test locking until a certain date and starting at another date.""" _old_until_date = settings.UNTIL_DATE _old_after_date = settings.AFTER_DATE yesterday = datetime.datetime.now() - datetime.timedelta(days=1) tomorrow = datetime.datetime.now() + datetime.timedelta(days=1) try: settings.UNTIL_DATE = yesterday settings.AFTER_DATE = yesterday response = self.client.get(self.locked_url) self.assertTemplateUsed(response, 'lockdown/form.html') settings.UNTIL_DATE = tomorrow settings.AFTER_DATE = tomorrow response = self.client.get(self.locked_url) self.assertTemplateUsed(response, 'lockdown/form.html') settings.UNTIL_DATE = yesterday settings.AFTER_DATE = tomorrow response = self.client.get(self.locked_url) self.assertEqual(response.content, self.locked_contents) finally: settings.UNTIL_DATE = _old_until_date settings.AFTER_DATE = _old_after_date def test_missing_session_middleware(self): """Test behavior with missing session middleware. When the session middleware isn't present an ImproperlyConfigured error is expected. """ with self.modify_settings(MIDDLEWARE_CLASSES={ 'remove': [ 'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware' ] }): self.assertRaises(ImproperlyConfigured, self.client.get, self.locked_url) class DecoratorTests(BaseTests): """Tests for using lockdown via decorators.""" locked_url = '/locked/view/' locked_contents = b'A locked view.' def test_overridden_password(self): """Test that locking works when overriding the password.""" url = '/overridden/locked/view/' response = self.client.post(url, {'password': 'letmein'}, follow=True) self.assertTemplateUsed(response, 'lockdown/form.html') response = self.client.post(url, {'password': 'squirrel'}, follow=True) self.assertTemplateNotUsed(response, 'lockdown/form.html') self.assertEqual(response.content, self.locked_contents) def test_overridden_url_exceptions(self): """Test that locking works when overriding the url exceptions.""" url = '/locked/view/with/exception1/' response = self.client.post(url, follow=True) self.assertTemplateUsed(response, 'lockdown/form.html') url = '/locked/view/with/exception2/' response = self.client.post(url, follow=True) self.assertTemplateNotUsed(response, 'lockdown/form.html') self.assertEqual(response.content, self.locked_contents) def test_overridden_until_date(self): """Test that locking works when overriding the until date.""" url = '/locked/view/until/yesterday/' response = self.client.post(url, follow=True) self.assertTemplateNotUsed(response, 'lockdown/form.html') self.assertEqual(response.content, self.locked_contents) url = '/locked/view/until/tomorrow/' response = self.client.post(url, follow=True) self.assertTemplateUsed(response, 'lockdown/form.html') def test_overridden_after_date(self): """Test that locking works when overriding the after date.""" url = '/locked/view/after/yesterday/' response = self.client.post(url, follow=True) self.assertTemplateUsed(response, 'lockdown/form.html') url = '/locked/view/after/tomorrow/' response = self.client.post(url, follow=True) self.assertTemplateNotUsed(response, 'lockdown/form.html') self.assertEqual(response.content, self.locked_contents) def test_overridden_both_dates(self): """Test that locking works when overriding the after date.""" url = '/locked/view/until/and/after/' response = self.client.post(url, follow=True) self.assertTemplateNotUsed(response, 'lockdown/form.html') self.assertEqual(response.content, self.locked_contents) class MiddlewareTests(BaseTests): """Tests for using lockdown via its middleware.""" locked_url = '/a/view/' locked_contents = b'A view.' def setUp(self): """Additional setup for middleware tests.""" super(MiddlewareTests, self).setUp() self._old_middleware_classes = django_settings.MIDDLEWARE_CLASSES django_settings.MIDDLEWARE_CLASSES += ( 'lockdown.middleware.LockdownMiddleware', ) def tearDown(self): """Additional tear down for middleware tests.""" django_settings.MIDDLEWARE_CLASSES = self._old_middleware_classes super(MiddlewareTests, self).tearDown() class AuthFormTests(LockdownTestCase): """Tests for using the auth form for previewing locked pages.""" def test_using_form(self): """Test unauthorized access to locked page. Unauthorized access to a to locked page should show the auth form """ url = '/auth/user/locked/view/' response = self.client.get(url) self.assertTemplateUsed(response, 'lockdown/form.html') form = response.context['form'] self.failUnless(isinstance(form, AuthForm)) def add_user(self, username='test', password='pw', **kwargs): """Add a user used for testing the auth form.""" from django.contrib.auth.models import User user = User(username=username, **kwargs) user.set_password(password) user.save() def test_user(self): """Test access to a locked page which requires authorization.""" url = '/auth/user/locked/view/' self.add_user() # Incorrect password. post_data = {'username': 'test', 'password': 'bad'} response = self.client.post(url, post_data, follow=True) self.assertTemplateUsed(response, 'lockdown/form.html') # Correct password. post_data = {'username': 'test', 'password': 'pw'} response = self.client.post(url, post_data, follow=True) self.assertTemplateNotUsed(response, 'lockdown/form.html') def test_staff(self): """Test access to a locked page which requires a staff user.""" url = '/auth/staff/locked/view/' self.add_user(username='user') self.add_user(username='staff', is_staff=True) # Non-staff member. post_data = {'username': 'user', 'password': 'pw'} response = self.client.post(url, post_data, follow=True) self.assertTemplateUsed(response, 'lockdown/form.html') # Incorrect password. post_data = {'username': 'staff', 'password': 'bad'} response = self.client.post(url, post_data, follow=True) self.assertTemplateUsed(response, 'lockdown/form.html') # Correct password. post_data = {'username': 'staff', 'password': 'pw'} response = self.client.post(url, post_data, follow=True) self.assertTemplateNotUsed(response, 'lockdown/form.html') def test_superuser(self): """Test access to a locked page which requires a superuser.""" url = '/auth/superuser/locked/view/' self.add_user(username='staff', is_staff=True) self.add_user(username='superuser', is_staff=True, is_superuser=True) # Non-superuser. post_data = {'username': 'staff', 'password': 'pw'} response = self.client.post(url, post_data, follow=True) self.assertTemplateUsed(response, 'lockdown/form.html') # Incorrect password. post_data = {'username': 'superuser', 'password': 'bad'} response = self.client.post(url, post_data, follow=True) self.assertTemplateUsed(response, 'lockdown/form.html') # Correct password. post_data = {'username': 'superuser', 'password': 'pw'} response = self.client.post(url, post_data, follow=True) self.assertTemplateNotUsed(response, 'lockdown/form.html') # Remove the BaseTests class from the module namespace, so it won't get picked # up by unittest. del BaseTests PKNFY%lockdown/templates/lockdown/base.html {% block title %}{% endblock %} {% block content %} {% endblock %} PKNFͦ/%lockdown/templates/lockdown/form.html{% extends "lockdown/base.html" %} {% block title %}Coming soon...{% endblock %} {% block content %}

Coming soon...

This is not yet available to the public.

{% if form %}
{% csrf_token %} {{ form.as_p }}

{% endif %}
{% endblock %} PKXGw##-django_lockdown-1.2.dist-info/DESCRIPTION.rst=============== django-lockdown =============== .. image:: https://travis-ci.org/Dunedan/django-lockdown.svg?branch=master :target: https://travis-ci.org/Dunedan/django-lockdown :alt: Build Status .. image:: https://coveralls.io/repos/Dunedan/django-lockdown/badge.svg :target: https://coveralls.io/r/Dunedan/django-lockdown :alt: Test Coverage .. image:: https://landscape.io/github/Dunedan/django-lockdown/master/landscape.svg?style=flat :target: https://landscape.io/github/Dunedan/django-lockdown/master :alt: Code Health .. image:: https://img.shields.io/pypi/v/django-lockdown.svg :target: https://pypi.python.org/pypi/django-lockdown/ :alt: Latest Version .. image:: https://img.shields.io/pypi/dm/django-lockdown.svg :target: https://pypi.python.org/pypi/django-lockdown/ :alt: Downloads ``django-lockdown`` is a reusable Django application for locking down an entire site (or particular views), with customizable date ranges and preview authorization. Installation ============ Install from PyPI with ``easy_install`` or ``pip``:: pip install django-lockdown To use ``django-lockdown`` in your Django project: 1. Add ``'lockdown'`` to your ``INSTALLED_APPS``. 2. To enable admin preview of locked-down sites or views with passwords, set the `LOCKDOWN_PASSWORDS`_ setting to a tuple of one or more plain-text passwords. 3. Protect the entire site by using middleware, or protect individual views by applying a decorator to them. For more advanced customization of admin preview authorization, see the `LOCKDOWN_FORM`_ setting. Dependencies ------------ ``django-lockdown`` requires `Python`_ 2.7 or later and `Django`_ 1.8 or later. .. _Python: https://www.python.org/ .. _Django: https://www.djangoproject.com/ Usage ===== Using the middleware -------------------- To lock down the entire site, add the lockdown middleware to your ``MIDDLEWARE_CLASSES`` setting:: MIDDLEWARE_CLASSES = ( # ... 'lockdown.middleware.LockdownMiddleware', ) Optionally, you may also add URL regular expressions to a `LOCKDOWN_URL_EXCEPTIONS`_ setting. Using the decorator ------------------- - Import the decorator:: from lockdown.decorators import lockdown - Apply the decorator to individual views you want to protect. For example:: @lockdown() def secret_page(request): # ... The decorator accepts six arguments: ``form`` The form to use for providing an admin preview, rather than the form referenced by `LOCKDOWN_FORM`_. Note that this must be an actual form class, not a module reference like the setting. ``until_date`` The date to use rather than the date provided by `LOCKDOWN_UNTIL`_. ``after_date`` The date to use rather than the date provided by `LOCKDOWN_AFTER`_. ``logout_key`` A preview logout key to use, rather than the one provided by `LOCKDOWN_LOGOUT_KEY`_. ``session_key`` The session key to use, rather than the one provided by `LOCKDOWN_SESSION_KEY`_. ``url_exceptions`` A list of regular expressions for which matching urls can bypass the lockdown (rather than using those defined in `LOCKDOWN_URL_EXCEPTIONS`_). Any further keyword arguments are passed to the admin preview form. The default form accepts one argument: ``passwords`` A tuple of passwords to use, rather than the ones provided by `LOCKDOWN_PASSWORDS`_. Settings ======== LOCKDOWN_ENABLED ---------------- An optional boolean value that, if set to False, disables ``django-lockdown`` globally. Defaults to True (lock down enabled). LOCKDOWN_PASSWORDS ------------------ One or more plain-text passwords which allow the previewing of the site or views protected by django-lockdown:: LOCKDOWN_PASSWORDS = ('letmein', 'beta') If this setting is not provided (and the default `LOCKDOWN_FORM`_ is being used), there will be no admin preview for locked-down pages. If a `LOCKDOWN_FORM`_ other than the default is used, this setting has no effect. LOCKDOWN_URL_EXCEPTIONS ----------------------- An optional list/tuple of regular expressions to be matched against incoming URLs. If a URL matches a regular expression in this list, it will not be locked. For example:: LOCKDOWN_URL_EXCEPTIONS = ( r'^/about/$', # unlock /about/ r'\.json$', # unlock JSON API ) LOCKDOWN_UNTIL -------------- Used to lock the site down up until a certain date. Set to a ``datetime.datetime`` object. If neither ``LOCKDOWN_UNTIL`` nor `LOCKDOWN_AFTER`_ is provided (the default), the site or views will always be locked. LOCKDOWN_AFTER -------------- Used to lock the site down after a certain date. Set to a ``datetime.datetime`` object. See also: `LOCKDOWN_UNTIL`_. LOCKDOWN_LOGOUT_KEY ------------------- A key which, if provided in the query string of a locked URL, will log out the user from the preview. LOCKDOWN_FORM ------------- The default lockdown form allows admin preview by entering a preset plain-text password (checked, by default, against the `LOCKDOWN_PASSWORDS`_ setting). To set up more advanced methods of authenticating access to locked-down pages, set ``LOCKDOWN_FORM`` to the Python dotted path to a Django ``Form`` subclass. This form will be displayed on the lockout page. If the form validates when submitted, the user will be allowed access to locked pages:: LOCKDOWN_FORM = 'path.to.my.CustomLockdownForm' A form for authenticating against ``django.contrib.auth`` users is provided with django-lockdown (use ``LOCKDOWN_FORM = 'lockdown.forms.AuthForm'``). It accepts two keyword arguments (in the ``lockdown`` decorator): ``staff_only`` Only allow staff members to preview. Defaults to ``True`` (but the default can be provided as a `LOCKDOWN_AUTHFORM_STAFF_ONLY`_ setting). ``superusers_only`` Only allow superusers to preview. Defaults to ``False`` (but the default can be provided as a `LOCKDOWN_AUTHFORM_SUPERUSERS_ONLY`_ setting). LOCKDOWN_AUTHFORM_STAFF_ONLY ---------------------------- If using ``lockdown.forms.AuthForm`` and this setting is ``True``, only staff users will be allowed to preview (True by default). Has no effect if not using ``lockdown.forms.AuthForm``. LOCKDOWN_AUTHFORM_SUPERUSERS_ONLY --------------------------------- If using ``lockdown.forms.AuthForm`` and this setting is ``True``, only superusers will be allowed to preview (False by default). Has no effect if not using ``lockdown.forms.AuthForm``. LOCKDOWN_SESSION_KEY -------------------- Once a client is authorized for admin preview, they will continue to be authorized for the remainder of their browsing session (using Django's built-in session support). ``LOCKDOWN_SESSION_KEY`` defines the session key used; the default is ``'lockdown-allow'``. Templates ========= ``django-lockdown`` uses a single template, ``lockdown/form.html``. The default template displays a simple "coming soon" message and the preview authorization form. If you want to use a different template, you can use Djangos `TEMPLATE_LOADERS`_ configuration option to specify a path inside your project to search for templates, before searching for templates included in ``django-lockdown``. In your overwritten template the lockdown preview form is available in the template context as ``form``. .. _TEMPLATE_LOADERS: https://docs.djangoproject.com/en/1.8/ref/settings/#template-loaders CHANGES ======= 1.2 (2015-12-03) ---------------- - Adds support for Python 3.5. - Adds support for Django 1.9. - Drops support for Django <=1.7. - Fixes not working URL exceptions when specifying them in the decorator arguments. - Improves tests. 1.1 (2015-04-06) ---------------- - Proper new version after 0.1.2 and 0.1.3 have been tagged after the release of 1.0. Contains all new features of 0.1.2 and 0.1.3, most notably support for Python 3. - Last version of django-lockdown with support for Django 1.3, 1.5 and 1.6. Upcoming versions will only support Django versions with official security support. For the time being these are Django 1.4 LTS, 1.7 and 1.8 LTS. - Fixes testing for Django >=1.7 0.1.3 (2014-03-15) (never released) ----------------------------------- - Added ``LOCKDOWN_ENABLED`` setting. - Removed Django 1.1 backport of ``decorator_from_middleware_with_args``. 0.1.2 (2014-03-15) (never released) ----------------------------------- - Require at least Django 1.3. - Fixed the test runner script to work with recent Django versions. - Added the csrf_token template tag to the included form template. - Minor syntax adjustments for Python 3 compatibility. 1.0 (2013-07-10) ---------------- - BACKWARDS INCOMPATIBLE: Allow multiple passwords (the passwords setting has changed from ``LOCKDOWN_PASSWORD`` to ``LOCKDOWN_PASSWORDS``). - Decorator changed to a callable decorator (so settings can be overridden for an individual decorator). - Add ``AuthForm`` which can be used to allow previewing from authenticated users (via ``django.contrib.auth``). - Allow locking up until or only after certain dates. 0.1.1 (2009-11-24) ------------------ - Fix setup.py so ``tests`` package is not installed. 0.1 (2009-11-16) ---------------- - Initial release. PKXGua  +django_lockdown-1.2.dist-info/metadata.json{"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Framework :: Django", "Framework :: Django :: 1.8", "Framework :: Django :: 1.9"], "extensions": {"python.details": {"contacts": [{"email": "danielroschka@phoenitydawn.de", "name": "Daniel Roschka", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "https://github.com/Dunedan/django-lockdown/"}}}, "extras": [], "generator": "bdist_wheel (0.26.0)", "metadata_version": "2.0", "name": "django-lockdown", "run_requires": [{"requires": ["Django (>=1.8)"]}], "summary": "Lock down a Django site or individual views, with configurable preview authorization", "version": "1.2"}PKXGҚ +django_lockdown-1.2.dist-info/top_level.txtlockdown PKXGndnn#django_lockdown-1.2.dist-info/WHEELWheel-Version: 1.0 Generator: bdist_wheel (0.26.0) Root-Is-Purelib: true Tag: py2-none-any Tag: py3-none-any PKXGyX<''&django_lockdown-1.2.dist-info/METADATAMetadata-Version: 2.0 Name: django-lockdown Version: 1.2 Summary: Lock down a Django site or individual views, with configurable preview authorization Home-page: https://github.com/Dunedan/django-lockdown/ Author: Daniel Roschka Author-email: danielroschka@phoenitydawn.de License: UNKNOWN Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Web Environment Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: BSD License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Framework :: Django Classifier: Framework :: Django :: 1.8 Classifier: Framework :: Django :: 1.9 Requires-Dist: Django (>=1.8) =============== django-lockdown =============== .. image:: https://travis-ci.org/Dunedan/django-lockdown.svg?branch=master :target: https://travis-ci.org/Dunedan/django-lockdown :alt: Build Status .. image:: https://coveralls.io/repos/Dunedan/django-lockdown/badge.svg :target: https://coveralls.io/r/Dunedan/django-lockdown :alt: Test Coverage .. image:: https://landscape.io/github/Dunedan/django-lockdown/master/landscape.svg?style=flat :target: https://landscape.io/github/Dunedan/django-lockdown/master :alt: Code Health .. image:: https://img.shields.io/pypi/v/django-lockdown.svg :target: https://pypi.python.org/pypi/django-lockdown/ :alt: Latest Version .. image:: https://img.shields.io/pypi/dm/django-lockdown.svg :target: https://pypi.python.org/pypi/django-lockdown/ :alt: Downloads ``django-lockdown`` is a reusable Django application for locking down an entire site (or particular views), with customizable date ranges and preview authorization. Installation ============ Install from PyPI with ``easy_install`` or ``pip``:: pip install django-lockdown To use ``django-lockdown`` in your Django project: 1. Add ``'lockdown'`` to your ``INSTALLED_APPS``. 2. To enable admin preview of locked-down sites or views with passwords, set the `LOCKDOWN_PASSWORDS`_ setting to a tuple of one or more plain-text passwords. 3. Protect the entire site by using middleware, or protect individual views by applying a decorator to them. For more advanced customization of admin preview authorization, see the `LOCKDOWN_FORM`_ setting. Dependencies ------------ ``django-lockdown`` requires `Python`_ 2.7 or later and `Django`_ 1.8 or later. .. _Python: https://www.python.org/ .. _Django: https://www.djangoproject.com/ Usage ===== Using the middleware -------------------- To lock down the entire site, add the lockdown middleware to your ``MIDDLEWARE_CLASSES`` setting:: MIDDLEWARE_CLASSES = ( # ... 'lockdown.middleware.LockdownMiddleware', ) Optionally, you may also add URL regular expressions to a `LOCKDOWN_URL_EXCEPTIONS`_ setting. Using the decorator ------------------- - Import the decorator:: from lockdown.decorators import lockdown - Apply the decorator to individual views you want to protect. For example:: @lockdown() def secret_page(request): # ... The decorator accepts six arguments: ``form`` The form to use for providing an admin preview, rather than the form referenced by `LOCKDOWN_FORM`_. Note that this must be an actual form class, not a module reference like the setting. ``until_date`` The date to use rather than the date provided by `LOCKDOWN_UNTIL`_. ``after_date`` The date to use rather than the date provided by `LOCKDOWN_AFTER`_. ``logout_key`` A preview logout key to use, rather than the one provided by `LOCKDOWN_LOGOUT_KEY`_. ``session_key`` The session key to use, rather than the one provided by `LOCKDOWN_SESSION_KEY`_. ``url_exceptions`` A list of regular expressions for which matching urls can bypass the lockdown (rather than using those defined in `LOCKDOWN_URL_EXCEPTIONS`_). Any further keyword arguments are passed to the admin preview form. The default form accepts one argument: ``passwords`` A tuple of passwords to use, rather than the ones provided by `LOCKDOWN_PASSWORDS`_. Settings ======== LOCKDOWN_ENABLED ---------------- An optional boolean value that, if set to False, disables ``django-lockdown`` globally. Defaults to True (lock down enabled). LOCKDOWN_PASSWORDS ------------------ One or more plain-text passwords which allow the previewing of the site or views protected by django-lockdown:: LOCKDOWN_PASSWORDS = ('letmein', 'beta') If this setting is not provided (and the default `LOCKDOWN_FORM`_ is being used), there will be no admin preview for locked-down pages. If a `LOCKDOWN_FORM`_ other than the default is used, this setting has no effect. LOCKDOWN_URL_EXCEPTIONS ----------------------- An optional list/tuple of regular expressions to be matched against incoming URLs. If a URL matches a regular expression in this list, it will not be locked. For example:: LOCKDOWN_URL_EXCEPTIONS = ( r'^/about/$', # unlock /about/ r'\.json$', # unlock JSON API ) LOCKDOWN_UNTIL -------------- Used to lock the site down up until a certain date. Set to a ``datetime.datetime`` object. If neither ``LOCKDOWN_UNTIL`` nor `LOCKDOWN_AFTER`_ is provided (the default), the site or views will always be locked. LOCKDOWN_AFTER -------------- Used to lock the site down after a certain date. Set to a ``datetime.datetime`` object. See also: `LOCKDOWN_UNTIL`_. LOCKDOWN_LOGOUT_KEY ------------------- A key which, if provided in the query string of a locked URL, will log out the user from the preview. LOCKDOWN_FORM ------------- The default lockdown form allows admin preview by entering a preset plain-text password (checked, by default, against the `LOCKDOWN_PASSWORDS`_ setting). To set up more advanced methods of authenticating access to locked-down pages, set ``LOCKDOWN_FORM`` to the Python dotted path to a Django ``Form`` subclass. This form will be displayed on the lockout page. If the form validates when submitted, the user will be allowed access to locked pages:: LOCKDOWN_FORM = 'path.to.my.CustomLockdownForm' A form for authenticating against ``django.contrib.auth`` users is provided with django-lockdown (use ``LOCKDOWN_FORM = 'lockdown.forms.AuthForm'``). It accepts two keyword arguments (in the ``lockdown`` decorator): ``staff_only`` Only allow staff members to preview. Defaults to ``True`` (but the default can be provided as a `LOCKDOWN_AUTHFORM_STAFF_ONLY`_ setting). ``superusers_only`` Only allow superusers to preview. Defaults to ``False`` (but the default can be provided as a `LOCKDOWN_AUTHFORM_SUPERUSERS_ONLY`_ setting). LOCKDOWN_AUTHFORM_STAFF_ONLY ---------------------------- If using ``lockdown.forms.AuthForm`` and this setting is ``True``, only staff users will be allowed to preview (True by default). Has no effect if not using ``lockdown.forms.AuthForm``. LOCKDOWN_AUTHFORM_SUPERUSERS_ONLY --------------------------------- If using ``lockdown.forms.AuthForm`` and this setting is ``True``, only superusers will be allowed to preview (False by default). Has no effect if not using ``lockdown.forms.AuthForm``. LOCKDOWN_SESSION_KEY -------------------- Once a client is authorized for admin preview, they will continue to be authorized for the remainder of their browsing session (using Django's built-in session support). ``LOCKDOWN_SESSION_KEY`` defines the session key used; the default is ``'lockdown-allow'``. Templates ========= ``django-lockdown`` uses a single template, ``lockdown/form.html``. The default template displays a simple "coming soon" message and the preview authorization form. If you want to use a different template, you can use Djangos `TEMPLATE_LOADERS`_ configuration option to specify a path inside your project to search for templates, before searching for templates included in ``django-lockdown``. In your overwritten template the lockdown preview form is available in the template context as ``form``. .. _TEMPLATE_LOADERS: https://docs.djangoproject.com/en/1.8/ref/settings/#template-loaders CHANGES ======= 1.2 (2015-12-03) ---------------- - Adds support for Python 3.5. - Adds support for Django 1.9. - Drops support for Django <=1.7. - Fixes not working URL exceptions when specifying them in the decorator arguments. - Improves tests. 1.1 (2015-04-06) ---------------- - Proper new version after 0.1.2 and 0.1.3 have been tagged after the release of 1.0. Contains all new features of 0.1.2 and 0.1.3, most notably support for Python 3. - Last version of django-lockdown with support for Django 1.3, 1.5 and 1.6. Upcoming versions will only support Django versions with official security support. For the time being these are Django 1.4 LTS, 1.7 and 1.8 LTS. - Fixes testing for Django >=1.7 0.1.3 (2014-03-15) (never released) ----------------------------------- - Added ``LOCKDOWN_ENABLED`` setting. - Removed Django 1.1 backport of ``decorator_from_middleware_with_args``. 0.1.2 (2014-03-15) (never released) ----------------------------------- - Require at least Django 1.3. - Fixed the test runner script to work with recent Django versions. - Added the csrf_token template tag to the included form template. - Minor syntax adjustments for Python 3 compatibility. 1.0 (2013-07-10) ---------------- - BACKWARDS INCOMPATIBLE: Allow multiple passwords (the passwords setting has changed from ``LOCKDOWN_PASSWORD`` to ``LOCKDOWN_PASSWORDS``). - Decorator changed to a callable decorator (so settings can be overridden for an individual decorator). - Add ``AuthForm`` which can be used to allow previewing from authenticated users (via ``django.contrib.auth``). - Allow locking up until or only after certain dates. 0.1.1 (2009-11-24) ------------------ - Fix setup.py so ``tests`` package is not installed. 0.1 (2009-11-16) ---------------- - Initial release. PKXGr&"<<$django_lockdown-1.2.dist-info/RECORDdjango_lockdown-1.2.dist-info/DESCRIPTION.rst,sha256=uu53Lc8dmYPQBpd0KbrapX5clnIwW9ZXzvMYv6UQYHs,9186 django_lockdown-1.2.dist-info/METADATA,sha256=SSCLEf54fGPvU4nenuUDEbuqWH4D-kzpX-ZMK6nKbyI,10119 django_lockdown-1.2.dist-info/RECORD,, django_lockdown-1.2.dist-info/WHEEL,sha256=GrqQvamwgBV4nLoJe0vhYRSWzWsx7xjlt74FT0SWYfE,110 django_lockdown-1.2.dist-info/metadata.json,sha256=WTS7fgOYaB0vJYrejSATyFUFtdmUULisCWAvUiqpSFs,1033 django_lockdown-1.2.dist-info/top_level.txt,sha256=Z9fMGPN8YOLxs5NfRJvgKJBvUoDycwZl7OAcjjeyb-k,9 lockdown/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 lockdown/decorators.py,sha256=z6GKb-ncgQBwhz5thOGl9ygF72ou6sTA5RPO-rz72j0,498 lockdown/forms.py,sha256=cymVa8V0XHSPrBZGxlIujnWoe-g0dfl4u-ak3cLktTQ,3861 lockdown/middleware.py,sha256=Wvi6etmwDZFUhSZsBCH4UQXLV5zyD7iQP6fIi0i9ZvM,5826 lockdown/settings.py,sha256=DVeMHIi8Io8207__GxpXwbW9nk-axBhi4vPGa9Q8CmM,634 lockdown/templates/lockdown/base.html,sha256=Gg73RI5sPLR9T2W2qS6c3jjW4WK6V6b-BsOV0YAVkrs,153 lockdown/templates/lockdown/form.html,sha256=yL2T2V3ial4vO3ha69TE6aSKJycLsjoc43BajhIXP8Q,384 lockdown/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 lockdown/tests/forms.py,sha256=_I3x3yHBELDRdXiXrCIbrHsznCovxl-ErS3KfLPs22k,399 lockdown/tests/test_settings.py,sha256=YZVUiLtxhpqjyA1lJkbpPLqQO1nBL0z91IbKigHr-qg,757 lockdown/tests/tests.py,sha256=AHwMrLL8Zqg76oATUz66auiiEjHY38R4MZdkAsm7sTs,14592 lockdown/tests/urls.py,sha256=KwiiGlY5bN_mJHYhg19mP5OR2kuz5E9KNOFGt8ac4ww,964 lockdown/tests/views.py,sha256=2K7JcUzVXRTsOnFAFuKe5oNlTyYDbPTkFts6hzPnJ6E,2283 PKTFlockdown/__init__.pyPKF\2lockdown/decorators.pyPK=hG[HXlockdown/forms.pyPK=hGbzzlockdown/settings.pyPKDhG5Hlockdown/middleware.pyPKFoku>+lockdown/tests/urls.pyPKF6/lockdown/tests/forms.pyPK;FxN0lockdown/tests/views.pyPKKF!:h:lockdown/tests/test_settings.pyPKܸGL=lockdown/tests/__init__.pyPKܸGq99=lockdown/tests/tests.pyPKNFY%vlockdown/templates/lockdown/base.htmlPKNFͦ/%wlockdown/templates/lockdown/form.htmlPKXGw##-Xydjango_lockdown-1.2.dist-info/DESCRIPTION.rstPKXGua  +django_lockdown-1.2.dist-info/metadata.jsonPKXGҚ +סdjango_lockdown-1.2.dist-info/top_level.txtPKXGndnn#)django_lockdown-1.2.dist-info/WHEELPKXGyX<''&آdjango_lockdown-1.2.dist-info/METADATAPKXGr&"<<$django_lockdown-1.2.dist-info/RECORDPK!