From 6fbf72d0e7334f206ace423a356091424536e775 Mon Sep 17 00:00:00 2001 From: meeb Date: Fri, 19 Feb 2021 12:58:34 +1100 Subject: [PATCH] optional basic HTTP authentication, resolves #62 --- Pipfile | 1 + Pipfile.lock | 10 ++++- README.md | 40 ++++++++++++++++++- tubesync/common/middleware.py | 11 +++++ tubesync/tubesync/local_settings.py.container | 12 ++++++ tubesync/tubesync/settings.py | 7 ++++ 6 files changed, 79 insertions(+), 2 deletions(-) diff --git a/Pipfile b/Pipfile index 03e83ad..7f93ee7 100644 --- a/Pipfile +++ b/Pipfile @@ -17,6 +17,7 @@ httptools = "*" youtube-dl = "*" django-background-tasks = "*" requests = "*" +django-basicauth = "*" [requires] python_version = "3" diff --git a/Pipfile.lock b/Pipfile.lock index f3c0553..6b2df6a 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "a4bb556fc61ee4583f9588980450b071814298ee4d1a1023fad149c14d14aaba" + "sha256": "f698e2853dec2d325d2d7e752620fc81d911022d394a57f2f8a9349ac2682752" }, "pipfile-spec": 6, "requires": { @@ -59,6 +59,14 @@ "index": "pypi", "version": "==1.2.5" }, + "django-basicauth": { + "hashes": [ + "sha256:15e9e366f698f53c71b1e794dafea060f990a2ac556bae6b7330dd25324a091c", + "sha256:e5e47d1acdc1943bedcc1bf673059d6c15e257dfe9eef67a22fb824f79546c0d" + ], + "index": "pypi", + "version": "==0.5.3" + }, "django-compat": { "hashes": [ "sha256:3ac9a3bedc56b9365d9eb241bc5157d0c193769bf995f9a78dc1bc24e7c2331b" diff --git a/README.md b/README.md index 8c7ea29..146e234 100644 --- a/README.md +++ b/README.md @@ -139,6 +139,40 @@ Alternatively, for Docker Compose, you can use something like: - PGID=1000 ``` + +## Optional authentication + +If you want to enable a basic username and password to be required to access the +TubeSync dashboard you can set them with the following environment variables: + +```bash +HTTP_USER +HTTP_PASS +``` + +For example in the `docker run ...` line add in: + +```bash +... +-e HTTP_USER=some-username \ +-e HTTP_PASS=some-secure-password \ +... +``` + +Or in your Docker Compose file you would add in: + +```yaml +... + environment: + - HTTP_USER=some-username + - HTTP_PASS=some-secure-password +... +``` + +When BOTH `HTTP_USER` and `HTTP_PASS` are set then basic HTTP authentication will be +enabled. + + # Updating To update, you can just pull a new version of the container image as they are released. @@ -300,7 +334,9 @@ can log in at http://localhost:4848/admin ### Are there user accounts or multi-user support? -No not at the moment. This could be added later if there is demand for it. +There is support for basic HTTP authentication by setting the `HTTP_USER` and +`HTTP_PASS` environment variables. There is not support for multi-user or user +management. ### Does TubeSync support HTTPS? @@ -328,6 +364,8 @@ useful if you are manually installing TubeSync in some other environment. These | GUNICORN_WORKERS | Number of gunicorn workers to spawn | 3 | | LISTEN_HOST | IP address for gunicorn to listen on | 127.0.0.1 | | LISTEN_PORT | Port number for gunicorn to listen on | 8080 | +| HTTP_USER | Sets the username for HTTP basic authentication | some-username | +| HTTP_PASS | Sets the password for HTTP basic authentication | some-secure-password | # Manual, non-containerised, installation diff --git a/tubesync/common/middleware.py b/tubesync/common/middleware.py index 17b97b0..3f46c48 100644 --- a/tubesync/common/middleware.py +++ b/tubesync/common/middleware.py @@ -1,4 +1,6 @@ +from django.conf import settings from django.forms import BaseForm +from basicauth.middleware import BasicAuthMiddleware as BaseBasicAuthMiddleware class MaterializeDefaultFieldsMiddleware: @@ -19,3 +21,12 @@ class MaterializeDefaultFieldsMiddleware: for _, field in v.fields.items(): field.widget.attrs.update({'class':'browser-default'}) return response + + +class BasicAuthMiddleware(BaseBasicAuthMiddleware): + + def process_request(self, request): + bypass_uris = getattr(settings, 'BASICAUTH_ALWAYS_ALLOW_URIS', []) + if request.path in bypass_uris: + return None + return super().process_request(request) diff --git a/tubesync/tubesync/local_settings.py.container b/tubesync/tubesync/local_settings.py.container index dbc104a..39840e4 100644 --- a/tubesync/tubesync/local_settings.py.container +++ b/tubesync/tubesync/local_settings.py.container @@ -38,3 +38,15 @@ if BACKGROUND_TASK_ASYNC_THREADS > MAX_BACKGROUND_TASK_ASYNC_THREADS: MEDIA_ROOT = CONFIG_BASE_DIR / 'media' DOWNLOAD_ROOT = DOWNLOADS_BASE_DIR YOUTUBE_DL_CACHEDIR = CONFIG_BASE_DIR / 'cache' + + +BASICAUTH_USERNAME = os.getenv('HTTP_USER', '').strip() +BASICAUTH_PASSWORD = os.getenv('HTTP_PASS', '').strip() +if BASICAUTH_USERNAME and BASICAUTH_PASSWORD: + BASICAUTH_DISABLE = False + BASICAUTH_USERS = { + BASICAUTH_USERNAME: BASICAUTH_PASSWORD, + } +else: + BASICAUTH_DISABLE = True + BASICAUTH_USERS = {} diff --git a/tubesync/tubesync/settings.py b/tubesync/tubesync/settings.py index 8f73ade..90e9c2c 100644 --- a/tubesync/tubesync/settings.py +++ b/tubesync/tubesync/settings.py @@ -37,6 +37,7 @@ MIDDLEWARE = [ 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'whitenoise.middleware.WhiteNoiseMiddleware', 'common.middleware.MaterializeDefaultFieldsMiddleware', + 'common.middleware.BasicAuthMiddleware', ] @@ -117,6 +118,12 @@ Disallow: / X_FRAME_OPTIONS = 'SAMEORIGIN' +BASICAUTH_DISABLE = True +BASICAUTH_REALM = 'Authenticate to TubeSync' +BASICAUTH_ALWAYS_ALLOW_URIS = ('/healthcheck',) +BASICAUTH_USERS = {} + + HEALTHCHECK_FIREWALL = True HEALTHCHECK_ALLOWED_IPS = ('127.0.0.1',)