diff --git a/backoffice/.envs/local/.django b/backoffice/.envs/local/.django index a0fd784e..fd5afd91 100644 --- a/backoffice/.envs/local/.django +++ b/backoffice/.envs/local/.django @@ -24,3 +24,6 @@ AIRFLOW_BASE_URL=http://airflow-webserver:8080 AIRFLOW_TOKEN=YWlyZmxvdzphaXJmbG93 SERVICENOW_URL=https://cerntraining.service-now.com + +# Frontend +FRONTEND_LOGIN_SUCCESS=http://127.0.0.1:5000/success diff --git a/backoffice/config/settings/base.py b/backoffice/config/settings/base.py index e8fa6288..ba06396d 100644 --- a/backoffice/config/settings/base.py +++ b/backoffice/config/settings/base.py @@ -95,6 +95,7 @@ "allauth", "allauth.account", "allauth.socialaccount", + "allauth.headless", "django_celery_beat", "rest_framework", "rest_framework.authtoken", @@ -127,7 +128,7 @@ # https://docs.djangoproject.com/en/dev/ref/settings/#auth-user-model AUTH_USER_MODEL = "users.User" # https://docs.djangoproject.com/en/dev/ref/settings/#login-redirect-url -LOGIN_REDIRECT_URL = "users:redirect" +LOGIN_REDIRECT_URL = env("FRONTEND_LOGIN_SUCCESS", default="users:redirect") # https://docs.djangoproject.com/en/dev/ref/settings/#login-url LOGIN_URL = "account_login" @@ -331,7 +332,7 @@ # https://django-allauth.readthedocs.io/en/latest/configuration.html ACCOUNT_USER_MODEL_USERNAME_FIELD = None # https://django-allauth.readthedocs.io/en/latest/configuration.html -ACCOUNT_EMAIL_VERIFICATION = "mandatory" +ACCOUNT_EMAIL_VERIFICATION = False # https://django-allauth.readthedocs.io/en/latest/configuration.html ACCOUNT_ADAPTER = "backoffice.users.adapters.AccountAdapter" # https://django-allauth.readthedocs.io/en/latest/forms.html diff --git a/backoffice/config/settings/local.py b/backoffice/config/settings/local.py index 0f089894..7141c1b8 100644 --- a/backoffice/config/settings/local.py +++ b/backoffice/config/settings/local.py @@ -70,3 +70,18 @@ # ------------------------------------------------------------------------------ # http://whitenoise.evans.io/en/latest/django.html#using-whitenoise-in-development INSTALLED_APPS = ["whitenoise.runserver_nostatic"] + INSTALLED_APPS # noqa: F405 + +# ORCID +# ---------- +SOCIALACCOUNT_PROVIDERS = { + "orcid": { + # For each OAuth based provider, either add a ``SocialApp`` + # (``socialaccount`` app) containing the required client + # credentials, or list them here: + "APP": { + "client_id": env("ORCID_CLIENT_ID", default=""), + "secret": env("ORCID_CLIENT_SECRET", default=""), + }, + "BASE_DOMAIN": "sandbox.orcid.org" + } +} diff --git a/backoffice/config/urls.py b/backoffice/config/urls.py index 045b7976..fdb5ee4f 100644 --- a/backoffice/config/urls.py +++ b/backoffice/config/urls.py @@ -1,3 +1,4 @@ +from allauth.socialaccount.providers.orcid.views import oauth2_login from django.conf import settings from django.conf.urls.static import static from django.contrib import admin @@ -8,6 +9,8 @@ from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView from rest_framework.authtoken.views import obtain_auth_token from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView +from django.views.decorators.csrf import csrf_exempt + urlpatterns = [ path("", TemplateView.as_view(template_name="pages/home.html"), name="home"), @@ -18,6 +21,7 @@ path(settings.ADMIN_URL, admin.site.urls), # User management path("users/", include("backoffice.users.urls", namespace="users")), + path("accounts/orcid/login/", csrf_exempt(oauth2_login), name="orcid_login"), path("accounts/", include("allauth.urls")), path("", include("django_prometheus.urls")), ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) @@ -40,6 +44,7 @@ ), path("api/token/", TokenObtainPairView.as_view(), name="token_obtain_pair"), path("api/token/refresh/", TokenRefreshView.as_view(), name="token_refresh"), + path("api/_allauth/", include("allauth.headless.urls")), ] diff --git a/backoffice/poetry.lock b/backoffice/poetry.lock index c4aea059..d4d6a13b 100644 --- a/backoffice/poetry.lock +++ b/backoffice/poetry.lock @@ -943,24 +943,23 @@ bcrypt = ["bcrypt"] [[package]] name = "django-allauth" -version = "0.57.0" +version = "65.0.1" description = "Integrated set of Django applications addressing authentication, registration, account management as well as 3rd party (social) account authentication." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "django-allauth-0.57.0.tar.gz", hash = "sha256:a095ef0db7de305d9175772c78e765ebd5fceb004ae61c1383d7fc1af0f7c5b1"}, + {file = "django_allauth-65.0.1.tar.gz", hash = "sha256:1f8281e2dc17d3b977bcd95b99538f128c5cd2fb2551346a7f8ad31aa76f17cc"}, ] [package.dependencies] -Django = ">=3.2" -pyjwt = {version = ">=1.7", extras = ["crypto"]} -python3-openid = ">=3.0.8" -requests = ">=2.0.0" -requests-oauthlib = ">=0.3.0" +Django = ">=4.2" [package.extras] -mfa = ["qrcode (>=7.0.0)"] +mfa = ["fido2 (>=1.1.2)", "qrcode (>=7.0.0)"] +openid = ["python3-openid (>=3.0.8)"] saml = ["python3-saml (>=1.15.0,<2.0.0)"] +socialaccount = ["pyjwt[crypto] (>=1.7)", "requests (>=2.0.0)", "requests-oauthlib (>=0.3.0)"] +steam = ["python3-openid (>=3.0.8)"] [[package]] name = "django-anymail" @@ -2568,22 +2567,6 @@ files = [ [package.dependencies] setuptools = "*" -[[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 = "opensearch" version = "0.9.2" @@ -3042,9 +3025,6 @@ files = [ {file = "PyJWT-2.8.0.tar.gz", hash = "sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de"}, ] -[package.dependencies] -cryptography = {version = ">=3.4.0", optional = true, markers = "extra == \"crypto\""} - [package.extras] crypto = ["cryptography (>=3.4.0)"] dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"] @@ -3296,24 +3276,6 @@ text-unidecode = ">=1.3" [package.extras] unidecode = ["Unidecode (>=1.1.1)"] -[[package]] -name = "python3-openid" -version = "3.2.0" -description = "OpenID support for modern servers and consumers." -optional = false -python-versions = "*" -files = [ - {file = "python3-openid-3.2.0.tar.gz", hash = "sha256:33fbf6928f401e0b790151ed2b5290b02545e8775f982485205a066f874aaeaf"}, - {file = "python3_openid-3.2.0-py3-none-any.whl", hash = "sha256:6626f771e0417486701e0b4daff762e7212e820ca5b29fcc0d05f6f8736dfa6b"}, -] - -[package.dependencies] -defusedxml = "*" - -[package.extras] -mysql = ["mysql-connector-python"] -postgresql = ["psycopg2"] - [[package]] name = "pytz" version = "2023.3.post1" @@ -3546,24 +3508,6 @@ files = [ [package.dependencies] requests = ">=1.0.0" -[[package]] -name = "requests-oauthlib" -version = "1.3.1" -description = "OAuthlib authentication support for Requests." -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -files = [ - {file = "requests-oauthlib-1.3.1.tar.gz", hash = "sha256:75beac4a47881eeb94d5ea5d6ad31ef88856affe2332b9aafb52c6452ccf0d7a"}, - {file = "requests_oauthlib-1.3.1-py2.py3-none-any.whl", hash = "sha256:2577c501a2fb8d05a304c09d090d6e47c306fef15809d102b327cf8364bddab5"}, -] - -[package.dependencies] -oauthlib = ">=3.0.0" -requests = ">=2.0.0" - -[package.extras] -rsa = ["oauthlib[signedtoken] (>=3.0.0)"] - [[package]] name = "rfc3987" version = "1.3.8" @@ -4092,7 +4036,6 @@ description = "Automatically mock your HTTP interactions to simplify and speed u optional = false python-versions = ">=3.8" files = [ - {file = "vcrpy-6.0.1-py2.py3-none-any.whl", hash = "sha256:621c3fb2d6bd8aa9f87532c688e4575bcbbde0c0afeb5ebdb7e14cac409edfdd"}, {file = "vcrpy-6.0.1.tar.gz", hash = "sha256:9e023fee7f892baa0bbda2f7da7c8ac51165c1c6e38ff8688683a12a4bde9278"}, ] @@ -4594,4 +4537,4 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "2.0" python-versions = "~3.11" -content-hash = "0cf383a9ffe3a318a847633e21d94c82e2c87d36cbc195cd47200abb23cd7474" +content-hash = "3c0dd3196ea27814deb8e3d2f003b2ad7f68631b2d135bce258850efc27af669" diff --git a/backoffice/pyproject.toml b/backoffice/pyproject.toml index 40d4c1c1..35939651 100644 --- a/backoffice/pyproject.toml +++ b/backoffice/pyproject.toml @@ -125,7 +125,6 @@ uvicorn = {version = "0.23.2", extras = ["standard"]} django = "4.2.6" django-environ = "0.11.2" django-model-utils = "4.3.1" -django-allauth = "0.57.0" django-crispy-forms = "2.1" crispy-bootstrap5 = "0.7" django-redis = "5.4.0" @@ -151,6 +150,7 @@ opensearch-py = "2.6.0" djangorestframework-simplejwt = "^5.3.1" django-json-widget = "^2.0.1" sentry-sdk = "1.19.1" +django-allauth = {version = "65.0.1", extras = ["headless"]} [tool.poetry.dev-dependencies] factory-boy = "3.3.0" diff --git a/ruff.toml b/ruff.toml index d849b4ae..00a551a8 100644 --- a/ruff.toml +++ b/ruff.toml @@ -1,5 +1,5 @@ target-version = "py311" -ignore = ["PT009"] +lint.ignore = ["PT009"] [lint.flake8-tidy-imports] ban-relative-imports = "all"