Code Monkey home page Code Monkey logo

django-basic-auth-ip-whitelist's Introduction

django-basic-auth-ip-whitelist

GitHub actions CI status

image

image

This simple package ships middleware that lets you to set basic authentication and IP whitelisting via Django settings.

Use case

This package has been created for staging and demo sites that need to be completely hidden from the Internet behind a password or accessible only to certain IP networks.

Do not depend on this package to protect highly valuable information. This package is at a good way to disable staging sites being discovered by search engines and Internet users trying to access staging sites. It is advised that any sensitive information is protected using Django authentication system.

Requirements

  • Django 1.8, 1.9, 1.10, 1.11, 2.0, 2.1, 2.2 or 3.0.
  • Python 3.4, 3.5, 3.6, 3.7 or 3.8.

Installation

The package is on PyPI so you can just install it with pip.

pip install django-basic-auth-ip-whitelist

Configuration

In your Django settings you can configure the following settings:

BASIC_AUTH_LOGIN and BASIC_AUTH_PASSWORD

Credentials that you want to use with your basic authentication.

BASIC_AUTH_WHITELISTED_IP_NETWORKS

Set a list of network ranges (strings) compatible with Python’s ipaddress.ip_network that you want to be able to access the website without authentication from. It must be either a string with networks separated by comma or Python iterable.

BASIC_AUTH_REALM

String specifying the realm of the default response.

Example settings

MIDDLEWARE += [
    'baipw.middleware.BasicAuthIPWhitelistMiddleware'
]
BASIC_AUTH_LOGIN = 'somelogin'
BASIC_AUTH_PASSWORD = 'greatpassword'
BASIC_AUTH_WHITELISTED_IP_NETWORKS = [
    '192.168.0.0/28',
    '2001:db00::0/24',
]

Advanced customisation

Getting IP

If you want to have a custom behaviour when getting IP, you can create a custom function that takes request as a parameter and specify path to it in the BASIC_AUTH_GET_CLIENT_IP_FUNCTION settings, e.g.

BASIC_AUTH_GET_CLIENT_IP_FUNCTION = 'utils.ip.get_client_ip'

BASIC_AUTH_WHITELISTED_HTTP_HOSTS

Set a list of hosts that your website will be open to without basic authentication. This is useful if your website is hosted under multiple domains and you want only one of them to be publicly visible, e.g. by search engines.

This is by no means a security feature. Please do not use to secure your site.

BASIC_AUTH_WHITELISTED_HTTP_HOSTS = [
    'your-public-domain.com',
]

BASIC_AUTH_WHITELISTED_PATHS

Set a list of paths that your website will serve without basic authentication. This can be used to support API integrations for example with third-party services which don't support basic authentication.

Paths listed in the setting BASIC_AUTH_WHITELISTED_PATHS are treated as roots, and any subpath will be whitelisted too. For example:

BASIC_AUTH_WHITELISTED_PATHS = [
    '/api',
]

This will open up the path https://mydomain.com/api/, as well as anything below it, e.g. https://mydomain.com/api/document/1/.

BASIC_AUTH_RESPONSE_TEMPLATE

If you want to display a different template on the 401 page, please use this setting to point at the template.

BASIC_AUTH_RESPONSE_TEMPLATE = '401.html'

BASIC_AUTH_RESPONSE_CLASS

If you want to specify custom response class, you can do so with this setting. Provide the path as a string.

BASIC_AUTH_RESPONSE_CLASS = 'yourmodule.response.CustomUnathorisedResponse'

BASIC_AUTH_DISABLE_CONSUMING_AUTHORIZATION_HEADER

Set this setting to True if you want the Authorization HTTP header to not be deleted from the request object after it has been used by this package's middleware.

BASIC_AUTH_DISABLE_CONSUMING_AUTHORIZATION_HEADER = True

Skip middleware

You can skip the middleware by setting _skip_basic_auth_ip_whitelist_middleware_check attribute on the request to True.

setattr(request, '_skip_basic_auth_ip_whitelist_middleware_check', True)

This may be handy if you have other middleware that you want to have co-existing different middleware that restrict access to the website.

django-basic-auth-ip-whitelist's People

Contributors

nimasmi avatar thibaudcolas avatar tm-kn avatar todd-dembrey avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

django-basic-auth-ip-whitelist's Issues

ValueError in Azure App Service

👋 Trying to run this on a Wagtail project in Azure App Service (containerised), I’m getting the following exception:

ValueError: '147.243.178.14:13250' does not appear to be an IPv4 or IPv6 address

Full stack trace:

[…]
  File "/usr/local/lib/python3.8/site-packages/baipw/middleware.py", line 18, in __call__
    response = self.process_request(request)
  File "/usr/local/lib/python3.8/site-packages/baipw/middleware.py", line 35, in process_request
    if self._is_ip_whitelisted(request):
  File "/usr/local/lib/python3.8/site-packages/baipw/middleware.py", line 128, in _is_ip_whitelisted
    ip_address = ipaddress.ip_address(self._get_client_ip(request))
  File "/usr/local/lib/python3.8/ipaddress.py", line 53, in ip_address
    raise ValueError('%r does not appear to be an IPv4 or IPv6 address' %
ValueError: '147.243.178.14:13250' does not appear to be an IPv4 or IPv6 address

This looks like it would be due to the port. It’s not too clear to me which HTTP header might contain it though. Here is my hacky workaround to remove the port:

Edit: removed as my workaround was only working locally when manually setting a few specific headers.

One-liner to try this out:

curl -I --header 'X-Forwarded-For: 147.243.178.14:13250' http://localhost:8000/

Plan out new ways of getting an IP

  • Make it more generic.
    • Third party libraries?
    • Pluggable backends?
    • Configurable rules for different providers?
  • Make user's IP address won't crash the server.

Related: #7, #4

Perhaps this needs to be improved, or at least documented

https://github.com/tm-kn/django-basic-auth-ip-whitelist/blob/318006b15b598c035cf52031c8fa63dbf241440f/baipw/utils.py#L23

This is the situation:

  • this default get_client_ip is called by self._get_client_ip()
  • which takes whatever this returns and passes it to ipaddress.ip_address()
  • which doesn't accept None as an input
  • so if this code path is hit, ipaddress.ip_address() will exception out
  • but baipw doesn't handle this exception, so it just escalates up, and the whole app just ends up 500-ing.

So this code path is problematic, if there isn't a saner return, then at least maybe warn others that if this code branch is hit, the app will blow up.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.