Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/installation/guides/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -237,9 +237,9 @@ system like GitHub.
- copy the file `securitysettings.py.default` and rename it to
`securitysettings.py`

!!! danger
!!! note

You must remove or fill placeholder in SOCIALACCOUNT_PROVIDERS in order to avoid an error due to empty provider ID when trying to login.
Third-party sign-in through the NFDI RegApp is off unless `OEP_REGAPP_CLIENT_ID`, `OEP_REGAPP_SECRET` and `OEP_REGAPP_SERVER_URL` are set in the environment. Never add an app with an empty `provider_id` to `SOCIALACCOUNT_PROVIDERS`: the sign-in and sign-up pages then fail.

??? note "How to configure securitysettings.py"

Expand Down
16 changes: 16 additions & 0 deletions docs/installation/production-podman/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,22 @@ re-run it after changing the domain or config. To override the domain:
steps (1–5) as the service user and only this nginx step via `sudo`. The script
handles being run as root.

### 6c. Sign-in through the NFDI RegApp (optional)

Register the platform as a client at the RegApp with the redirect URI
`https://your-domain.org/accounts/oidc/RegApp/login/callback/`, then fill in the
three keys in `~/.config/oeplatform/oep.env`:

```sh
OEP_REGAPP_CLIENT_ID=<client id>
OEP_REGAPP_SECRET=<secret>
OEP_REGAPP_SERVER_URL=<issuer>/.well-known/openid-configuration
```

Restart the app (`systemctl --user restart oep-oeplatform`). The sign-in page
then offers "NFDI-RegApp AAI"; with `OEP_REGAPP_CLIENT_ID` empty it offers no
third-party sign-in.

## 7. Make services survive logout and reboot

Rootless `--user` services stop when the user logs out unless **linger** is
Expand Down
30 changes: 18 additions & 12 deletions docs/oeplatform-code/apps/login.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,21 +34,27 @@ allauth:

Filling out the values in the dictionary depends on your Provider. They should provide documentation or provide you with the relevant credentials. In some cases the provider_id must be in line with the specification of the provider in others you can choose your own name here. The client_id & secret should also be provided as well as the server_url.

The template configures the NFDI RegApp AAI from three environment variables,
`OEP_REGAPP_CLIENT_ID`, `OEP_REGAPP_SECRET` and `OEP_REGAPP_SERVER_URL`, and
offers no provider while the client id is unset. Per app, allauth reads only
`name`, `provider_id`, `client_id`, `secret`, `key` and `settings`; switches
such as `verified_email` go into `settings`, in lower case. The template sets
none, so an address counts as verified only when the provider says so:

```python
SOCIALACCOUNT_PROVIDERS = {
"openid_connect": {
# For each OAuth based provider, either add a ``SocialApp``
# (``socialaccount`` app) containing the required client
# credentials, or list them here:
"APPS": [{
"provider_id": "",
"name": "",
"client_id": "",
"secret": "",
"VERIFIED_EMAIL": True,
"EMAIL_AUTHENTICATION": True,
"settings": {"server_url": ""},
}]
"APPS": [
{
"provider_id": "RegApp",
"name": "NFDI-RegApp AAI",
"client_id": os.environ["OEP_REGAPP_CLIENT_ID"],
"secret": os.environ["OEP_REGAPP_SECRET"],
"settings": {"server_url": os.environ["OEP_REGAPP_SERVER_URL"]},
}
]
if os.environ.get("OEP_REGAPP_CLIENT_ID")
else [],
}
}
```
Expand Down
47 changes: 34 additions & 13 deletions login/tests/test_account_pages_render.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,14 @@
entrypoints, a fresh dev instance) answered both pages with a 500. The test
reads the template itself, so it guards it on a machine with a real provider
too.

The template offers the NFDI RegApp only when its OEP_REGAPP_* variables are
set (as `oep.env` does on a Podman server), so both cases are rendered.
""" # noqa: 501

import ast
import runpy
from pathlib import Path
from unittest import mock

from django.conf import settings
from django.test import TestCase, override_settings
Expand All @@ -23,20 +27,37 @@
TEMPLATE = Path(settings.BASE_DIR) / "oeplatform" / "securitysettings.py.default"


def template_setting(name):
for node in ast.parse(TEMPLATE.read_text()).body:
if isinstance(node, ast.Assign) and any(
getattr(target, "id", None) == name for target in node.targets
):
return ast.literal_eval(node.value)
raise LookupError(f"{name} is not set in {TEMPLATE}")
REGAPP = {
"OEP_REGAPP_CLIENT_ID": "client",
"OEP_REGAPP_SECRET": "secret",
"OEP_REGAPP_SERVER_URL": "https://regapp.example/.well-known/openid-configuration",
}


def template_setting(name, environ):
with mock.patch.dict("os.environ", environ, clear=True):
return runpy.run_path(str(TEMPLATE))[name]


class AccountPagesRenderTest(TestCase):
def test_with_the_templates_login_providers(self):
with override_settings(
SOCIALACCOUNT_PROVIDERS=template_setting("SOCIALACCOUNT_PROVIDERS")
):
def assert_pages_render(self, providers):
with override_settings(SOCIALACCOUNT_PROVIDERS=providers):
for name in ("account_signup", "account_login"):
with self.subTest(page=name):
self.assertEqual(self.client.get(reverse(name)).status_code, 200)
response = self.client.get(reverse(name))
self.assertEqual(response.status_code, 200)
return response

def test_without_a_provider_configured(self):
providers = template_setting("SOCIALACCOUNT_PROVIDERS", {})
self.assertEqual(providers["openid_connect"]["APPS"], [])
self.assert_pages_render(providers)

def test_with_the_regapp_configured(self):
providers = template_setting("SOCIALACCOUNT_PROVIDERS", REGAPP)
(app,) = providers["openid_connect"]["APPS"]
self.assertEqual(app["client_id"], "client")
self.assertEqual(app["settings"]["server_url"], REGAPP["OEP_REGAPP_SERVER_URL"])
self.assertNotIn("verified_email", app["settings"])
response = self.assert_pages_render(providers)
self.assertContains(response, "/accounts/oidc/RegApp/login/")
36 changes: 20 additions & 16 deletions oeplatform/securitysettings.py.default
Original file line number Diff line number Diff line change
Expand Up @@ -138,24 +138,28 @@ CORS_ORIGIN_ALLOW_ALL = True
DJANGO_VITE = {"default": {"dev_mode": os.environ.get("VITE_DEV_MODE", DEBUG), "manifest_path": Path(BASE_DIR, "assets", "manifest.json")}}
VITE_DEV_SERVER_URL = os.environ.get("VITE_DEV_SERVER_URL" "http://vite:5173")

# Sign-in through the NFDI RegApp AAI (OpenID Connect). Offered only when
# OEP_REGAPP_CLIENT_ID is set; register
# https://<OEP_URL>/accounts/oidc/RegApp/login/callback/ as the redirect URI.
# OEP_REGAPP_SERVER_URL is "<issuer>/.well-known/openid-configuration".
# Never list an app with an empty "provider_id": no login URL can be built for
# it, and the sign-in and sign-up pages fail.
SOCIALACCOUNT_PROVIDERS = {
"openid_connect": {
# For each OAuth based provider, either add a ``SocialApp``
# (``socialaccount`` app) containing the required client
# credentials, or list them here. Leave the list empty when there is
# none: an entry with an empty "provider_id" makes the sign-in and
# sign-up pages fail, because no login URL can be built for it.
# Example:
# {
# "provider_id": "RegApp",
# "name": "NFDI-RegApp AAI",
# "client_id": "<client id>",
# "secret": "<secret>",
# "VERIFIED_EMAIL": True,
# "EMAIL_AUTHENTICATION": True,
# "settings": {"server_url": "<issuer>/.well-known/openid-configuration"},
# },
"APPS": [],
"APPS": [
{
"provider_id": "RegApp",
"name": "NFDI-RegApp AAI",
"client_id": os.environ["OEP_REGAPP_CLIENT_ID"],
"secret": os.environ["OEP_REGAPP_SECRET"],
# No "verified_email": an address counts as verified only when
# the provider says so (its email_verified claim).
# Email authentication is on for every provider in settings.py.
"settings": {"server_url": os.environ["OEP_REGAPP_SERVER_URL"]},
}
]
if os.environ.get("OEP_REGAPP_CLIENT_ID")
else [],
}
}

Expand Down
8 changes: 8 additions & 0 deletions podman/quadlets/oep.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,11 @@ OEP_ALLOWED_HOSTS=openenergyplatform.example.org
OEP_BEHIND_TLS_PROXY=True
# Comma-separated HTTPS origins trusted for CSRF (scheme required).
OEP_CSRF_TRUSTED_ORIGINS=https://openenergyplatform.example.org

# ── Sign-in through the NFDI RegApp AAI (optional) ────────────────────────────
# Leave OEP_REGAPP_CLIENT_ID empty to offer no third-party sign-in. Register
# https://<OEP_URL>/accounts/oidc/RegApp/login/callback/ as the redirect URI.
OEP_REGAPP_CLIENT_ID=
OEP_REGAPP_SECRET=
# The issuer's discovery document, <issuer>/.well-known/openid-configuration
OEP_REGAPP_SERVER_URL=
7 changes: 7 additions & 0 deletions versions/changelogs/current.md
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,13 @@ the previous release's highlights.
the `Authorization` header are deliberately not logged. The maintenance guide
documents the fields and a one-liner ranking paths by total server time
[(#2670)](https://github.com/OpenEnergyPlatform/oeplatform/pull/2670)
- Sign-in through the NFDI RegApp AAI is configured from the environment: the
`securitysettings.py` template offers it when `OEP_REGAPP_CLIENT_ID`,
`OEP_REGAPP_SECRET` and `OEP_REGAPP_SERVER_URL` are set (on a Podman server in
`oep.env`), and offers no third-party sign-in otherwise. The template's
upper-case `VERIFIED_EMAIL`/`EMAIL_AUTHENTICATION` keys are gone: allauth
never read them on an app, so sign-in behaves as before
[(#2723)](https://github.com/OpenEnergyPlatform/oeplatform/pull/2723)
- The profile's datasets tab is one dense list of your own Datasets, replacing
the cards: Dataset (title linked to its page, the name beneath), Status
(Draft, or Published since a date), Tables (a count whose popover names the
Expand Down
Loading