api: change client's password handling (#89456) #291
Open
yweber
wants to merge 1 commits from
wip/89456-api-client-password
into main
pull from: wip/89456-api-client-password
merge into: entrouvert:main
entrouvert:main
entrouvert:wip/89940-auth-oidc-logger-l-id-token-avan
entrouvert:wip/89627-dans-le-journal-pouvoir-filtrer
entrouvert:wip/83700-api-users-crud-phone-uniqueness-tel
entrouvert:wip/40685-squash-des-migrations-partial
entrouvert:wip/88158-phone-authn-lost-password-config-in-template-ctx
entrouvert:wip/88146-phone-authn-registration-fields-not-optional
entrouvert:wip/86937-accounts-multivalued-attribute-multiselect
entrouvert:wip/87701-phone-identifier-attribute-required
entrouvert:wip/56850-IndexError-filtrage-par-ou
entrouvert:wip/76835-open-redirection
entrouvert:wip/40685-squash-des-migrations
entrouvert:wip/72462-BO-inclure-courriels-dans-l-impo
entrouvert:wip/75205-rbac-admin-role-user-perm-restriction
entrouvert:wip/86671-accounts-multiple-attribute-readonly-display
entrouvert:wip/86670-api-users-attributes-multiple
entrouvert:wip/86663-idp-oidc-multiple-attributes-into-claims
entrouvert:wip/86086-FileNotFoundError-en-cherchant-a
entrouvert:wip/76224-enable-client-id-secret-edition-for-oidc-service
entrouvert:wip/76359-list-api-client-inherited-roles
entrouvert:wip/76858-Ne-pas-permettre-la-reutilisatio
entrouvert:wip/82737-authn-tel-post-registration-account-selection-buggy-form
entrouvert:wip/85276-bo-phone-identifier-duplicate-prevention
entrouvert:wip/75684-add-aria-required-to-registration-field
entrouvert:wip/82736-account-create-as-recent-authn
entrouvert:wip/68946-auth-oidc-provider-jwkset-from-wellknown
entrouvert:wip/82739-account-deletion-no-phone-yet-validated
entrouvert:wip/82522-ldap-user-bo-page-no-deletion-info
entrouvert:wip/83078-role-summary-refresh-cache-job-infra
entrouvert:wip/83211-a11y-add-title-attribute-to-password-policy-rules
entrouvert:wip/83078-role-summary-refresh-cache
entrouvert:wip/83227-phone-based-registration-api-save-registration-data
entrouvert:wip/83190-phone-registration-api-endpoint
entrouvert:wip/83024-idp-oidc-authz-default-max-value
entrouvert:wip/81334-manage-apiclient-edit-tabs
entrouvert:wip/81845-bo-form-error-on-hidden-tab
entrouvert:wip/82388-phone-authn-accounts-verification-label
entrouvert:wip/66416-ldap-add-ppolicy-support
entrouvert:wip/82128-do-not-migrate-role-attribution-condition-with-on-name-set
entrouvert:wip/81943-drf314
entrouvert:wip/81945-bookworm-jwcrypto-version
entrouvert:wip/81282-remove-user-phone-column
entrouvert:wip/81478-csv-buggy-password-hashes
entrouvert:wip/81152-phone-info-stats
entrouvert:wip/79807-zxcvbn-champs-profil
entrouvert:wip/80236-vacuum-at-cleanup
entrouvert:wip/78907-zxcvbn-champs-profil
entrouvert:wip/72614-phone-identifier-modification-ui
entrouvert:wip/79183-phone-authn-healthcheck-endpoint
entrouvert:wip/75474-auth-oidc-active-attributes-mapping
entrouvert:wip/79135-user-phone-model-field-deprecation
entrouvert:wip/79489-configuration-d-un-moyen-d-authe
entrouvert:wip/79507-page-d-info-sur-un-moyen-d-authe
entrouvert:wip/79528-libelle-valeur-par-defaut-du-sys
entrouvert:wip/77243-Voir-les-roles-administres-par-u
entrouvert:tmp-test-authn-migration
entrouvert:wip/78919-authn-local-admin-manager-perm
entrouvert:wip/78046-password-authn-identifier-selection
entrouvert:wip/78409-password-lost-phone-retrieval-next-url
entrouvert:wip/78096-password-lost-phone-retrieval-next-url
entrouvert:wip/78157-phone-registration-enforce-signed-next-url
entrouvert:wip/77756-authn-addroleaction-conditions
entrouvert:wip/77452-idp-oidc-ne-pas-lever-d-erreur-c
entrouvert:wip/77296-default-saml-service-appearance
entrouvert:wip/77366-authn-manager-oidc-claim-edit
entrouvert:wip/77309-default-saml-service-appearance
entrouvert:wip/69890-password-lost-sms-recovery
entrouvert:wip/72449-login-authn-single-identifier-field
entrouvert:wip/74969-auth-oidc-masquer-les-options-ho
entrouvert:wip/75138-sso-authz-default-appearance
entrouvert:wip/75139-neutral-authz-theme-bo-config
entrouvert:wip/76835-Verifier-la-possibilite-de-redir
entrouvert:wip/72538-auth-oidc-prompt-none-error
entrouvert:wip/76542-utiliser-hobo-multitenant-spoole
entrouvert:wip/76342-a2_rbac-role-natural-keys
entrouvert:wip/69606-statistics-performance
entrouvert:wip/65942-rebase
entrouvert:wip/73677-phone-usages-stats-command
entrouvert:wip/66053-csv-import-stocker-une-informati-postrebase-paul
entrouvert:wip/73150-fc-existing-account-manual-link
entrouvert:wip/66053-csv-import-stocker-une-informati
entrouvert:wip/73148-fc-link-mail-validation-on-account-create
entrouvert:wip/69561-page-title
entrouvert:wip/65877-idp-oidc-sync-claim-resolution
entrouvert:wip/65942-idp-oidc-client-api-access-queryset-reduction
entrouvert:wip/72870-fc-nolink-default
entrouvert:wip/auth-oidc-passive
entrouvert:wip/62710-auth-oidc-mainline-sync-cmd
entrouvert:wip/test-tox-4
entrouvert:wip/71463-api-ou-permissions-filtering
entrouvert:wip/66053-csv-import-verification-source
entrouvert:hotfix/v4.49
entrouvert:wip/71069-a11y-close-label-email-hint
entrouvert:wip/65411-auth-fc-locker-le-sub-pendant-le
entrouvert:wip/69335-check-password-drf-api
entrouvert:wip/69468-ldap-password-policy-control-mes
entrouvert:wip/69466-PasswordResetConfirmView-gerer-c
entrouvert:wip/69464-PasswordChangeView-en-cas-de-ref
entrouvert:hotfix/v4.37
entrouvert:wip/blocktrans-trimmed
entrouvert:wip/69526-apiclient-key
entrouvert:wip/62868-su-view-ldap-authn-failed-crash
entrouvert:wip/65411-auth-fc-sub-lock
entrouvert:wip/68607-Preparation-django-DeprecationWa
entrouvert:wip/68607-local-paul
entrouvert:wip/43221-CAS-and-referer-header
entrouvert:wip/xdist
entrouvert:wip/66986-saml-bo-idp-md-sources
entrouvert:wip/66794-role-add-form
entrouvert:wip/66497-manager-homepage
entrouvert:wip/60783-manu
entrouvert:wip/66207-sidepage-menu
entrouvert:wip/65943-idp-oidc-api-user-attr-reduction
entrouvert:wip/65122-user-deletion-message
entrouvert:wip/distutils
entrouvert:wip/63937-ldapobject-timeout
entrouvert:wip/62900-pm-personal-data-minimization-during-authz
entrouvert:wip/62889-pm-do-not-ask-again
entrouvert:wip/20690-Ajouter-automatiquement-des-role
entrouvert:hotfix/v3.81
entrouvert:wip/34829-Avoir-des-vues-backoffice-pour-q
entrouvert:wip/57499-role-members-through-soft-deletion
entrouvert:wip/61299-attribute-kinds-title
entrouvert:wip-paul/non-binary-title
entrouvert:wip/61196-manager-utiliser-le-nouveau-widg
entrouvert:wip/61188-UI-gestion-des-roles-impossible-
entrouvert:wip/50861-api-memberships-roles-ne-pas-ecr
entrouvert:wip/60493-ldap-enabled-option
entrouvert:wip/60488-auth-oidc-strategy-email
entrouvert:wip/locale-boolean-attr
entrouvert:wip/59414-test-59482
entrouvert:wip/58829-django-rbac-operation-model
entrouvert:wip/58948-missing-migration
entrouvert:wip/57663-Definir-une-permission-pour-acce
entrouvert:hotfix/v3.50
entrouvert:wip/47024-auth_oidc-faulty-provider-attribute-sharing-consent
entrouvert:wip/56850-IndexError-list-index-out-of-ran
entrouvert:wip/tox
entrouvert:wip/tel-account-simple
entrouvert:wip/53754-authentification-forcee-ForceAut
entrouvert:wip/54525-journal-expired-sessions
entrouvert:wip/54185-ldap-password-messages
entrouvert:hotfix/v3.34
entrouvert:wip/26277-remove-duplicated-jquery
entrouvert:hotfix/v3.32
entrouvert:wip/test-eo-jenkins-lib
entrouvert:hotfix/v3.2
entrouvert:hotfix/v2.100
entrouvert:wip/tel-account
entrouvert:wip/22687-pouvoir-utiliser-le-niveau-d-isolatoin-serializable-sur-postgresql
entrouvert:hotfix/v2.82
entrouvert:wip/48090-crash-migrations
entrouvert:wip/48352-custom-user-dans-free-text-searc
entrouvert:wip/tmp/paul-devinst-crash-troubleshooting
entrouvert:hotfix/v2.67
entrouvert:wip/36966-auth-oidc-signed-requests
entrouvert:hotfix/v2.64
entrouvert:hotfix/v2.62
entrouvert:hotfix/v2.47-email-validation
entrouvert:wip/importlib-resources-limit
entrouvert:wip/virtualenv-limit
entrouvert:wip/py3-nouvelle-vague
entrouvert:hotfix/v2.18
entrouvert:hotfix/v2.7
entrouvert:wip/33550-multifacteurs-2-haut-niv
entrouvert:wip/move-a2-rbac-tests
entrouvert:hotfix/v2.1.78
entrouvert:wip/33745-missing-migration-files
entrouvert:wip/misc_paul_ui_snapshots
entrouvert:wip/25645-roles-in-users-api
entrouvert:wip/26251-avatar-cadrage-cote-client-de-l-
entrouvert:wip/play-with-jenkinsfile
entrouvert:wip/25645-API-pour-obtenir-la-liste-des-roles-portes-par-un-utilisateur
entrouvert:wip/22865-Ne-plug-utiliser-pkg-resources-pour-charger-les-applications-incluses-dans-authentic
entrouvert:wip/stretch
entrouvert:wip/review-25045
entrouvert:wip/delete-render-block
entrouvert:wip/newpassword
entrouvert:wip/django111
entrouvert:release-2.1.20
entrouvert:release-2.1.19
entrouvert:release-2.1.18
entrouvert:release-2.1.15
entrouvert:release-2.1.14
entrouvert:release-2.1.13
entrouvert:debian-squeeze
No reviewers
Labels
Clear labels
No items
No Label
Milestone
Clear milestone
No items
No Milestone
Assignees
Clear assignees
No Assignees
2 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.
No due date set.
Dependencies
No dependencies set.
Reference: entrouvert/authentic#291
Reference in New Issue
No description provided.
Delete Branch "wip/89456-api-client-password"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Je ne suis vraiment pas certain de ne pas m'être embarqué sur une mauvaise piste d'implémentation
308fd38115
to1f734b3ab6
1f734b3ab6
tob9f51f7c2a
Ça m'a l'air ok, juste un souci pour la migration, il faudrait créer d'abord ton nouveau champ sous le nom new_password. Faire une migration de donnée pour prendre les valeurs en clair, les hasher, les déplacer dans le nouveau champ et à la fin supprimer l'ancien champ et renommer le nouveau.
Ensuite je ne sais pas dans quel mesure on peut reprendre le code de User.check_password() qui s'occupe aussi de mettre à jour le hachage utilisé régulièrement pendant la validation (par exemple Django augmente régulièrement le nombre de round de hachage).
@ -1472,2 +1472,3 @@
try:
api_client = APIClient.objects.get(identifier=identifier, password=password)
api_client = APIClient.objects.get(identifier=identifier)
if not api_client.check_password(password):
Tu peux mettre
or not api_client.check_password() or
ans leif
plus loin.Bien vu, merci !
@ -73,2 +73,3 @@
try:
return APIClient.objects.get(identifier=userid, password=password), None
api_client = APIClient.objects.get(identifier=userid)
if not api_client.check_password(password):
Juste faire
if check_password(): return api_cient, None
non ? Pas la peine de nettoyer la variable api_client.Complètement ! merci :)
@ -759,2 +765,4 @@
return False
def check_password(self, password):
del self.password
Là j'ai un peu du mal à comprendre.
Ouai, c'est un peu bizarre (et ça mérite clairement un commentaire).
Au moment ou on créé une instance avec
APIClient.objects.create(..., password='toto')
le champ s'occupe bien de hasher le mot de passe avant de l'insérer en DB, mais l'attributpassword
vaudra encore la valeur'toto'
non hashé.Du coup le
del
de l'attribut force à recharger la valeur de l'attribut depuis la DB etself.password
aura bien en valeur le mot de passe hashé.Je ne suis pas certain que cette situation se produise dans un cas "réel", mais pour certain tests oui. Peut être qu'une meilleure solution serait de modifier les tests en question ?
Ah oui merci !
Très bonne idée, merci, je vais essayer de faire ça !
edit : Je ne sais pas s'il y avait une raison particulière pour découper en plusieurs migrations, mais comme il y a un moyen de le faire en une seule je propose d'abord cette solution.
b9f51f7c2a
to8f137a709a
8f137a709a
to153727ad3b
153727ad3b
to01e8fb310c
01e8fb310c
to36d7f0ff0d
WIP: api: change client's password handling (#89456)to api: change client's password handling (#89456)36d7f0ff0d
to0c24f87890
0c24f87890
to34e6cd3712
34e6cd3712
to9c73efa703
@ -0,0 +16,4 @@
def fake_hash_reverse(apps, schema_editor):
APIClient = apps.get_model('authentic2', 'APIClient')
for dummy in APIClient.objects.all():
raise NotImplementedError('Not reversible')
Je ne suis pas certain que ça soit la meilleur idée, mais j'ai pas trouvé mieux pour faire comme si la migration était reversible pour permettre les tests de migration (lors des tests il n'y a rien à "reverse" donc ça ne raise pas).
Ça ira.
Oui, je décrivais juste le déroulé si ça passe dans la même migration pas de soucis.
Je ne suis pas certain que le système PasswordField / PasswordInput va fonctionner, il n'y a pas de test qui teste le formulaire d'édition sans toucher au champ mot de passe mais je suppose que le widget est initialisé avec la valeur hashée du mot de passe et en sauvant ça va rehasher cette chaîne. Comme de toute façon on a pas envie que le mot de passe haché ou pas se retrouve dans le HTML de l'interface, je serais plus à l'aise si on reprenait aussi le fonctionnement de django.contrib.auth avec une fonction set_password() et des formulaire d'éditions / ajout qui excluent explicitement le champ "password" du modèle via ModelForm.Meta.exclude et une gestion de la modification mise en place du premier mot de passe dans Form.clean(), ça retirera le besoin du
del self.password
et on retombera sur du code quasi identique à ce qui se fait pour django.contrib.auth.models.User.@ -212,6 +212,7 @@ class UserEditForm(LimitQuerysetFormMixin, CssClass, BaseUserForm):
class Meta:
model = User
widgets = {'password': forms.PasswordInput()}
Plus haut ajouter un Field explicite "password" mais pas besoin d'un PasswordInput, on va devoir noter ce mot de passe dans un coin pour le filer au client plus tard de toute façon, un help text pour dire de le noter parce que c'est la dernière fois qu'on le verra en clair ce serait bien.
En édition (si self.instance.id n'est pas None) si le champ reste de vide, on conserve la valeur existante en appelant pas set_password().
Merci !
En plus je me suis rendu compte que j'étais pas sur le bon formulaire -__-
@ -213,3 +213,4 @@
class Meta:
model = User
widgets = {'password': forms.PasswordInput()}
exclude = (
Ici on ajoute password.
@ -53,6 +53,12 @@ from .utils.misc import ServiceAccessDenied
from .utils.sms import create_sms_code
class PasswordField(models.CharField):
À mon avis on a pas besoin d'un nouveau champ de modèle, ça obscurcit un peu le code.
Oui, d'autant que comme tu l'as bien noté au dessus il va entraîner des soucis de re-hash de mot de passe déjà hashé : pas bien pratique...
9c73efa703
to787607e6ab
api: change client's password handling (#89456)to WIP: api: change client's password handling (#89456)787607e6ab
to1208553533
1208553533
tob2f1e45887
WIP: api: change client's password handling (#89456)to api: change client's password handling (#89456)Merci pour ces remarques qui m'ont bien aidés !
Du coup, au final, en me basant sur ce qui était fait dans django, j'ai ajouté un APIClientManager permettant de créer un APIClient avec sa méthode create_user() .
Par rapport à l'implémentation du manager j'ai préféré me baser sur ce qui était fait dans django (et dans custom_user de a2) et implémenter la méthode create_user plutôt que surcharger la méthode create (ce que j'aurais fait spontanément).
Je me demandais aussi dans quel mesure le code relatif à APIClient ne serait pas mieux dans dans custom_user qui dispose d'un module managers avec déjà le manager custom pour les utilisateurs custom de a2 (si j'ai bien compris) ?
Step 1:
From your project repository, check out a new branch and test the changes.Step 2:
Merge the changes and update on Gitea.