Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sécurité: activation de l'intergiciel LoginRequiredMiddleware #5178

Draft
wants to merge 7 commits into
base: master
Choose a base branch
from

Conversation

xavfernandez
Copy link
Contributor

@xavfernandez xavfernandez commented Nov 29, 2024

🤔 Pourquoi ?

Pour avoir des vues protégées par défaut (en gardant en tête qu'être authentifié n'apporte aucune garantie, vu la facilité à se créer un compte).

(il reste le nettoyage des LoginRequiredMixin & login_required)

🍰 Comment ?

Les débats à trancher:

  • pour les Class Based Views:

    • utilisation d'un décorateur sur le dispatch
    • ou définition/utilisation d'un mixin pour décorer dans as_view

    => la seconde solution me semble plus propre/claire

  • pour les vues utilisant un user_passes_test pour rediriger les utilisateurs loggés vers une autre vue: cela rentre en conflit avec l'intergiciel, qui utilise le login_url défini par ce décorateur pour rediriger lors de l'authentification ce qui n'est pas du tout ce que l'on souhaite:

    • soit utilisation de mon unset_login_redirect
    • soit redéfinition d'un décorateur maison qui fait le redirect
    • soit incorporation de ce check dans les différentes vues

    => je serais plutôt en faveur d'un décorateur maison qui aurait le mérite, comme user_passes_test actuellement de mettre en évidence les utilisateurs susceptibles d'accéder à cette vue)

🚨 À vérifier

  • Mettre à jour le CHANGELOG_breaking_changes.md ?

🏝️ Comment tester

Les instructions pour reproduire le problème, les profils de test, le parcours spécifique à utiliser, etc. Si vous disposez d'une recette jetable, mettre l'URL pour tester dans cette partie.

💻 Captures d'écran

@xavfernandez xavfernandez added the no-changelog Ne doit pas figurer dans le journal des changements. label Nov 29, 2024
@xavfernandez xavfernandez self-assigned this Nov 29, 2024
@xavfernandez xavfernandez force-pushed the xfernandez/LoginRequiredMiddleware branch from 6bcbd50 to 1fe34fa Compare December 2, 2024 09:22
@@ -272,7 +273,9 @@ def details_for_company(request, job_application_id, template_name="apply/proces
return render(request, template_name, context)


@login_required
# XXX this is dirty
# Should we stop using user_passes_test ? Define our own ?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stop using user_passes_test. De toute façon, je ne vois pas comment un employeur pourrait se retrouver sur cette vue. À mon avis, c’est du ceinture bretelle peu utile pour éviter une 404. J’aimerais autant que le système évite de rattraper silencieusement les erreurs des dévs.

La ligne date de 2021, je ne suis vraiment pas convaincu qu’elle ait déjà servi. (a532e86)

Copy link
Contributor Author

@xavfernandez xavfernandez Dec 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moi j'aime bien comme préfiltre pour dire rapidement qui est censé avoir accès à cette vue.
Plutôt d'accord qu'il vaudrait mieux servir une 403/404 plutôt que de de renvoyer discrètement vers le dashboard.

Je verrais bien des décorateurs à la require_http_methods du genre def require_user_kinds(*user_kinds).
@require_user_kind(UserKind.PRESCRIBER, UserKind.EMPLOYER).
Cela sert à la fois de garde-fou et de documentation.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Si tu veux. En général on va chercher plus que ça pour les autorisations d’accès, mais ça fait une description basique des permissions 🤷

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dans l'idée le décorateur permet globalement de s'éviter le boilerplate if not has_rights(): raise PermissionDenied au début de chaque fonction (il n'y a pas ça dans les vues stats et ça nous pète à la gueule de temps en temps) mais je suis d'accord que renvoyer vers la page de login est assez inutile dans notre cas car souvent la personne est déjà connectée donc elle peux rien faire de plus (i.e. erreur 403).
Et au vu des @user_passes_test() actuel le user.is_active pourrais probablement être généralisé, et ensuite on ne check que le UserKind (modulo les is_prescriber_with_authorized_org), et l'avantage des décorateurs c'est qu'on peux facilement les empiler au besoin.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actuellement on utilise 3 infos dans nos user_passes_test:

  • le kind (via is_prescriber, etc)
  • is_superuser
  • is_prescriber_with_authorized_org
    Donc je serais plutôt pour garder une syntaxe similaire à user_passes_test, ou à défaut lister les attributs à vérifier :
    @require_user_passes(["is_employer", "is_prescriber_with_authorized_org"]

Par contre, en effet, la redirection vers login_url ou vers le dashboard n'est pas pertinente, autant lever une 404 et se rendre compte qu'il y a un trou dans la passoire quelque part.

@@ -266,6 +278,10 @@ class CompanyUserView(CompanyBaseView, TemplateView):

template_name = "signup/employer.html"

@login_not_required
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

À se demander si on ne voudrait pas un LoginNotRequiredMixin ? (réponse C de la 1ere question 😛)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tu veux dire la réponse B/ce Mixin ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oui, mis à part que j’aurais décoré dispatch pour être symmétrique avec le LoginRequiredMixin de Django. 🤷

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alors oui et non.
Le LoginRequiredMixin fait des choses dans le dispatch.
Alors que le LoginNotRequiredMixin.dispatch ne ferait rien.
Le but est vraiment de mettre l'attribut login_required à False sur la vue retournée par as_view() pour que LoginRequiredMiddleware la laisse tranquille.
Et Django autorise de décorer la fonction dispatch mais à la fin il fait juste https://github.com/django/django/blob/5.1.3/django/views/generic/base.py#L115-L117 🙈

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 pour le mixin, je trouve que ça fait bizarre de devoir utiliser un décorateur sur une méthode très spécifique (et pas forcément surcharger) dans le cas des CBV.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hummm, merci pour l’explication. Dans ce cas, 2. (as_view) me semble également préférable.

Copy link
Contributor

@rsebille rsebille left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vu qu'on à clairement plus de vue connectée que non-connectée ça me semble OK comme logique.

@@ -266,6 +278,10 @@ class CompanyUserView(CompanyBaseView, TemplateView):

template_name = "signup/employer.html"

@login_not_required
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 pour le mixin, je trouve que ça fait bizarre de devoir utiliser un décorateur sur une méthode très spécifique (et pas forcément surcharger) dans le cas des CBV.

@@ -272,7 +273,9 @@ def details_for_company(request, job_application_id, template_name="apply/proces
return render(request, template_name, context)


@login_required
# XXX this is dirty
# Should we stop using user_passes_test ? Define our own ?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dans l'idée le décorateur permet globalement de s'éviter le boilerplate if not has_rights(): raise PermissionDenied au début de chaque fonction (il n'y a pas ça dans les vues stats et ça nous pète à la gueule de temps en temps) mais je suis d'accord que renvoyer vers la page de login est assez inutile dans notre cas car souvent la personne est déjà connectée donc elle peux rien faire de plus (i.e. erreur 403).
Et au vu des @user_passes_test() actuel le user.is_active pourrais probablement être généralisé, et ensuite on ne check que le UserKind (modulo les is_prescriber_with_authorized_org), et l'avantage des décorateurs c'est qu'on peux facilement les empiler au besoin.

@xavfernandez xavfernandez force-pushed the xfernandez/LoginRequiredMiddleware branch 2 times, most recently from 61aeaa0 to 886545e Compare December 3, 2024 08:03
@xavfernandez xavfernandez force-pushed the xfernandez/LoginRequiredMiddleware branch 3 times, most recently from 5bd0e1b to 210d8b1 Compare December 3, 2024 08:36
@xavfernandez xavfernandez force-pushed the xfernandez/LoginRequiredMiddleware branch from 210d8b1 to d8d8806 Compare December 3, 2024 12:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
no-changelog Ne doit pas figurer dans le journal des changements.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants