forked from Github-Mirrors/canaille
Use a unique identifier to indentify users in URLS
Previously we used the uid since we supposed this value was always valid, but some users user the mail attribute as the User RDN in their OpenLDAP installation, and do not have a uuid.
This commit is contained in:
parent
4551dc3f60
commit
57af18d557
22 changed files with 143 additions and 125 deletions
|
@ -85,6 +85,10 @@ class User(canaille.core.models.User, LDAPObject):
|
||||||
|
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
@property
|
||||||
|
def identifier(self):
|
||||||
|
return self.rdn_value
|
||||||
|
|
||||||
def has_password(self):
|
def has_password(self):
|
||||||
return bool(self.password)
|
return bool(self.password)
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ def index():
|
||||||
|
|
||||||
if user.can_edit_self or user.can_manage_users:
|
if user.can_edit_self or user.can_manage_users:
|
||||||
return redirect(
|
return redirect(
|
||||||
url_for("account.profile_edition", username=current_user().user_name[0])
|
url_for("account.profile_edition", identifier=current_user().identifier)
|
||||||
)
|
)
|
||||||
|
|
||||||
if user.can_use_oidc:
|
if user.can_use_oidc:
|
||||||
|
@ -82,7 +82,7 @@ def about():
|
||||||
def login():
|
def login():
|
||||||
if current_user():
|
if current_user():
|
||||||
return redirect(
|
return redirect(
|
||||||
url_for("account.profile_edition", username=current_user().user_name[0])
|
url_for("account.profile_edition", identifier=current_user().identifier)
|
||||||
)
|
)
|
||||||
|
|
||||||
form = LoginForm(request.form or None)
|
form = LoginForm(request.form or None)
|
||||||
|
@ -93,7 +93,7 @@ def login():
|
||||||
|
|
||||||
user = models.User.get_from_login(form.login.data)
|
user = models.User.get_from_login(form.login.data)
|
||||||
if user and not user.has_password():
|
if user and not user.has_password():
|
||||||
return redirect(url_for("account.firstlogin", user_name=user.user_name[0]))
|
return redirect(url_for("account.firstlogin", identifier=user.identifier))
|
||||||
|
|
||||||
if not form.validate():
|
if not form.validate():
|
||||||
models.User.logout()
|
models.User.logout()
|
||||||
|
@ -119,7 +119,7 @@ def password():
|
||||||
|
|
||||||
user = models.User.get_from_login(session["attempt_login"])
|
user = models.User.get_from_login(session["attempt_login"])
|
||||||
if user and not user.has_password():
|
if user and not user.has_password():
|
||||||
return redirect(url_for("account.firstlogin", user_name=user.user_name[0]))
|
return redirect(url_for("account.firstlogin", identifier=user.identifier))
|
||||||
|
|
||||||
if not form.validate() or not user:
|
if not form.validate() or not user:
|
||||||
models.User.logout()
|
models.User.logout()
|
||||||
|
@ -160,15 +160,15 @@ def logout():
|
||||||
return redirect("/")
|
return redirect("/")
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/firstlogin/<user_name>", methods=("GET", "POST"))
|
@bp.route("/firstlogin/<identifier>", methods=("GET", "POST"))
|
||||||
def firstlogin(user_name):
|
def firstlogin(identifier):
|
||||||
user = models.User.get_from_login(user_name)
|
user = models.User.get_from_login(identifier)
|
||||||
if not user or user.has_password():
|
if not user or user.has_password():
|
||||||
abort(404)
|
abort(404)
|
||||||
|
|
||||||
form = FirstLoginForm(request.form or None)
|
form = FirstLoginForm(request.form or None)
|
||||||
if not request.form:
|
if not request.form:
|
||||||
return render_template("firstlogin.html", form=form, user_name=user_name)
|
return render_template("firstlogin.html", form=form, identifier=identifier)
|
||||||
|
|
||||||
form.validate()
|
form.validate()
|
||||||
|
|
||||||
|
@ -182,7 +182,7 @@ def firstlogin(user_name):
|
||||||
else:
|
else:
|
||||||
flash(_("Could not send the password initialization email"), "error")
|
flash(_("Could not send the password initialization email"), "error")
|
||||||
|
|
||||||
return render_template("firstlogin.html", form=form, user_name=user_name)
|
return render_template("firstlogin.html", form=form, identifier=identifier)
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/users", methods=["GET", "POST"])
|
@bp.route("/users", methods=["GET", "POST"])
|
||||||
|
@ -360,7 +360,7 @@ def registration(data, hash):
|
||||||
user = profile_create(current_app, form)
|
user = profile_create(current_app, form)
|
||||||
user.login()
|
user.login()
|
||||||
flash(_("Your account has been created successfully."), "success")
|
flash(_("Your account has been created successfully."), "success")
|
||||||
return redirect(url_for("account.profile_edition", username=user.user_name[0]))
|
return redirect(url_for("account.profile_edition", identifier=user.identifier))
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/profile", methods=("GET", "POST"))
|
@bp.route("/profile", methods=("GET", "POST"))
|
||||||
|
@ -393,7 +393,7 @@ def profile_creation(user):
|
||||||
)
|
)
|
||||||
|
|
||||||
user = profile_create(current_app, form)
|
user = profile_create(current_app, form)
|
||||||
return redirect(url_for("account.profile_edition", username=user.user_name[0]))
|
return redirect(url_for("account.profile_edition", identifier=user.identifier))
|
||||||
|
|
||||||
|
|
||||||
def profile_create(current_app, form):
|
def profile_create(current_app, form):
|
||||||
|
@ -424,19 +424,19 @@ def profile_create(current_app, form):
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/profile/<username>", methods=("GET", "POST"))
|
@bp.route("/profile/<identifier>", methods=("GET", "POST"))
|
||||||
@user_needed()
|
@user_needed()
|
||||||
def profile_edition(user, username):
|
def profile_edition(user, identifier):
|
||||||
editor = user
|
editor = user
|
||||||
if not user.can_manage_users and not (
|
if not user.can_manage_users and not (
|
||||||
user.can_edit_self and username == user.user_name[0]
|
user.can_edit_self and identifier == user.identifier
|
||||||
):
|
):
|
||||||
abort(403)
|
abort(403)
|
||||||
|
|
||||||
menuitem = "profile" if username == editor.user_name[0] else "users"
|
menuitem = "profile" if identifier == editor.identifier else "users"
|
||||||
fields = editor.read | editor.write
|
fields = editor.read | editor.write
|
||||||
if username != editor.user_name[0]:
|
if identifier != editor.identifier:
|
||||||
user = models.User.get_from_login(username)
|
user = models.User.get_from_login(identifier)
|
||||||
else:
|
else:
|
||||||
user = editor
|
user = editor
|
||||||
|
|
||||||
|
@ -524,18 +524,18 @@ def profile_edition(user, username):
|
||||||
|
|
||||||
user.save()
|
user.save()
|
||||||
flash(_("Profile updated successfully."), "success")
|
flash(_("Profile updated successfully."), "success")
|
||||||
return redirect(url_for("account.profile_edition", username=username))
|
return redirect(url_for("account.profile_edition", identifier=identifier))
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/profile/<username>/settings", methods=("GET", "POST"))
|
@bp.route("/profile/<identifier>/settings", methods=("GET", "POST"))
|
||||||
@user_needed()
|
@user_needed()
|
||||||
def profile_settings(user, username):
|
def profile_settings(user, identifier):
|
||||||
if not user.can_manage_users and not (
|
if not user.can_manage_users and not (
|
||||||
user.can_edit_self and username == user.user_name[0]
|
user.can_edit_self and identifier == user.identifier
|
||||||
):
|
):
|
||||||
abort(403)
|
abort(403)
|
||||||
|
|
||||||
edited_user = models.User.get_from_login(username)
|
edited_user = models.User.get_from_login(identifier)
|
||||||
if not edited_user:
|
if not edited_user:
|
||||||
abort(404)
|
abort(404)
|
||||||
|
|
||||||
|
@ -640,7 +640,7 @@ def profile_settings_edit(editor, edited_user):
|
||||||
edited_user.save()
|
edited_user.save()
|
||||||
flash(_("Profile updated successfully."), "success")
|
flash(_("Profile updated successfully."), "success")
|
||||||
return redirect(
|
return redirect(
|
||||||
url_for("account.profile_settings", username=edited_user.user_name[0])
|
url_for("account.profile_settings", identifier=edited_user.identifier)
|
||||||
)
|
)
|
||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
|
@ -671,10 +671,10 @@ def profile_delete(user, edited_user):
|
||||||
return redirect(url_for("account.users"))
|
return redirect(url_for("account.users"))
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/impersonate/<username>")
|
@bp.route("/impersonate/<identifier>")
|
||||||
@permissions_needed("impersonate_users")
|
@permissions_needed("impersonate_users")
|
||||||
def impersonate(user, username):
|
def impersonate(user, identifier):
|
||||||
puppet = models.User.get_from_login(username)
|
puppet = models.User.get_from_login(identifier)
|
||||||
if not puppet:
|
if not puppet:
|
||||||
abort(404)
|
abort(404)
|
||||||
|
|
||||||
|
@ -735,16 +735,16 @@ def forgotten():
|
||||||
return render_template("forgotten-password.html", form=form)
|
return render_template("forgotten-password.html", form=form)
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/reset/<user_name>/<hash>", methods=["GET", "POST"])
|
@bp.route("/reset/<identifier>/<hash>", methods=["GET", "POST"])
|
||||||
def reset(user_name, hash):
|
def reset(identifier, hash):
|
||||||
if not current_app.config.get("ENABLE_PASSWORD_RECOVERY", True):
|
if not current_app.config.get("ENABLE_PASSWORD_RECOVERY", True):
|
||||||
abort(404)
|
abort(404)
|
||||||
|
|
||||||
form = PasswordResetForm(request.form)
|
form = PasswordResetForm(request.form)
|
||||||
user = models.User.get_from_login(user_name)
|
user = models.User.get_from_login(identifier)
|
||||||
|
|
||||||
if not user or hash != profile_hash(
|
if not user or hash != profile_hash(
|
||||||
user.user_name[0],
|
user.identifier,
|
||||||
user.preferred_email,
|
user.preferred_email,
|
||||||
user.password[0] if user.has_password() else "",
|
user.password[0] if user.has_password() else "",
|
||||||
):
|
):
|
||||||
|
@ -759,19 +759,19 @@ def reset(user_name, hash):
|
||||||
user.login()
|
user.login()
|
||||||
|
|
||||||
flash(_("Your password has been updated successfully"), "success")
|
flash(_("Your password has been updated successfully"), "success")
|
||||||
return redirect(url_for("account.profile_edition", username=user_name))
|
return redirect(url_for("account.profile_edition", identifier=identifier))
|
||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
"reset-password.html", form=form, user_name=user_name, hash=hash
|
"reset-password.html", form=form, identifier=identifier, hash=hash
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/profile/<user_name>/<field>")
|
@bp.route("/profile/<identifier>/<field>")
|
||||||
def photo(user_name, field):
|
def photo(identifier, field):
|
||||||
if field.lower() != "photo":
|
if field.lower() != "photo":
|
||||||
abort(404)
|
abort(404)
|
||||||
|
|
||||||
user = models.User.get_from_login(user_name)
|
user = models.User.get_from_login(identifier)
|
||||||
if not user:
|
if not user:
|
||||||
abort(404)
|
abort(404)
|
||||||
|
|
||||||
|
@ -779,7 +779,7 @@ def photo(user_name, field):
|
||||||
if request.if_modified_since and request.if_modified_since >= user.last_modified:
|
if request.if_modified_since and request.if_modified_since >= user.last_modified:
|
||||||
return "", 304
|
return "", 304
|
||||||
|
|
||||||
etag = profile_hash(user_name, user.last_modified.isoformat())
|
etag = profile_hash(identifier, user.last_modified.isoformat())
|
||||||
if request.if_none_match and etag in request.if_none_match:
|
if request.if_none_match and etag in request.if_none_match:
|
||||||
return "", 304
|
return "", 304
|
||||||
|
|
||||||
|
|
|
@ -75,8 +75,8 @@ def password_init_html(user):
|
||||||
base_url = url_for("account.index", _external=True)
|
base_url = url_for("account.index", _external=True)
|
||||||
reset_url = url_for(
|
reset_url = url_for(
|
||||||
"account.reset",
|
"account.reset",
|
||||||
user_name=user.user_name[0],
|
identifier=user.identifier,
|
||||||
hash=profile_hash(user.user_name[0], user.preferred_email, user.password[0]),
|
hash=profile_hash(user.identifier, user.preferred_email, user.password[0]),
|
||||||
_external=True,
|
_external=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -98,8 +98,8 @@ def password_init_txt(user):
|
||||||
base_url = url_for("account.index", _external=True)
|
base_url = url_for("account.index", _external=True)
|
||||||
reset_url = url_for(
|
reset_url = url_for(
|
||||||
"account.reset",
|
"account.reset",
|
||||||
user_name=user.user_name[0],
|
identifier=user.identifier,
|
||||||
hash=profile_hash(user.user_name[0], user.preferred_email, user.password[0]),
|
hash=profile_hash(user.identifier, user.preferred_email, user.password[0]),
|
||||||
_external=True,
|
_external=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -117,8 +117,8 @@ def password_reset_html(user):
|
||||||
base_url = url_for("account.index", _external=True)
|
base_url = url_for("account.index", _external=True)
|
||||||
reset_url = url_for(
|
reset_url = url_for(
|
||||||
"account.reset",
|
"account.reset",
|
||||||
user_name=user.user_name[0],
|
identifier=user.identifier,
|
||||||
hash=profile_hash(user.user_name[0], user.preferred_email, user.password[0]),
|
hash=profile_hash(user.identifier, user.preferred_email, user.password[0]),
|
||||||
_external=True,
|
_external=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -140,8 +140,8 @@ def password_reset_txt(user):
|
||||||
base_url = url_for("account.index", _external=True)
|
base_url = url_for("account.index", _external=True)
|
||||||
reset_url = url_for(
|
reset_url = url_for(
|
||||||
"account.reset",
|
"account.reset",
|
||||||
user_name=user.user_name[0],
|
identifier=user.identifier,
|
||||||
hash=profile_hash(user.user_name[0], user.preferred_email, user.password[0]),
|
hash=profile_hash(user.identifier, user.preferred_email, user.password[0]),
|
||||||
_external=True,
|
_external=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -153,14 +153,14 @@ def password_reset_txt(user):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/mail/<user_name>/<email>/invitation.html")
|
@bp.route("/mail/<identifier>/<email>/invitation.html")
|
||||||
@permissions_needed("manage_oidc")
|
@permissions_needed("manage_oidc")
|
||||||
def invitation_html(user, user_name, email):
|
def invitation_html(user, identifier, email):
|
||||||
base_url = url_for("account.index", _external=True)
|
base_url = url_for("account.index", _external=True)
|
||||||
registration_url = url_for(
|
registration_url = url_for(
|
||||||
"account.registration",
|
"account.registration",
|
||||||
data=obj_to_b64([user_name, email]),
|
data=obj_to_b64([identifier, email]),
|
||||||
hash=profile_hash(user_name, email),
|
hash=profile_hash(identifier, email),
|
||||||
_external=True,
|
_external=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -176,14 +176,14 @@ def invitation_html(user, user_name, email):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/mail/<user_name>/<email>/invitation.txt")
|
@bp.route("/mail/<identifier>/<email>/invitation.txt")
|
||||||
@permissions_needed("manage_oidc")
|
@permissions_needed("manage_oidc")
|
||||||
def invitation_txt(user, user_name, email):
|
def invitation_txt(user, identifier, email):
|
||||||
base_url = url_for("account.index", _external=True)
|
base_url = url_for("account.index", _external=True)
|
||||||
registration_url = url_for(
|
registration_url = url_for(
|
||||||
"account.registration",
|
"account.registration",
|
||||||
data=obj_to_b64([user_name, email]),
|
data=obj_to_b64([identifier, email]),
|
||||||
hash=profile_hash(user_name, email),
|
hash=profile_hash(identifier, email),
|
||||||
_external=True,
|
_external=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -39,9 +39,9 @@ def send_password_reset_mail(user):
|
||||||
base_url = url_for("account.index", _external=True)
|
base_url = url_for("account.index", _external=True)
|
||||||
reset_url = url_for(
|
reset_url = url_for(
|
||||||
"account.reset",
|
"account.reset",
|
||||||
user_name=user.user_name[0],
|
identifier=user.identifier,
|
||||||
hash=profile_hash(
|
hash=profile_hash(
|
||||||
user.user_name[0],
|
user.identifier,
|
||||||
user.preferred_email,
|
user.preferred_email,
|
||||||
user.password[0] if user.has_password() else "",
|
user.password[0] if user.has_password() else "",
|
||||||
),
|
),
|
||||||
|
@ -79,9 +79,9 @@ def send_password_initialization_mail(user):
|
||||||
base_url = url_for("account.index", _external=True)
|
base_url = url_for("account.index", _external=True)
|
||||||
reset_url = url_for(
|
reset_url = url_for(
|
||||||
"account.reset",
|
"account.reset",
|
||||||
user_name=user.user_name[0],
|
identifier=user.identifier,
|
||||||
hash=profile_hash(
|
hash=profile_hash(
|
||||||
user.user_name[0],
|
user.identifier,
|
||||||
user.preferred_email,
|
user.preferred_email,
|
||||||
user.password[0] if user.has_password() else "",
|
user.password[0] if user.has_password() else "",
|
||||||
),
|
),
|
||||||
|
|
|
@ -34,6 +34,14 @@ class User:
|
||||||
except (IndexError, KeyError):
|
except (IndexError, KeyError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@property
|
||||||
|
def identifier(self):
|
||||||
|
"""
|
||||||
|
Returns a unique value that will be used to identify the user.
|
||||||
|
This value will be used in URLs in canaille, so it should be unique and short.
|
||||||
|
"""
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
def has_password(self):
|
def has_password(self):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
|
@ -101,8 +101,8 @@
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<div class="right floated content">
|
<div class="right floated content">
|
||||||
<div class="ui buttons">
|
<div class="ui buttons">
|
||||||
<a class="ui button primary" href="{{ url_for("admin.invitation_txt", user_name=user.user_name, email=user.preferred_email) }}">TXT</a>
|
<a class="ui button primary" href="{{ url_for("admin.invitation_txt", identifier=user.identifier, email=user.preferred_email) }}">TXT</a>
|
||||||
<a class="ui button primary" href="{{ url_for("admin.invitation_html", user_name=user.user_name, email=user.preferred_email) }}">HTML</a>
|
<a class="ui button primary" href="{{ url_for("admin.invitation_html", identifier=user.identifier, email=user.preferred_email) }}">HTML</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="middle aligned content">
|
<div class="middle aligned content">
|
||||||
|
|
|
@ -70,7 +70,7 @@
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ _("Subject") }}</td>
|
<td>{{ _("Subject") }}</td>
|
||||||
<td>
|
<td>
|
||||||
<a href="{{ url_for("account.profile_edition", username=token.subject.user_name[0]) }}">
|
<a href="{{ url_for("account.profile_edition", identifier=token.subject.identifier) }}">
|
||||||
{{ token.subject.name }} - {{ token.subject.user_name[0] }}
|
{{ token.subject.name }} - {{ token.subject.user_name[0] }}
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
</h2>
|
</h2>
|
||||||
<div class="ui message">
|
<div class="ui message">
|
||||||
<p>
|
<p>
|
||||||
{{ _("You are currently logged in as %(username)s.", username=user.formatted_name[0]) }}
|
{{ _("You are currently logged in as %(username)s.", username=user.identifier) }}
|
||||||
{% if client %}
|
{% if client %}
|
||||||
{{ _("The application %(client_name)s wants to disconnect your account.", client_name=client.client_name) }}
|
{{ _("The application %(client_name)s wants to disconnect your account.", client_name=client.client_name) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
<td><a href="{{ url_for('oidc.authorizations.view', authorization_id=authorization.authorization_code_id) }}">{{ authorization.authorization_code_id }}</a></td>
|
<td><a href="{{ url_for('oidc.authorizations.view', authorization_id=authorization.authorization_code_id) }}">{{ authorization.authorization_code_id }}</a></td>
|
||||||
<td><a href="{{ url_for('oidc.clients.edit', client_id=authorization.client.client_id) }}">{{ authorization.client.client_id }}</a></td>
|
<td><a href="{{ url_for('oidc.clients.edit', client_id=authorization.client.client_id) }}">{{ authorization.client.client_id }}</a></td>
|
||||||
<td>
|
<td>
|
||||||
<a href="{{ url_for("account.profile_edition", username=authorization.subject.user_name[0]) }}">
|
<a href="{{ url_for("account.profile_edition", identifier=authorization.subject.identifier) }}">
|
||||||
{{ authorization.subject.user_name[0] }}
|
{{ authorization.subject.user_name[0] }}
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a href="{{ url_for("account.profile_edition", username=token.subject.user_name[0]) }}">
|
<a href="{{ url_for("account.profile_edition", identifier=token.subject.identifier) }}">
|
||||||
{{ token.subject.user_name[0] }}
|
{{ token.subject.user_name[0] }}
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
<tr>
|
<tr>
|
||||||
{% if user.can_read("photo") %}
|
{% if user.can_read("photo") %}
|
||||||
<td>
|
<td>
|
||||||
<a href="{{ url_for('account.profile_edition', username=watched_user.user_name[0]) }}">
|
<a href="{{ url_for('account.profile_edition', identifier=watched_user.identifier) }}">
|
||||||
{% if user.can_manage_users and watched_user.locked %}
|
{% if user.can_manage_users and watched_user.locked %}
|
||||||
<i class="lock circle big black icon" title="{% trans %}This account is locked{% endtrans %}"></i>
|
<i class="lock circle big black icon" title="{% trans %}This account is locked{% endtrans %}"></i>
|
||||||
{% elif watched_user.photo and watched_user.photo[0] %}
|
{% elif watched_user.photo and watched_user.photo[0] %}
|
||||||
|
@ -36,7 +36,7 @@
|
||||||
</td>
|
</td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if user.can_read("user_name") %}
|
{% if user.can_read("user_name") %}
|
||||||
<td><a href="{{ url_for('account.profile_edition', username=watched_user.user_name[0]) }}">{{ watched_user.user_name[0] }}</a></td>
|
<td><a href="{{ url_for('account.profile_edition', identifier=watched_user.identifier) }}">{{ watched_user.user_name[0] }}</a></td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if user.can_read("family_name") or user.can_read("given_name") %}
|
{% if user.can_read("family_name") or user.can_read("given_name") %}
|
||||||
<td>{{ watched_user.formatted_name[0] }}</td>
|
<td>{{ watched_user.formatted_name[0] }}</td>
|
||||||
|
|
|
@ -18,11 +18,11 @@
|
||||||
|
|
||||||
{% block submenu %}
|
{% block submenu %}
|
||||||
<nav class="ui bottom attached two item borderless menu">
|
<nav class="ui bottom attached two item borderless menu">
|
||||||
<a class="active item" href="{{ url_for('account.profile_edition', username=edited_user.user_name[0]) }}">
|
<a class="active item" href="{{ url_for('account.profile_edition', identifier=edited_user.identifier) }}">
|
||||||
<i class="id card icon"></i>
|
<i class="id card icon"></i>
|
||||||
{% trans %}Personal information{% endtrans %}
|
{% trans %}Personal information{% endtrans %}
|
||||||
</a>
|
</a>
|
||||||
<a class="item" href="{{ url_for('account.profile_settings', username=edited_user.user_name[0]) }}">
|
<a class="item" href="{{ url_for('account.profile_settings', identifier=edited_user.identifier) }}">
|
||||||
<i class="tools icon"></i>
|
<i class="tools icon"></i>
|
||||||
{% trans %}Account information{% endtrans %}
|
{% trans %}Account information{% endtrans %}
|
||||||
</a>
|
</a>
|
||||||
|
@ -66,7 +66,7 @@
|
||||||
<a class="ui right corner label photo-delete-icon" title="{{ _("Delete the photo") }}">
|
<a class="ui right corner label photo-delete-icon" title="{{ _("Delete the photo") }}">
|
||||||
<i class="times icon"></i>
|
<i class="times icon"></i>
|
||||||
</a>
|
</a>
|
||||||
<img src="{% if photo %}{{ url_for("account.photo", user_name=edited_user.user_name[0], field="photo") }}{% endif %}" alt="User photo">
|
<img src="{% if photo %}{{ url_for("account.photo", identifier=edited_user.identifier, field="photo") }}{% endif %}" alt="User photo">
|
||||||
</label>
|
</label>
|
||||||
<label
|
<label
|
||||||
class="ui centered photo-placeholder"
|
class="ui centered photo-placeholder"
|
||||||
|
|
|
@ -15,11 +15,11 @@
|
||||||
|
|
||||||
{% block submenu %}
|
{% block submenu %}
|
||||||
<nav class="ui bottom attached two item borderless menu">
|
<nav class="ui bottom attached two item borderless menu">
|
||||||
<a class="item" href="{{ url_for('account.profile_edition', username=edited_user.user_name[0]) }}">
|
<a class="item" href="{{ url_for('account.profile_edition', identifier=edited_user.identifier) }}">
|
||||||
<i class="id card icon"></i>
|
<i class="id card icon"></i>
|
||||||
{% trans %}Personal information{% endtrans %}
|
{% trans %}Personal information{% endtrans %}
|
||||||
</a>
|
</a>
|
||||||
<a class="active item" href="{{ url_for('account.profile_settings', username=edited_user.user_name[0]) }}">
|
<a class="active item" href="{{ url_for('account.profile_settings', identifier=edited_user.identifier) }}">
|
||||||
<i class="tools icon"></i>
|
<i class="tools icon"></i>
|
||||||
{% trans %}Account information{% endtrans %}
|
{% trans %}Account information{% endtrans %}
|
||||||
</a>
|
</a>
|
||||||
|
@ -188,8 +188,8 @@
|
||||||
</button>
|
</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if user.can_impersonate_users and user.user_name != edited_user.user_name %}
|
{% if user.can_impersonate_users and user.identifier != edited_user.identifier %}
|
||||||
<a href="{{ url_for('account.impersonate', username=edited_user.user_name[0]) }}" class="ui right floated basic button" name="action" value="impersonate" id="impersonate" hx-boost="false">
|
<a href="{{ url_for('account.impersonate', identifier=edited_user.identifier) }}" class="ui right floated basic button" name="action" value="impersonate" id="impersonate" hx-boost="false">
|
||||||
{{ _("Impersonate") }}
|
{{ _("Impersonate") }}
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
<div class="ui attached clearing segment">
|
<div class="ui attached clearing segment">
|
||||||
{{ fui.render_form(form, _("Password reset"), action=url_for("account.reset", user_name=user_name, hash=hash)) }}
|
{{ fui.render_form(form, _("Password reset"), action=url_for("account.reset", identifier=identifier, hash=hash)) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
|
|
||||||
{% if user.can_edit_self %}
|
{% if user.can_edit_self %}
|
||||||
<a class="item {% if menuitem == "profile" %}active{% endif %}"
|
<a class="item {% if menuitem == "profile" %}active{% endif %}"
|
||||||
href="{{ url_for('account.profile_edition', username=user.user_name[0]) }}">
|
href="{{ url_for('account.profile_edition', identifier=user.identifier) }}">
|
||||||
<i class="id card icon"></i>
|
<i class="id card icon"></i>
|
||||||
{% trans %}Profile{% endtrans %}
|
{% trans %}Profile{% endtrans %}
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -77,7 +77,7 @@ USER_BASE = "ou=users,dc=mydomain,dc=tld"
|
||||||
# USER_CLASS = "inetOrgPerson"
|
# USER_CLASS = "inetOrgPerson"
|
||||||
|
|
||||||
# The attribute to identify an object in the User dn.
|
# The attribute to identify an object in the User dn.
|
||||||
USER_ID_ATTRIBUTE = "uid"
|
# USER_ID_ATTRIBUTE = "uid"
|
||||||
|
|
||||||
# Filter to match users on sign in. Supports a variable
|
# Filter to match users on sign in. Supports a variable
|
||||||
# {login} that can be used to compare against several fields:
|
# {login} that can be used to compare against several fields:
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a class="item {% if menuitem == "profile" %}active{% endif %}"
|
<a class="item {% if menuitem == "profile" %}active{% endif %}"
|
||||||
href="{{ url_for('account.profile_edition', username=user.user_name[0]) }}">
|
href="{{ url_for('account.profile_edition', identifier=user.identifier) }}">
|
||||||
<i class="id card icon"></i>
|
<i class="id card icon"></i>
|
||||||
{% trans %}My profile{% endtrans %}
|
{% trans %}My profile{% endtrans %}
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -34,6 +34,7 @@ def ldap_configuration(configuration, slapd_server):
|
||||||
"BIND_DN": slapd_server.root_dn,
|
"BIND_DN": slapd_server.root_dn,
|
||||||
"BIND_PW": slapd_server.root_pw,
|
"BIND_PW": slapd_server.root_pw,
|
||||||
"USER_BASE": "ou=users",
|
"USER_BASE": "ou=users",
|
||||||
|
"USER_ID_ATTRIBUTE": "uid",
|
||||||
"USER_FILTER": "(uid={login})",
|
"USER_FILTER": "(uid={login})",
|
||||||
"GROUP_BASE": "ou=groups",
|
"GROUP_BASE": "ou=groups",
|
||||||
"TIMEOUT": 0.1,
|
"TIMEOUT": 0.1,
|
||||||
|
|
|
@ -33,7 +33,7 @@ def test_object_creation(app, backend):
|
||||||
|
|
||||||
def test_repr(backend, foo_group, user):
|
def test_repr(backend, foo_group, user):
|
||||||
assert repr(foo_group) == "<Group display_name=foo>"
|
assert repr(foo_group) == "<Group display_name=foo>"
|
||||||
assert repr(user) == "<User formatted_name=John (johnny) Doe>"
|
assert repr(user) == "<User user_name=user>"
|
||||||
|
|
||||||
|
|
||||||
def test_dn_when_leading_space_in_id_attribute(backend):
|
def test_dn_when_leading_space_in_id_attribute(backend):
|
||||||
|
@ -47,7 +47,7 @@ def test_dn_when_leading_space_in_id_attribute(backend):
|
||||||
|
|
||||||
assert ldap.dn.is_dn(user.dn)
|
assert ldap.dn.is_dn(user.dn)
|
||||||
assert ldap.dn.dn2str(ldap.dn.str2dn(user.dn)) == user.dn
|
assert ldap.dn.dn2str(ldap.dn.str2dn(user.dn)) == user.dn
|
||||||
assert user.dn == "cn=Doe,ou=users,dc=mydomain,dc=tld"
|
assert user.dn == "uid=user,ou=users,dc=mydomain,dc=tld"
|
||||||
|
|
||||||
user.delete()
|
user.delete()
|
||||||
|
|
||||||
|
@ -56,14 +56,14 @@ def test_dn_when_ldap_special_char_in_id_attribute(backend):
|
||||||
user = models.User(
|
user = models.User(
|
||||||
formatted_name="#Doe", # special char
|
formatted_name="#Doe", # special char
|
||||||
family_name="Doe",
|
family_name="Doe",
|
||||||
user_name="user",
|
user_name="#user",
|
||||||
emails="john@doe.com",
|
emails="john@doe.com",
|
||||||
)
|
)
|
||||||
user.save()
|
user.save()
|
||||||
|
|
||||||
assert ldap.dn.is_dn(user.dn)
|
assert ldap.dn.is_dn(user.dn)
|
||||||
assert ldap.dn.dn2str(ldap.dn.str2dn(user.dn)) == user.dn
|
assert ldap.dn.dn2str(ldap.dn.str2dn(user.dn)) == user.dn
|
||||||
assert user.dn == "cn=\\#Doe,ou=users,dc=mydomain,dc=tld"
|
assert user.dn == "uid=\\#user,ou=users,dc=mydomain,dc=tld"
|
||||||
|
|
||||||
user.delete()
|
user.delete()
|
||||||
|
|
||||||
|
@ -182,7 +182,7 @@ def test_object_class_update(backend, testclient):
|
||||||
testclient.app.config["BACKENDS"]["LDAP"]["USER_CLASS"] = ["inetOrgPerson"]
|
testclient.app.config["BACKENDS"]["LDAP"]["USER_CLASS"] = ["inetOrgPerson"]
|
||||||
setup_ldap_models(testclient.app.config)
|
setup_ldap_models(testclient.app.config)
|
||||||
|
|
||||||
user1 = models.User(cn="foo1", sn="bar1")
|
user1 = models.User(cn="foo1", sn="bar1", user_name="baz1")
|
||||||
user1.save()
|
user1.save()
|
||||||
|
|
||||||
assert user1.objectClass == ["inetOrgPerson"]
|
assert user1.objectClass == ["inetOrgPerson"]
|
||||||
|
@ -194,7 +194,7 @@ def test_object_class_update(backend, testclient):
|
||||||
]
|
]
|
||||||
setup_ldap_models(testclient.app.config)
|
setup_ldap_models(testclient.app.config)
|
||||||
|
|
||||||
user2 = models.User(cn="foo2", sn="bar2")
|
user2 = models.User(cn="foo2", sn="bar2", user_name="baz2")
|
||||||
user2.save()
|
user2.save()
|
||||||
|
|
||||||
assert user2.objectClass == ["inetOrgPerson", "extensibleObject"]
|
assert user2.objectClass == ["inetOrgPerson", "extensibleObject"]
|
||||||
|
|
|
@ -180,7 +180,9 @@ def test_model_references_set_unsaved_object(
|
||||||
group.save()
|
group.save()
|
||||||
user.reload() # an LDAP group can be inconsistent by containing members which doesn't exist
|
user.reload() # an LDAP group can be inconsistent by containing members which doesn't exist
|
||||||
|
|
||||||
non_existent_user = models.User(formatted_name="foo", family_name="bar")
|
non_existent_user = models.User(
|
||||||
|
formatted_name="foo", family_name="bar", user_name="baz"
|
||||||
|
)
|
||||||
group.members = group.members + [non_existent_user]
|
group.members = group.members + [non_existent_user]
|
||||||
assert group.members == [user, non_existent_user]
|
assert group.members == [user, non_existent_user]
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,9 @@ def test_required_methods(testclient):
|
||||||
with pytest.raises(NotImplementedError):
|
with pytest.raises(NotImplementedError):
|
||||||
user.set_password("password")
|
user.set_password("password")
|
||||||
|
|
||||||
|
with pytest.raises(NotImplementedError):
|
||||||
|
user.identifier
|
||||||
|
|
||||||
|
|
||||||
def test_user_get_from_login(testclient, user, backend):
|
def test_user_get_from_login(testclient, user, backend):
|
||||||
assert models.User.get_from_login(login="invalid") is None
|
assert models.User.get_from_login(login="invalid") is None
|
||||||
|
|
|
@ -4,14 +4,14 @@ from canaille.oidc.oauth import get_jwt_config
|
||||||
|
|
||||||
|
|
||||||
def test_end_session(testclient, backend, logged_user, client, id_token):
|
def test_end_session(testclient, backend, logged_user, client, id_token):
|
||||||
testclient.get(f"/profile/{logged_user.user_name[0]}", status=200)
|
testclient.get(f"/profile/{logged_user.identifier}", status=200)
|
||||||
|
|
||||||
post_logout_redirect_url = "https://mydomain.tld/disconnected"
|
post_logout_redirect_url = "https://mydomain.tld/disconnected"
|
||||||
res = testclient.get(
|
res = testclient.get(
|
||||||
"/oauth/end_session",
|
"/oauth/end_session",
|
||||||
params={
|
params={
|
||||||
"id_token_hint": id_token,
|
"id_token_hint": id_token,
|
||||||
"logout_hint": logged_user.user_name[0],
|
"logout_hint": logged_user.identifier,
|
||||||
"client_id": client.client_id,
|
"client_id": client.client_id,
|
||||||
"post_logout_redirect_uri": post_logout_redirect_url,
|
"post_logout_redirect_uri": post_logout_redirect_url,
|
||||||
"state": "foobar",
|
"state": "foobar",
|
||||||
|
@ -24,18 +24,18 @@ def test_end_session(testclient, backend, logged_user, client, id_token):
|
||||||
with testclient.session_transaction() as sess:
|
with testclient.session_transaction() as sess:
|
||||||
assert not sess.get("user_id")
|
assert not sess.get("user_id")
|
||||||
|
|
||||||
testclient.get(f"/profile/{logged_user.user_name[0]}", status=403)
|
testclient.get(f"/profile/{logged_user.identifier}", status=403)
|
||||||
|
|
||||||
|
|
||||||
def test_end_session_no_client_id(testclient, backend, logged_user, client, id_token):
|
def test_end_session_no_client_id(testclient, backend, logged_user, client, id_token):
|
||||||
testclient.get(f"/profile/{logged_user.user_name[0]}", status=200)
|
testclient.get(f"/profile/{logged_user.identifier}", status=200)
|
||||||
|
|
||||||
post_logout_redirect_url = "https://mydomain.tld/disconnected"
|
post_logout_redirect_url = "https://mydomain.tld/disconnected"
|
||||||
res = testclient.get(
|
res = testclient.get(
|
||||||
"/oauth/end_session",
|
"/oauth/end_session",
|
||||||
params={
|
params={
|
||||||
"id_token_hint": id_token,
|
"id_token_hint": id_token,
|
||||||
"logout_hint": logged_user.user_name[0],
|
"logout_hint": logged_user.identifier,
|
||||||
"post_logout_redirect_uri": post_logout_redirect_url,
|
"post_logout_redirect_uri": post_logout_redirect_url,
|
||||||
"state": "foobar",
|
"state": "foobar",
|
||||||
},
|
},
|
||||||
|
@ -47,19 +47,19 @@ def test_end_session_no_client_id(testclient, backend, logged_user, client, id_t
|
||||||
with testclient.session_transaction() as sess:
|
with testclient.session_transaction() as sess:
|
||||||
assert not sess.get("user_id")
|
assert not sess.get("user_id")
|
||||||
|
|
||||||
testclient.get(f"/profile/{logged_user.user_name[0]}", status=403)
|
testclient.get(f"/profile/{logged_user.identifier}", status=403)
|
||||||
|
|
||||||
|
|
||||||
def test_no_redirect_uri_no_redirect(
|
def test_no_redirect_uri_no_redirect(
|
||||||
testclient, backend, logged_user, client, id_token
|
testclient, backend, logged_user, client, id_token
|
||||||
):
|
):
|
||||||
testclient.get(f"/profile/{logged_user.user_name[0]}", status=200)
|
testclient.get(f"/profile/{logged_user.identifier}", status=200)
|
||||||
|
|
||||||
res = testclient.get(
|
res = testclient.get(
|
||||||
"/oauth/end_session",
|
"/oauth/end_session",
|
||||||
params={
|
params={
|
||||||
"id_token_hint": id_token,
|
"id_token_hint": id_token,
|
||||||
"logout_hint": logged_user.user_name[0],
|
"logout_hint": logged_user.identifier,
|
||||||
"client_id": client.client_id,
|
"client_id": client.client_id,
|
||||||
"state": "foobar",
|
"state": "foobar",
|
||||||
},
|
},
|
||||||
|
@ -71,20 +71,20 @@ def test_no_redirect_uri_no_redirect(
|
||||||
with testclient.session_transaction() as sess:
|
with testclient.session_transaction() as sess:
|
||||||
assert not sess.get("user_id")
|
assert not sess.get("user_id")
|
||||||
|
|
||||||
testclient.get(f"/profile/{logged_user.user_name[0]}", status=403)
|
testclient.get(f"/profile/{logged_user.identifier}", status=403)
|
||||||
|
|
||||||
|
|
||||||
def test_bad_redirect_uri_no_redirect(
|
def test_bad_redirect_uri_no_redirect(
|
||||||
testclient, backend, logged_user, client, id_token
|
testclient, backend, logged_user, client, id_token
|
||||||
):
|
):
|
||||||
testclient.get(f"/profile/{logged_user.user_name[0]}", status=200)
|
testclient.get(f"/profile/{logged_user.identifier}", status=200)
|
||||||
|
|
||||||
post_logout_redirect_url = "https://mydomain.tld/invalid-uri"
|
post_logout_redirect_url = "https://mydomain.tld/invalid-uri"
|
||||||
res = testclient.get(
|
res = testclient.get(
|
||||||
"/oauth/end_session",
|
"/oauth/end_session",
|
||||||
params={
|
params={
|
||||||
"id_token_hint": id_token,
|
"id_token_hint": id_token,
|
||||||
"logout_hint": logged_user.user_name[0],
|
"logout_hint": logged_user.identifier,
|
||||||
"client_id": client.client_id,
|
"client_id": client.client_id,
|
||||||
"post_logout_redirect_uri": post_logout_redirect_url,
|
"post_logout_redirect_uri": post_logout_redirect_url,
|
||||||
"state": "foobar",
|
"state": "foobar",
|
||||||
|
@ -97,17 +97,17 @@ def test_bad_redirect_uri_no_redirect(
|
||||||
with testclient.session_transaction() as sess:
|
with testclient.session_transaction() as sess:
|
||||||
assert not sess.get("user_id")
|
assert not sess.get("user_id")
|
||||||
|
|
||||||
testclient.get(f"/profile/{logged_user.user_name[0]}", status=403)
|
testclient.get(f"/profile/{logged_user.identifier}", status=403)
|
||||||
|
|
||||||
|
|
||||||
def test_no_client_hint_no_redirect(testclient, backend, logged_user, client, id_token):
|
def test_no_client_hint_no_redirect(testclient, backend, logged_user, client, id_token):
|
||||||
testclient.get(f"/profile/{logged_user.user_name[0]}", status=200)
|
testclient.get(f"/profile/{logged_user.identifier}", status=200)
|
||||||
|
|
||||||
post_logout_redirect_url = "https://mydomain.tld/disconnected"
|
post_logout_redirect_url = "https://mydomain.tld/disconnected"
|
||||||
res = testclient.get(
|
res = testclient.get(
|
||||||
"/oauth/end_session",
|
"/oauth/end_session",
|
||||||
params={
|
params={
|
||||||
"logout_hint": logged_user.user_name[0],
|
"logout_hint": logged_user.identifier,
|
||||||
"post_logout_redirect_uri": post_logout_redirect_url,
|
"post_logout_redirect_uri": post_logout_redirect_url,
|
||||||
"state": "foobar",
|
"state": "foobar",
|
||||||
},
|
},
|
||||||
|
@ -121,17 +121,17 @@ def test_no_client_hint_no_redirect(testclient, backend, logged_user, client, id
|
||||||
with testclient.session_transaction() as sess:
|
with testclient.session_transaction() as sess:
|
||||||
assert not sess.get("user_id")
|
assert not sess.get("user_id")
|
||||||
|
|
||||||
testclient.get(f"/profile/{logged_user.user_name[0]}", status=403)
|
testclient.get(f"/profile/{logged_user.identifier}", status=403)
|
||||||
|
|
||||||
|
|
||||||
def test_end_session_invalid_client_id(testclient, backend, logged_user, client):
|
def test_end_session_invalid_client_id(testclient, backend, logged_user, client):
|
||||||
testclient.get(f"/profile/{logged_user.user_name[0]}", status=200)
|
testclient.get(f"/profile/{logged_user.identifier}", status=200)
|
||||||
|
|
||||||
post_logout_redirect_url = "https://mydomain.tld/disconnected"
|
post_logout_redirect_url = "https://mydomain.tld/disconnected"
|
||||||
res = testclient.get(
|
res = testclient.get(
|
||||||
"/oauth/end_session",
|
"/oauth/end_session",
|
||||||
params={
|
params={
|
||||||
"logout_hint": logged_user.user_name[0],
|
"logout_hint": logged_user.identifier,
|
||||||
"post_logout_redirect_uri": post_logout_redirect_url,
|
"post_logout_redirect_uri": post_logout_redirect_url,
|
||||||
"client_id": "invalid_client_id",
|
"client_id": "invalid_client_id",
|
||||||
"state": "foobar",
|
"state": "foobar",
|
||||||
|
@ -147,7 +147,7 @@ def test_end_session_invalid_client_id(testclient, backend, logged_user, client)
|
||||||
with testclient.session_transaction() as sess:
|
with testclient.session_transaction() as sess:
|
||||||
assert not sess.get("user_id")
|
assert not sess.get("user_id")
|
||||||
|
|
||||||
testclient.get(f"/profile/{logged_user.user_name[0]}", status=403)
|
testclient.get(f"/profile/{logged_user.identifier}", status=403)
|
||||||
|
|
||||||
|
|
||||||
def test_client_hint_invalid(testclient, backend, logged_user, client):
|
def test_client_hint_invalid(testclient, backend, logged_user, client):
|
||||||
|
@ -158,14 +158,14 @@ def test_client_hint_invalid(testclient, backend, logged_user, client):
|
||||||
**get_jwt_config(None),
|
**get_jwt_config(None),
|
||||||
)
|
)
|
||||||
|
|
||||||
testclient.get(f"/profile/{logged_user.user_name[0]}", status=200)
|
testclient.get(f"/profile/{logged_user.identifier}", status=200)
|
||||||
|
|
||||||
post_logout_redirect_url = "https://mydomain.tld/disconnected"
|
post_logout_redirect_url = "https://mydomain.tld/disconnected"
|
||||||
res = testclient.get(
|
res = testclient.get(
|
||||||
"/oauth/end_session",
|
"/oauth/end_session",
|
||||||
params={
|
params={
|
||||||
"id_token_hint": id_token,
|
"id_token_hint": id_token,
|
||||||
"logout_hint": logged_user.user_name[0],
|
"logout_hint": logged_user.identifier,
|
||||||
"post_logout_redirect_uri": post_logout_redirect_url,
|
"post_logout_redirect_uri": post_logout_redirect_url,
|
||||||
"state": "foobar",
|
"state": "foobar",
|
||||||
},
|
},
|
||||||
|
@ -177,17 +177,17 @@ def test_client_hint_invalid(testclient, backend, logged_user, client):
|
||||||
with testclient.session_transaction() as sess:
|
with testclient.session_transaction() as sess:
|
||||||
assert not sess.get("user_id")
|
assert not sess.get("user_id")
|
||||||
|
|
||||||
testclient.get(f"/profile/{logged_user.user_name[0]}", status=403)
|
testclient.get(f"/profile/{logged_user.identifier}", status=403)
|
||||||
|
|
||||||
|
|
||||||
def test_no_jwt_logout(testclient, backend, logged_user, client):
|
def test_no_jwt_logout(testclient, backend, logged_user, client):
|
||||||
testclient.get(f"/profile/{logged_user.user_name[0]}", status=200)
|
testclient.get(f"/profile/{logged_user.identifier}", status=200)
|
||||||
|
|
||||||
post_logout_redirect_url = "https://mydomain.tld/disconnected"
|
post_logout_redirect_url = "https://mydomain.tld/disconnected"
|
||||||
res = testclient.get(
|
res = testclient.get(
|
||||||
"/oauth/end_session",
|
"/oauth/end_session",
|
||||||
params={
|
params={
|
||||||
"logout_hint": logged_user.user_name[0],
|
"logout_hint": logged_user.identifier,
|
||||||
"client_id": client.client_id,
|
"client_id": client.client_id,
|
||||||
"post_logout_redirect_uri": post_logout_redirect_url,
|
"post_logout_redirect_uri": post_logout_redirect_url,
|
||||||
"state": "foobar",
|
"state": "foobar",
|
||||||
|
@ -203,17 +203,17 @@ def test_no_jwt_logout(testclient, backend, logged_user, client):
|
||||||
|
|
||||||
assert res.location == f"{post_logout_redirect_url}?state=foobar"
|
assert res.location == f"{post_logout_redirect_url}?state=foobar"
|
||||||
|
|
||||||
testclient.get(f"/profile/{logged_user.user_name[0]}", status=403)
|
testclient.get(f"/profile/{logged_user.identifier}", status=403)
|
||||||
|
|
||||||
|
|
||||||
def test_no_jwt_no_logout(testclient, backend, logged_user, client):
|
def test_no_jwt_no_logout(testclient, backend, logged_user, client):
|
||||||
testclient.get(f"/profile/{logged_user.user_name[0]}", status=200)
|
testclient.get(f"/profile/{logged_user.identifier}", status=200)
|
||||||
|
|
||||||
post_logout_redirect_url = "https://mydomain.tld/disconnected"
|
post_logout_redirect_url = "https://mydomain.tld/disconnected"
|
||||||
res = testclient.get(
|
res = testclient.get(
|
||||||
"/oauth/end_session",
|
"/oauth/end_session",
|
||||||
params={
|
params={
|
||||||
"logout_hint": logged_user.user_name[0],
|
"logout_hint": logged_user.identifier,
|
||||||
"client_id": client.client_id,
|
"client_id": client.client_id,
|
||||||
"post_logout_redirect_uri": post_logout_redirect_url,
|
"post_logout_redirect_uri": post_logout_redirect_url,
|
||||||
"state": "foobar",
|
"state": "foobar",
|
||||||
|
@ -228,20 +228,20 @@ def test_no_jwt_no_logout(testclient, backend, logged_user, client):
|
||||||
|
|
||||||
assert res.location == "/"
|
assert res.location == "/"
|
||||||
|
|
||||||
testclient.get(f"/profile/{logged_user.user_name[0]}", status=200)
|
testclient.get(f"/profile/{logged_user.identifier}", status=200)
|
||||||
|
|
||||||
|
|
||||||
def test_jwt_not_issued_here(testclient, backend, logged_user, client, id_token):
|
def test_jwt_not_issued_here(testclient, backend, logged_user, client, id_token):
|
||||||
testclient.app.config["OIDC"]["JWT"]["ISS"] = "https://foo.bar"
|
testclient.app.config["OIDC"]["JWT"]["ISS"] = "https://foo.bar"
|
||||||
|
|
||||||
testclient.get(f"/profile/{logged_user.user_name[0]}", status=200)
|
testclient.get(f"/profile/{logged_user.identifier}", status=200)
|
||||||
|
|
||||||
post_logout_redirect_url = "https://mydomain.tld/disconnected"
|
post_logout_redirect_url = "https://mydomain.tld/disconnected"
|
||||||
res = testclient.get(
|
res = testclient.get(
|
||||||
"/oauth/end_session",
|
"/oauth/end_session",
|
||||||
params={
|
params={
|
||||||
"id_token_hint": id_token,
|
"id_token_hint": id_token,
|
||||||
"logout_hint": logged_user.user_name[0],
|
"logout_hint": logged_user.identifier,
|
||||||
"client_id": client.client_id,
|
"client_id": client.client_id,
|
||||||
"post_logout_redirect_uri": post_logout_redirect_url,
|
"post_logout_redirect_uri": post_logout_redirect_url,
|
||||||
"state": "foobar",
|
"state": "foobar",
|
||||||
|
@ -263,14 +263,14 @@ def test_client_hint_mismatch(testclient, backend, logged_user, client):
|
||||||
**get_jwt_config(None),
|
**get_jwt_config(None),
|
||||||
)
|
)
|
||||||
|
|
||||||
testclient.get(f"/profile/{logged_user.user_name[0]}", status=200)
|
testclient.get(f"/profile/{logged_user.identifier}", status=200)
|
||||||
|
|
||||||
post_logout_redirect_url = "https://mydomain.tld/disconnected"
|
post_logout_redirect_url = "https://mydomain.tld/disconnected"
|
||||||
res = testclient.get(
|
res = testclient.get(
|
||||||
"/oauth/end_session",
|
"/oauth/end_session",
|
||||||
params={
|
params={
|
||||||
"id_token_hint": id_token,
|
"id_token_hint": id_token,
|
||||||
"logout_hint": logged_user.user_name[0],
|
"logout_hint": logged_user.identifier,
|
||||||
"client_id": client.client_id,
|
"client_id": client.client_id,
|
||||||
"post_logout_redirect_uri": post_logout_redirect_url,
|
"post_logout_redirect_uri": post_logout_redirect_url,
|
||||||
"state": "foobar",
|
"state": "foobar",
|
||||||
|
@ -285,7 +285,7 @@ def test_client_hint_mismatch(testclient, backend, logged_user, client):
|
||||||
|
|
||||||
|
|
||||||
def test_bad_user_id_token_mismatch(testclient, backend, logged_user, client, admin):
|
def test_bad_user_id_token_mismatch(testclient, backend, logged_user, client, admin):
|
||||||
testclient.get(f"/profile/{logged_user.user_name[0]}", status=200)
|
testclient.get(f"/profile/{logged_user.identifier}", status=200)
|
||||||
|
|
||||||
id_token = generate_id_token(
|
id_token = generate_id_token(
|
||||||
{},
|
{},
|
||||||
|
@ -299,7 +299,7 @@ def test_bad_user_id_token_mismatch(testclient, backend, logged_user, client, ad
|
||||||
"/oauth/end_session",
|
"/oauth/end_session",
|
||||||
params={
|
params={
|
||||||
"id_token_hint": id_token,
|
"id_token_hint": id_token,
|
||||||
"logout_hint": logged_user.user_name[0],
|
"logout_hint": logged_user.identifier,
|
||||||
"client_id": client.client_id,
|
"client_id": client.client_id,
|
||||||
"post_logout_redirect_uri": post_logout_redirect_url,
|
"post_logout_redirect_uri": post_logout_redirect_url,
|
||||||
"state": "foobar",
|
"state": "foobar",
|
||||||
|
@ -315,18 +315,18 @@ def test_bad_user_id_token_mismatch(testclient, backend, logged_user, client, ad
|
||||||
|
|
||||||
assert res.location == f"{post_logout_redirect_url}?state=foobar"
|
assert res.location == f"{post_logout_redirect_url}?state=foobar"
|
||||||
|
|
||||||
testclient.get(f"/profile/{logged_user.user_name[0]}", status=403)
|
testclient.get(f"/profile/{logged_user.identifier}", status=403)
|
||||||
|
|
||||||
|
|
||||||
def test_bad_user_hint(testclient, backend, logged_user, client, id_token, admin):
|
def test_bad_user_hint(testclient, backend, logged_user, client, id_token, admin):
|
||||||
testclient.get(f"/profile/{logged_user.user_name[0]}", status=200)
|
testclient.get(f"/profile/{logged_user.identifier}", status=200)
|
||||||
|
|
||||||
post_logout_redirect_url = "https://mydomain.tld/disconnected"
|
post_logout_redirect_url = "https://mydomain.tld/disconnected"
|
||||||
res = testclient.get(
|
res = testclient.get(
|
||||||
"/oauth/end_session",
|
"/oauth/end_session",
|
||||||
params={
|
params={
|
||||||
"id_token_hint": id_token,
|
"id_token_hint": id_token,
|
||||||
"logout_hint": admin.user_name[0],
|
"logout_hint": admin.identifier,
|
||||||
"client_id": client.client_id,
|
"client_id": client.client_id,
|
||||||
"post_logout_redirect_uri": post_logout_redirect_url,
|
"post_logout_redirect_uri": post_logout_redirect_url,
|
||||||
"state": "foobar",
|
"state": "foobar",
|
||||||
|
@ -342,17 +342,17 @@ def test_bad_user_hint(testclient, backend, logged_user, client, id_token, admin
|
||||||
|
|
||||||
assert res.location == f"{post_logout_redirect_url}?state=foobar"
|
assert res.location == f"{post_logout_redirect_url}?state=foobar"
|
||||||
|
|
||||||
testclient.get(f"/profile/{logged_user.user_name[0]}", status=403)
|
testclient.get(f"/profile/{logged_user.identifier}", status=403)
|
||||||
|
|
||||||
|
|
||||||
def test_no_jwt_bad_csrf(testclient, backend, logged_user, client):
|
def test_no_jwt_bad_csrf(testclient, backend, logged_user, client):
|
||||||
testclient.get(f"/profile/{logged_user.user_name[0]}", status=200)
|
testclient.get(f"/profile/{logged_user.identifier}", status=200)
|
||||||
|
|
||||||
post_logout_redirect_url = "https://mydomain.tld/disconnected"
|
post_logout_redirect_url = "https://mydomain.tld/disconnected"
|
||||||
res = testclient.get(
|
res = testclient.get(
|
||||||
"/oauth/end_session",
|
"/oauth/end_session",
|
||||||
params={
|
params={
|
||||||
"logout_hint": logged_user.user_name[0],
|
"logout_hint": logged_user.identifier,
|
||||||
"client_id": client.client_id,
|
"client_id": client.client_id,
|
||||||
"post_logout_redirect_uri": post_logout_redirect_url,
|
"post_logout_redirect_uri": post_logout_redirect_url,
|
||||||
"state": "foobar",
|
"state": "foobar",
|
||||||
|
@ -371,7 +371,7 @@ def test_end_session_already_disconnected(testclient, backend, user, client, id_
|
||||||
"/oauth/end_session",
|
"/oauth/end_session",
|
||||||
params={
|
params={
|
||||||
"id_token_hint": id_token,
|
"id_token_hint": id_token,
|
||||||
"logout_hint": user.user_name[0],
|
"logout_hint": user.identifier,
|
||||||
"client_id": client.client_id,
|
"client_id": client.client_id,
|
||||||
"post_logout_redirect_uri": post_logout_redirect_url,
|
"post_logout_redirect_uri": post_logout_redirect_url,
|
||||||
"state": "foobar",
|
"state": "foobar",
|
||||||
|
@ -383,14 +383,14 @@ def test_end_session_already_disconnected(testclient, backend, user, client, id_
|
||||||
|
|
||||||
|
|
||||||
def test_end_session_no_state(testclient, backend, logged_user, client, id_token):
|
def test_end_session_no_state(testclient, backend, logged_user, client, id_token):
|
||||||
testclient.get(f"/profile/{logged_user.user_name[0]}", status=200)
|
testclient.get(f"/profile/{logged_user.identifier}", status=200)
|
||||||
|
|
||||||
post_logout_redirect_url = "https://mydomain.tld/disconnected"
|
post_logout_redirect_url = "https://mydomain.tld/disconnected"
|
||||||
res = testclient.get(
|
res = testclient.get(
|
||||||
"/oauth/end_session",
|
"/oauth/end_session",
|
||||||
params={
|
params={
|
||||||
"id_token_hint": id_token,
|
"id_token_hint": id_token,
|
||||||
"logout_hint": logged_user.user_name[0],
|
"logout_hint": logged_user.identifier,
|
||||||
"client_id": client.client_id,
|
"client_id": client.client_id,
|
||||||
"post_logout_redirect_uri": post_logout_redirect_url,
|
"post_logout_redirect_uri": post_logout_redirect_url,
|
||||||
},
|
},
|
||||||
|
@ -402,4 +402,4 @@ def test_end_session_no_state(testclient, backend, logged_user, client, id_token
|
||||||
with testclient.session_transaction() as sess:
|
with testclient.session_transaction() as sess:
|
||||||
assert not sess.get("user_id")
|
assert not sess.get("user_id")
|
||||||
|
|
||||||
testclient.get(f"/profile/{logged_user.user_name[0]}", status=403)
|
testclient.get(f"/profile/{logged_user.identifier}", status=403)
|
||||||
|
|
Loading…
Reference in a new issue