Development #24056
interrompre la connexion en cas de nouveau champ obligatoire (/demandé à l'inscription)
0%
Description
Quand dans un profil on définit un nouveau champ obligatoire, il faudrait qu'à la connexion suivante on arrête l'usager sur une page lui demandant de remplir ces champs.
(ça peut être particulièrement utile pour arrêter l'usager après l'ajout d'un champ "acceptation des cgu (nouvelle version)")
Fichiers
Demandes liées
Révisions associées
misc: refactor ViewRestrictionMiddleware (#24056)
The generic code for checking restrictions is separated from the code
specific to each specific check; here the code to check for
PasswordReset models is extracted into
check_password_reset_view_restriction().
misc: block user without required_on_login attributes (#24056)
Superuser are exempted from the restriction.
Historique
Mis à jour par Benjamin Dauvergne il y a presque 6 ans
La mécanique pour bloquer la navigation sur un critère et rediriger sur une autre page est déjà là (authentic2.middleware.ViewRestrictionMiddleware).
Actuellement chaque plugin a2 peut proposer via une méthode check_view_restriction()
qui doit retourner le nom d'une vue ou une URL. Vu que le concept de plugin est en cours de déprécation pour utiliser simplement des applications Django et leur objet AppConfig à la place il faudrait ici plutôt passer par un hook (donc modifier ViewRestrictionMiddleware pour appeler call_hooks('check_view_restriction')).
Ensuite il suffit de renvoyer l'URL de la vue de profil et de poser un message sur la requête du genre "Vous devez valider les CGUs"[1].
Ce qui m'embête c'est comment générer ce message de manière automatique et intelligible, on génèrera facilement un message du genre "Veuillez compléter les champs requis suivants: date de naissance, validation des CGUs" mais est-ce que c'est suffisant ?
1
def a2_hook_check_view_restriction(self, request): if 'required_fields' in request.session: return # on vérifie si tous les champs requis sont là if unfilled_required_fields: message = _('You must complete required fields: %s') % ', '.join([field.label for field in unfilled_required_fields]) messages.info(request, message) return 'profile_edit' request.session['required_fields'] = True return None
C'est bien si on ne valide une restriction qu'une fois par session (sinon ça fait des requêtes intempestives en base pour rien), i.e. si une restriction de vue passe, il faut le noter dans request.session pour ne pas le refaire.
Mis à jour par Brice Mallet il y a plus de 5 ans
Ce qui m'embête c'est comment générer ce message de manière automatique et intelligible, on génèrera facilement un message du genre "Veuillez compléter les champs requis suivants: date de naissance, validation des CGUs" mais est-ce que c'est suffisant ?
Dans le contexte du cas d'usage "acceptation des CGU" pour un compte créé avant obligation de celui-ci, cela me semble OK
Mis à jour par Benjamin Dauvergne il y a presque 3 ans
- Assigné à mis à Benjamin Dauvergne
- Planning mis à Non
C'est pour moi, joie.
Mis à jour par Benjamin Dauvergne il y a presque 3 ans
- Fichier 0003-misc-block-user-without-required_on_login-attributes.patch 0003-misc-block-user-without-required_on_login-attributes.patch ajouté
- Fichier 0002-misc-refactor-ViewRestrictionMiddleware-24056.patch 0002-misc-refactor-ViewRestrictionMiddleware-24056.patch ajouté
- Fichier 0001-misc-add-a-required_on_login-flag-on-Attribute-24056.patch 0001-misc-add-a-required_on_login-flag-on-Attribute-24056.patch ajouté
- Statut changé de Nouveau à Solution proposée
- Patch proposed changé de Non à Oui
Ça n'aura d'impact que là où c'est activé (en posant required_on_login sur un attribut); sera testé dans un premier temps sur GLC, l'habillage y sera fait via un template custom (pour mettre le lien vers les CGUs dans le label du champ).
Mis à jour par Paul Marillonnet il y a presque 3 ans
- j'ai fait un tour (à coup de find -exec grep) des vues concernées par
Ok pour le logout.if 'logout' in url_name or '-slo' in url_name:
Le SLO c’est les vues deauthentic2.idp.saml
qui vont être concernées. En renommanta2-idp-saml-finish-slo
ena2-idp-saml-slo-finish
on peut avoir un test un peu plus carré à base de.startswith('a2-idp-saml-slo
').
Autre chose dansauthentic2.idp.saml.saml2_enpdoints
il me semble qu’il y a plein d’autres vues frontchannel qui ne contiennent paslogout
ni-slo
et qui pourtant doivent être exemptées de cette redirection vers la page de complétion des attributs manquants par l’usager.
- avec la nouvelle méthode de classe
EditRequired.get_fields
on perd la logique de vérification des scopes des attributs. L’usager peut donc se voir présenter des attributs auxquels il n’a pas accès dans sa page standard d’édition de profil (EditProfile
). Étrange.
De façon plus générale, à la généralisation de ces attributs requis au login, je me pose la question des perfs lorsqu’on tape cette vérification dans le middleware plutôt que d’isoler les vues candidates une à une. Mais bon la valeur de 60 secondes minimum entre deux vérifications en succès deux paraît raisonnable.
(Rien à voir, mais un petit s/succesfull/successful/
dans une ligne de commentaire de 0002.)
Mis à jour par Benjamin Dauvergne il y a presque 3 ans
Paul Marillonnet a écrit :
Dans 0002 :
- j'ai fait un tour (à coup de find -exec grep) des vues concernées par [...] Ok pour le logout.
Le SLO c’est les vues deauthentic2.idp.saml
qui vont être concernées. En renommanta2-idp-saml-finish-slo
ena2-idp-saml-slo-finish
on peut avoir un test un peu plus carré à base de.startswith('a2-idp-saml-slo
').
La vue finish n'est pas concernée, c'est uniquement les vues de SLO initiée par le SP, pas toutes les vues frontchannel, disons que que ça pourrait arriver entre le moment d'émettre un SLO et de recevoir sa réponse, mais je préfère ignorer le problème.
Dans 0003 :
- avec la nouvelle méthode de classe
EditRequired.get_fields
on perd la logique de vérification des scopes des attributs. L’usager peut donc se voir présenter des attributs auxquels il n’a pas accès dans sa page standard d’édition de profil (EditProfile
). Étrange.
Les scopes ne servent pas à cacher des attributs, donc non ça ne sert à rien ici, on peut l'ignorer sans souci.
De façon plus générale, à la généralisation de ces attributs requis au login, je me pose la question des perfs lorsqu’on tape cette vérification dans le middleware plutôt que d’isoler les vues candidates une à une. Mais bon la valeur de 60 secondes minimum entre deux vérifications en succès deux paraît raisonnable.
Je ne pense pas que ce soit un problème.
Mis à jour par Paul Marillonnet il y a presque 3 ans
Benjamin Dauvergne a écrit :
Paul Marillonnet a écrit :
Dans 0002 :
- j'ai fait un tour (à coup de find -exec grep) des vues concernées par [...] Ok pour le logout.
Le SLO c’est les vues deauthentic2.idp.saml
qui vont être concernées. En renommanta2-idp-saml-finish-slo
ena2-idp-saml-slo-finish
on peut avoir un test un peu plus carré à base de.startswith('a2-idp-saml-slo
').La vue finish n'est pas concernée, c'est uniquement les vues de SLO initiée par le SP, pas toutes les vues frontchannel, disons que que ça pourrait arriver entre le moment d'émettre un SLO et de recevoir sa réponse, mais je préfère ignorer le problème.
Où est-ce que tu vois que toutes les vues frontchannel ne vont pas tomber dans cette logique de vérification/redirection ? J’ai loupé ce passage dans le patch.
Dans 0003 :
- avec la nouvelle méthode de classe
EditRequired.get_fields
on perd la logique de vérification des scopes des attributs. L’usager peut donc se voir présenter des attributs auxquels il n’a pas accès dans sa page standard d’édition de profil (EditProfile
). Étrange.Les scopes ne servent pas à cacher des attributs, donc non ça ne sert à rien ici, on peut l'ignorer sans souci.
Et pourtant c’est ce que je comprends à la lecture de EditProfile.get_fields
:
# […]
if scopes:
scopes = set(scopes)
default_fields = [
attribute.name for attribute in attributes if scopes & set(attribute.scopes.split())
]
# […]
if scopes:
# restrict fields to those in the scopes
fields = [field for field in fields if field in default_fields]
# […]
lesquels fields
sont ensuite servis au modelform_factory
. Je loupe un truc ?
De façon plus générale, à la généralisation de ces attributs requis au login, je me pose la question des perfs lorsqu’on tape cette vérification dans le middleware plutôt que d’isoler les vues candidates une à une. Mais bon la valeur de 60 secondes minimum entre deux vérifications en succès deux paraît raisonnable.
Je ne pense pas que ce soit un problème.
Ok, fair enough.
Mis à jour par Benjamin Dauvergne il y a presque 3 ans
- Fichier 0003-misc-block-user-without-required_on_login-attributes.patch 0003-misc-block-user-without-required_on_login-attributes.patch ajouté
- Fichier 0002-misc-refactor-ViewRestrictionMiddleware-24056.patch 0002-misc-refactor-ViewRestrictionMiddleware-24056.patch ajouté
- Fichier 0001-misc-add-a-required_on_login-flag-on-Attribute-24056.patch 0001-misc-add-a-required_on_login-flag-on-Attribute-24056.patch ajouté
Après réflexion j'ai changé mon fusil d'épaule, je passe plutôt par un flag directement sur les vues liées au logout. Le logout SOAP est hors session donc n'est pas concerné.
Mis à jour par Benjamin Dauvergne il y a presque 3 ans
Paul Marillonnet a écrit :
Et pourtant c’est ce que je comprends à la lecture de
EditProfile.get_fields
:
[...] lesquelsfields
sont ensuite servis aumodelform_factory
. Je loupe un truc ?
Le scope est un truc passé en paramètre de la vue, c'est pour limiter le formulaire à un certain ensemble de champs pour des raisons d'organisation, à Strasbourg je crois (genre séparer les champs d'adresse des champs d'état civil). Je ne vois pas de lien avec la fonctionnalité ici implémentée.
Mis à jour par Paul Marillonnet il y a presque 3 ans
Benjamin Dauvergne a écrit :
Le scope est un truc passé en paramètre de la vue, c'est pour limiter le formulaire à un certain ensemble de champs pour des raisons d'organisation, à Strasbourg je crois (genre séparer les champs d'adresse des champs d'état civil). Je ne vois pas de lien avec la fonctionnalité ici implémentée.
D’ac je n’avais pas connaissance de cet usage.
Mis à jour par Paul Marillonnet il y a presque 3 ans
Benjamin Dauvergne a écrit :
Après réflexion j'ai changé mon fusil d'épaule, je passe plutôt par un flag directement sur les vues liées au logout. Le logout SOAP est hors session donc n'est pas concerné.
Oui sur cette épaule ça vise plus juste :)
Juste une remarque de détail avant le ack : du code churn entre 0002 et 0003 qu’on pourrait s'éviter, genre dans 0002 on introduit
+ # prevent blocking people when they logout
+ if 'logout' in url_name or '-slo' in url_name:
qui est une idée finalement non retenue et qu’on vient ensuite changer complètement à nouveau dans 0003.
(Je pense qu’on peut laisser ce bout de méthode
process_view
inchangé dans 0002 et balancer la version finale directement dans 0003.)Mis à jour par Benjamin Dauvergne il y a presque 3 ans
- Fichier 0003-misc-block-user-without-required_on_login-attributes.patch 0003-misc-block-user-without-required_on_login-attributes.patch ajouté
- Fichier 0004-to-be-fixed-up-use-a-decorator-to-indicate-views-whe.patch 0004-to-be-fixed-up-use-a-decorator-to-indicate-views-whe.patch ajouté
- Fichier 0002-misc-refactor-ViewRestrictionMiddleware-24056.patch 0002-misc-refactor-ViewRestrictionMiddleware-24056.patch ajouté
- Fichier 0001-misc-add-a-required_on_login-flag-on-Attribute-24056.patch 0001-misc-add-a-required_on_login-flag-on-Attribute-24056.patch ajouté
(J'ai pris en compte ta remarque sur le code churn, dans la refactorisation je ne garde que le comportement existant, i.e. view == 'auth_logout', donc juste de la refactorisation sans changement de comportement).
Encore un changement, j'ai préféré une approche opt-in, désormais les vues qui sont des points sûrs pour arrêter le parcours de l'utilisateur sont explicitement indiquées, ça concerne :- la homepage (qui dans 99% des cas fait un redirect vers combo, et le 1% restant vers /accounts/ sur GLC)
- /accounts/
- toutes les vues de SSO ou de terminaison de SSO quand le comportement est coupé en deux comme pour CAS et SAML (sso, login, authorize, continue..)
Mis à jour par Benjamin Dauvergne il y a presque 3 ans
J'ai corrigé le bug dans l'IdP SAML sur make_url(continue_sso, ...)
.
Mis à jour par Paul Marillonnet il y a presque 3 ans
Benjamin Dauvergne a écrit :
(J'ai pris en compte ta remarque sur le code churn, dans la refactorisation je ne garde que le comportement existant, i.e. view == 'auth_logout', donc juste de la refactorisation sans changement de comportement).
Encore un changement, j'ai préféré une approche opt-in, désormais les vues qui sont des points sûrs pour arrêter le parcours de l'utilisateur sont explicitement indiquées, ça concerne :
[…]
Oui en mode opt-in c’est bien aussi.
Je ne comprends pas l’idée du décorateur cependant. Pour moi ce flag view_restriction
c’est inhérent à la vue, et non quelque chose qui s’applique à une ou plusieurs de ses occurrences dans les urls.py
.
Du coup avec le décorateur ça donne du code de copie qui il me semble n’a pas lieu d'être : on ne se retrouve pas dans le cas où deux versions (l’une originale, l’autre copiée-décorée) de la vue coexistent.
Mis à jour par Benjamin Dauvergne il y a presque 3 ans
- Fichier 0003-misc-block-user-without-required_on_login-attributes.patch 0003-misc-block-user-without-required_on_login-attributes.patch ajouté
- Fichier 0004-to-be-fixed-up-use-a-decorator-to-indicate-views-whe.patch 0004-to-be-fixed-up-use-a-decorator-to-indicate-views-whe.patch ajouté
- Fichier 0002-misc-refactor-ViewRestrictionMiddleware-24056.patch 0002-misc-refactor-ViewRestrictionMiddleware-24056.patch ajouté
- Fichier 0001-misc-add-a-required_on_login-flag-on-Attribute-24056.patch 0001-misc-add-a-required_on_login-flag-on-Attribute-24056.patch ajouté
J'ai gardé le décorateur parce que j'aime bien ça car c'est beaucoup plus visible que les xxx.flag = True
après les vues mais j'ai grandement simplifié et là c'est directement visible dans les views.py.
Mis à jour par Paul Marillonnet il y a presque 3 ans
- Statut changé de Solution proposée à Solution validée
D’ac ça me va comme ça. Juste attendre que Jenkins voie vert pour pousser mais dans l’esprit de la solution proposée c’est ack pour moi.
Mis à jour par Benjamin Dauvergne il y a presque 3 ans
- Statut changé de Solution validée à Résolu (à déployer)
commit 5ff1ccaae83d7a095c9f479adf2615aea0af0320 Author: Benjamin Dauvergne <bdauvergne@entrouvert.com> Date: Fri Jul 16 10:57:24 2021 +0200 misc: block user without required_on_login attributes (#24056) Superuser are exempted from the restriction. commit c8e3f9376ba1e3315be1e2a7edb50ad66df26cf6 Author: Benjamin Dauvergne <bdauvergne@entrouvert.com> Date: Tue Jul 6 10:12:23 2021 +0200 misc: refactor ViewRestrictionMiddleware (#24056) The generic code for checking restrictions is separated from the code specific to each specific check; here the code to check for PasswordReset models is extracted into check_password_reset_view_restriction(). commit afd5f689cb2438f133771cd7bbcbdd30b0ddd791 Author: Benjamin Dauvergne <bdauvergne@entrouvert.com> Date: Fri Jul 2 11:47:58 2021 +0200 misc: add a required_on_login flag on Attribute (#24056)
Mis à jour par Frédéric Péters il y a presque 3 ans
- Statut changé de Résolu (à déployer) à Solution déployée
Mis à jour par Mikaël Ates (de retour le 29 avril) il y a plus de 2 ans
- Lié à Development #55865: Ajouter la case à cocher « Requis à la connexion » sur la page de configuration des attributs de profil. ajouté
misc: add a required_on_login flag on Attribute (#24056)