diff --git a/.env.example b/.env.example index dddc28ad..373ca9b8 100644 --- a/.env.example +++ b/.env.example @@ -11,4 +11,12 @@ VITE_DEV=True VITE_DEV_SERVER_URL=http://localhost:5173 # Sentry -SENTRY_DSN= \ No newline at end of file +SENTRY_DSN= + +# authbroker config +AUTHBROKER_URL=speak-to-webops-team-for-access +AUTHBROKER_CLIENT_ID=speak-to-webops-team-for-access +AUTHBROKER_CLIENT_SECRET=speak-to-webops-team-for-access +AUTHBROKER_STAFF_SSO_SCOPE=any-additional-scope-values +AUTHBROKER_ANONYMOUS_PATHS=(Tuple/list of paths that should be unprotected) +AUTHBROKER_ANONYMOUS_URL_NAMES=(list of url names that should be unprotected) \ No newline at end of file diff --git a/config/settings/base.py b/config/settings/base.py index 4b37f14b..2eddb1cc 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -18,6 +18,7 @@ import sentry_sdk from dbt_copilot_python.database import database_url_from_env from dbt_copilot_python.network import is_copilot, setup_allowed_hosts +from django.urls import reverse_lazy from sentry_sdk.integrations.django import DjangoIntegration from sentry_sdk.integrations.redis import RedisIntegration @@ -60,6 +61,7 @@ "django.contrib.staticfiles", "django.contrib.postgres", "core.apps.CoreConfig", + "authbroker_client", ] MIDDLEWARE: list[str] = [ @@ -70,6 +72,7 @@ "django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", + "authbroker_client.middleware.ProtectAllViewsMiddleware", ] TEMPLATES: list[dict[str, Any]] = [ @@ -88,6 +91,25 @@ }, ] +AUTHENTICATION_BACKENDS = [ + "django.contrib.auth.backends.ModelBackend", + "authbroker_client.backends.AuthbrokerBackend", +] + + +LOGIN_URL = reverse_lazy("authbroker_client:login") +LOGIN_REDIRECT_URL = "/" + + +# authbroker config +AUTHBROKER_URL = env("AUTHBROKER_URL") +AUTHBROKER_CLIENT_ID = env("AUTHBROKER_CLIENT_ID") +AUTHBROKER_CLIENT_SECRET = env("AUTHBROKER_CLIENT_SECRET") +AUTHBROKER_STAFF_SSO_SCOPE = env("AUTHBROKER_STAFF_SSO_SCOPE") +AUTHBROKER_ANONYMOUS_PATHS = env("AUTHBROKER_ANONYMOUS_PATHS") +AUTHBROKER_ANONYMOUS_URL_NAMES = env("AUTHBROKER_ANONYMOUS_URL_NAMES") + + # Sentry # https://docs.sentry.io/platforms/python/integrations/django/ SENTRY_DSN: str = env.str("SENTRY_DSN") diff --git a/config/urls.py b/config/urls.py index 6b236670..3a4b5a1a 100644 --- a/config/urls.py +++ b/config/urls.py @@ -22,4 +22,5 @@ urlpatterns = [ path("", include("core.urls")), path("admin/", admin.site.urls), + path("auth/", include("authbroker_client.urls")), ] diff --git a/core/views.py b/core/views.py index 96d34c31..9c57c58c 100644 --- a/core/views.py +++ b/core/views.py @@ -1,6 +1,8 @@ +from django.contrib.auth.decorators import login_required from django.shortcuts import render +@login_required def index(request): return render(request, "core/base.html") diff --git a/poetry.lock b/poetry.lock index 836057bf..136730fb 100644 --- a/poetry.lock +++ b/poetry.lock @@ -560,6 +560,24 @@ files = [ [package.dependencies] Django = ">=3.2" +[[package]] +name = "django-staff-sso-client" +version = "4.3.0" +description = "Reusable Django app to facilitate gov.uk Staff Single Sign On" +optional = false +python-versions = "*" +files = [ + {file = "django_staff_sso_client-4.3.0-py3-none-any.whl", hash = "sha256:873279b74cc40517af6b5c6c043db74e66d3d4f147ed1495ec357ac26c14d6fa"}, + {file = "django_staff_sso_client-4.3.0.tar.gz", hash = "sha256:4f320c5c5da02a9da9f5da90b32749ff3a0ad0dcf51eb758fb85fd0e932b5261"}, +] + +[package.dependencies] +Django = ">=4.2.10,<6.0" +requests-oauthlib = "*" + +[package.extras] +test = ["build", "codecov", "flake8 (==4.0.1)", "pytest (==7.1.1)", "pytest-cov", "pytest-django", "raven", "requests-mock", "setuptools", "twine", "wheel"] + [[package]] name = "ghp-import" version = "2.1.0" @@ -1256,6 +1274,22 @@ files = [ fast = ["fastnumbers (>=2.0.0)"] icu = ["PyICU (>=1.0.0)"] +[[package]] +name = "oauthlib" +version = "3.2.2" +description = "A generic, spec-compliant, thorough implementation of the OAuth request-signing logic" +optional = false +python-versions = ">=3.6" +files = [ + {file = "oauthlib-3.2.2-py3-none-any.whl", hash = "sha256:8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca"}, + {file = "oauthlib-3.2.2.tar.gz", hash = "sha256:9859c40929662bec5d64f34d01c99e093149682a3f38915dc0655d5a633dd918"}, +] + +[package.extras] +rsa = ["cryptography (>=3.0.0)"] +signals = ["blinker (>=1.4.0)"] +signedtoken = ["cryptography (>=3.0.0)", "pyjwt (>=2.0.0,<3)"] + [[package]] name = "opentelemetry-api" version = "1.22.0" @@ -1908,6 +1942,24 @@ urllib3 = ">=1.21.1,<3" socks = ["PySocks (>=1.5.6,!=1.5.7)"] use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] +[[package]] +name = "requests-oauthlib" +version = "2.0.0" +description = "OAuthlib authentication support for Requests." +optional = false +python-versions = ">=3.4" +files = [ + {file = "requests-oauthlib-2.0.0.tar.gz", hash = "sha256:b3dffaebd884d8cd778494369603a9e7b58d29111bf6b41bdc2dcd87203af4e9"}, + {file = "requests_oauthlib-2.0.0-py2.py3-none-any.whl", hash = "sha256:7dd8a5c40426b779b0868c404bdef9768deccf22749cde15852df527e6269b36"}, +] + +[package.dependencies] +oauthlib = ">=3.0.0" +requests = ">=2.0.0" + +[package.extras] +rsa = ["oauthlib[signedtoken] (>=3.0.0)"] + [[package]] name = "sentry-sdk" version = "2.17.0" @@ -2275,4 +2327,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = "^3.12" -content-hash = "656aa2f3025e8b8a38629748050542105533786e5c237804f57eaa392ae79a59" +content-hash = "8135f503546f75367166ef9e21635d63c9b01017c7908fcdc159041c2ec0d716" diff --git a/pyproject.toml b/pyproject.toml index 2f603b6c..db289cb6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,6 +16,7 @@ sentry-sdk = "^2.16.0" dbt-copilot-python = "^0.2.2" dj-database-url = "^2.2.0" granian = "^1.6.3" +django-staff-sso-client = "^4.3.0" [tool.poetry.group.dev.dependencies] black = "^24.10.0"