authentik.events.tests.test_notifications

Notification tests

  1"""Notification tests"""
  2
  3from unittest.mock import MagicMock, patch
  4
  5from django.urls import reverse
  6from rest_framework.test import APITestCase
  7
  8from authentik.core.models import Group, User
  9from authentik.core.tests.utils import create_test_user
 10from authentik.events.models import (
 11    Event,
 12    EventAction,
 13    Notification,
 14    NotificationRule,
 15    NotificationSeverity,
 16    NotificationTransport,
 17    NotificationWebhookMapping,
 18    TransportMode,
 19)
 20from authentik.lib.generators import generate_id
 21from authentik.policies.event_matcher.models import EventMatcherPolicy
 22from authentik.policies.exceptions import PolicyException
 23from authentik.policies.models import PolicyBinding
 24
 25
 26class TestEventsNotifications(APITestCase):
 27    """Test Event Notifications"""
 28
 29    def setUp(self) -> None:
 30        self.group = Group.objects.create(name="test-group")
 31        self.user = User.objects.create(name="test-user", username="test")
 32        self.group.users.add(self.user)
 33        self.group.save()
 34
 35    def test_trigger_empty(self):
 36        """Test trigger without any policies attached"""
 37        transport = NotificationTransport.objects.create(name=generate_id())
 38        trigger = NotificationRule.objects.create(name=generate_id(), destination_group=self.group)
 39        trigger.transports.add(transport)
 40        trigger.save()
 41
 42        execute_mock = MagicMock()
 43        with patch("authentik.events.models.NotificationTransport.send", execute_mock):
 44            Event.new(EventAction.CUSTOM_PREFIX).save()
 45        self.assertEqual(execute_mock.call_count, 0)
 46
 47    def test_trigger_single(self):
 48        """Test simple transport triggering"""
 49        transport = NotificationTransport.objects.create(name=generate_id())
 50        trigger = NotificationRule.objects.create(name=generate_id(), destination_group=self.group)
 51        trigger.transports.add(transport)
 52        trigger.save()
 53        matcher = EventMatcherPolicy.objects.create(
 54            name="matcher", action=EventAction.CUSTOM_PREFIX
 55        )
 56        PolicyBinding.objects.create(target=trigger, policy=matcher, order=0)
 57
 58        execute_mock = MagicMock()
 59        with patch("authentik.events.models.NotificationTransport.send", execute_mock):
 60            Event.new(EventAction.CUSTOM_PREFIX).save()
 61        self.assertEqual(execute_mock.call_count, 1)
 62
 63    def test_trigger_event_user(self):
 64        """Test trigger with event user"""
 65        user = create_test_user()
 66        transport = NotificationTransport.objects.create(name=generate_id())
 67        trigger = NotificationRule.objects.create(name=generate_id(), destination_event_user=True)
 68        trigger.transports.add(transport)
 69        trigger.save()
 70        matcher = EventMatcherPolicy.objects.create(
 71            name="matcher", action=EventAction.CUSTOM_PREFIX
 72        )
 73        PolicyBinding.objects.create(target=trigger, policy=matcher, order=0)
 74
 75        execute_mock = MagicMock()
 76        with patch("authentik.events.models.NotificationTransport.send", execute_mock):
 77            Event.new(EventAction.CUSTOM_PREFIX).set_user(user).save()
 78        self.assertEqual(execute_mock.call_count, 1)
 79        notification: Notification = execute_mock.call_args[0][0]
 80        self.assertEqual(notification.user, user)
 81
 82    def test_trigger_no_group(self):
 83        """Test trigger without group"""
 84        trigger = NotificationRule.objects.create(name=generate_id())
 85        matcher = EventMatcherPolicy.objects.create(
 86            name="matcher", action=EventAction.CUSTOM_PREFIX
 87        )
 88        PolicyBinding.objects.create(target=trigger, policy=matcher, order=0)
 89
 90        execute_mock = MagicMock()
 91        with patch("authentik.events.models.NotificationTransport.send", execute_mock):
 92            Event.new(EventAction.CUSTOM_PREFIX).save()
 93        self.assertEqual(execute_mock.call_count, 0)
 94
 95    def test_policy_error_recursive(self):
 96        """Test Policy error which would cause recursion"""
 97        transport = NotificationTransport.objects.create(name=generate_id())
 98        NotificationRule.objects.filter(name__startswith="default").delete()
 99        trigger = NotificationRule.objects.create(name=generate_id(), destination_group=self.group)
100        trigger.transports.add(transport)
101        trigger.save()
102        matcher = EventMatcherPolicy.objects.create(
103            name="matcher", action=EventAction.CUSTOM_PREFIX
104        )
105        PolicyBinding.objects.create(target=trigger, policy=matcher, order=0)
106
107        execute_mock = MagicMock()
108        passes = MagicMock(side_effect=PolicyException)
109        with patch("authentik.policies.event_matcher.models.EventMatcherPolicy.passes", passes):
110            with patch("authentik.events.models.NotificationTransport.send", execute_mock):
111                Event.new(EventAction.CUSTOM_PREFIX).save()
112        self.assertEqual(passes.call_count, 1)
113
114    def test_transport_once(self):
115        """Test transport's send_once"""
116        user2 = User.objects.create(name="test2-user", username="test2")
117        self.group.users.add(user2)
118        self.group.save()
119
120        transport = NotificationTransport.objects.create(name=generate_id(), send_once=True)
121        NotificationRule.objects.filter(name__startswith="default").delete()
122        trigger = NotificationRule.objects.create(name=generate_id(), destination_group=self.group)
123        trigger.transports.add(transport)
124        trigger.save()
125        matcher = EventMatcherPolicy.objects.create(
126            name="matcher", action=EventAction.CUSTOM_PREFIX
127        )
128        PolicyBinding.objects.create(target=trigger, policy=matcher, order=0)
129
130        execute_mock = MagicMock()
131        with patch("authentik.events.models.NotificationTransport.send", execute_mock):
132            Event.new(EventAction.CUSTOM_PREFIX).save()
133        self.assertEqual(execute_mock.call_count, 1)
134
135    def test_transport_mapping(self):
136        """Test transport mapping"""
137        mapping = NotificationWebhookMapping.objects.create(
138            name=generate_id(),
139            expression="""notification.body = 'foo'""",
140        )
141
142        transport = NotificationTransport.objects.create(
143            name=generate_id(), webhook_mapping_body=mapping, mode=TransportMode.LOCAL
144        )
145        NotificationRule.objects.filter(name__startswith="default").delete()
146        trigger = NotificationRule.objects.create(name=generate_id(), destination_group=self.group)
147        trigger.transports.add(transport)
148        matcher = EventMatcherPolicy.objects.create(
149            name="matcher", action=EventAction.CUSTOM_PREFIX
150        )
151        PolicyBinding.objects.create(target=trigger, policy=matcher, order=0)
152
153        Notification.objects.all().delete()
154        Event.new(EventAction.CUSTOM_PREFIX).save()
155        self.assertEqual(Notification.objects.first().body, "foo")
156
157    def test_api_mark_all_seen(self):
158        """Test mark_all_seen"""
159        self.client.force_login(self.user)
160
161        Notification.objects.create(
162            severity=NotificationSeverity.NOTICE, body="foo", user=self.user, seen=False
163        )
164
165        response = self.client.post(reverse("authentik_api:notification-mark-all-seen"))
166        self.assertEqual(response.status_code, 204)
167        self.assertFalse(Notification.objects.filter(body="foo", seen=False).exists())
class TestEventsNotifications(rest_framework.test.APITestCase):
 27class TestEventsNotifications(APITestCase):
 28    """Test Event Notifications"""
 29
 30    def setUp(self) -> None:
 31        self.group = Group.objects.create(name="test-group")
 32        self.user = User.objects.create(name="test-user", username="test")
 33        self.group.users.add(self.user)
 34        self.group.save()
 35
 36    def test_trigger_empty(self):
 37        """Test trigger without any policies attached"""
 38        transport = NotificationTransport.objects.create(name=generate_id())
 39        trigger = NotificationRule.objects.create(name=generate_id(), destination_group=self.group)
 40        trigger.transports.add(transport)
 41        trigger.save()
 42
 43        execute_mock = MagicMock()
 44        with patch("authentik.events.models.NotificationTransport.send", execute_mock):
 45            Event.new(EventAction.CUSTOM_PREFIX).save()
 46        self.assertEqual(execute_mock.call_count, 0)
 47
 48    def test_trigger_single(self):
 49        """Test simple transport triggering"""
 50        transport = NotificationTransport.objects.create(name=generate_id())
 51        trigger = NotificationRule.objects.create(name=generate_id(), destination_group=self.group)
 52        trigger.transports.add(transport)
 53        trigger.save()
 54        matcher = EventMatcherPolicy.objects.create(
 55            name="matcher", action=EventAction.CUSTOM_PREFIX
 56        )
 57        PolicyBinding.objects.create(target=trigger, policy=matcher, order=0)
 58
 59        execute_mock = MagicMock()
 60        with patch("authentik.events.models.NotificationTransport.send", execute_mock):
 61            Event.new(EventAction.CUSTOM_PREFIX).save()
 62        self.assertEqual(execute_mock.call_count, 1)
 63
 64    def test_trigger_event_user(self):
 65        """Test trigger with event user"""
 66        user = create_test_user()
 67        transport = NotificationTransport.objects.create(name=generate_id())
 68        trigger = NotificationRule.objects.create(name=generate_id(), destination_event_user=True)
 69        trigger.transports.add(transport)
 70        trigger.save()
 71        matcher = EventMatcherPolicy.objects.create(
 72            name="matcher", action=EventAction.CUSTOM_PREFIX
 73        )
 74        PolicyBinding.objects.create(target=trigger, policy=matcher, order=0)
 75
 76        execute_mock = MagicMock()
 77        with patch("authentik.events.models.NotificationTransport.send", execute_mock):
 78            Event.new(EventAction.CUSTOM_PREFIX).set_user(user).save()
 79        self.assertEqual(execute_mock.call_count, 1)
 80        notification: Notification = execute_mock.call_args[0][0]
 81        self.assertEqual(notification.user, user)
 82
 83    def test_trigger_no_group(self):
 84        """Test trigger without group"""
 85        trigger = NotificationRule.objects.create(name=generate_id())
 86        matcher = EventMatcherPolicy.objects.create(
 87            name="matcher", action=EventAction.CUSTOM_PREFIX
 88        )
 89        PolicyBinding.objects.create(target=trigger, policy=matcher, order=0)
 90
 91        execute_mock = MagicMock()
 92        with patch("authentik.events.models.NotificationTransport.send", execute_mock):
 93            Event.new(EventAction.CUSTOM_PREFIX).save()
 94        self.assertEqual(execute_mock.call_count, 0)
 95
 96    def test_policy_error_recursive(self):
 97        """Test Policy error which would cause recursion"""
 98        transport = NotificationTransport.objects.create(name=generate_id())
 99        NotificationRule.objects.filter(name__startswith="default").delete()
100        trigger = NotificationRule.objects.create(name=generate_id(), destination_group=self.group)
101        trigger.transports.add(transport)
102        trigger.save()
103        matcher = EventMatcherPolicy.objects.create(
104            name="matcher", action=EventAction.CUSTOM_PREFIX
105        )
106        PolicyBinding.objects.create(target=trigger, policy=matcher, order=0)
107
108        execute_mock = MagicMock()
109        passes = MagicMock(side_effect=PolicyException)
110        with patch("authentik.policies.event_matcher.models.EventMatcherPolicy.passes", passes):
111            with patch("authentik.events.models.NotificationTransport.send", execute_mock):
112                Event.new(EventAction.CUSTOM_PREFIX).save()
113        self.assertEqual(passes.call_count, 1)
114
115    def test_transport_once(self):
116        """Test transport's send_once"""
117        user2 = User.objects.create(name="test2-user", username="test2")
118        self.group.users.add(user2)
119        self.group.save()
120
121        transport = NotificationTransport.objects.create(name=generate_id(), send_once=True)
122        NotificationRule.objects.filter(name__startswith="default").delete()
123        trigger = NotificationRule.objects.create(name=generate_id(), destination_group=self.group)
124        trigger.transports.add(transport)
125        trigger.save()
126        matcher = EventMatcherPolicy.objects.create(
127            name="matcher", action=EventAction.CUSTOM_PREFIX
128        )
129        PolicyBinding.objects.create(target=trigger, policy=matcher, order=0)
130
131        execute_mock = MagicMock()
132        with patch("authentik.events.models.NotificationTransport.send", execute_mock):
133            Event.new(EventAction.CUSTOM_PREFIX).save()
134        self.assertEqual(execute_mock.call_count, 1)
135
136    def test_transport_mapping(self):
137        """Test transport mapping"""
138        mapping = NotificationWebhookMapping.objects.create(
139            name=generate_id(),
140            expression="""notification.body = 'foo'""",
141        )
142
143        transport = NotificationTransport.objects.create(
144            name=generate_id(), webhook_mapping_body=mapping, mode=TransportMode.LOCAL
145        )
146        NotificationRule.objects.filter(name__startswith="default").delete()
147        trigger = NotificationRule.objects.create(name=generate_id(), destination_group=self.group)
148        trigger.transports.add(transport)
149        matcher = EventMatcherPolicy.objects.create(
150            name="matcher", action=EventAction.CUSTOM_PREFIX
151        )
152        PolicyBinding.objects.create(target=trigger, policy=matcher, order=0)
153
154        Notification.objects.all().delete()
155        Event.new(EventAction.CUSTOM_PREFIX).save()
156        self.assertEqual(Notification.objects.first().body, "foo")
157
158    def test_api_mark_all_seen(self):
159        """Test mark_all_seen"""
160        self.client.force_login(self.user)
161
162        Notification.objects.create(
163            severity=NotificationSeverity.NOTICE, body="foo", user=self.user, seen=False
164        )
165
166        response = self.client.post(reverse("authentik_api:notification-mark-all-seen"))
167        self.assertEqual(response.status_code, 204)
168        self.assertFalse(Notification.objects.filter(body="foo", seen=False).exists())

Test Event Notifications

def setUp(self) -> None:
30    def setUp(self) -> None:
31        self.group = Group.objects.create(name="test-group")
32        self.user = User.objects.create(name="test-user", username="test")
33        self.group.users.add(self.user)
34        self.group.save()

Hook method for setting up the test fixture before exercising it.

def test_trigger_empty(self):
36    def test_trigger_empty(self):
37        """Test trigger without any policies attached"""
38        transport = NotificationTransport.objects.create(name=generate_id())
39        trigger = NotificationRule.objects.create(name=generate_id(), destination_group=self.group)
40        trigger.transports.add(transport)
41        trigger.save()
42
43        execute_mock = MagicMock()
44        with patch("authentik.events.models.NotificationTransport.send", execute_mock):
45            Event.new(EventAction.CUSTOM_PREFIX).save()
46        self.assertEqual(execute_mock.call_count, 0)

Test trigger without any policies attached

def test_trigger_single(self):
48    def test_trigger_single(self):
49        """Test simple transport triggering"""
50        transport = NotificationTransport.objects.create(name=generate_id())
51        trigger = NotificationRule.objects.create(name=generate_id(), destination_group=self.group)
52        trigger.transports.add(transport)
53        trigger.save()
54        matcher = EventMatcherPolicy.objects.create(
55            name="matcher", action=EventAction.CUSTOM_PREFIX
56        )
57        PolicyBinding.objects.create(target=trigger, policy=matcher, order=0)
58
59        execute_mock = MagicMock()
60        with patch("authentik.events.models.NotificationTransport.send", execute_mock):
61            Event.new(EventAction.CUSTOM_PREFIX).save()
62        self.assertEqual(execute_mock.call_count, 1)

Test simple transport triggering

def test_trigger_event_user(self):
64    def test_trigger_event_user(self):
65        """Test trigger with event user"""
66        user = create_test_user()
67        transport = NotificationTransport.objects.create(name=generate_id())
68        trigger = NotificationRule.objects.create(name=generate_id(), destination_event_user=True)
69        trigger.transports.add(transport)
70        trigger.save()
71        matcher = EventMatcherPolicy.objects.create(
72            name="matcher", action=EventAction.CUSTOM_PREFIX
73        )
74        PolicyBinding.objects.create(target=trigger, policy=matcher, order=0)
75
76        execute_mock = MagicMock()
77        with patch("authentik.events.models.NotificationTransport.send", execute_mock):
78            Event.new(EventAction.CUSTOM_PREFIX).set_user(user).save()
79        self.assertEqual(execute_mock.call_count, 1)
80        notification: Notification = execute_mock.call_args[0][0]
81        self.assertEqual(notification.user, user)

Test trigger with event user

def test_trigger_no_group(self):
83    def test_trigger_no_group(self):
84        """Test trigger without group"""
85        trigger = NotificationRule.objects.create(name=generate_id())
86        matcher = EventMatcherPolicy.objects.create(
87            name="matcher", action=EventAction.CUSTOM_PREFIX
88        )
89        PolicyBinding.objects.create(target=trigger, policy=matcher, order=0)
90
91        execute_mock = MagicMock()
92        with patch("authentik.events.models.NotificationTransport.send", execute_mock):
93            Event.new(EventAction.CUSTOM_PREFIX).save()
94        self.assertEqual(execute_mock.call_count, 0)

Test trigger without group

def test_policy_error_recursive(self):
 96    def test_policy_error_recursive(self):
 97        """Test Policy error which would cause recursion"""
 98        transport = NotificationTransport.objects.create(name=generate_id())
 99        NotificationRule.objects.filter(name__startswith="default").delete()
100        trigger = NotificationRule.objects.create(name=generate_id(), destination_group=self.group)
101        trigger.transports.add(transport)
102        trigger.save()
103        matcher = EventMatcherPolicy.objects.create(
104            name="matcher", action=EventAction.CUSTOM_PREFIX
105        )
106        PolicyBinding.objects.create(target=trigger, policy=matcher, order=0)
107
108        execute_mock = MagicMock()
109        passes = MagicMock(side_effect=PolicyException)
110        with patch("authentik.policies.event_matcher.models.EventMatcherPolicy.passes", passes):
111            with patch("authentik.events.models.NotificationTransport.send", execute_mock):
112                Event.new(EventAction.CUSTOM_PREFIX).save()
113        self.assertEqual(passes.call_count, 1)

Test Policy error which would cause recursion

def test_transport_once(self):
115    def test_transport_once(self):
116        """Test transport's send_once"""
117        user2 = User.objects.create(name="test2-user", username="test2")
118        self.group.users.add(user2)
119        self.group.save()
120
121        transport = NotificationTransport.objects.create(name=generate_id(), send_once=True)
122        NotificationRule.objects.filter(name__startswith="default").delete()
123        trigger = NotificationRule.objects.create(name=generate_id(), destination_group=self.group)
124        trigger.transports.add(transport)
125        trigger.save()
126        matcher = EventMatcherPolicy.objects.create(
127            name="matcher", action=EventAction.CUSTOM_PREFIX
128        )
129        PolicyBinding.objects.create(target=trigger, policy=matcher, order=0)
130
131        execute_mock = MagicMock()
132        with patch("authentik.events.models.NotificationTransport.send", execute_mock):
133            Event.new(EventAction.CUSTOM_PREFIX).save()
134        self.assertEqual(execute_mock.call_count, 1)

Test transport's send_once

def test_transport_mapping(self):
136    def test_transport_mapping(self):
137        """Test transport mapping"""
138        mapping = NotificationWebhookMapping.objects.create(
139            name=generate_id(),
140            expression="""notification.body = 'foo'""",
141        )
142
143        transport = NotificationTransport.objects.create(
144            name=generate_id(), webhook_mapping_body=mapping, mode=TransportMode.LOCAL
145        )
146        NotificationRule.objects.filter(name__startswith="default").delete()
147        trigger = NotificationRule.objects.create(name=generate_id(), destination_group=self.group)
148        trigger.transports.add(transport)
149        matcher = EventMatcherPolicy.objects.create(
150            name="matcher", action=EventAction.CUSTOM_PREFIX
151        )
152        PolicyBinding.objects.create(target=trigger, policy=matcher, order=0)
153
154        Notification.objects.all().delete()
155        Event.new(EventAction.CUSTOM_PREFIX).save()
156        self.assertEqual(Notification.objects.first().body, "foo")

Test transport mapping

def test_api_mark_all_seen(self):
158    def test_api_mark_all_seen(self):
159        """Test mark_all_seen"""
160        self.client.force_login(self.user)
161
162        Notification.objects.create(
163            severity=NotificationSeverity.NOTICE, body="foo", user=self.user, seen=False
164        )
165
166        response = self.client.post(reverse("authentik_api:notification-mark-all-seen"))
167        self.assertEqual(response.status_code, 204)
168        self.assertFalse(Notification.objects.filter(body="foo", seen=False).exists())

Test mark_all_seen