diff --git a/authentik/enterprise/providers/ssf/tasks.py b/authentik/enterprise/providers/ssf/tasks.py index 335db4bd9797..e3779d6d397f 100644 --- a/authentik/enterprise/providers/ssf/tasks.py +++ b/authentik/enterprise/providers/ssf/tasks.py @@ -5,6 +5,7 @@ from requests.exceptions import RequestException from structlog.stdlib import get_logger +from authentik.core.models import User from authentik.enterprise.providers.ssf.models import ( DeliveryMethods, EventTypes, @@ -17,6 +18,7 @@ from authentik.events.system_tasks import SystemTask from authentik.lib.utils.http import get_http_session from authentik.lib.utils.time import timedelta_from_string +from authentik.policies.engine import PolicyEngine from authentik.root.celery import CELERY_APP session = get_http_session() @@ -43,10 +45,32 @@ def send_ssf_event( return _send_ssf_event.delay(payload) +def _check_app_access(stream_uuid: str, event_data: dict) -> bool: + """Check if event is related to user and if so, check + if the user has access to the application""" + stream = Stream.objects.filter(pk=stream_uuid).first() + if not stream: + return False + # `event_data` is a dict version of a StreamEvent + sub_id = event_data.get("payload", {}).get("sub_id", {}) + email = sub_id.get("user", {}).get("email", None) + if not email: + return True + user = User.objects.filter(email=email).first() + if not user: + return True + engine = PolicyEngine(stream.provider.backchannel_application, user) + engine.use_cache = False + engine.build() + return engine.passing + + @CELERY_APP.task() def _send_ssf_event(event_data: list[tuple[str, dict]]): tasks = [] for stream, data in event_data: + if not _check_app_access(stream, data): + continue event = StreamEvent.objects.create(**data) tasks.extend(send_single_ssf_event(stream, str(event.uuid))) main_task = group(*tasks) diff --git a/authentik/enterprise/providers/ssf/tests/test_signals.py b/authentik/enterprise/providers/ssf/tests/test_signals.py index 8f838f6658c9..72c5423d3d92 100644 --- a/authentik/enterprise/providers/ssf/tests/test_signals.py +++ b/authentik/enterprise/providers/ssf/tests/test_signals.py @@ -3,18 +3,20 @@ from django.urls import reverse from rest_framework.test import APITestCase -from authentik.core.models import Application +from authentik.core.models import Application, Group from authentik.core.tests.utils import ( create_test_cert, create_test_user, ) from authentik.enterprise.providers.ssf.models import ( + EventTypes, SSFEventStatus, SSFProvider, Stream, StreamEvent, ) from authentik.lib.generators import generate_id +from authentik.policies.models import PolicyBinding from authentik.stages.authenticator_webauthn.models import WebAuthnDevice @@ -147,3 +149,20 @@ def test_signal_authenticator_deleted(self): 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_policy_ignore(self): + """Test event not being created for user that doesn't have access to the application""" + PolicyBinding.objects.create( + target=self.application, group=Group.objects.create(name=generate_id()), order=0 + ) + user = create_test_user() + self.client.force_login(user) + user.set_password(generate_id()) + user.save() + + stream = Stream.objects.filter(provider=self.provider).first() + self.assertIsNotNone(stream) + event = StreamEvent.objects.filter( + stream=stream, type=EventTypes.CAEP_CREDENTIAL_CHANGE + ).first() + self.assertIsNone(event) diff --git a/web/src/admin/providers/ssf/SSFProviderViewPage.ts b/web/src/admin/providers/ssf/SSFProviderViewPage.ts index 4359c7d999c3..4741f62058e0 100644 --- a/web/src/admin/providers/ssf/SSFProviderViewPage.ts +++ b/web/src/admin/providers/ssf/SSFProviderViewPage.ts @@ -110,55 +110,61 @@ export class SSFProviderViewPage extends AKElement { if (!this.provider) { return html``; } - return html`
-
-
-
-
-
- ${msg("Name")} -
-
-
${this.provider.name}
-
-
-
-
- ${msg("URL")} -
-
-
- -
-
-
-
+ return html`
+ ${msg("SSF Provider is in preview.")} + ${msg("Send us feedback!")} +
+
+
+
+
+
+
+ ${msg("Name")} +
+
+
+ ${this.provider.name} +
+
+
+
+
+ ${msg("URL")} +
+
+
+ +
+
+
+
+
+
- -
-
${msg("Streams")}
- - -
-
`; +
`; } }