enterprise/providers/SSF: fix a couple of bugs after real world testing (#12987)

* providers/ssf: fix txn being inside the event not the SET itself

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix incorrect ssf format

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix web form

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
Jens L.
2025-02-11 15:08:06 +01:00
committed by GitHub
parent b6cf27b421
commit ff60607851
4 changed files with 68 additions and 57 deletions

View File

@ -70,7 +70,10 @@ def ssf_user_logged_out_session_revoked(sender, request: HttpRequest, user: User
send_ssf_event(
EventTypes.CAEP_SESSION_REVOKED,
{
"subject": {
"initiating_entity": "user",
},
sub_id={
"format": "complex",
"session": {
"format": "opaque",
"id": sha256(request.session.session_key.encode("ascii")).hexdigest(),
@ -80,8 +83,6 @@ def ssf_user_logged_out_session_revoked(sender, request: HttpRequest, user: User
"email": user.email,
},
},
"initiating_entity": "user",
},
request=request,
)
@ -95,7 +96,10 @@ def ssf_user_session_delete_session_revoked(sender, instance: AuthenticatedSessi
send_ssf_event(
EventTypes.CAEP_SESSION_REVOKED,
{
"subject": {
"initiating_entity": "user",
},
sub_id={
"format": "complex",
"session": {
"format": "opaque",
"id": sha256(instance.session_key.encode("ascii")).hexdigest(),
@ -105,8 +109,6 @@ def ssf_user_session_delete_session_revoked(sender, instance: AuthenticatedSessi
"email": instance.user.email,
},
},
"initiating_entity": "user",
},
)
@ -116,15 +118,16 @@ def ssf_password_changed_cred_change(sender, user: User, password: str | None, *
send_ssf_event(
EventTypes.CAEP_CREDENTIAL_CHANGE,
{
"subject": {
"credential_type": "password",
"change_type": "revoke" if password is None else "update",
},
sub_id={
"format": "complex",
"user": {
"format": "email",
"email": user.email,
},
},
"credential_type": "password",
"change_type": "revoke" if password is None else "update",
},
)
@ -144,19 +147,23 @@ def ssf_device_post_save(sender: type[Model], instance: Device, created: bool, *
return
device_type = device_type_map.get(instance.__class__)
data = {
"subject": {
"user": {
"format": "email",
"email": instance.user.email,
},
},
"credential_type": device_type,
"change_type": "create" if created else "update",
"friendly_name": instance.name,
}
if isinstance(instance, WebAuthnDevice) and instance.aaguid != UNKNOWN_DEVICE_TYPE_AAGUID:
data["fido2_aaguid"] = instance.aaguid
send_ssf_event(EventTypes.CAEP_CREDENTIAL_CHANGE, data)
send_ssf_event(
EventTypes.CAEP_CREDENTIAL_CHANGE,
data,
sub_id={
"format": "complex",
"user": {
"format": "email",
"email": instance.user.email,
},
},
)
@receiver(post_delete)
@ -167,16 +174,20 @@ def ssf_device_post_delete(sender: type[Model], instance: Device, **_):
return
device_type = device_type_map.get(instance.__class__)
data = {
"subject": {
"user": {
"format": "email",
"email": instance.user.email,
},
},
"credential_type": device_type,
"change_type": "delete",
"friendly_name": instance.name,
}
if isinstance(instance, WebAuthnDevice) and instance.aaguid != UNKNOWN_DEVICE_TYPE_AAGUID:
data["fido2_aaguid"] = instance.aaguid
send_ssf_event(EventTypes.CAEP_CREDENTIAL_CHANGE, data)
send_ssf_event(
EventTypes.CAEP_CREDENTIAL_CHANGE,
data,
sub_id={
"format": "complex",
"user": {
"format": "email",
"email": instance.user.email,
},
},
)

View File

@ -36,7 +36,7 @@ def send_ssf_event(
stream_filter = {}
stream_filter["events_requested__contains"] = [event_type]
if request and hasattr(request, "request_id"):
data.setdefault("txn", request.request_id)
extra_data.setdefault("txn", request.request_id)
for stream in Stream.objects.filter(**stream_filter):
event_data = stream.prepare_event_payload(event_type, data, **extra_data)
payload.append((str(stream.uuid), event_data))

View File

@ -65,9 +65,10 @@ class TestSignals(APITestCase):
"https://schemas.openid.net/secevent/caep/event-type/session-revoked"
]
self.assertEqual(event_payload["initiating_entity"], "user")
self.assertEqual(event_payload["subject"]["session"]["format"], "opaque")
self.assertEqual(event_payload["subject"]["user"]["format"], "email")
self.assertEqual(event_payload["subject"]["user"]["email"], user.email)
self.assertEqual(event.payload["sub_id"]["format"], "complex")
self.assertEqual(event.payload["sub_id"]["session"]["format"], "opaque")
self.assertEqual(event.payload["sub_id"]["user"]["format"], "email")
self.assertEqual(event.payload["sub_id"]["user"]["email"], user.email)
def test_signal_password_change(self):
"""Test user password change"""
@ -86,8 +87,9 @@ class TestSignals(APITestCase):
]
self.assertEqual(event_payload["change_type"], "update")
self.assertEqual(event_payload["credential_type"], "password")
self.assertEqual(event_payload["subject"]["user"]["format"], "email")
self.assertEqual(event_payload["subject"]["user"]["email"], user.email)
self.assertEqual(event.payload["sub_id"]["format"], "complex")
self.assertEqual(event.payload["sub_id"]["user"]["format"], "email")
self.assertEqual(event.payload["sub_id"]["user"]["email"], user.email)
def test_signal_authenticator_added(self):
"""Test authenticator creation signal"""
@ -113,8 +115,9 @@ class TestSignals(APITestCase):
self.assertEqual(event_payload["fido2_aaguid"], dev.aaguid)
self.assertEqual(event_payload["friendly_name"], dev.name)
self.assertEqual(event_payload["credential_type"], "fido-u2f")
self.assertEqual(event_payload["subject"]["user"]["format"], "email")
self.assertEqual(event_payload["subject"]["user"]["email"], user.email)
self.assertEqual(event.payload["sub_id"]["format"], "complex")
self.assertEqual(event.payload["sub_id"]["user"]["format"], "email")
self.assertEqual(event.payload["sub_id"]["user"]["email"], user.email)
def test_signal_authenticator_deleted(self):
"""Test authenticator deletion signal"""
@ -141,5 +144,6 @@ class TestSignals(APITestCase):
self.assertEqual(event_payload["fido2_aaguid"], dev.aaguid)
self.assertEqual(event_payload["friendly_name"], dev.name)
self.assertEqual(event_payload["credential_type"], "fido-u2f")
self.assertEqual(event_payload["subject"]["user"]["format"], "email")
self.assertEqual(event_payload["subject"]["user"]["email"], user.email)
self.assertEqual(event.payload["sub_id"]["format"], "complex")
self.assertEqual(event.payload["sub_id"]["user"]["format"], "email")
self.assertEqual(event.payload["sub_id"]["user"]["email"], user.email)

View File

@ -1,5 +1,4 @@
import "@goauthentik/admin/common/ak-crypto-certificate-search";
import "@goauthentik/admin/common/ak-flow-search/ak-flow-search";
import { BaseProviderForm } from "@goauthentik/admin/providers/BaseProviderForm";
import {
oauth2ProvidersProvider,
@ -7,14 +6,11 @@ import {
} from "@goauthentik/admin/providers/oauth2/OAuth2ProvidersProvider";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { first } from "@goauthentik/common/utils";
import "@goauthentik/components/ak-radio-input";
import "@goauthentik/components/ak-text-input";
import "@goauthentik/components/ak-textarea-input";
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
import "@goauthentik/elements/ak-dual-select/ak-dual-select-provider.js";
import "@goauthentik/elements/forms/FormGroup";
import "@goauthentik/elements/forms/HorizontalFormElement";
import "@goauthentik/elements/forms/Radio";
import "@goauthentik/elements/forms/SearchSelect";
import "@goauthentik/elements/utils/TimeDeltaHelp";
@ -75,9 +71,9 @@ export class SSFProviderFormPage extends BaseProviderForm<SSFProvider> {
<p class="pf-c-form__helper-text">${msg("Key used to sign the events.")}</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal
label=${msg("Session duration")}
?required=${true}
name="sessionDuration"
label=${msg("Event Retention")}
required
name="eventRetention"
>
<input
type="text"