1
0
mirror of https://gitlab.crans.org/bde/nk20 synced 2025-07-04 22:54:05 +02:00

Compare commits

..

17 Commits

Author SHA1 Message Date
85ea43a7cf change pipeline 2025-07-04 16:27:04 +02:00
f54dd30482 fix logout test 2025-07-03 15:18:29 +02:00
7eafe33945 Merge branch 'main' into django-5.2 2025-07-03 14:24:58 +02:00
6edef619aa change requirements.txt 2025-07-03 11:37:07 +02:00
8a1f30ebe2 Merge branch 'wei' into 'main'
Wei

See merge request bde/nk20!325
2025-07-01 18:14:45 +02:00
1567bc6ce5 Merge branch 'oidc' into 'main'
Oidc

See merge request bde/nk20!324
2025-06-27 22:29:51 +02:00
c411197af3 multiline support for RSA key in env 2025-06-27 22:13:43 +02:00
cdc6f0a3f8 Fix jwks.json 2025-06-27 12:13:54 +02:00
c153d5f10a Merge branch 'wei' into 'main'
Wei

See merge request bde/nk20!323
2025-06-26 17:08:27 +02:00
763535bea4 Merge branch 'oidc' into 'main'
OIDC 0 Quark 1

See merge request bde/nk20!322
2025-06-17 16:02:40 +02:00
df0d886db9 linters 2025-06-17 11:46:33 +02:00
092cc37320 OIDC 0 Quark 1 2025-06-17 00:38:11 +02:00
16b55e23af Merge branch 'thomasl-main-patch-84944' into 'main'
Update doc about scripts

See merge request bde/nk20!321
2025-06-14 20:24:49 +02:00
97621e8704 Update doc about scripts 2025-06-14 20:07:29 +02:00
cf4c23d1ac Merge branch 'oidc' into 'main'
oidc

See merge request bde/nk20!320
2025-06-14 18:36:24 +02:00
d71105976f oidc 2025-06-14 18:01:42 +02:00
89cc03141b allow search with club name 2025-06-12 18:48:29 +02:00
14 changed files with 82 additions and 45 deletions

View File

@ -21,3 +21,6 @@ EMAIL_PASSWORD=CHANGE_ME
# Wiki configuration
WIKI_USER=NoteKfet2020
WIKI_PASSWORD=
# OIDC
OIDC_RSA_PRIVATE_KEY=CHANGE_ME

View File

@ -8,7 +8,7 @@ variables:
GIT_SUBMODULE_STRATEGY: recursive
# Ubuntu 22.04
py310-django42:
py310-django52:
stage: test
image: ubuntu:22.04
before_script:
@ -22,10 +22,10 @@ py310-django42:
python3-djangorestframework python3-django-oauth-toolkit python3-psycopg2 python3-pil
python3-babel python3-lockfile python3-pip python3-phonenumbers python3-memcache
python3-bs4 python3-setuptools tox texlive-xetex
script: tox -e py310-django42
script: tox -e py310-django52
# Debian Bookworm
py311-django42:
py311-django52:
stage: test
image: debian:bookworm
before_script:
@ -37,7 +37,7 @@ py311-django42:
python3-djangorestframework python3-django-oauth-toolkit python3-psycopg2 python3-pil
python3-babel python3-lockfile python3-pip python3-phonenumbers python3-memcache
python3-bs4 python3-setuptools tox texlive-xetex
script: tox -e py311-django42
script: tox -e py311-django52
linters:
stage: quality-assurance

View File

@ -61,8 +61,8 @@ Bien que cela permette de créer une instance sur toutes les distributions,
6. (Optionnel) **Création d'une clé privée OpenID Connect**
Pour activer le support d'OpenID Connect, il faut générer une clé privée, par
exemple avec openssl (`openssl genrsa -out oidc.key 4096`), et renseigner son
emplacement dans `OIDC_RSA_PRIVATE_KEY` (par défaut `/var/secrets/oidc.key`).
exemple avec openssl (`openssl genrsa -out oidc.key 4096`), et copier la clé dans .env dans le champ
`OIDC_RSA_PRIVATE_KEY`.
7. Enjoy :
@ -237,8 +237,8 @@ Sinon vous pouvez suivre les étapes décrites ci-dessous.
7. **Création d'une clé privée OpenID Connect**
Pour activer le support d'OpenID Connect, il faut générer une clé privée, par
exemple avec openssl (`openssl genrsa -out oidc.key 4096`), et renseigner son
emplacement dans `OIDC_RSA_PRIVATE_KEY` (par défaut `/var/secrets/oidc.key`).
exemple avec openssl (`openssl genrsa -out oidc.key 4096`), et renseigner le champ
`OIDC_RSA_PRIVATE_KEY` dans le .env (par défaut `/var/secrets/oidc.key`).
8. *Enjoy \o/*

View File

@ -63,7 +63,8 @@ class FoodListView(ProtectQuerysetMixin, LoginRequiredMixin, MultiTableMixin, Li
valid_regex = is_regex(pattern)
suffix = '__iregex' if valid_regex else '__istartswith'
prefix = '^' if valid_regex else ''
qs = qs.filter(Q(**{f'name{suffix}': prefix + pattern}))
qs = qs.filter(Q(**{f'name{suffix}': prefix + pattern})
| Q(**{f'owner__name{suffix}': prefix + pattern}))
else:
qs = qs.none()
search_table = qs.filter(PermissionBackend.filter_queryset(self.request, Food, 'view'))

View File

@ -44,7 +44,7 @@ class TemplateLoggedInTests(TestCase):
self.assertRedirects(response, settings.LOGIN_REDIRECT_URL, 302, 302)
def test_logout(self):
response = self.client.get(reverse("logout"))
response = self.client.post(reverse("logout"))
self.assertEqual(response.status_code, 200)
def test_admin_index(self):

View File

@ -13,7 +13,7 @@ def register_note_urls(router, path):
router.register(path + '/note', NotePolymorphicViewSet)
router.register(path + '/alias', AliasViewSet)
router.register(path + '/trust', TrustViewSet)
router.register(path + '/consumer', ConsumerViewSet)
router.register(path + '/consumer', ConsumerViewSet, basename='alias2')
router.register(path + '/transaction/category', TemplateCategoryViewSet)
router.register(path + '/transaction/transaction', TransactionViewSet)

View File

@ -1,8 +1,10 @@
# Copyright (C) 2018-2025 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
from oauth2_provider.oauth2_validators import OAuth2Validator
from oauth2_provider.scopes import BaseScopes
from member.models import Club
from note.models import Alias
from note_kfet.middlewares import get_current_request
from .backends import PermissionBackend
@ -17,25 +19,46 @@ class PermissionScopes(BaseScopes):
"""
def get_all_scopes(self):
return {f"{p.id}_{club.id}": f"{p.description} (club {club.name})"
for p in Permission.objects.all() for club in Club.objects.all()}
scopes = {f"{p.id}_{club.id}": f"{p.description} (club {club.name})"
for p in Permission.objects.all() for club in Club.objects.all()}
scopes['openid'] = "OpenID Connect"
return scopes
def get_available_scopes(self, application=None, request=None, *args, **kwargs):
if not application:
return []
return [f"{p.id}_{p.membership.club.id}"
for t in Permission.PERMISSION_TYPES
for p in PermissionBackend.get_raw_permissions(get_current_request(), t[0])]
scopes = [f"{p.id}_{p.membership.club.id}"
for t in Permission.PERMISSION_TYPES
for p in PermissionBackend.get_raw_permissions(get_current_request(), t[0])]
scopes.append('openid')
return scopes
def get_default_scopes(self, application=None, request=None, *args, **kwargs):
if not application:
return []
return [f"{p.id}_{p.membership.club.id}"
for p in PermissionBackend.get_raw_permissions(get_current_request(), 'view')]
scopes = [f"{p.id}_{p.membership.club.id}"
for p in PermissionBackend.get_raw_permissions(get_current_request(), 'view')]
scopes.append('openid')
return scopes
class PermissionOAuth2Validator(OAuth2Validator):
oidc_claim_scope = None # fix breaking change of django-oauth-toolkit 2.0.0
oidc_claim_scope = OAuth2Validator.oidc_claim_scope
oidc_claim_scope.update({"name": 'openid',
"normalized_name": 'openid',
"email": 'openid',
})
def get_additional_claims(self, request):
return {
"name": request.user.username,
"normalized_name": Alias.normalize(request.user.username),
"email": request.user.email,
}
def get_discovery_claims(self, request):
claims = super().get_discovery_claims(self)
return claims + ["name", "normalized_name", "email"]
def validate_scopes(self, client_id, scopes, client, request, *args, **kwargs):
"""
@ -54,6 +77,8 @@ class PermissionOAuth2Validator(OAuth2Validator):
if scope in scopes:
valid_scopes.add(scope)
request.scopes = valid_scopes
if 'openid' in scopes:
valid_scopes.add('openid')
request.scopes = valid_scopes
return valid_scopes

View File

@ -19,6 +19,7 @@ EXCLUDED = [
'oauth2_provider.accesstoken',
'oauth2_provider.grant',
'oauth2_provider.refreshtoken',
'oauth2_provider.idtoken',
'sessions.session',
]

View File

@ -171,7 +171,7 @@ class ScopesView(LoginRequiredMixin, TemplateView):
available_scopes = scopes.get_available_scopes(app)
context["scopes"][app] = OrderedDict()
items = [(k, v) for (k, v) in all_scopes.items() if k in available_scopes]
items.sort(key=lambda x: (int(x[0].split("_")[1]), int(x[0].split("_")[0])))
# items.sort(key=lambda x: (int(x[0].split("_")[1]), int(x[0].split("_")[0])))
for k, v in items:
context["scopes"][app][k] = v

View File

@ -136,7 +136,7 @@ de diffusion utiles.
Faîtes attention, donc où la sortie est stockée.
Il prend 2 options :
Il prend 4 options :
* ``--type``, qui prend en argument ``members`` (défaut), ``clubs``, ``events``, ``art``,
``sport``, qui permet respectivement de sortir la liste des adresses mails des adhérent⋅es
@ -149,7 +149,10 @@ Il prend 2 options :
pour la ML Adhérents, pour exporter les mails des adhérents au BDE pendant n'importe
laquelle des ``n+1`` dernières années.
Le script sort sur la sortie standard la liste des adresses mails à inscrire.
* ``--email``, qui prend en argument une chaine de caractère contenant une adresse email.
Si aucun email n'est renseigné, le script sort sur la sortie standard la liste des adresses mails à inscrire.
Dans le cas contraire, la liste est envoyée à l'adresse passée en argument.
Attention : il y a parfois certains cas particuliers à prendre en compte, il n'est
malheureusement pas aussi simple que de simplement supposer que ces listes sont exhaustives.

View File

@ -39,6 +39,7 @@ SECURE_HSTS_PRELOAD = True
INSTALLED_APPS = [
# External apps
'bootstrap_datepicker_plus',
'cas_server',
'colorfield',
'crispy_bootstrap4',
'crispy_forms',
@ -270,7 +271,7 @@ OAUTH2_PROVIDER = {
'PKCE_REQUIRED': False, # PKCE (fix a breaking change of django-oauth-toolkit 2.0.0)
'OIDC_ENABLED': True,
'OIDC_RSA_PRIVATE_KEY':
os.getenv('OIDC_RSA_PRIVATE_KEY', '/var/secrets/oidc.key'),
os.getenv('OIDC_RSA_PRIVATE_KEY', 'CHANGE_ME_IN_ENV_SETTINGS').replace('\\n', '\n'), # for multilines
'SCOPES': { 'openid': "OpenID Connect scope" },
}

View File

@ -138,9 +138,12 @@ SPDX-License-Identifier: GPL-3.0-or-later
<a class="dropdown-item" href="{% url 'member:user_detail' pk=request.user.pk %}">
<i class="fa fa-user"></i> {% trans "My account" %}
</a>
<a class="dropdown-item" href="{% url 'logout' %}">
<i class="fa fa-sign-out"></i> {% trans "Log out" %}
</a>
<form method="post" action="{% url 'logout' %}">
{% csrf_token %}
<button class="dropdown-item" type=submit">
<i class="fa fa-sign-out"></i> {% trans "Log out" %}
</button>
</form>
</div>
</li>
{% else %}

View File

@ -1,20 +1,20 @@
beautifulsoup4~=4.12.3
crispy-bootstrap4~=2023.1
Django~=4.2.9
beautifulsoup4~=4.13.4
crispy-bootstrap4~=2025.6
Django~=5.2.4
django-bootstrap-datepicker-plus~=5.0.5
#django-cas-server~=2.0.0
django-colorfield~=0.11.0
django-crispy-forms~=2.1.0
django-extensions>=3.2.3
django-filter~=23.5
django-cas-server~=3.1.0
django-colorfield~=0.14.0
django-crispy-forms~=2.4.0
django-extensions>=4.1.0
django-filter~=25.1
#django-htcpcp-tea~=0.8.1
django-mailer~=2.3.1
django-oauth-toolkit~=2.3.0
django-phonenumber-field~=7.3.0
django-mailer~=2.3.2
django-oauth-toolkit~=3.0.1
django-phonenumber-field~=8.1.0
django-polymorphic~=3.1.0
djangorestframework~=3.14.0
djangorestframework~=3.16.0
django-rest-polymorphic~=0.1.10
django-tables2~=2.7.0
django-tables2~=2.7.5
python-memcached~=1.62
phonenumbers~=8.13.28
Pillow>=10.2.0
phonenumbers~=9.0.8
Pillow>=11.3.0

View File

@ -1,13 +1,13 @@
[tox]
envlist =
# Ubuntu 22.04 Python
py310-django42
py310-django52
# Debian Bookworm Python
py311-django42
py311-django52
# Ubuntu 24.04 Python
py312-django42
py312-django52
linters
skipsdist = True