From ab5cb7210a0c42e9248dce72dea0029a29a2479a Mon Sep 17 00:00:00 2001 From: Viicos <65306057+Viicos@users.noreply.github.com> Date: Wed, 14 Feb 2024 11:24:41 +0100 Subject: [PATCH 01/15] Replace drepecated `uget*` calls --- src/objecttypes/accounts/models.py | 2 +- src/objecttypes/api/serializers.py | 2 +- src/objecttypes/api/v1/views.py | 2 +- src/objecttypes/api/v2/views.py | 2 +- src/objecttypes/api/validators.py | 2 +- src/objecttypes/core/admin.py | 2 +- src/objecttypes/core/constants.py | 2 +- src/objecttypes/core/forms.py | 2 +- src/objecttypes/core/models.py | 2 +- src/objecttypes/token/authentication.py | 2 +- src/objecttypes/token/management/commands/generate_token.py | 2 +- src/objecttypes/token/models.py | 2 +- src/objecttypes/utils/autoschema.py | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/objecttypes/accounts/models.py b/src/objecttypes/accounts/models.py index 53911146..dfbca325 100644 --- a/src/objecttypes/accounts/models.py +++ b/src/objecttypes/accounts/models.py @@ -1,7 +1,7 @@ from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin from django.db import models from django.utils import timezone -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from .managers import UserManager diff --git a/src/objecttypes/api/serializers.py b/src/objecttypes/api/serializers.py index 3b2285af..4014b4b9 100644 --- a/src/objecttypes/api/serializers.py +++ b/src/objecttypes/api/serializers.py @@ -1,4 +1,4 @@ -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from rest_framework import serializers from rest_framework_nested.relations import NestedHyperlinkedRelatedField diff --git a/src/objecttypes/api/v1/views.py b/src/objecttypes/api/v1/views.py index 76fce8de..3fe5469b 100644 --- a/src/objecttypes/api/v1/views.py +++ b/src/objecttypes/api/v1/views.py @@ -1,4 +1,4 @@ -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from drf_spectacular.utils import extend_schema, extend_schema_view from rest_framework import viewsets diff --git a/src/objecttypes/api/v2/views.py b/src/objecttypes/api/v2/views.py index f2325e07..57966164 100644 --- a/src/objecttypes/api/v2/views.py +++ b/src/objecttypes/api/v2/views.py @@ -1,4 +1,4 @@ -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from drf_spectacular.utils import extend_schema, extend_schema_view from rest_framework import viewsets diff --git a/src/objecttypes/api/validators.py b/src/objecttypes/api/validators.py index ccfc47db..23ede440 100644 --- a/src/objecttypes/api/validators.py +++ b/src/objecttypes/api/validators.py @@ -1,5 +1,5 @@ from django.core.exceptions import ValidationError -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from rest_framework import serializers diff --git a/src/objecttypes/core/admin.py b/src/objecttypes/core/admin.py index 3aa797aa..0d4b4af9 100644 --- a/src/objecttypes/core/admin.py +++ b/src/objecttypes/core/admin.py @@ -6,7 +6,7 @@ from django.shortcuts import redirect, render from django.urls import path, reverse from django.utils.html import format_html -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from jsonsuit.widgets import READONLY_WIDGET_MEDIA_CSS, READONLY_WIDGET_MEDIA_JS from sharing_configs.admin import SharingConfigsExportMixin, SharingConfigsImportMixin diff --git a/src/objecttypes/core/constants.py b/src/objecttypes/core/constants.py index a77fbe20..e96ae205 100644 --- a/src/objecttypes/core/constants.py +++ b/src/objecttypes/core/constants.py @@ -1,4 +1,4 @@ -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from djchoices import ChoiceItem, DjangoChoices diff --git a/src/objecttypes/core/forms.py b/src/objecttypes/core/forms.py index 88bd0cd2..a48b5519 100644 --- a/src/objecttypes/core/forms.py +++ b/src/objecttypes/core/forms.py @@ -2,7 +2,7 @@ from django import forms from django.core.exceptions import ValidationError -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ import requests from rest_framework import exceptions diff --git a/src/objecttypes/core/models.py b/src/objecttypes/core/models.py index e96958d8..06f8c227 100644 --- a/src/objecttypes/core/models.py +++ b/src/objecttypes/core/models.py @@ -2,7 +2,7 @@ from datetime import date from django.db import models -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from .constants import ( DataClassificationChoices, diff --git a/src/objecttypes/token/authentication.py b/src/objecttypes/token/authentication.py index 925d108a..c5c8bf71 100644 --- a/src/objecttypes/token/authentication.py +++ b/src/objecttypes/token/authentication.py @@ -1,4 +1,4 @@ -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from rest_framework import exceptions from rest_framework.authentication import TokenAuthentication as _TokenAuthentication diff --git a/src/objecttypes/token/management/commands/generate_token.py b/src/objecttypes/token/management/commands/generate_token.py index acdc56fe..418a0a4f 100644 --- a/src/objecttypes/token/management/commands/generate_token.py +++ b/src/objecttypes/token/management/commands/generate_token.py @@ -1,5 +1,5 @@ from django.core.management import BaseCommand -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from objecttypes.token.models import TokenAuth diff --git a/src/objecttypes/token/models.py b/src/objecttypes/token/models.py index 3a73a552..cb8818c7 100644 --- a/src/objecttypes/token/models.py +++ b/src/objecttypes/token/models.py @@ -2,7 +2,7 @@ import os from django.db import models -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ class TokenAuth(models.Model): diff --git a/src/objecttypes/utils/autoschema.py b/src/objecttypes/utils/autoschema.py index c5a32ffc..f29302ec 100644 --- a/src/objecttypes/utils/autoschema.py +++ b/src/objecttypes/utils/autoschema.py @@ -1,6 +1,6 @@ from uuid import UUID -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from drf_spectacular.openapi import AutoSchema as _AutoSchema from drf_spectacular.utils import OpenApiParameter From 60b5e10aeb42248b19f3ad1051e4a31ca6350f92 Mon Sep 17 00:00:00 2001 From: Viicos <65306057+Viicos@users.noreply.github.com> Date: Wed, 14 Feb 2024 11:24:56 +0100 Subject: [PATCH 02/15] Update `isort` config Remove deprecated option, use profiles --- setup.cfg | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/setup.cfg b/setup.cfg index cf5b7f91..1bd47879 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,18 +1,15 @@ [pycodestyle] -[pep8] ignore=W293,W291,E501,E261 max-line-length=88 exclude=migrations,static,media [isort] +profile = black combine_as_imports = true -default_section = THIRDPARTY -include_trailing_comma = true -line_length = 88 -multi_line_output = 3 -skip = env,node_modules +skip = + env + node_modules skip_glob = **/migrations/** -not_skip = __init__.py known_django=django known_first_party=objecttypes sections=FUTURE,STDLIB,DJANGO,THIRDPARTY,FIRSTPARTY,LOCALFOLDER From 7d03ff2aefabc524792d57529a190bf11f2f0207 Mon Sep 17 00:00:00 2001 From: Viicos <65306057+Viicos@users.noreply.github.com> Date: Wed, 14 Feb 2024 11:29:18 +0100 Subject: [PATCH 03/15] Upgrade GH action versions --- .github/workflows/ci.yml | 10 +++++----- .github/workflows/code-quality.yml | 10 +++++----- .github/workflows/generate-postman-collection.yml | 4 ++-- .github/workflows/generate-sdks.yml | 4 ++-- .github/workflows/lint-oas.yml | 4 ++-- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 121de9e9..bad1cc9b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,11 +28,11 @@ jobs: options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 with: python-version: '3.10' - - uses: actions/setup-node@v2-beta + - uses: actions/setup-node@v4 with: node-version: '18' @@ -61,7 +61,7 @@ jobs: DB_PASSWORD: '' - name: Publish coverage report - uses: codecov/codecov-action@v1 + uses: codecov/codecov-action@v4 docker: needs: tests @@ -70,7 +70,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set tag id: vars diff --git a/.github/workflows/code-quality.yml b/.github/workflows/code-quality.yml index 3a0a2b90..4e99398e 100644 --- a/.github/workflows/code-quality.yml +++ b/.github/workflows/code-quality.yml @@ -8,11 +8,11 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 with: python-version: '3.10' - - uses: isort/isort-action@v0.1.0 + - uses: isort/isort-action@v1 with: requirementsFiles: requirements/dev.txt sortPaths: "src" @@ -23,8 +23,8 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 with: python-version: '3.10' - name: Install dependencies diff --git a/.github/workflows/generate-postman-collection.yml b/.github/workflows/generate-postman-collection.yml index fb4a1452..7aa8d6f8 100644 --- a/.github/workflows/generate-postman-collection.yml +++ b/.github/workflows/generate-postman-collection.yml @@ -19,9 +19,9 @@ jobs: name: Run with version ${{ matrix.version }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Use Node.js - uses: actions/setup-node@v1 + uses: actions/setup-node@v4 with: node-version: '18' - name: Install dependencies diff --git a/.github/workflows/generate-sdks.yml b/.github/workflows/generate-sdks.yml index 77b523c1..7109e0de 100644 --- a/.github/workflows/generate-sdks.yml +++ b/.github/workflows/generate-sdks.yml @@ -19,9 +19,9 @@ jobs: name: Run with version ${{ matrix.version }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Use Node.js - uses: actions/setup-node@v1 + uses: actions/setup-node@v4 with: node-version: '18' - name: Install dependencies diff --git a/.github/workflows/lint-oas.yml b/.github/workflows/lint-oas.yml index f058475c..d9749b55 100644 --- a/.github/workflows/lint-oas.yml +++ b/.github/workflows/lint-oas.yml @@ -19,9 +19,9 @@ jobs: name: Run with version ${{ matrix.version }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Use Node.js - uses: actions/setup-node@v1 + uses: actions/setup-node@v4 with: node-version: '18' - name: Install spectral From 297df31f3559fe387cbf03bd0acf76d9d79f67c5 Mon Sep 17 00:00:00 2001 From: Viicos <65306057+Viicos@users.noreply.github.com> Date: Wed, 14 Feb 2024 11:35:52 +0100 Subject: [PATCH 04/15] Switch to `requires_context` for DRF --- src/objecttypes/api/validators.py | 34 +++++++++---------------------- 1 file changed, 10 insertions(+), 24 deletions(-) diff --git a/src/objecttypes/api/validators.py b/src/objecttypes/api/validators.py index 23ede440..7bd692be 100644 --- a/src/objecttypes/api/validators.py +++ b/src/objecttypes/api/validators.py @@ -10,21 +10,14 @@ class VersionUpdateValidator: message = _("Only draft versions can be changed") code = "non-draft-version-update" + requires_context = True - def set_context(self, serializer): - """ - This hook is called by the serializer instance, - prior to the validation call being made. - """ - # Determine the existing instance, if this is an update operation. - self.instance = getattr(serializer, "instance", None) - self.request = serializer.context["request"] - - def __call__(self, attrs): - if not self.instance: + def __call__(self, attrs, serializer): + instance = getattr(serializer, "instance", None) + if not instance: return - if self.instance.status != ObjectVersionStatus.draft: + if instance.status != ObjectVersionStatus.draft: raise serializers.ValidationError(self.message, code=self.code) @@ -45,22 +38,15 @@ class IsImmutableValidator: message = _("This field can't be changed") code = "immutable-field" + requires_context = True - def set_context(self, serializer_field): - """ - This hook is called by the serializer instance, - prior to the validation call being made. - """ - # Determine the existing instance, if this is an update operation. - self.serializer_field = serializer_field - self.instance = getattr(serializer_field.parent, "instance", None) - - def __call__(self, new_value): + def __call__(self, new_value, serializer_field): # no instance -> it's not an update - if not self.instance: + instance = getattr(serializer_field.parent, "instance", None) + if not instance: return - current_value = getattr(self.instance, self.serializer_field.source) + current_value = getattr(instance, serializer_field.source) if new_value != current_value: raise serializers.ValidationError(self.message, code=self.code) From 2b6b2ba1b812193c4598ee78e160cc8dc7633d89 Mon Sep 17 00:00:00 2001 From: Viicos <65306057+Viicos@users.noreply.github.com> Date: Wed, 14 Feb 2024 11:36:55 +0100 Subject: [PATCH 05/15] Remove deprecated `default_app_config` --- src/objecttypes/accounts/__init__.py | 1 - src/objecttypes/utils/__init__.py | 1 - 2 files changed, 2 deletions(-) diff --git a/src/objecttypes/accounts/__init__.py b/src/objecttypes/accounts/__init__.py index 3ef458c7..e69de29b 100644 --- a/src/objecttypes/accounts/__init__.py +++ b/src/objecttypes/accounts/__init__.py @@ -1 +0,0 @@ -default_app_config = "objecttypes.accounts.apps.AccountsConfig" diff --git a/src/objecttypes/utils/__init__.py b/src/objecttypes/utils/__init__.py index ef53cf91..e69de29b 100644 --- a/src/objecttypes/utils/__init__.py +++ b/src/objecttypes/utils/__init__.py @@ -1 +0,0 @@ -default_app_config = "objecttypes.utils.apps.UtilsConfig" From cabdcd9532d4e306a5d97e520277d32433140f47 Mon Sep 17 00:00:00 2001 From: Viicos <65306057+Viicos@users.noreply.github.com> Date: Wed, 14 Feb 2024 11:44:42 +0100 Subject: [PATCH 06/15] Remove usage of `django-choices` --- requirements/base.in | 1 - requirements/base.txt | 4 +--- src/objecttypes/core/constants.py | 39 ++++++++++++++----------------- 3 files changed, 19 insertions(+), 25 deletions(-) diff --git a/requirements/base.in b/requirements/base.in index 9491acfd..57be6ad6 100644 --- a/requirements/base.in +++ b/requirements/base.in @@ -10,7 +10,6 @@ jsonschema django django-admin-index django-axes -django-choices django-hijack django-jsonsuit django-redis diff --git a/requirements/base.txt b/requirements/base.txt index 44012b56..778cfd79 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -95,9 +95,7 @@ django-admin-index==3.0.0 django-axes==5.41.1 # via -r requirements/base.in django-choices==1.7.2 - # via - # -r requirements/base.in - # commonground-api-common + # via commonground-api-common django-filter==23.2 # via # -r requirements/base.in diff --git a/src/objecttypes/core/constants.py b/src/objecttypes/core/constants.py index e96ae205..d795b06f 100644 --- a/src/objecttypes/core/constants.py +++ b/src/objecttypes/core/constants.py @@ -1,28 +1,25 @@ +from django.db import models from django.utils.translation import gettext_lazy as _ -from djchoices import ChoiceItem, DjangoChoices +class ObjectVersionStatus(models.TextChoices): + published = "published", _("Published") + draft = "draft", _("Draft") + deprecated = "deprecated", _("Deprecated") -class ObjectVersionStatus(DjangoChoices): - published = ChoiceItem("published", _("Published")) - draft = ChoiceItem("draft", _("Draft")) - deprecated = ChoiceItem("deprecated", _("Deprecated")) +class DataClassificationChoices(models.TextChoices): + open = "open", _("Open") + intern = "intern", _("Intern") + confidential = "confidential", _("Confidential") + strictly_confidential = "strictly_confidential", _("Strictly confidential") -class DataClassificationChoices(DjangoChoices): - open = ChoiceItem("open", _("Open")) - intern = ChoiceItem("intern", _("Intern")) - confidential = ChoiceItem("confidential", _("Confidential")) - strictly_confidential = ChoiceItem( - "strictly_confidential", _("Strictly confidential") - ) - -class UpdateFrequencyChoices(DjangoChoices): - real_time = ChoiceItem("real_time", _("Real-time")) - hourly = ChoiceItem("hourly", _("Hourly")) - daily = ChoiceItem("daily", _("Daily")) - weekly = ChoiceItem("weekly", _("Weekly")) - monthly = ChoiceItem("monthly", _("Monthly")) - yearly = ChoiceItem("yearly", _("Yearly")) - unknown = ChoiceItem("unknown", _("Unknown")) +class UpdateFrequencyChoices(models.TextChoices): + real_time = "real_time", _("Real-time") + hourly = "hourly", _("Hourly") + daily = "daily", _("Daily") + weekly = "weekly", _("Weekly") + monthly = "monthly", _("Monthly") + yearly = "yearly", _("Yearly") + unknown = "unknown", _("Unknown") From 83a9fb66678fa59797607b6919b7b7d63f50de83 Mon Sep 17 00:00:00 2001 From: Viicos <65306057+Viicos@users.noreply.github.com> Date: Wed, 14 Feb 2024 11:51:46 +0100 Subject: [PATCH 07/15] Remove `django-hijack` and `django-sniplates` --- requirements/base.in | 2 -- requirements/base.txt | 6 ------ requirements/ci.txt | 6 ------ requirements/dev.txt | 6 ------ src/objecttypes/conf/base.py | 19 ++----------------- src/objecttypes/urls.py | 1 - 6 files changed, 2 insertions(+), 38 deletions(-) diff --git a/requirements/base.in b/requirements/base.in index 57be6ad6..df9c8322 100644 --- a/requirements/base.in +++ b/requirements/base.in @@ -10,11 +10,9 @@ jsonschema django django-admin-index django-axes -django-hijack django-jsonsuit django-redis django-rosetta -django-sniplates maykin-django-two-factor-auth maykin-django-two-factor-auth[phonenumbers] mozilla-django-oidc-db diff --git a/requirements/base.txt b/requirements/base.txt index 778cfd79..5ddbc790 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -67,7 +67,6 @@ django==3.2.20 # django-choices # django-filter # django-formtools - # django-hijack # django-jsonform # django-jsonsuit # django-otp @@ -78,7 +77,6 @@ django==3.2.20 # django-rest-framework-condition # django-rosetta # django-simple-certmanager - # django-sniplates # django-solo # djangorestframework # drf-nested-routers @@ -102,8 +100,6 @@ django-filter==23.2 # commonground-api-common django-formtools==2.4.1 # via maykin-django-two-factor-auth -django-hijack==3.3.0 - # via -r requirements/base.in django-ipware==6.0.3 # via django-axes django-jsonform==2.21.5 @@ -130,8 +126,6 @@ django-sendfile2==0.7.0 # via django-privates django-simple-certmanager==1.3.0 # via zgw-consumers -django-sniplates==0.7.1 - # via -r requirements/base.in django-solo==2.0.0 # via # commonground-api-common diff --git a/requirements/ci.txt b/requirements/ci.txt index 95606130..3b71d429 100644 --- a/requirements/ci.txt +++ b/requirements/ci.txt @@ -101,7 +101,6 @@ django==3.2.20 # django-choices # django-filter # django-formtools - # django-hijack # django-jenkins # django-jsonform # django-jsonsuit @@ -114,7 +113,6 @@ django==3.2.20 # django-rosetta # django-sendfile2 # django-simple-certmanager - # django-sniplates # django-solo # djangorestframework # drf-nested-routers @@ -142,8 +140,6 @@ django-formtools==2.4.1 # via # -r requirements/base.txt # maykin-django-two-factor-auth -django-hijack==3.3.0 - # via -r requirements/base.txt django-ipware==6.0.3 # via # -r requirements/base.txt @@ -192,8 +188,6 @@ django-simple-certmanager==1.3.0 # via # -r requirements/base.txt # zgw-consumers -django-sniplates==0.7.1 - # via -r requirements/base.txt django-solo==2.0.0 # via # -r requirements/base.txt diff --git a/requirements/dev.txt b/requirements/dev.txt index 84059270..f2fd361f 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -121,7 +121,6 @@ django==3.2.20 # django-extensions # django-filter # django-formtools - # django-hijack # django-jenkins # django-jsonform # django-jsonsuit @@ -134,7 +133,6 @@ django==3.2.20 # django-rosetta # django-sendfile2 # django-simple-certmanager - # django-sniplates # django-solo # djangorestframework # drf-nested-routers @@ -166,8 +164,6 @@ django-formtools==2.4.1 # via # -r requirements/ci.txt # maykin-django-two-factor-auth -django-hijack==3.3.0 - # via -r requirements/ci.txt django-ipware==6.0.3 # via # -r requirements/ci.txt @@ -216,8 +212,6 @@ django-simple-certmanager==1.3.0 # via # -r requirements/ci.txt # zgw-consumers -django-sniplates==0.7.1 - # via -r requirements/ci.txt django-solo==2.0.0 # via # -r requirements/ci.txt diff --git a/src/objecttypes/conf/base.py b/src/objecttypes/conf/base.py index 1439eb18..6adeff73 100644 --- a/src/objecttypes/conf/base.py +++ b/src/objecttypes/conf/base.py @@ -1,6 +1,5 @@ import os -# Django-hijack (and Django-hijack-admin) from django.urls import reverse_lazy from sentry_sdk.integrations import django, redis @@ -71,9 +70,6 @@ # External applications. "axes", "jsonsuit.apps.JSONSuitConfig", - "sniplates", - "hijack", - "hijack.contrib.admin", "mozilla_django_oidc", "mozilla_django_oidc_db", "django_jsonform", @@ -106,7 +102,6 @@ "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", "axes.middleware.AxesMiddleware", - "hijack.middleware.HijackUserMiddleware", "django_otp.middleware.OTPMiddleware", ] @@ -358,22 +353,12 @@ "REMOTE_ADDR", ) -# Django-Hijack -HIJACK_LOGIN_REDIRECT_URL = "/" -HIJACK_LOGOUT_REDIRECT_URL = reverse_lazy("admin:accounts_user_changelist") -# The Admin mixin is used because we use a custom User-model. -HIJACK_REGISTER_ADMIN = False -# This is a CSRF-security risk. -# See: http://django-hijack.readthedocs.io/en/latest/configuration/#allowing-get-method-for-hijack-views -HIJACK_ALLOW_GET_REQUESTS = True - # # Sending EMAIL # EMAIL_HOST = config("EMAIL_HOST", default="localhost") -EMAIL_PORT = config( - "EMAIL_PORT", default=25 -) # disabled on Google Cloud, use 487 instead +# disabled on Google Cloud, use 487 instead: +EMAIL_PORT = config("EMAIL_PORT", default=25) EMAIL_HOST_USER = config("EMAIL_HOST_USER", default="") EMAIL_HOST_PASSWORD = config("EMAIL_HOST_PASSWORD", default="") EMAIL_USE_TLS = config("EMAIL_USE_TLS", default=False) diff --git a/src/objecttypes/urls.py b/src/objecttypes/urls.py index c26a583c..b02f064d 100644 --- a/src/objecttypes/urls.py +++ b/src/objecttypes/urls.py @@ -25,7 +25,6 @@ auth_views.PasswordResetDoneView.as_view(), name="password_reset_done", ), - path("admin/hijack/", include("hijack.urls")), path("admin/", admin.site.urls), path( "reset///", From 8e4531775e026a33c547b23fb5febe7ef78dc239 Mon Sep 17 00:00:00 2001 From: Viicos <65306057+Viicos@users.noreply.github.com> Date: Wed, 14 Feb 2024 14:08:52 +0100 Subject: [PATCH 08/15] Bump some requirements required for the next `commonground-api-common` update --- requirements/base.txt | 19 +++++-------------- requirements/ci.txt | 22 ++++------------------ requirements/dev.txt | 22 ++++------------------ 3 files changed, 13 insertions(+), 50 deletions(-) diff --git a/requirements/base.txt b/requirements/base.txt index 5ddbc790..d5cbd282 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -44,14 +44,12 @@ click-plugins==1.1.1 # via celery click-repl==0.2.0 # via celery -commonground-api-common==1.10.2 +commonground-api-common==1.12.1 # via -r requirements/base.in coreapi==2.3.3 - # via drf-yasg + # via commonground-api-common coreschema==0.0.4 - # via - # coreapi - # drf-yasg + # via coreapi cryptography==40.0.2 # via # django-simple-certmanager @@ -64,7 +62,6 @@ django==3.2.20 # commonground-api-common # django-admin-index # django-axes - # django-choices # django-filter # django-formtools # django-jsonform @@ -92,8 +89,6 @@ django-admin-index==3.0.0 # via -r requirements/base.in django-axes==5.41.1 # via -r requirements/base.in -django-choices==1.7.2 - # via commonground-api-common django-filter==23.2 # via # -r requirements/base.in @@ -151,7 +146,7 @@ drf-nested-routers==0.93.4 # commonground-api-common drf-spectacular==0.16.0 # via -r requirements/base.in -drf-yasg==1.21.5 +drf-yasg==1.21.7 # via commonground-api-common elastic-apm==6.15.1 # via -r requirements/base.in @@ -245,6 +240,7 @@ pyyaml==6.0 # via # commonground-api-common # drf-spectacular + # drf-yasg # gemma-zds-client # oyaml qrcode==6.1 @@ -263,10 +259,6 @@ requests==2.31.0 # zgw-consumers requests-mock==1.10.0 # via zgw-consumers -ruamel-yaml==0.17.26 - # via drf-yasg -ruamel-yaml-clib==0.2.7 - # via ruamel-yaml sentry-sdk==1.23.1 # via -r requirements/base.in sharing-configs==0.1.2 @@ -274,7 +266,6 @@ sharing-configs==0.1.2 six==1.16.0 # via # click-repl - # django-choices # isodate # python-dateutil # qrcode diff --git a/requirements/ci.txt b/requirements/ci.txt index 3b71d429..c47c56fa 100644 --- a/requirements/ci.txt +++ b/requirements/ci.txt @@ -70,17 +70,16 @@ click-repl==0.2.0 # via # -r requirements/base.txt # celery -commonground-api-common==1.10.2 +commonground-api-common==1.12.1 # via -r requirements/base.txt coreapi==2.3.3 # via # -r requirements/base.txt - # drf-yasg + # commonground-api-common coreschema==0.0.4 # via # -r requirements/base.txt # coreapi - # drf-yasg coverage==4.5.4 # via -r requirements/test-tools.in cryptography==40.0.2 @@ -98,7 +97,6 @@ django==3.2.20 # commonground-api-common # django-admin-index # django-axes - # django-choices # django-filter # django-formtools # django-jenkins @@ -128,10 +126,6 @@ django-admin-index==3.0.0 # via -r requirements/base.txt django-axes==5.41.1 # via -r requirements/base.txt -django-choices==1.7.2 - # via - # -r requirements/base.txt - # commonground-api-common django-filter==23.2 # via # -r requirements/base.txt @@ -217,7 +211,7 @@ drf-nested-routers==0.93.4 # commonground-api-common drf-spectacular==0.16.0 # via -r requirements/base.txt -drf-yasg==1.21.5 +drf-yasg==1.21.7 # via # -r requirements/base.txt # commonground-api-common @@ -371,6 +365,7 @@ pyyaml==6.0 # -r requirements/base.txt # commonground-api-common # drf-spectacular + # drf-yasg # gemma-zds-client # oyaml qrcode==6.1 @@ -397,14 +392,6 @@ requests-mock==1.10.0 # -r requirements/base.txt # -r requirements/test-tools.in # zgw-consumers -ruamel-yaml==0.17.26 - # via - # -r requirements/base.txt - # drf-yasg -ruamel-yaml-clib==0.2.7 - # via - # -r requirements/base.txt - # ruamel-yaml sentry-sdk==1.23.1 # via -r requirements/base.txt sharing-configs==0.1.2 @@ -413,7 +400,6 @@ six==1.16.0 # via # -r requirements/base.txt # click-repl - # django-choices # isodate # python-dateutil # qrcode diff --git a/requirements/dev.txt b/requirements/dev.txt index f2fd361f..e08479af 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -86,17 +86,16 @@ click-repl==0.2.0 # via # -r requirements/ci.txt # celery -commonground-api-common==1.10.2 +commonground-api-common==1.12.1 # via -r requirements/ci.txt coreapi==2.3.3 # via # -r requirements/ci.txt - # drf-yasg + # commonground-api-common coreschema==0.0.4 # via # -r requirements/ci.txt # coreapi - # drf-yasg coverage==4.5.4 # via -r requirements/ci.txt cryptography==40.0.2 @@ -116,7 +115,6 @@ django==3.2.20 # commonground-api-common # django-admin-index # django-axes - # django-choices # django-debug-toolbar # django-extensions # django-filter @@ -148,10 +146,6 @@ django-admin-index==3.0.0 # via -r requirements/ci.txt django-axes==5.41.1 # via -r requirements/ci.txt -django-choices==1.7.2 - # via - # -r requirements/ci.txt - # commonground-api-common django-debug-toolbar==4.1.0 # via -r requirements/dev.in django-extensions==3.2.1 @@ -245,7 +239,7 @@ drf-nested-routers==0.93.4 # commonground-api-common drf-spectacular==0.16.0 # via -r requirements/ci.txt -drf-yasg==1.21.5 +drf-yasg==1.21.7 # via # -r requirements/ci.txt # commonground-api-common @@ -429,6 +423,7 @@ pyyaml==6.0 # -r requirements/ci.txt # commonground-api-common # drf-spectacular + # drf-yasg # gemma-zds-client # oyaml qrcode==6.1 @@ -455,14 +450,6 @@ requests-mock==1.10.0 # via # -r requirements/ci.txt # zgw-consumers -ruamel-yaml==0.17.26 - # via - # -r requirements/ci.txt - # drf-yasg -ruamel-yaml-clib==0.2.7 - # via - # -r requirements/ci.txt - # ruamel-yaml sentry-sdk==1.23.1 # via -r requirements/ci.txt sharing-configs==0.1.2 @@ -471,7 +458,6 @@ six==1.16.0 # via # -r requirements/ci.txt # click-repl - # django-choices # isodate # python-dateutil # qrcode From 9c2c8cc8c58e8a2ee8c5d11a80431baa83e64695 Mon Sep 17 00:00:00 2001 From: Viicos <65306057+Viicos@users.noreply.github.com> Date: Wed, 14 Feb 2024 15:00:21 +0100 Subject: [PATCH 09/15] Use new 2FA solution --- requirements/base.in | 3 +- requirements/base.txt | 31 ++++++++++----- requirements/ci.txt | 39 ++++++++++++++----- requirements/dev.txt | 39 ++++++++++++++----- src/objecttypes/conf/base.py | 19 ++++++--- src/objecttypes/conf/ci.py | 3 -- src/objecttypes/conf/dev.py | 5 ++- .../templates/admin/base_site.html | 6 +-- src/objecttypes/templates/admin/login.html | 16 -------- .../templates/maykin_2fa/base.html | 9 +++++ .../templates/maykin_2fa/login.html | 23 +++++++++++ .../templates/two_factor/admin/login.html | 1 - .../tests/test_objecttype_admin.py | 3 ++ src/objecttypes/tests/test_sharing_configs.py | 2 + src/objecttypes/urls.py | 5 +++ 15 files changed, 142 insertions(+), 62 deletions(-) delete mode 100644 src/objecttypes/templates/admin/login.html create mode 100644 src/objecttypes/templates/maykin_2fa/base.html create mode 100644 src/objecttypes/templates/maykin_2fa/login.html delete mode 100644 src/objecttypes/templates/two_factor/admin/login.html diff --git a/requirements/base.in b/requirements/base.in index df9c8322..ea7ea985 100644 --- a/requirements/base.in +++ b/requirements/base.in @@ -13,8 +13,7 @@ django-axes django-jsonsuit django-redis django-rosetta -maykin-django-two-factor-auth -maykin-django-two-factor-auth[phonenumbers] +maykin-2fa mozilla-django-oidc-db sharing-configs diff --git a/requirements/base.txt b/requirements/base.txt index d5cbd282..71967b9d 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -8,6 +8,8 @@ amqp==5.1.1 # via kombu asgiref==3.6.0 # via django +asn1crypto==1.5.1 + # via webauthn async-timeout==4.0.2 # via redis attrs==23.1.0 @@ -20,6 +22,8 @@ boltons==23.0.0 # via # face # glom +cbor2==5.6.1 + # via webauthn celery==5.2.7 # via notifications-api-common certifi==2023.5.7 @@ -50,12 +54,13 @@ coreapi==2.3.3 # via commonground-api-common coreschema==0.0.4 # via coreapi -cryptography==40.0.2 +cryptography==42.0.2 # via # django-simple-certmanager # josepy # mozilla-django-oidc # pyopenssl + # webauthn django==3.2.20 # via # -r requirements/base.in @@ -75,11 +80,12 @@ django==3.2.20 # django-rosetta # django-simple-certmanager # django-solo + # django-two-factor-auth # djangorestframework # drf-nested-routers # drf-spectacular # drf-yasg - # maykin-django-two-factor-auth + # maykin-2fa # mozilla-django-oidc # mozilla-django-oidc-db # notifications-api-common @@ -94,7 +100,7 @@ django-filter==23.2 # -r requirements/base.in # commonground-api-common django-formtools==2.4.1 - # via maykin-django-two-factor-auth + # via django-two-factor-auth django-ipware==6.0.3 # via django-axes django-jsonform==2.21.5 @@ -104,9 +110,9 @@ django-jsonsuit==0.5.0 django-ordered-model==3.7.4 # via django-admin-index django-otp==1.2.0 - # via maykin-django-two-factor-auth + # via django-two-factor-auth django-phonenumber-field==5.2.0 - # via maykin-django-two-factor-auth + # via django-two-factor-auth django-privates==2.0.0.post0 # via django-simple-certmanager django-redis==5.2.0 @@ -128,6 +134,8 @@ django-solo==2.0.0 # notifications-api-common # sharing-configs # zgw-consumers +django-two-factor-auth[phonenumberslite,webauthn]==1.16.0 + # via maykin-2fa djangorestframework==3.12.4 # via # -r requirements/base.in @@ -185,7 +193,7 @@ kombu==5.2.4 # via celery markupsafe==2.1.2 # via jinja2 -maykin-django-two-factor-auth[phonenumbers]==2.0.4 +maykin-2fa==1.0.0 # via -r requirements/base.in mozilla-django-oidc==4.0.0 # via mozilla-django-oidc-db @@ -197,8 +205,8 @@ oyaml==1.0 # via commonground-api-common packaging==23.1 # via drf-yasg -phonenumbers==8.13.11 - # via maykin-django-two-factor-auth +phonenumberslite==8.13.30 + # via django-two-factor-auth pillow==9.5.0 # via -r requirements/base.in polib==1.2.0 @@ -213,10 +221,11 @@ pyjwt==2.7.0 # via # commonground-api-common # gemma-zds-client -pyopenssl==23.1.1 +pyopenssl==24.0.0 # via # django-simple-certmanager # josepy + # webauthn # zgw-consumers pyrsistent==0.19.3 # via jsonschema @@ -244,7 +253,7 @@ pyyaml==6.0 # gemma-zds-client # oyaml qrcode==6.1 - # via maykin-django-two-factor-auth + # via django-two-factor-auth redis==4.5.5 # via django-redis requests==2.31.0 @@ -291,6 +300,8 @@ vine==5.0.0 # kombu wcwidth==0.2.6 # via prompt-toolkit +webauthn==2.0.0 + # via django-two-factor-auth wrapt==1.15.0 # via elastic-apm zgw-consumers==0.26.1 diff --git a/requirements/ci.txt b/requirements/ci.txt index c47c56fa..0aceecbf 100644 --- a/requirements/ci.txt +++ b/requirements/ci.txt @@ -12,6 +12,10 @@ asgiref==3.6.0 # via # -r requirements/base.txt # django +asn1crypto==1.5.1 + # via + # -r requirements/base.txt + # webauthn async-timeout==4.0.2 # via # -r requirements/base.txt @@ -32,6 +36,10 @@ boltons==23.0.0 # -r requirements/base.txt # face # glom +cbor2==5.6.1 + # via + # -r requirements/base.txt + # webauthn celery==5.2.7 # via # -r requirements/base.txt @@ -82,13 +90,14 @@ coreschema==0.0.4 # coreapi coverage==4.5.4 # via -r requirements/test-tools.in -cryptography==40.0.2 +cryptography==42.0.2 # via # -r requirements/base.txt # django-simple-certmanager # josepy # mozilla-django-oidc # pyopenssl + # webauthn cssselect==1.2.0 # via pyquery django==3.2.20 @@ -112,11 +121,12 @@ django==3.2.20 # django-sendfile2 # django-simple-certmanager # django-solo + # django-two-factor-auth # djangorestframework # drf-nested-routers # drf-spectacular # drf-yasg - # maykin-django-two-factor-auth + # maykin-2fa # mozilla-django-oidc # mozilla-django-oidc-db # notifications-api-common @@ -133,7 +143,7 @@ django-filter==23.2 django-formtools==2.4.1 # via # -r requirements/base.txt - # maykin-django-two-factor-auth + # django-two-factor-auth django-ipware==6.0.3 # via # -r requirements/base.txt @@ -153,11 +163,11 @@ django-ordered-model==3.7.4 django-otp==1.2.0 # via # -r requirements/base.txt - # maykin-django-two-factor-auth + # django-two-factor-auth django-phonenumber-field==5.2.0 # via # -r requirements/base.txt - # maykin-django-two-factor-auth + # django-two-factor-auth django-privates==2.0.0.post0 # via # -r requirements/base.txt @@ -190,6 +200,10 @@ django-solo==2.0.0 # notifications-api-common # sharing-configs # zgw-consumers +django-two-factor-auth[phonenumberslite,webauthn]==1.16.0 + # via + # -r requirements/base.txt + # maykin-2fa django-webtest==1.9.10 # via -r requirements/test-tools.in djangorestframework==3.12.4 @@ -283,7 +297,7 @@ markupsafe==2.1.2 # via # -r requirements/base.txt # jinja2 -maykin-django-two-factor-auth[phonenumbers]==2.0.4 +maykin-2fa==1.0.0 # via -r requirements/base.txt mozilla-django-oidc==4.0.0 # via @@ -303,10 +317,10 @@ packaging==23.1 # via # -r requirements/base.txt # drf-yasg -phonenumbers==8.13.11 +phonenumberslite==8.13.30 # via # -r requirements/base.txt - # maykin-django-two-factor-auth + # django-two-factor-auth pillow==9.5.0 # via -r requirements/base.txt polib==1.2.0 @@ -328,11 +342,12 @@ pyjwt==2.7.0 # -r requirements/base.txt # commonground-api-common # gemma-zds-client -pyopenssl==23.1.1 +pyopenssl==24.0.0 # via # -r requirements/base.txt # django-simple-certmanager # josepy + # webauthn # zgw-consumers pyquery==2.0.0 # via -r requirements/test-tools.in @@ -371,7 +386,7 @@ pyyaml==6.0 qrcode==6.1 # via # -r requirements/base.txt - # maykin-django-two-factor-auth + # django-two-factor-auth redis==4.5.5 # via # -r requirements/base.txt @@ -438,6 +453,10 @@ wcwidth==0.2.6 # via # -r requirements/base.txt # prompt-toolkit +webauthn==2.0.0 + # via + # -r requirements/base.txt + # django-two-factor-auth webob==1.8.7 # via webtest webtest==3.0.0 diff --git a/requirements/dev.txt b/requirements/dev.txt index e08479af..82b0870f 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -14,6 +14,10 @@ asgiref==3.6.0 # via # -r requirements/ci.txt # django +asn1crypto==1.5.1 + # via + # -r requirements/ci.txt + # webauthn async-timeout==4.0.2 # via # -r requirements/ci.txt @@ -46,6 +50,10 @@ bump2version==1.0.1 # via bumpversion bumpversion==0.6.0 # via -r requirements/dev.in +cbor2==5.6.1 + # via + # -r requirements/ci.txt + # webauthn celery==5.2.7 # via # -r requirements/ci.txt @@ -98,13 +106,14 @@ coreschema==0.0.4 # coreapi coverage==4.5.4 # via -r requirements/ci.txt -cryptography==40.0.2 +cryptography==42.0.2 # via # -r requirements/ci.txt # django-simple-certmanager # josepy # mozilla-django-oidc # pyopenssl + # webauthn cssselect==1.2.0 # via # -r requirements/ci.txt @@ -132,11 +141,12 @@ django==3.2.20 # django-sendfile2 # django-simple-certmanager # django-solo + # django-two-factor-auth # djangorestframework # drf-nested-routers # drf-spectacular # drf-yasg - # maykin-django-two-factor-auth + # maykin-2fa # mozilla-django-oidc # mozilla-django-oidc-db # notifications-api-common @@ -157,7 +167,7 @@ django-filter==23.2 django-formtools==2.4.1 # via # -r requirements/ci.txt - # maykin-django-two-factor-auth + # django-two-factor-auth django-ipware==6.0.3 # via # -r requirements/ci.txt @@ -177,11 +187,11 @@ django-ordered-model==3.7.4 django-otp==1.2.0 # via # -r requirements/ci.txt - # maykin-django-two-factor-auth + # django-two-factor-auth django-phonenumber-field==5.2.0 # via # -r requirements/ci.txt - # maykin-django-two-factor-auth + # django-two-factor-auth django-privates==2.0.0.post0 # via # -r requirements/ci.txt @@ -214,6 +224,10 @@ django-solo==2.0.0 # notifications-api-common # sharing-configs # zgw-consumers +django-two-factor-auth[phonenumberslite,webauthn]==1.16.0 + # via + # -r requirements/ci.txt + # maykin-2fa django-webtest==1.9.10 # via -r requirements/ci.txt djangorestframework==3.12.4 @@ -320,7 +334,7 @@ markupsafe==2.1.2 # via # -r requirements/ci.txt # jinja2 -maykin-django-two-factor-auth[phonenumbers]==2.0.4 +maykin-2fa==1.0.0 # via -r requirements/ci.txt mccabe==0.7.0 # via flake8 @@ -349,10 +363,10 @@ packaging==23.1 # sphinx pathspec==0.11.1 # via black -phonenumbers==8.13.11 +phonenumberslite==8.13.30 # via # -r requirements/ci.txt - # maykin-django-two-factor-auth + # django-two-factor-auth pillow==9.5.0 # via -r requirements/ci.txt pip-tools==6.13.0 @@ -384,11 +398,12 @@ pyjwt==2.7.0 # -r requirements/ci.txt # commonground-api-common # gemma-zds-client -pyopenssl==23.1.1 +pyopenssl==24.0.0 # via # -r requirements/ci.txt # django-simple-certmanager # josepy + # webauthn # zgw-consumers pyproject-hooks==1.0.0 # via build @@ -429,7 +444,7 @@ pyyaml==6.0 qrcode==6.1 # via # -r requirements/ci.txt - # maykin-django-two-factor-auth + # django-two-factor-auth redis==4.5.5 # via # -r requirements/ci.txt @@ -528,6 +543,10 @@ wcwidth==0.2.6 # via # -r requirements/ci.txt # prompt-toolkit +webauthn==2.0.0 + # via + # -r requirements/ci.txt + # django-two-factor-auth webob==1.8.7 # via # -r requirements/ci.txt diff --git a/src/objecttypes/conf/base.py b/src/objecttypes/conf/base.py index 6adeff73..b31914e3 100644 --- a/src/objecttypes/conf/base.py +++ b/src/objecttypes/conf/base.py @@ -77,11 +77,12 @@ "solo", "drf_spectacular", "vng_api_common", - # 2fa apps + # Two-factor authentication in the Django admin, enforced. "django_otp", "django_otp.plugins.otp_static", "django_otp.plugins.otp_totp", "two_factor", + "maykin_2fa", "sharing_configs", # Project applications. "objecttypes.accounts", @@ -98,11 +99,11 @@ "django.middleware.common.CommonMiddleware", "django.middleware.csrf.CsrfViewMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", + "maykin_2fa.middleware.OTPMiddleware", "mozilla_django_oidc_db.middleware.SessionRefresh", "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", "axes.middleware.AxesMiddleware", - "django_otp.middleware.OTPMiddleware", ] ROOT_URLCONF = "objecttypes.urls" @@ -407,10 +408,18 @@ # -# Maykin fork of DJANGO-TWO-FACTOR-AUTH +# MAYKIN-2FA +# Uses django-two-factor-auth under the hood, so relevant upstream package settings +# apply too. # -TWO_FACTOR_FORCE_OTP_ADMIN = config("TWO_FACTOR_FORCE_OTP_ADMIN", not DEBUG) -TWO_FACTOR_PATCH_ADMIN = config("TWO_FACTOR_PATCH_ADMIN", True) + +# we run the admin site monkeypatch instead. +TWO_FACTOR_PATCH_ADMIN = False +# add entries from AUTHENTICATION_BACKENDS that already enforce their own two-factor +# auth, avoiding having some set up MFA again in the project. +MAYKIN_2FA_ALLOW_MFA_BYPASS_BACKENDS = [ + "mozilla_django_oidc_db.backends.OIDCAuthenticationBackend", +] # # Mozilla Django OIDC DB settings diff --git a/src/objecttypes/conf/ci.py b/src/objecttypes/conf/ci.py index 756a6fe1..e8c8c3ff 100644 --- a/src/objecttypes/conf/ci.py +++ b/src/objecttypes/conf/ci.py @@ -25,6 +25,3 @@ # Django-axes # AXES_BEHIND_REVERSE_PROXY = False - -# Maykin fork of DJANGO-TWO-FACTOR-AUTH -TWO_FACTOR_FORCE_OTP_ADMIN = False diff --git a/src/objecttypes/conf/dev.py b/src/objecttypes/conf/dev.py index c2e0000c..a467ddab 100644 --- a/src/objecttypes/conf/dev.py +++ b/src/objecttypes/conf/dev.py @@ -107,8 +107,9 @@ r"django\.db\.models\.fields", ) -if "test" in sys.argv: - TWO_FACTOR_FORCE_OTP_ADMIN = False +# None of the authentication backends require two-factor authentication. +if config("DISABLE_2FA", default=True): # pragma: no cover + MAYKIN_2FA_ALLOW_MFA_BYPASS_BACKENDS = AUTHENTICATION_BACKENDS # Override settings with local settings. try: diff --git a/src/objecttypes/templates/admin/base_site.html b/src/objecttypes/templates/admin/base_site.html index 45d313da..d8df6af0 100644 --- a/src/objecttypes/templates/admin/base_site.html +++ b/src/objecttypes/templates/admin/base_site.html @@ -23,9 +23,9 @@

{{ settings.PROJECT_NAME }} {% if site_url %} {{ settings.SITE_TITLE }} / {% endif %} - {% url 'admin:two_factor:profile' as 2fa_profile_url %} - {% if 2fa_profile_url %} - {% trans "View 2fa profile" %} / + {% url 'maykin_2fa:account_security' as 2fa_account_security_url %} + {% if 2fa_account_security_url %} + {% trans "Account security" %} / {% endif %} {% if user.has_usable_password %} {% trans 'Change password' %} / diff --git a/src/objecttypes/templates/admin/login.html b/src/objecttypes/templates/admin/login.html deleted file mode 100644 index d408af04..00000000 --- a/src/objecttypes/templates/admin/login.html +++ /dev/null @@ -1,16 +0,0 @@ -{% extends "two_factor/admin/login.html" %} -{% load solo_tags i18n %} - - -{% block content %} -{{ block.super }} - -{% get_solo 'mozilla_django_oidc_db.OpenIDConnectConfig' as oidc_config %} -{% if oidc_config.enabled %} - - -{% endif %} - -{% endblock %} diff --git a/src/objecttypes/templates/maykin_2fa/base.html b/src/objecttypes/templates/maykin_2fa/base.html new file mode 100644 index 00000000..68fa4301 --- /dev/null +++ b/src/objecttypes/templates/maykin_2fa/base.html @@ -0,0 +1,9 @@ +{% extends "maykin_2fa/base.html" %} + +{# Django 3.2 #} +{% block breadcrumbs %}{% endblock %} + +{# Do not show any version information #} +{% block footer %} + +{% endblock %} diff --git a/src/objecttypes/templates/maykin_2fa/login.html b/src/objecttypes/templates/maykin_2fa/login.html new file mode 100644 index 00000000..51987a80 --- /dev/null +++ b/src/objecttypes/templates/maykin_2fa/login.html @@ -0,0 +1,23 @@ +{% extends "maykin_2fa/login.html" %} +{% load solo_tags i18n %} + +{% block extra_login_options %} + {% get_solo 'mozilla_django_oidc_db.OpenIDConnectConfig' as oidc_config %} + {% if oidc_config.enabled %} + + + {% endif %} +{% endblock %} + +{% block extra_recovery_options %} +
  • + {% trans 'Contact support to start the account recovery process' %} +
  • +{% endblock extra_recovery_options %} + +{# Do not show any version information #} +{% block footer %} + +{% endblock %} diff --git a/src/objecttypes/templates/two_factor/admin/login.html b/src/objecttypes/templates/two_factor/admin/login.html deleted file mode 100644 index afdff9b3..00000000 --- a/src/objecttypes/templates/two_factor/admin/login.html +++ /dev/null @@ -1 +0,0 @@ -{% extends "admin/login.html" %} diff --git a/src/objecttypes/tests/test_objecttype_admin.py b/src/objecttypes/tests/test_objecttype_admin.py index f9fb9739..3d24f1f4 100644 --- a/src/objecttypes/tests/test_objecttype_admin.py +++ b/src/objecttypes/tests/test_objecttype_admin.py @@ -6,6 +6,7 @@ import requests_mock from django_webtest import WebTest from freezegun import freeze_time +from maykin_2fa.test import disable_admin_mfa from objecttypes.accounts.tests.factories import SuperUserFactory from objecttypes.core.constants import ( @@ -27,6 +28,7 @@ @freeze_time("2020-01-01") +@disable_admin_mfa() class AdminAddTests(WebTest): url = reverse_lazy("admin:core_objecttype_add") import_from_url = reverse_lazy("admin:import_from_url") @@ -244,6 +246,7 @@ def test_create_objecttype_from_url_with_nonexistent_url(self): self.assertEqual(ObjectType.objects.count(), 0) +@disable_admin_mfa() class AdminDetailTests(WebTest): @classmethod def setUpTestData(cls): diff --git a/src/objecttypes/tests/test_sharing_configs.py b/src/objecttypes/tests/test_sharing_configs.py index c88af9ce..e877f291 100644 --- a/src/objecttypes/tests/test_sharing_configs.py +++ b/src/objecttypes/tests/test_sharing_configs.py @@ -8,6 +8,7 @@ import requests_mock from django_webtest import WebTest from freezegun import freeze_time +from maykin_2fa.test import disable_admin_mfa from sharing_configs.models import SharingConfigsConfig from objecttypes.accounts.tests.factories import SuperUserFactory @@ -19,6 +20,7 @@ SHARING_CONFIGS_API_ROOT = "https://sharing-configs-api.example.org/api/v1/" +@disable_admin_mfa() @freeze_time("2020-01-01") class SharingConfigsTests(WebTest): def setUp(self) -> None: diff --git a/src/objecttypes/urls.py b/src/objecttypes/urls.py index b02f064d..a9c70b5f 100644 --- a/src/objecttypes/urls.py +++ b/src/objecttypes/urls.py @@ -7,6 +7,8 @@ from django.urls import include, path from django.views.generic.base import TemplateView +from maykin_2fa import monkeypatch_admin +from maykin_2fa.urls import urlpatterns as maykin_2fa_urlpatterns from rest_framework.settings import api_settings handler500 = "objecttypes.utils.views.server_error" @@ -14,6 +16,8 @@ admin.site.site_title = "objecttypes admin" admin.site.index_title = "Welcome to the objecttypes admin" +monkeypatch_admin() + urlpatterns = [ path( "admin/password_reset/", @@ -25,6 +29,7 @@ auth_views.PasswordResetDoneView.as_view(), name="password_reset_done", ), + path("admin/", include((maykin_2fa_urlpatterns, "maykin_2fa"))), path("admin/", admin.site.urls), path( "reset///", From 2e33e8f134d5a318e118e32e59ed2d5c14eb8982 Mon Sep 17 00:00:00 2001 From: Viicos <65306057+Viicos@users.noreply.github.com> Date: Wed, 14 Feb 2024 15:07:13 +0100 Subject: [PATCH 10/15] Fixes for deprecation warnings --- requirements/base.txt | 2 +- requirements/ci.txt | 2 +- requirements/dev.txt | 2 +- src/objecttypes/conf/base.py | 2 -- 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/requirements/base.txt b/requirements/base.txt index 71967b9d..dc28a9d4 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -189,7 +189,7 @@ jsonschema==4.17.3 # via # -r requirements/base.in # drf-spectacular -kombu==5.2.4 +kombu==5.3.5 # via celery markupsafe==2.1.2 # via jinja2 diff --git a/requirements/ci.txt b/requirements/ci.txt index 0aceecbf..2525b337 100644 --- a/requirements/ci.txt +++ b/requirements/ci.txt @@ -287,7 +287,7 @@ jsonschema==4.17.3 # via # -r requirements/base.txt # drf-spectacular -kombu==5.2.4 +kombu==5.3.5 # via # -r requirements/base.txt # celery diff --git a/requirements/dev.txt b/requirements/dev.txt index 82b0870f..f7d7acbd 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -322,7 +322,7 @@ jsonschema==4.17.3 # via # -r requirements/ci.txt # drf-spectacular -kombu==5.2.4 +kombu==5.3.5 # via # -r requirements/ci.txt # celery diff --git a/src/objecttypes/conf/base.py b/src/objecttypes/conf/base.py index b31914e3..2c46100f 100644 --- a/src/objecttypes/conf/base.py +++ b/src/objecttypes/conf/base.py @@ -168,8 +168,6 @@ USE_I18N = True -USE_L10N = True - USE_TZ = True USE_THOUSAND_SEPARATOR = True From 4e31701f959e65a96f9750ac5e9b3c89e1e2780f Mon Sep 17 00:00:00 2001 From: Viicos <65306057+Viicos@users.noreply.github.com> Date: Tue, 5 Mar 2024 17:01:22 +0100 Subject: [PATCH 11/15] Update to Django 4.2 --- requirements/base.in | 2 +- requirements/base.txt | 9 ++++----- requirements/ci.txt | 9 ++++----- requirements/dev.txt | 9 ++++----- 4 files changed, 13 insertions(+), 16 deletions(-) diff --git a/requirements/base.in b/requirements/base.in index ea7ea985..e4489695 100644 --- a/requirements/base.in +++ b/requirements/base.in @@ -7,7 +7,7 @@ python-decouple # processing of envvar configs jsonschema # Framework libraries -django +django~=4.2 django-admin-index django-axes django-jsonsuit diff --git a/requirements/base.txt b/requirements/base.txt index dc28a9d4..3eb96db1 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -48,7 +48,7 @@ click-plugins==1.1.1 # via celery click-repl==0.2.0 # via celery -commonground-api-common==1.12.1 +commonground-api-common==1.13.0 # via -r requirements/base.in coreapi==2.3.3 # via commonground-api-common @@ -61,7 +61,7 @@ cryptography==42.0.2 # mozilla-django-oidc # pyopenssl # webauthn -django==3.2.20 +django==4.2.11 # via # -r requirements/base.in # commonground-api-common @@ -136,7 +136,7 @@ django-solo==2.0.0 # zgw-consumers django-two-factor-auth[phonenumberslite,webauthn]==1.16.0 # via maykin-2fa -djangorestframework==3.12.4 +djangorestframework==3.14.0 # via # -r requirements/base.in # commonground-api-common @@ -243,11 +243,10 @@ pytz==2023.3 # via # -r requirements/base.in # celery - # django + # djangorestframework # drf-yasg pyyaml==6.0 # via - # commonground-api-common # drf-spectacular # drf-yasg # gemma-zds-client diff --git a/requirements/ci.txt b/requirements/ci.txt index 2525b337..8795434e 100644 --- a/requirements/ci.txt +++ b/requirements/ci.txt @@ -78,7 +78,7 @@ click-repl==0.2.0 # via # -r requirements/base.txt # celery -commonground-api-common==1.12.1 +commonground-api-common==1.13.0 # via -r requirements/base.txt coreapi==2.3.3 # via @@ -100,7 +100,7 @@ cryptography==42.0.2 # webauthn cssselect==1.2.0 # via pyquery -django==3.2.20 +django==4.2.11 # via # -r requirements/base.txt # commonground-api-common @@ -206,7 +206,7 @@ django-two-factor-auth[phonenumberslite,webauthn]==1.16.0 # maykin-2fa django-webtest==1.9.10 # via -r requirements/test-tools.in -djangorestframework==3.12.4 +djangorestframework==3.14.0 # via # -r requirements/base.txt # commonground-api-common @@ -373,12 +373,11 @@ pytz==2023.3 # via # -r requirements/base.txt # celery - # django + # djangorestframework # drf-yasg pyyaml==6.0 # via # -r requirements/base.txt - # commonground-api-common # drf-spectacular # drf-yasg # gemma-zds-client diff --git a/requirements/dev.txt b/requirements/dev.txt index f7d7acbd..75778c0e 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -94,7 +94,7 @@ click-repl==0.2.0 # via # -r requirements/ci.txt # celery -commonground-api-common==1.12.1 +commonground-api-common==1.13.0 # via -r requirements/ci.txt coreapi==2.3.3 # via @@ -118,7 +118,7 @@ cssselect==1.2.0 # via # -r requirements/ci.txt # pyquery -django==3.2.20 +django==4.2.11 # via # -r requirements/ci.txt # commonground-api-common @@ -230,7 +230,7 @@ django-two-factor-auth[phonenumberslite,webauthn]==1.16.0 # maykin-2fa django-webtest==1.9.10 # via -r requirements/ci.txt -djangorestframework==3.12.4 +djangorestframework==3.14.0 # via # -r requirements/ci.txt # commonground-api-common @@ -431,12 +431,11 @@ pytz==2023.3 # via # -r requirements/ci.txt # celery - # django + # djangorestframework # drf-yasg pyyaml==6.0 # via # -r requirements/ci.txt - # commonground-api-common # drf-spectacular # drf-yasg # gemma-zds-client From 6a8407247584d73f5f23a36947cb8ab4a4ff1dc4 Mon Sep 17 00:00:00 2001 From: Viicos <65306057+Viicos@users.noreply.github.com> Date: Thu, 14 Mar 2024 11:08:02 +0100 Subject: [PATCH 12/15] Update to PostgreSQL 12 --- .github/workflows/ci.yml | 2 +- INSTALL.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bad1cc9b..93abec22 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ jobs: services: postgres: - image: postgres:10 + image: postgres:12 env: POSTGRES_HOST_AUTH_METHOD: trust ports: diff --git a/INSTALL.rst b/INSTALL.rst index 33af5a00..1868653b 100644 --- a/INSTALL.rst +++ b/INSTALL.rst @@ -20,7 +20,7 @@ You need the following libraries and/or programs: * `Python`_ 3.10 or above * Python `Virtualenv`_ and `Pip`_ -* `PostgreSQL`_ 10 or above +* `PostgreSQL`_ 12 or above * `Node.js`_ * `npm`_ From 68c4cb26ec4274edc94e46bf419006b4d9fe9498 Mon Sep 17 00:00:00 2001 From: Viicos <65306057+Viicos@users.noreply.github.com> Date: Mon, 8 Apr 2024 17:18:02 +0200 Subject: [PATCH 13/15] Add `DISABLE_2FA` config in base --- src/objecttypes/conf/base.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/objecttypes/conf/base.py b/src/objecttypes/conf/base.py index 2c46100f..135f89a7 100644 --- a/src/objecttypes/conf/base.py +++ b/src/objecttypes/conf/base.py @@ -425,3 +425,6 @@ OIDC_AUTHENTICATE_CLASS = "mozilla_django_oidc_db.views.OIDCAuthenticationRequestView" MOZILLA_DJANGO_OIDC_DB_CACHE = "oidc" MOZILLA_DJANGO_OIDC_DB_CACHE_TIMEOUT = 5 * 60 + +if config("DISABLE_2FA", default=False): # pragma: no cover + MAYKIN_2FA_ALLOW_MFA_BYPASS_BACKENDS = AUTHENTICATION_BACKENDS From a8ffb23ff4eb50202ecfda1d537f18aa7bfb6fdc Mon Sep 17 00:00:00 2001 From: Anna Shamray Date: Tue, 9 Apr 2024 14:19:45 +0200 Subject: [PATCH 14/15] :memo: add warning to CHANGELOG --- CHANGELOG.rst | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 8a936c54..3b6eb728 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,18 @@ Change history ============== +2.2.0 (WIP) +----------- + +**Bugfixes and QOL** + +* updated to Django 4.2 (objects-api#385) + +.. warning:: + + Two-factor authentication is enabled by default. The ``DISABLE_2FA`` environment variable + can be used to disable it if needed. + 2.1.2 (2024-02-06) ------------------ @@ -10,7 +22,6 @@ Change history * added ``USE_X_FORWARDED_HOST`` environment variable (#353) * added email environment variables (#366) - 2.1.1 (2024-02-06) ------------------ From a23e004b0d4b78688f9ac2de4d7705eb89655223 Mon Sep 17 00:00:00 2001 From: Viicos <65306057+Viicos@users.noreply.github.com> Date: Tue, 9 Apr 2024 17:25:44 +0200 Subject: [PATCH 15/15] Update to `drf-spectacular==0.26.5` Latest version without too much breaking changes Fix `AutoSchema` subclass Regenerate schemas Add regression test --- requirements/base.txt | 3 ++- requirements/ci.txt | 3 ++- requirements/dev.txt | 4 +++- src/objecttypes/tests/v1/test_schema.py | 10 ++++++++++ src/objecttypes/tests/v2/test_schema.py | 10 ++++++++++ src/objecttypes/utils/autoschema.py | 8 ++++++-- 6 files changed, 33 insertions(+), 5 deletions(-) create mode 100644 src/objecttypes/tests/v1/test_schema.py create mode 100644 src/objecttypes/tests/v2/test_schema.py diff --git a/requirements/base.txt b/requirements/base.txt index 3eb96db1..03cda47f 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -78,6 +78,7 @@ django==4.2.11 # django-relativedelta # django-rest-framework-condition # django-rosetta + # django-sendfile2 # django-simple-certmanager # django-solo # django-two-factor-auth @@ -152,7 +153,7 @@ drf-nested-routers==0.93.4 # via # -r requirements/base.in # commonground-api-common -drf-spectacular==0.16.0 +drf-spectacular==0.26.5 # via -r requirements/base.in drf-yasg==1.21.7 # via commonground-api-common diff --git a/requirements/ci.txt b/requirements/ci.txt index 8795434e..ff6d6606 100644 --- a/requirements/ci.txt +++ b/requirements/ci.txt @@ -203,6 +203,7 @@ django-solo==2.0.0 django-two-factor-auth[phonenumberslite,webauthn]==1.16.0 # via # -r requirements/base.txt + # django-two-factor-auth # maykin-2fa django-webtest==1.9.10 # via -r requirements/test-tools.in @@ -223,7 +224,7 @@ drf-nested-routers==0.93.4 # via # -r requirements/base.txt # commonground-api-common -drf-spectacular==0.16.0 +drf-spectacular==0.26.5 # via -r requirements/base.txt drf-yasg==1.21.7 # via diff --git a/requirements/dev.txt b/requirements/dev.txt index 75778c0e..fc8143c7 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -227,6 +227,7 @@ django-solo==2.0.0 django-two-factor-auth[phonenumberslite,webauthn]==1.16.0 # via # -r requirements/ci.txt + # django-two-factor-auth # maykin-2fa django-webtest==1.9.10 # via -r requirements/ci.txt @@ -251,7 +252,7 @@ drf-nested-routers==0.93.4 # via # -r requirements/ci.txt # commonground-api-common -drf-spectacular==0.16.0 +drf-spectacular==0.26.5 # via -r requirements/ci.txt drf-yasg==1.21.7 # via @@ -514,6 +515,7 @@ tomli==2.0.1 # via # black # build + # pyproject-hooks uritemplate==4.1.1 # via # -r requirements/ci.txt diff --git a/src/objecttypes/tests/v1/test_schema.py b/src/objecttypes/tests/v1/test_schema.py new file mode 100644 index 00000000..e0b07335 --- /dev/null +++ b/src/objecttypes/tests/v1/test_schema.py @@ -0,0 +1,10 @@ +from rest_framework import status +from rest_framework.test import APITestCase + +from .utils import reverse + + +class APISchemaTest(APITestCase): + def test_schema_endoint(self): + response = self.client.get(reverse("schema-redoc")) + self.assertEqual(response.status_code, status.HTTP_200_OK) diff --git a/src/objecttypes/tests/v2/test_schema.py b/src/objecttypes/tests/v2/test_schema.py new file mode 100644 index 00000000..e0b07335 --- /dev/null +++ b/src/objecttypes/tests/v2/test_schema.py @@ -0,0 +1,10 @@ +from rest_framework import status +from rest_framework.test import APITestCase + +from .utils import reverse + + +class APISchemaTest(APITestCase): + def test_schema_endoint(self): + response = self.client.get(reverse("schema-redoc")) + self.assertEqual(response.status_code, status.HTTP_200_OK) diff --git a/src/objecttypes/utils/autoschema.py b/src/objecttypes/utils/autoschema.py index f29302ec..9faa4d7e 100644 --- a/src/objecttypes/utils/autoschema.py +++ b/src/objecttypes/utils/autoschema.py @@ -24,9 +24,13 @@ def get_override_parameters(self): parent_path_headers = self.get_parent_path_headers() return content_type_headers + parent_path_headers - def _get_response_for_code(self, serializer, status_code, media_types=None): + def _get_response_for_code( + self, serializer, status_code, media_types=None, direction="response" + ): """add default description to the response""" - response = super()._get_response_for_code(serializer, status_code, media_types) + response = super()._get_response_for_code( + serializer, status_code, media_types, direction + ) if not response.get("description"): response["description"] = HTTP_STATUS_CODE_TITLES.get(int(status_code))