forked from Github-Mirrors/canaille
Added an option to disable self edition
This commit is contained in:
parent
f496617f81
commit
8217d423ad
16 changed files with 261 additions and 149 deletions
|
@ -10,6 +10,7 @@ Added
|
|||
*****
|
||||
|
||||
- ``DISABLE_PASSWORD_RESET`` configuration option to disable password recovery. :pr:`46`
|
||||
- ``edit_self`` ACL permission to control user self edition. :pr:`47`
|
||||
|
||||
Fixed
|
||||
*****
|
||||
|
|
|
@ -48,9 +48,20 @@ bp = Blueprint("account", __name__)
|
|||
|
||||
@bp.route("/")
|
||||
def index():
|
||||
if not current_user():
|
||||
user = current_user()
|
||||
|
||||
if not user:
|
||||
return redirect(url_for("account.login"))
|
||||
return redirect(url_for("account.profile_edition", username=current_user().uid[0]))
|
||||
|
||||
if user.can_edit_self or user.can_manage_users:
|
||||
return redirect(
|
||||
url_for("account.profile_edition", username=current_user().uid[0])
|
||||
)
|
||||
|
||||
if user.can_use_oidc:
|
||||
return redirect(url_for("oidc.consents.consents"))
|
||||
|
||||
return redirect(url_for("account.about"))
|
||||
|
||||
|
||||
@bp.route("/about")
|
||||
|
@ -380,7 +391,9 @@ def profile_create(current_app, form):
|
|||
@bp.route("/profile/<username>", methods=("GET", "POST"))
|
||||
@user_needed()
|
||||
def profile_edition(user, username):
|
||||
if not user.can_manage_users and username != user.uid[0]:
|
||||
if not user.can_manage_users and not (
|
||||
user.can_edit_self and username == user.uid[0]
|
||||
):
|
||||
abort(403)
|
||||
|
||||
if request.method == "GET" or request.form.get("action") == "edit":
|
||||
|
@ -538,11 +551,21 @@ def forgotten():
|
|||
return render_template("forgotten-password.html", form=form)
|
||||
|
||||
user = User.get(form.login.data)
|
||||
success_message = _(
|
||||
"A password reset link has been sent at your email address. You should receive it within 10 minutes."
|
||||
)
|
||||
if current_app.config.get("HIDE_INVALID_LOGINS", True) and (
|
||||
not user or not user.can_edit_self
|
||||
):
|
||||
flash(success_message, "success")
|
||||
return render_template("forgotten-password.html", form=form)
|
||||
|
||||
if not user:
|
||||
if not user.can_edit_self:
|
||||
flash(
|
||||
_(
|
||||
"A password reset link has been sent at your email address. You should receive it within 10 minutes."
|
||||
"The user '%(user)s' does not have permissions to update their password. "
|
||||
"We cannot send a password reset email.",
|
||||
user=user.name,
|
||||
),
|
||||
"success",
|
||||
)
|
||||
|
@ -551,14 +574,12 @@ def forgotten():
|
|||
success = send_password_reset_mail(user)
|
||||
|
||||
if success:
|
||||
flash(
|
||||
_(
|
||||
"A password reset link has been sent at your email address. You should receive it within 10 minutes."
|
||||
),
|
||||
"success",
|
||||
)
|
||||
flash(success_message, "success")
|
||||
else:
|
||||
flash(_("Could not reset your password"), "error")
|
||||
flash(
|
||||
_("We encountered an issue while we sent the password recovery email."),
|
||||
"error",
|
||||
)
|
||||
|
||||
return render_template("forgotten-password.html", form=form)
|
||||
|
||||
|
|
|
@ -111,6 +111,7 @@ GROUP_BASE = "ou=groups,dc=mydomain,dc=tld"
|
|||
#
|
||||
# The 'PERMISSIONS' parameter that is an list of items the users in the access
|
||||
# control will be able to manage. 'PERMISSIONS' is optionnal. Values can be:
|
||||
# - "edit_self" to allow users to edit their own profile
|
||||
# - "use_oidc" to allow OpenID Connect authentication
|
||||
# - "manage_oidc" to allow OpenID Connect client managements
|
||||
# - "manage_users" to allow other users management
|
||||
|
@ -122,7 +123,7 @@ GROUP_BASE = "ou=groups,dc=mydomain,dc=tld"
|
|||
# The 'READ' and 'WRITE' attributes are the LDAP attributes of the user
|
||||
# object that users will be able to read and/or write.
|
||||
[ACL.DEFAULT]
|
||||
PERMISSIONS = ["use_oidc"]
|
||||
PERMISSIONS = ["edit_self", "use_oidc"]
|
||||
READ = ["uid", "groups"]
|
||||
WRITE = ["givenName", "sn", "userPassword", "telephoneNumber", "jpegPhoto", "mail", "labeledURI"]
|
||||
|
||||
|
|
|
@ -153,6 +153,10 @@ class User(LDAPObject):
|
|||
def can_writec(self, field):
|
||||
return field in self.write
|
||||
|
||||
@property
|
||||
def can_edit_self(self):
|
||||
return "edit_self" in self.permissions
|
||||
|
||||
@property
|
||||
def can_use_oidc(self):
|
||||
return "use_oidc" in self.permissions
|
||||
|
|
|
@ -181,7 +181,7 @@
|
|||
{% elif not edited_user.has_password() %}
|
||||
|
||||
<div class="ui message warning">
|
||||
{% if has_smtp %}
|
||||
{% if has_smtp and edited_user.can_edit_self %}
|
||||
{% if request.method == "POST" and request.form.action == "password-initialization-mail" %}
|
||||
<button type="submit" name="action" value="password-initialization-mail" class="ui right floated button">
|
||||
{% trans %}Send again{% endtrans %}
|
||||
|
@ -195,7 +195,7 @@
|
|||
<div class="header">
|
||||
{% trans %}This user does not have a password yet{% endtrans %}
|
||||
</div>
|
||||
{% if has_smtp %}
|
||||
{% if has_smtp and edited_user.can_edit_self %}
|
||||
<p>{% trans %}You can solve this by:{% endtrans %}</p>
|
||||
<ul class="ui list">
|
||||
<li>{% trans %}setting a password using this form;{% endtrans %}</li>
|
||||
|
@ -207,7 +207,7 @@
|
|||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% elif has_smtp and edited_user.uid != user.uid and edited_user.has_password() %}
|
||||
{% elif has_smtp and edited_user.uid != user.uid and edited_user.has_password() and edited_user.can_edit_self %}
|
||||
|
||||
<div class="ui message info">
|
||||
<button type="submit" name="action" value="password-reset-mail" class="ui right floated button">
|
||||
|
|
|
@ -33,11 +33,13 @@
|
|||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
<a class="item {% if menuitem == "profile" %}active{% endif %}"
|
||||
href="{{ url_for('account.profile_edition', username=user.uid[0]) }}">
|
||||
<i class="id card icon"></i>
|
||||
{% trans %}My profile{% endtrans %}
|
||||
</a>
|
||||
{% if user.can_edit_self %}
|
||||
<a class="item {% if menuitem == "profile" %}active{% endif %}"
|
||||
href="{{ url_for('account.profile_edition', username=user.uid[0]) }}">
|
||||
<i class="id card icon"></i>
|
||||
{% trans %}My profile{% endtrans %}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if user.can_use_oidc %}
|
||||
<a class="item {% if menuitem == "consents" %}active{% endif %}"
|
||||
href="{{ url_for('oidc.consents.consents') }}">
|
||||
|
|
Binary file not shown.
|
@ -9,37 +9,37 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: contact@yaal.fr\n"
|
||||
"POT-Creation-Date: 2022-02-23 10:58+0100\n"
|
||||
"PO-Revision-Date: 2022-02-23 10:59+0100\n"
|
||||
"POT-Creation-Date: 2022-04-06 17:43+0200\n"
|
||||
"PO-Revision-Date: 2022-04-06 17:44+0200\n"
|
||||
"Last-Translator: Éloi Rivard <eloi@yaal.fr>\n"
|
||||
"Language: fr_FR\n"
|
||||
"Language-Team: French - France <equipe@yaal.fr>\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 2.9.1\n"
|
||||
"X-Generator: Gtranslator 40.0\n"
|
||||
|
||||
#: canaille/account.py:82 canaille/account.py:107 canaille/oidc/oauth.py:77
|
||||
#: canaille/account.py:93 canaille/account.py:118 canaille/oidc/oauth.py:77
|
||||
msgid "Login failed, please check your information"
|
||||
msgstr "La connexion a échoué, veuillez vérifier vos informations."
|
||||
|
||||
#: canaille/account.py:113
|
||||
#: canaille/account.py:124
|
||||
#, python-format
|
||||
msgid "Connection successful. Welcome %(user)s"
|
||||
msgstr "Connexion réussie. Bienvenue %(user)s"
|
||||
|
||||
#: canaille/account.py:126
|
||||
#: canaille/account.py:137
|
||||
#, python-format
|
||||
msgid "You have been disconnected. See you next time %(user)s"
|
||||
msgstr "Vous avez été déconnecté·e. À bientôt %(user)s"
|
||||
|
||||
#: canaille/account.py:143
|
||||
#: canaille/account.py:155
|
||||
msgid "Could not send the password initialization link."
|
||||
msgstr "Impossible d'envoyer le courriel d'initialisation de mot de passe."
|
||||
|
||||
#: canaille/account.py:148
|
||||
#: canaille/account.py:160
|
||||
msgid ""
|
||||
"A password initialization link has been sent at your email address. You "
|
||||
"should receive it within 10 minutes."
|
||||
|
@ -47,39 +47,45 @@ msgstr ""
|
|||
"Un lien d'initialisation de votre mot de passe vous a été envoyé par mail. "
|
||||
"Vous devriez le recevoir d'ici une dizaine de minutes."
|
||||
|
||||
#: canaille/account.py:154 canaille/account.py:398
|
||||
#: canaille/account.py:166 canaille/account.py:418
|
||||
msgid "Could not send the password initialization email"
|
||||
msgstr "Impossible d'envoyer le courriel d'initialisation de mot de passe."
|
||||
|
||||
#: canaille/account.py:247 canaille/account.py:324
|
||||
#: canaille/account.py:255 canaille/account.py:338
|
||||
msgid "User account creation failed."
|
||||
msgstr "La création du compte utilisateur a échoué."
|
||||
|
||||
#: canaille/account.py:268 canaille/account.py:296
|
||||
#: canaille/account.py:276 canaille/account.py:304
|
||||
msgid "The invitation link that brought you here was invalid."
|
||||
msgstr "Le lien d'invitation qui vous a amené ici est invalide."
|
||||
|
||||
#: canaille/account.py:275
|
||||
#: canaille/account.py:283
|
||||
msgid "The invitation link that brought you here has expired."
|
||||
msgstr "Le lien d'invitation qui vous a amené ici a expiré."
|
||||
|
||||
#: canaille/account.py:282
|
||||
#: canaille/account.py:290
|
||||
msgid "Your account has already been created."
|
||||
msgstr "Votre compte a déjà été créé."
|
||||
|
||||
#: canaille/account.py:289
|
||||
#: canaille/account.py:297
|
||||
msgid "You are already logged in, you cannot create an account."
|
||||
msgstr "Vous êtes déjà connectés, vous ne pouvez pas créer de compte."
|
||||
|
||||
#: canaille/account.py:329
|
||||
#: canaille/account.py:316 canaille/forms.py:179 canaille/forms.py:227
|
||||
#: canaille/templates/groups.html:11 canaille/templates/userlist.html:17
|
||||
#: canaille/themes/default/base.html:61
|
||||
msgid "Groups"
|
||||
msgstr "Groupes"
|
||||
|
||||
#: canaille/account.py:343
|
||||
msgid "You account has been created successfuly."
|
||||
msgstr "Votre compte utilisateur a été créé avec succès."
|
||||
|
||||
#: canaille/account.py:371
|
||||
#: canaille/account.py:385
|
||||
msgid "User account creation succeed."
|
||||
msgstr "La création du compte utilisateur a réussi."
|
||||
|
||||
#: canaille/account.py:392
|
||||
#: canaille/account.py:412
|
||||
msgid ""
|
||||
"A password initialization link has been sent at the user email address. It "
|
||||
"should be received within 10 minutes."
|
||||
|
@ -87,7 +93,7 @@ msgstr ""
|
|||
"Un lien d'initialisation de mot de passe a été envoyé à l'utilisateur par "
|
||||
"mail. Il devrait arriver d'ici une dizaine de minutes."
|
||||
|
||||
#: canaille/account.py:406
|
||||
#: canaille/account.py:429
|
||||
msgid ""
|
||||
"A password reset link has been sent at the user email address. It should be "
|
||||
"received within 10 minutes."
|
||||
|
@ -95,28 +101,28 @@ msgstr ""
|
|||
"Un lien de réinitialisation de mot de passe a été envoyé à l'utilisateur par "
|
||||
"mail. Il devrait arriver d'ici une dizaine de minutes."
|
||||
|
||||
#: canaille/account.py:412
|
||||
#: canaille/account.py:435
|
||||
msgid "Could not send the password reset email"
|
||||
msgstr "Impossible d'envoyer le lien de réinitialisation."
|
||||
|
||||
#: canaille/account.py:443
|
||||
#: canaille/account.py:469
|
||||
msgid "Profile edition failed."
|
||||
msgstr "L'édition du profil a échoué."
|
||||
|
||||
#: canaille/account.py:471
|
||||
#: canaille/account.py:497
|
||||
msgid "Profile updated successfuly."
|
||||
msgstr "Le profil a été mis à jour avec succès."
|
||||
|
||||
#: canaille/account.py:491
|
||||
#: canaille/account.py:520
|
||||
#, python-format
|
||||
msgid "The user %(user)s has been sucessfuly deleted"
|
||||
msgstr "L'utilisateur %(user)s a bien été supprimé"
|
||||
|
||||
#: canaille/account.py:515
|
||||
#: canaille/account.py:550
|
||||
msgid "Could not send the password reset link."
|
||||
msgstr "Impossible d'envoyer le lien de réinitialisation."
|
||||
|
||||
#: canaille/account.py:522 canaille/account.py:533
|
||||
#: canaille/account.py:554
|
||||
msgid ""
|
||||
"A password reset link has been sent at your email address. You should "
|
||||
"receive it within 10 minutes."
|
||||
|
@ -124,15 +130,26 @@ msgstr ""
|
|||
"Un lien de ré-initialisation de votre mot de passe vous a été envoyé par "
|
||||
"mail. Vous devriez le recevoir d'ici une dizaine de minutes."
|
||||
|
||||
#: canaille/account.py:539
|
||||
msgid "Could not reset your password"
|
||||
msgstr "Impossible de réinitialiser votre mot de passe"
|
||||
#: canaille/account.py:565
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The user '%(user)s' does not have permissions to update their password. We "
|
||||
"cannot send a password reset email."
|
||||
msgstr ""
|
||||
"L'utilisateur '%(user)s' n'a pas la permission d'éditer son mot de passe. "
|
||||
"Nous ne pouvons pas lui envoyer un email de réinitialisation."
|
||||
|
||||
#: canaille/account.py:553
|
||||
#: canaille/account.py:580
|
||||
msgid "We encountered an issue while we sent the password recovery email."
|
||||
msgstr ""
|
||||
"Nous avons rencontré un problème lors de l'envoi de l'email de "
|
||||
"réinitialisation de mot de passe."
|
||||
|
||||
#: canaille/account.py:599
|
||||
msgid "The password reset link that brought you here was invalid."
|
||||
msgstr "Le lien de réinitialisation qui vous a amené ici est invalide."
|
||||
|
||||
#: canaille/account.py:562
|
||||
#: canaille/account.py:608
|
||||
msgid "Your password has been updated successfuly"
|
||||
msgstr "Votre mot de passe a correctement été mis à jour."
|
||||
|
||||
|
@ -141,7 +158,7 @@ msgid "Email"
|
|||
msgstr "Courriel"
|
||||
|
||||
#: canaille/admin.py:29 canaille/forms.py:47 canaille/forms.py:71
|
||||
#: canaille/forms.py:123 canaille/forms.py:224
|
||||
#: canaille/forms.py:123 canaille/forms.py:221
|
||||
msgid "jane@doe.com"
|
||||
msgstr "camille@dupont.fr"
|
||||
|
||||
|
@ -165,7 +182,7 @@ msgstr "Invitation sur {website_name}"
|
|||
msgid "John Doe"
|
||||
msgstr "Camille Dupont"
|
||||
|
||||
#: canaille/apputils.py:44 canaille/forms.py:95 canaille/forms.py:212
|
||||
#: canaille/apputils.py:44 canaille/forms.py:95 canaille/forms.py:209
|
||||
msgid "jdoe"
|
||||
msgstr "cdupont"
|
||||
|
||||
|
@ -213,11 +230,11 @@ msgstr "Confirmation du mot de passe"
|
|||
msgid "Password and confirmation do not match."
|
||||
msgstr "Le mot de passe et sa confirmation ne correspondent pas."
|
||||
|
||||
#: canaille/forms.py:94 canaille/forms.py:211
|
||||
#: canaille/forms.py:94 canaille/forms.py:208
|
||||
msgid "Username"
|
||||
msgstr "Identifiant"
|
||||
|
||||
#: canaille/forms.py:98 canaille/forms.py:197 canaille/oidc/clients.py:36
|
||||
#: canaille/forms.py:98 canaille/forms.py:194 canaille/oidc/clients.py:36
|
||||
#: canaille/templates/groups.html:17
|
||||
#: canaille/templates/oidc/admin/client_list.html:23
|
||||
#: canaille/templates/userlist.html:11
|
||||
|
@ -240,7 +257,7 @@ msgstr "Nom de famille"
|
|||
msgid "Doe"
|
||||
msgstr "Dupont"
|
||||
|
||||
#: canaille/forms.py:117 canaille/forms.py:217
|
||||
#: canaille/forms.py:117 canaille/forms.py:214
|
||||
msgid "Email address"
|
||||
msgstr "Courriel"
|
||||
|
||||
|
@ -283,42 +300,36 @@ msgstr "Site internet"
|
|||
msgid "https://mywebsite.tld"
|
||||
msgstr "https://mon-site-internet.fr"
|
||||
|
||||
#: canaille/forms.py:182 canaille/forms.py:230
|
||||
#: canaille/templates/groups.html:11 canaille/templates/userlist.html:17
|
||||
#: canaille/themes/default/base.html:59
|
||||
msgid "Groups"
|
||||
msgstr "Groupes"
|
||||
|
||||
#: canaille/forms.py:184
|
||||
#: canaille/forms.py:181
|
||||
msgid "users, admins ..."
|
||||
msgstr "utilisateurs, administrateurs ..."
|
||||
|
||||
#: canaille/forms.py:200
|
||||
#: canaille/forms.py:197
|
||||
msgid "group"
|
||||
msgstr "groupe"
|
||||
|
||||
#: canaille/forms.py:204 canaille/templates/groups.html:18
|
||||
#: canaille/forms.py:201 canaille/templates/groups.html:18
|
||||
msgid "Description"
|
||||
msgstr "Description"
|
||||
|
||||
#: canaille/forms.py:215
|
||||
#: canaille/forms.py:212
|
||||
msgid "Username editable by the invitee"
|
||||
msgstr "L'identifiant sera éditable par la personne invitée"
|
||||
|
||||
#: canaille/groups.py:44
|
||||
#: canaille/groups.py:40
|
||||
msgid "Group creation failed."
|
||||
msgstr "La création du groupe a échoué."
|
||||
|
||||
#: canaille/groups.py:56
|
||||
#: canaille/groups.py:52
|
||||
#, python-format
|
||||
msgid "The group %(group)s has been sucessfully created"
|
||||
msgstr "Le groupe %(group)s a bien été créé"
|
||||
|
||||
#: canaille/groups.py:93
|
||||
#: canaille/groups.py:92
|
||||
msgid "Group edition failed."
|
||||
msgstr "L'édition du groupe a échoué."
|
||||
|
||||
#: canaille/groups.py:102
|
||||
#: canaille/groups.py:101
|
||||
#, python-format
|
||||
msgid "The group %(group)s has been sucessfully deleted"
|
||||
msgstr "Le groupe %(group)s a bien été supprimé"
|
||||
|
@ -327,11 +338,11 @@ msgstr "Le groupe %(group)s a bien été supprimé"
|
|||
msgid "You have been invited to create an account on {website_name}"
|
||||
msgstr "Vous êtes invités à vous créer un compte sur {website_name}"
|
||||
|
||||
#: canaille/ldap_backend/backend.py:48
|
||||
#: canaille/ldap_backend/backend.py:54
|
||||
msgid "Could not connect to the LDAP server '{uri}'"
|
||||
msgstr "Impossible de se connecter au serveur LDAP '{uri}'"
|
||||
|
||||
#: canaille/ldap_backend/backend.py:64
|
||||
#: canaille/ldap_backend/backend.py:70
|
||||
msgid "LDAP authentication failed with user '{user}'"
|
||||
msgstr ""
|
||||
"L'authentification au serveur LDAP a échoué pour l'utilisateur '{user}'"
|
||||
|
@ -408,15 +419,15 @@ msgstr "Le client n'a pas été ajouté. Veuillez vérifier vos informations."
|
|||
msgid "The client has been created."
|
||||
msgstr "Le client a été créé."
|
||||
|
||||
#: canaille/oidc/clients.py:218
|
||||
#: canaille/oidc/clients.py:222
|
||||
msgid "The client has not been edited. Please check your information."
|
||||
msgstr "Le client n'a pas été édité. Veuillez vérifier vos informations."
|
||||
|
||||
#: canaille/oidc/clients.py:244
|
||||
#: canaille/oidc/clients.py:248
|
||||
msgid "The client has been edited."
|
||||
msgstr "Le client a été édité."
|
||||
|
||||
#: canaille/oidc/clients.py:256
|
||||
#: canaille/oidc/clients.py:264
|
||||
msgid "The client has been deleted."
|
||||
msgstr "Le client a été supprimé."
|
||||
|
||||
|
@ -452,7 +463,7 @@ msgstr "Les groupes auxquels vous appartenez"
|
|||
msgid "You have been successfully logged out."
|
||||
msgstr "Vous avez été déconnecté·e."
|
||||
|
||||
#: canaille/templates/about.html:12 canaille/themes/default/base.html:102
|
||||
#: canaille/templates/about.html:12 canaille/themes/default/base.html:104
|
||||
msgid "About canaille"
|
||||
msgstr "À propos de canaille"
|
||||
|
||||
|
@ -806,7 +817,7 @@ msgstr ""
|
|||
msgid "User creation"
|
||||
msgstr "Nouvel utilisateur"
|
||||
|
||||
#: canaille/templates/profile.html:53 canaille/themes/default/base.html:39
|
||||
#: canaille/templates/profile.html:53 canaille/themes/default/base.html:40
|
||||
msgid "My profile"
|
||||
msgstr "Mon profil"
|
||||
|
||||
|
@ -1198,7 +1209,7 @@ msgid "Accept"
|
|||
msgstr "Accepter"
|
||||
|
||||
#: canaille/templates/oidc/user/consent_list.html:18
|
||||
#: canaille/themes/default/base.html:45
|
||||
#: canaille/themes/default/base.html:47
|
||||
msgid "My consents"
|
||||
msgstr "Mes autorisations"
|
||||
|
||||
|
@ -1235,27 +1246,27 @@ msgstr ""
|
|||
msgid "authorization interface"
|
||||
msgstr " - Interface de gestion des autorisations"
|
||||
|
||||
#: canaille/themes/default/base.html:52
|
||||
#: canaille/themes/default/base.html:54
|
||||
msgid "Users"
|
||||
msgstr "Utilisateurs"
|
||||
|
||||
#: canaille/themes/default/base.html:69
|
||||
#: canaille/themes/default/base.html:71
|
||||
msgid "Clients"
|
||||
msgstr "Clients"
|
||||
|
||||
#: canaille/themes/default/base.html:73
|
||||
#: canaille/themes/default/base.html:75
|
||||
msgid "Tokens"
|
||||
msgstr "Jetons"
|
||||
|
||||
#: canaille/themes/default/base.html:77
|
||||
#: canaille/themes/default/base.html:79
|
||||
msgid "Codes"
|
||||
msgstr "Codes"
|
||||
|
||||
#: canaille/themes/default/base.html:81
|
||||
#: canaille/themes/default/base.html:83
|
||||
msgid "Emails"
|
||||
msgstr "Courriels"
|
||||
|
||||
#: canaille/themes/default/base.html:88
|
||||
#: canaille/themes/default/base.html:90
|
||||
msgid "Log out"
|
||||
msgstr "Déconnexion"
|
||||
|
||||
|
@ -1422,3 +1433,6 @@ msgstr "Déconnexion"
|
|||
#~ "Vous avez été invité à créer un compte sur %(site_name)s. Pour continuer, "
|
||||
#~ "vous pouvez cliquer sur le bouton «Créer mon compte» ci-dessous et suivre "
|
||||
#~ "les instructions."
|
||||
|
||||
#~ msgid "Could not reset your password"
|
||||
#~ msgstr "Impossible de réinitialiser votre mot de passe"
|
||||
|
|
|
@ -8,7 +8,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2022-02-23 10:58+0100\n"
|
||||
"POT-Creation-Date: 2022-04-06 17:43+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
@ -17,110 +17,123 @@ msgstr ""
|
|||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 2.9.1\n"
|
||||
|
||||
#: canaille/account.py:82 canaille/account.py:107 canaille/oidc/oauth.py:77
|
||||
#: canaille/account.py:93 canaille/account.py:118 canaille/oidc/oauth.py:77
|
||||
msgid "Login failed, please check your information"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:113
|
||||
#: canaille/account.py:124
|
||||
#, python-format
|
||||
msgid "Connection successful. Welcome %(user)s"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:126
|
||||
#: canaille/account.py:137
|
||||
#, python-format
|
||||
msgid "You have been disconnected. See you next time %(user)s"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:143
|
||||
#: canaille/account.py:155
|
||||
msgid "Could not send the password initialization link."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:148
|
||||
#: canaille/account.py:160
|
||||
msgid ""
|
||||
"A password initialization link has been sent at your email address. You "
|
||||
"should receive it within 10 minutes."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:154 canaille/account.py:398
|
||||
#: canaille/account.py:166 canaille/account.py:418
|
||||
msgid "Could not send the password initialization email"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:247 canaille/account.py:324
|
||||
#: canaille/account.py:255 canaille/account.py:338
|
||||
msgid "User account creation failed."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:268 canaille/account.py:296
|
||||
#: canaille/account.py:276 canaille/account.py:304
|
||||
msgid "The invitation link that brought you here was invalid."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:275
|
||||
#: canaille/account.py:283
|
||||
msgid "The invitation link that brought you here has expired."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:282
|
||||
#: canaille/account.py:290
|
||||
msgid "Your account has already been created."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:289
|
||||
#: canaille/account.py:297
|
||||
msgid "You are already logged in, you cannot create an account."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:329
|
||||
#: canaille/account.py:316 canaille/forms.py:179 canaille/forms.py:227
|
||||
#: canaille/templates/groups.html:11 canaille/templates/userlist.html:17
|
||||
#: canaille/themes/default/base.html:61
|
||||
msgid "Groups"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:343
|
||||
msgid "You account has been created successfuly."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:371
|
||||
#: canaille/account.py:385
|
||||
msgid "User account creation succeed."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:392
|
||||
#: canaille/account.py:412
|
||||
msgid ""
|
||||
"A password initialization link has been sent at the user email address. "
|
||||
"It should be received within 10 minutes."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:406
|
||||
#: canaille/account.py:429
|
||||
msgid ""
|
||||
"A password reset link has been sent at the user email address. It should "
|
||||
"be received within 10 minutes."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:412
|
||||
#: canaille/account.py:435
|
||||
msgid "Could not send the password reset email"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:443
|
||||
#: canaille/account.py:469
|
||||
msgid "Profile edition failed."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:471
|
||||
#: canaille/account.py:497
|
||||
msgid "Profile updated successfuly."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:491
|
||||
#: canaille/account.py:520
|
||||
#, python-format
|
||||
msgid "The user %(user)s has been sucessfuly deleted"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:515
|
||||
#: canaille/account.py:550
|
||||
msgid "Could not send the password reset link."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:522 canaille/account.py:533
|
||||
#: canaille/account.py:554
|
||||
msgid ""
|
||||
"A password reset link has been sent at your email address. You should "
|
||||
"receive it within 10 minutes."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:539
|
||||
msgid "Could not reset your password"
|
||||
#: canaille/account.py:565
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The user '%(user)s' does not have permissions to update their password. "
|
||||
"We cannot send a password reset email."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:553
|
||||
#: canaille/account.py:580
|
||||
msgid "We encountered an issue while we sent the password recovery email."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:599
|
||||
msgid "The password reset link that brought you here was invalid."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:562
|
||||
#: canaille/account.py:608
|
||||
msgid "Your password has been updated successfuly"
|
||||
msgstr ""
|
||||
|
||||
|
@ -129,7 +142,7 @@ msgid "Email"
|
|||
msgstr ""
|
||||
|
||||
#: canaille/admin.py:29 canaille/forms.py:47 canaille/forms.py:71
|
||||
#: canaille/forms.py:123 canaille/forms.py:224
|
||||
#: canaille/forms.py:123 canaille/forms.py:221
|
||||
msgid "jane@doe.com"
|
||||
msgstr ""
|
||||
|
||||
|
@ -153,7 +166,7 @@ msgstr ""
|
|||
msgid "John Doe"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/apputils.py:44 canaille/forms.py:95 canaille/forms.py:212
|
||||
#: canaille/apputils.py:44 canaille/forms.py:95 canaille/forms.py:209
|
||||
msgid "jdoe"
|
||||
msgstr ""
|
||||
|
||||
|
@ -201,11 +214,11 @@ msgstr ""
|
|||
msgid "Password and confirmation do not match."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:94 canaille/forms.py:211
|
||||
#: canaille/forms.py:94 canaille/forms.py:208
|
||||
msgid "Username"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:98 canaille/forms.py:197 canaille/oidc/clients.py:36
|
||||
#: canaille/forms.py:98 canaille/forms.py:194 canaille/oidc/clients.py:36
|
||||
#: canaille/templates/groups.html:17
|
||||
#: canaille/templates/oidc/admin/client_list.html:23
|
||||
#: canaille/templates/userlist.html:11
|
||||
|
@ -228,7 +241,7 @@ msgstr ""
|
|||
msgid "Doe"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:117 canaille/forms.py:217
|
||||
#: canaille/forms.py:117 canaille/forms.py:214
|
||||
msgid "Email address"
|
||||
msgstr ""
|
||||
|
||||
|
@ -270,42 +283,36 @@ msgstr ""
|
|||
msgid "https://mywebsite.tld"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:182 canaille/forms.py:230
|
||||
#: canaille/templates/groups.html:11 canaille/templates/userlist.html:17
|
||||
#: canaille/themes/default/base.html:59
|
||||
msgid "Groups"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:184
|
||||
#: canaille/forms.py:181
|
||||
msgid "users, admins ..."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:200
|
||||
#: canaille/forms.py:197
|
||||
msgid "group"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:204 canaille/templates/groups.html:18
|
||||
#: canaille/forms.py:201 canaille/templates/groups.html:18
|
||||
msgid "Description"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:215
|
||||
#: canaille/forms.py:212
|
||||
msgid "Username editable by the invitee"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/groups.py:44
|
||||
#: canaille/groups.py:40
|
||||
msgid "Group creation failed."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/groups.py:56
|
||||
#: canaille/groups.py:52
|
||||
#, python-format
|
||||
msgid "The group %(group)s has been sucessfully created"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/groups.py:93
|
||||
#: canaille/groups.py:92
|
||||
msgid "Group edition failed."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/groups.py:102
|
||||
#: canaille/groups.py:101
|
||||
#, python-format
|
||||
msgid "The group %(group)s has been sucessfully deleted"
|
||||
msgstr ""
|
||||
|
@ -314,11 +321,11 @@ msgstr ""
|
|||
msgid "You have been invited to create an account on {website_name}"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/ldap_backend/backend.py:48
|
||||
#: canaille/ldap_backend/backend.py:54
|
||||
msgid "Could not connect to the LDAP server '{uri}'"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/ldap_backend/backend.py:64
|
||||
#: canaille/ldap_backend/backend.py:70
|
||||
msgid "LDAP authentication failed with user '{user}'"
|
||||
msgstr ""
|
||||
|
||||
|
@ -394,15 +401,15 @@ msgstr ""
|
|||
msgid "The client has been created."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/oidc/clients.py:218
|
||||
#: canaille/oidc/clients.py:222
|
||||
msgid "The client has not been edited. Please check your information."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/oidc/clients.py:244
|
||||
#: canaille/oidc/clients.py:248
|
||||
msgid "The client has been edited."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/oidc/clients.py:256
|
||||
#: canaille/oidc/clients.py:264
|
||||
msgid "The client has been deleted."
|
||||
msgstr ""
|
||||
|
||||
|
@ -438,7 +445,7 @@ msgstr ""
|
|||
msgid "You have been successfully logged out."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/about.html:12 canaille/themes/default/base.html:102
|
||||
#: canaille/templates/about.html:12 canaille/themes/default/base.html:104
|
||||
msgid "About canaille"
|
||||
msgstr ""
|
||||
|
||||
|
@ -758,7 +765,7 @@ msgstr ""
|
|||
msgid "User creation"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:53 canaille/themes/default/base.html:39
|
||||
#: canaille/templates/profile.html:53 canaille/themes/default/base.html:40
|
||||
msgid "My profile"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1112,7 +1119,7 @@ msgid "Accept"
|
|||
msgstr ""
|
||||
|
||||
#: canaille/templates/oidc/user/consent_list.html:18
|
||||
#: canaille/themes/default/base.html:45
|
||||
#: canaille/themes/default/base.html:47
|
||||
msgid "My consents"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1148,26 +1155,26 @@ msgstr ""
|
|||
msgid "authorization interface"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/themes/default/base.html:52
|
||||
#: canaille/themes/default/base.html:54
|
||||
msgid "Users"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/themes/default/base.html:69
|
||||
#: canaille/themes/default/base.html:71
|
||||
msgid "Clients"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/themes/default/base.html:73
|
||||
#: canaille/themes/default/base.html:75
|
||||
msgid "Tokens"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/themes/default/base.html:77
|
||||
#: canaille/themes/default/base.html:79
|
||||
msgid "Codes"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/themes/default/base.html:81
|
||||
#: canaille/themes/default/base.html:83
|
||||
msgid "Emails"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/themes/default/base.html:88
|
||||
#: canaille/themes/default/base.html:90
|
||||
msgid "Log out"
|
||||
msgstr ""
|
||||
|
|
|
@ -112,6 +112,7 @@ GROUP_BASE = "ou=groups,dc=mydomain,dc=tld"
|
|||
#
|
||||
# The 'PERMISSIONS' parameter that is an list of items the users in the access
|
||||
# control will be able to manage. 'PERMISSIONS' is optionnal. Values can be:
|
||||
# - "edit_self" to allow users to edit their own profile
|
||||
# - "use_oidc" to allow OpenID Connect authentication
|
||||
# - "manage_oidc" to allow OpenID Connect client managements
|
||||
# - "manage_users" to allow other users management
|
||||
|
|
|
@ -112,6 +112,7 @@ GROUP_BASE = "ou=groups,dc=mydomain,dc=tld"
|
|||
#
|
||||
# The 'PERMISSIONS' parameter that is an list of items the users in the access
|
||||
# control will be able to manage. 'PERMISSIONS' is optionnal. Values can be:
|
||||
# - "edit_self" to allow users to edit their own profile
|
||||
# - "use_oidc" to allow OpenID Connect authentication
|
||||
# - "manage_oidc" to allow OpenID Connect client managements
|
||||
# - "manage_users" to allow other users management
|
||||
|
@ -123,7 +124,7 @@ GROUP_BASE = "ou=groups,dc=mydomain,dc=tld"
|
|||
# The 'READ' and 'WRITE' attributes are the LDAP attributes of the user
|
||||
# object that users will be able to read and/or write.
|
||||
[ACL.DEFAULT]
|
||||
PERMISSIONS = ["use_oidc"]
|
||||
PERMISSIONS = ["edit_self", "use_oidc"]
|
||||
READ = ["uid", "groups"]
|
||||
WRITE = ["jpegPhoto", "givenName", "sn", "userPassword", "telephoneNumber", "mail", "labeledURI"]
|
||||
|
||||
|
|
|
@ -145,6 +145,7 @@ object that users will be able to read and/or write.
|
|||
:PERMISSIONS:
|
||||
*Optional.* A list of items the users in the access control will be able to manage. Values can be:
|
||||
|
||||
- **edit_self** to allow users to edit their own profile
|
||||
- **use_oidc** to allow OpenID Connect authentication
|
||||
- **manage_oidc** to allow OpenID Connect client managements
|
||||
- **manage_users** to allow other users management
|
||||
|
@ -154,12 +155,14 @@ object that users will be able to read and/or write.
|
|||
|
||||
:READ:
|
||||
*Optional.* A list of attributes of ``USER_CLASS`` the user will be able to see, but not edit.
|
||||
If the user has the ``manage_users`` permission, he will be able to see this fields on other users profile.
|
||||
If the users has the ``edit_self`` permission, they will be able to see those fields on their own account.
|
||||
If the users has the ``manage_users`` permission, the user will be able to see this fields on other users profile.
|
||||
If the list containts the special ``groups`` field, the user will be able to see the groups he belongs to.
|
||||
|
||||
:WRITE:
|
||||
*Optional.* A list of attributes of ``USER_CLASS`` the user will be able to edit.
|
||||
If the user has the ``manage_users`` permission, he will be able to edit this fields on other users profile.
|
||||
If the users has the ``edit_self`` permission, they will be able to edit those fields on their own account.
|
||||
If the users has the ``manage_users`` permission, they will be able to edit those fields on other users profile.
|
||||
If the list containts the special ``groups`` field, the user will be able to edit the groups he belongs to.
|
||||
|
||||
|
||||
|
|
|
@ -149,7 +149,7 @@ def configuration(slapd_server, smtpd, keypair_path):
|
|||
"ACL": {
|
||||
"DEFAULT": {
|
||||
"READ": ["uid", "groups"],
|
||||
"PERMISSIONS": ["use_oidc"],
|
||||
"PERMISSIONS": ["edit_self", "use_oidc"],
|
||||
"WRITE": [
|
||||
"mail",
|
||||
"givenName",
|
||||
|
|
|
@ -184,11 +184,14 @@ def test_user_self_deletion(testclient, slapd_connection):
|
|||
with testclient.session_transaction() as sess:
|
||||
sess["user_dn"] = [user.dn]
|
||||
|
||||
testclient.app.config["ACL"]["DEFAULT"]["PERMISSIONS"] = []
|
||||
testclient.app.config["ACL"]["DEFAULT"]["PERMISSIONS"] = ["edit_self"]
|
||||
res = testclient.get("/profile/temp")
|
||||
assert "Delete my account" not in res
|
||||
|
||||
testclient.app.config["ACL"]["DEFAULT"]["PERMISSIONS"] = ["delete_account"]
|
||||
testclient.app.config["ACL"]["DEFAULT"]["PERMISSIONS"] = [
|
||||
"edit_self",
|
||||
"delete_account",
|
||||
]
|
||||
res = testclient.get("/profile/temp")
|
||||
assert "Delete my account" in res
|
||||
res = (
|
||||
|
|
|
@ -47,3 +47,33 @@ def test_password_forgotten_invalid(smtpd, testclient, slapd_connection, user):
|
|||
assert "The login 'i-dont-really-exist' does not exist" in res.text
|
||||
|
||||
assert len(smtpd.messages) == 0
|
||||
|
||||
|
||||
def test_password_forgotten_invalid_when_user_cannot_self_edit(
|
||||
smtpd, testclient, slapd_connection, user
|
||||
):
|
||||
testclient.app.config["ACL"]["DEFAULT"]["PERMISSIONS"] = []
|
||||
|
||||
testclient.app.config["HIDE_INVALID_LOGINS"] = False
|
||||
res = testclient.get("/reset", status=200)
|
||||
|
||||
res.form["login"] = "user"
|
||||
res = res.form.submit(status=200)
|
||||
assert "A password reset link has been sent at your email address." not in res.text
|
||||
assert (
|
||||
"The user 'John (johnny) Doe' does not have permissions to update their password."
|
||||
in res.text
|
||||
)
|
||||
|
||||
testclient.app.config["HIDE_INVALID_LOGINS"] = True
|
||||
res = testclient.get("/reset", status=200)
|
||||
|
||||
res.form["login"] = "user"
|
||||
res = res.form.submit(status=200)
|
||||
assert (
|
||||
"The user 'John (johnny) Doe' does not have permissions to update their password."
|
||||
not in res.text
|
||||
)
|
||||
assert "A password reset link has been sent at your email address." in res.text
|
||||
|
||||
assert len(smtpd.messages) == 0
|
||||
|
|
|
@ -2,6 +2,24 @@ from canaille.models import User
|
|||
from webtest import Upload
|
||||
|
||||
|
||||
def test_edition_permission(
|
||||
testclient,
|
||||
slapd_server,
|
||||
slapd_connection,
|
||||
logged_user,
|
||||
admin,
|
||||
foo_group,
|
||||
bar_group,
|
||||
jpeg_photo,
|
||||
):
|
||||
|
||||
testclient.app.config["ACL"]["DEFAULT"]["PERMISSIONS"] = []
|
||||
testclient.get("/profile/user", status=403)
|
||||
|
||||
testclient.app.config["ACL"]["DEFAULT"]["PERMISSIONS"] = ["edit_self"]
|
||||
testclient.get("/profile/user", status=200)
|
||||
|
||||
|
||||
def test_edition(
|
||||
testclient,
|
||||
slapd_server,
|
||||
|
@ -75,7 +93,11 @@ def test_field_permissions_none(
|
|||
logged_user.telephoneNumber = ["555-666-777"]
|
||||
logged_user.save(conn=slapd_connection)
|
||||
|
||||
testclient.app.config["ACL"]["DEFAULT"] = {"READ": ["uid"], "WRITE": []}
|
||||
testclient.app.config["ACL"]["DEFAULT"] = {
|
||||
"READ": ["uid"],
|
||||
"WRITE": [],
|
||||
"PERMISSIONS": ["edit_self"],
|
||||
}
|
||||
|
||||
res = testclient.get("/profile/user", status=200)
|
||||
assert "telephoneNumber" not in res.form.fields
|
||||
|
@ -99,6 +121,7 @@ def test_field_permissions_read(
|
|||
testclient.app.config["ACL"]["DEFAULT"] = {
|
||||
"READ": ["uid", "telephoneNumber"],
|
||||
"WRITE": [],
|
||||
"PERMISSIONS": ["edit_self"],
|
||||
}
|
||||
res = testclient.get("/profile/user", status=200)
|
||||
assert "telephoneNumber" in res.form.fields
|
||||
|
@ -122,6 +145,7 @@ def test_field_permissions_write(
|
|||
testclient.app.config["ACL"]["DEFAULT"] = {
|
||||
"READ": ["uid"],
|
||||
"WRITE": ["telephoneNumber"],
|
||||
"PERMISSIONS": ["edit_self"],
|
||||
}
|
||||
res = testclient.get("/profile/user", status=200)
|
||||
assert "telephoneNumber" in res.form.fields
|
||||
|
|
Loading…
Reference in a new issue