add TOTP authentication method rules and display in user list

This commit is contained in:
Eduardo Silva
2026-03-15 17:20:18 -03:00
parent 01da3c9de0
commit 14bd4e8ccc
3 changed files with 30 additions and 3 deletions

View File

@@ -169,6 +169,7 @@ class AccessPolicyForm(forms.ModelForm):
has_local_password = False
local_password_count = 0
oidc_count = 0
totp_count = 0
has_groups = groups and len(groups) > 0
# Count authentication methods
@@ -179,6 +180,8 @@ class AccessPolicyForm(forms.ModelForm):
local_password_count += 1
elif method.auth_type == 'oidc':
oidc_count += 1
elif method.auth_type == 'totp':
totp_count += 1
# Rule: Cannot select more than one local password method
if local_password_count > 1:
@@ -188,10 +191,18 @@ class AccessPolicyForm(forms.ModelForm):
if oidc_count > 1:
self.add_error('methods', _("Cannot select more than one OpenID Connect (OIDC) authentication method."))
# Rule: Cannot select more than one TOTP method
if totp_count > 1:
self.add_error('methods', _("Cannot select more than one TOTP authentication method."))
# Rule: Cannot mix local password and oidc
if local_password_count > 0 and oidc_count > 0:
self.add_error('methods', _("Cannot select both Local Password and OpenID Connect (OIDC) authentication methods."))
# Rule: TOTP cannot be selected alone — must be combined with local_password or oidc
if totp_count > 0 and local_password_count == 0 and oidc_count == 0:
self.add_error('methods', _("TOTP must be combined with a Local Password or OpenID Connect authentication method."))
# Rule: If local password is selected, at least one user group must be selected
if has_local_password and not has_groups:
self.add_error('groups', _("At least one user group must be selected when using Local Password authentication."))

View File

@@ -24,7 +24,7 @@ def view_gatekeeper_list(request):
active_tab = request.GET.get('tab', 'auth_methods')
auth_methods = AuthMethod.objects.all().order_by('name')
users = GatekeeperUser.objects.all().order_by('username')
users = GatekeeperUser.objects.all().prefetch_related('groups').order_by('username')
groups = GatekeeperGroup.objects.all().order_by('name')
auth_domains = AuthMethodAllowedDomain.objects.all().order_by('domain')
auth_emails = AuthMethodAllowedEmail.objects.all().order_by('email')

View File

@@ -60,6 +60,8 @@
<tr>
<th>{% trans 'Username' %}</th>
<th>{% trans 'Email' %}</th>
<th>{% trans 'TOTP' %}</th>
<th>{% trans 'Groups' %}</th>
<th>{% trans 'Actions' %}</th>
</tr>
</thead>
@@ -68,6 +70,20 @@
<tr>
<td>{{ user.username }}</td>
<td>{{ user.email }}</td>
<td>
{% if user.totp_secret %}
<span class="badge badge-success"><i class="fas fa-check"></i> {% trans 'Yes' %}</span>
{% else %}
<span class="badge badge-secondary">{% trans 'No' %}</span>
{% endif %}
</td>
<td>
{% for group in user.groups.all %}
<span class="badge badge-info">{{ group.name }}</span>
{% empty %}
<span class="text-muted"></span>
{% endfor %}
</td>
<td style="width: 15%">
<a href="{% url 'manage_gatekeeper_user' %}?uuid={{ user.uuid }}"
class="btn btn-sm btn-info" title="{% trans 'Edit' %}">