Sunil Mohan Adapa 1a8868f0cd
users: Add support registering, editing, and deleting passkeys
Tests:

- Setup: add domain name mystable.example. Add an entry in /etc/hosts on the
  test machine. In Firefox, in about:config, set
  'security.webauthn.allow_with_certificate_override' to 'true'.
- Registration
  - Passkey successful registration:
    - After passkey registration, created time is time at which key is created.
    - After passkey registration, domain is the domain with which the interface
      is accessed at the time of addition of passkey.
    - After passkey registration, Added and Last Used columns show the current
      time in UTC. Signature counter and extensions and aaguid values in the DB
      are as expected.
    - First key's name is 'Key 1'. After that it is 'Key 2' and so on. If a key
      is renamed as 'Key 4', then next key will be named 'Key 5'.
    - Registering passkeys using testing container stable container works.
  - Links:
    - 'Manage passkeys' link is show in the user menu in navbar in both desktop
      mode and mobile mode. Clicking on it redirects the browser to current
      user's passkey management page.
    - User's edit page shows 'Use passkeys for better security'. Clicking on the
      link redirects the browser to passkey management page for the user who's
      account is being edited.
  - Listing:
    - All passkeys are show properly. Name, domain, added, last used, and
      operations show correctly.
    - When using a browser without Javascript script shows an error alert.
    - If not passkeys are present "No passkeys added to user account." message
      is shown.
  - Editing the passkey shows correct page. Title, heading, form labels, form
    value, and buttons are as expected. After editing, passkey is updated
    properly.
  - Deleting the passkey shows a model dialog with correct details. After
    confirmation, passkey is removed and page is refreshed.
  - Error handling:
    - On GNOME's Web, clicking the 'Add Passkey' shows the error 'Browser does
      not support passkeys'.
    - On Chromium, clicking the 'Add passkey' shows the error 'NotAllowedError:
      WebAuthn is not supported on sites with TLS certificate errors.'
    - Raising an error in passkey_add_begin() results in correct error message
      shown with 'Add passkey' button is clicked. Status code is 500.
    - Raising an error in passkey_add_complete() results in correct error
      message shown after unlocking the hardware token. Status code is 500.
    - Canceling the PIN dialog results in '...user denied permission' error
      alert.
    - Canceling the touch dialog results in '...user denied permission' error
      alert.
    - Multiple failed attempts result in multiple alerts being shown at the same
      time.
  - Editing another user's passkeys:
    - Listing passkeys show correct list of passkeys for the user account being
      managed.
    - Adding passkeys adds correctly to the user account being managed.
    - Editing passkey correctly edits passkey of the user account being managed.
      Redirect happens to the correct page after.
    - Deleting passkey correctly edits passkey of the user account being
      managed. Redirect happens to the correct page after.
    - If a non-admin user tries to access passkeys list/edit/delete URL of
      another user, 403 Forbidden error is raised

Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
2026-03-31 07:48:50 -04:00

79 lines
2.3 KiB
HTML

{% extends "base.html" %}
{% comment %}
# SPDX-License-Identifier: AGPL-3.0-or-later
{% endcomment %}
{% load bootstrap %}
{% load i18n %}
{% load static %}
{% block page_js %}
<script src="{% static 'users/users.js' %}" defer></script>
{% endblock %}
{% block content %}
<h3>
{% blocktrans trimmed with username=object.username %}
Edit User <em>{{ username }}</em>
{% endblocktrans %}
</h3>
<p>
{% url 'users:passkeys' object.username as passkeys_url %}
{% blocktrans trimmed %}
Use <a href="{{ passkeys_url }}">passkeys</a> for better security.
{% endblocktrans %}
{% url 'users:change_password' object.username as change_password_url %}
{% blocktrans trimmed %}
Use the <a href='{{ change_password_url }}'>change password form
</a> to change the password.
{% endblocktrans %}
</p>
<form class="form form-update" method="post">
{% csrf_token %}
{{ form|bootstrap }}
<input type="submit" class="btn btn-primary"
value="{% trans "Save Changes" %}"/>
</form>
<div id="user-delete-confirm-dialog" class="modal" tabindex="-1"
role="dialog">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">
{% blocktrans trimmed with username=object.username %}
Delete user <em>{{ username }}</em> and all the user's files?
{% endblocktrans %}
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"
aria-label="{% trans 'Close' %}">
</button>
</div>
<div class="modal-body">
<p>
{% blocktrans trimmed %}
Deleting a user account also removes all the files user's home
directory. If you wish to keep these files, disable the user
account instead.
{% endblocktrans %}
</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger confirm">
{% trans "Delete user and files" %}
</button>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
{% trans "Cancel" %}
</button>
</div>
</div>
</div>
</div>
{% endblock %}