From bf4e8dbedcbd9fcd8347bceb33324598f546ea44 Mon Sep 17 00:00:00 2001 From: "Jens L." Date: Tue, 24 Jun 2025 23:52:06 +0200 Subject: [PATCH] core: include more authenticator details when possible (#15224) Signed-off-by: Jens Langhammer --- authentik/core/api/devices.py | 22 +++++++++++-------- schema.yml | 9 +++++++- web/src/admin/users/UserDevicesTable.ts | 9 +++++--- .../user/user-settings/mfa/MFADevicesPage.ts | 12 +++++++--- 4 files changed, 36 insertions(+), 16 deletions(-) diff --git a/authentik/core/api/devices.py b/authentik/core/api/devices.py index 017bdae392..d6ceb932a8 100644 --- a/authentik/core/api/devices.py +++ b/authentik/core/api/devices.py @@ -1,6 +1,5 @@ """Authenticator Devices API Views""" -from django.utils.translation import gettext_lazy as _ from drf_spectacular.utils import extend_schema from guardian.shortcuts import get_objects_for_user from rest_framework.fields import ( @@ -23,7 +22,7 @@ from authentik.stages.authenticator_webauthn.models import WebAuthnDevice class DeviceSerializer(MetaNameSerializer): - """Serializer for Duo authenticator devices""" + """Serializer for authenticator devices""" pk = CharField() name = CharField() @@ -33,22 +32,27 @@ class DeviceSerializer(MetaNameSerializer): last_updated = DateTimeField(read_only=True) last_used = DateTimeField(read_only=True, allow_null=True) extra_description = SerializerMethodField() + external_id = SerializerMethodField() def get_type(self, instance: Device) -> str: """Get type of device""" return instance._meta.label - def get_extra_description(self, instance: Device) -> str: + def get_extra_description(self, instance: Device) -> str | None: """Get extra description""" if isinstance(instance, WebAuthnDevice): - return ( - instance.device_type.description - if instance.device_type - else _("Extra description not available") - ) + return instance.device_type.description if instance.device_type else None if isinstance(instance, EndpointDevice): return instance.data.get("deviceSignals", {}).get("deviceModel") - return "" + return None + + def get_external_id(self, instance: Device) -> str | None: + """Get external Device ID""" + if isinstance(instance, WebAuthnDevice): + return instance.device_type.aaguid if instance.device_type else None + if isinstance(instance, EndpointDevice): + return instance.data.get("deviceSignals", {}).get("deviceModel") + return None class DeviceViewSet(ViewSet): diff --git a/schema.yml b/schema.yml index cd95fb4f67..2aef9f924b 100644 --- a/schema.yml +++ b/schema.yml @@ -43953,7 +43953,7 @@ components: - name Device: type: object - description: Serializer for Duo authenticator devices + description: Serializer for authenticator devices properties: verbose_name: type: string @@ -43992,11 +43992,18 @@ components: nullable: true extra_description: type: string + nullable: true description: Get extra description readOnly: true + external_id: + type: string + nullable: true + description: Get external Device ID + readOnly: true required: - confirmed - created + - external_id - extra_description - last_updated - last_used diff --git a/web/src/admin/users/UserDevicesTable.ts b/web/src/admin/users/UserDevicesTable.ts index fe21970101..ebede0c508 100644 --- a/web/src/admin/users/UserDevicesTable.ts +++ b/web/src/admin/users/UserDevicesTable.ts @@ -7,7 +7,7 @@ import { PaginatedResponse } from "@goauthentik/elements/table/Table"; import { Table, TableColumn } from "@goauthentik/elements/table/Table"; import { msg, str } from "@lit/localize"; -import { TemplateResult, html } from "lit"; +import { TemplateResult, html, nothing } from "lit"; import { customElement, property } from "lit/decorators.js"; import { AuthenticatorsApi, Device } from "@goauthentik/api"; @@ -104,8 +104,11 @@ export class UserDeviceTable extends Table { row(item: Device): TemplateResult[] { return [ html`${item.name}`, - html`${deviceTypeName(item)} - ${item.extraDescription ? ` - ${item.extraDescription}` : ""}`, + html`
+ ${deviceTypeName(item)} + ${item.extraDescription ? ` - ${item.extraDescription}` : ""} +
+ ${item.externalId ? html` ${item.externalId} ` : nothing} `, html`${item.confirmed ? msg("Yes") : msg("No")}`, html`${item.created.getTime() > 0 ? html`
${formatElapsedTime(item.created)}
diff --git a/web/src/user/user-settings/mfa/MFADevicesPage.ts b/web/src/user/user-settings/mfa/MFADevicesPage.ts index 7cb8ee2f6f..ade90d59ed 100644 --- a/web/src/user/user-settings/mfa/MFADevicesPage.ts +++ b/web/src/user/user-settings/mfa/MFADevicesPage.ts @@ -13,7 +13,7 @@ import "@goauthentik/user/user-settings/mfa/MFADeviceForm"; import "@patternfly/elements/pf-tooltip/pf-tooltip.js"; import { msg, str } from "@lit/localize"; -import { TemplateResult, html } from "lit"; +import { TemplateResult, html, nothing } from "lit"; import { customElement, property } from "lit/decorators.js"; import { ifDefined } from "lit/directives/if-defined.js"; @@ -130,8 +130,14 @@ export class MFADevicesPage extends Table { row(item: Device): TemplateResult[] { return [ html`${item.name}`, - html`${deviceTypeName(item)} - ${item.extraDescription ? ` - ${item.extraDescription}` : ""}`, + html`
${deviceTypeName(item)}
+ ${item.extraDescription + ? html` + + ${item.extraDescription} + + ` + : nothing} `, html`${item.created.getTime() > 0 ? html`
${formatElapsedTime(item.created)}
${item.created.toLocaleString()}`