tenants: make event retention configurable on tenant level

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
Jens Langhammer 2021-07-24 19:21:35 +02:00
parent 1e28a1e311
commit 1972464a20
10 changed files with 147 additions and 4 deletions

View File

@ -24,8 +24,10 @@ from authentik.events.geo import GEOIP_READER
from authentik.events.utils import cleanse_dict, get_user, model_to_dict, sanitize_dict
from authentik.lib.sentry import SentryIgnoredException
from authentik.lib.utils.http import get_client_ip
from authentik.lib.utils.time import timedelta_from_string
from authentik.policies.models import PolicyBindingModel
from authentik.stages.email.utils import TemplateEmailMessage
from authentik.tenants.models import Tenant
from authentik.tenants.utils import DEFAULT_TENANT
LOGGER = get_logger("authentik.events")
@ -37,7 +39,8 @@ GAUGE_EVENTS = Gauge(
def default_event_duration():
"""Default duration an Event is saved"""
"""Default duration an Event is saved.
This is used as a fallback when no tenant is available"""
return now() + timedelta(days=365)
@ -147,7 +150,12 @@ class Event(ExpiringModel):
"method": request.method,
}
if hasattr(request, "tenant"):
self.tenant = sanitize_dict(model_to_dict(request.tenant))
tenant: Tenant = request.tenant
# Because self.created only gets set on save, we can't use it's value here
# hence we set self.created to now and then use it
self.created = now()
self.expires = self.created + timedelta_from_string(tenant.event_retention)
self.tenant = sanitize_dict(model_to_dict(tenant))
if hasattr(request, "user"):
original_user = None
if hasattr(request, "session"):

View File

@ -5,12 +5,12 @@ from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _
ALLOWED_KEYS = (
"days",
"seconds",
"microseconds",
"milliseconds",
"seconds",
"minutes",
"hours",
"days",
"weeks",
)

View File

@ -38,6 +38,7 @@ class TenantSerializer(ModelSerializer):
"flow_invalidation",
"flow_recovery",
"flow_unenrollment",
"event_retention",
]

View File

@ -0,0 +1,24 @@
# Generated by Django 3.2.5 on 2021-07-24 17:06
from django.db import migrations, models
import authentik.lib.utils.time
class Migration(migrations.Migration):
dependencies = [
("authentik_tenants", "0003_tenant_branding_favicon"),
]
operations = [
migrations.AddField(
model_name="tenant",
name="event_retention",
field=models.TextField(
default="days=365",
help_text="Events will be deleted after this duration.(Format: weeks=3;days=2;hours=3,seconds=2).",
validators=[authentik.lib.utils.time.timedelta_string_validator],
),
),
]

View File

@ -5,6 +5,7 @@ from django.db import models
from django.utils.translation import gettext_lazy as _
from authentik.flows.models import Flow
from authentik.lib.utils.time import timedelta_string_validator
class Tenant(models.Model):
@ -22,6 +23,7 @@ class Tenant(models.Model):
)
branding_title = models.TextField(default="authentik")
branding_logo = models.TextField(
default="/static/dist/assets/icons/icon_left_brand.svg"
)
@ -40,6 +42,17 @@ class Tenant(models.Model):
Flow, null=True, on_delete=models.SET_NULL, related_name="tenant_unenrollment"
)
event_retention = models.TextField(
default="days=365",
validators=[timedelta_string_validator],
help_text=_(
(
"Events will be deleted after this duration."
"(Format: weeks=3;days=2;hours=3,seconds=2)."
)
),
)
def __str__(self) -> str:
if self.default:
return "Default tenant"

View File

@ -1,9 +1,12 @@
"""Test tenants"""
from django.test import TestCase
from django.test.client import RequestFactory
from django.urls import reverse
from django.utils.encoding import force_str
from authentik.events.models import Event, EventAction
from authentik.lib.config import CONFIG
from authentik.lib.utils.time import timedelta_from_string
from authentik.tenants.models import Tenant
@ -57,3 +60,28 @@ class TestTenants(TestCase):
"ui_footer_links": CONFIG.y("footer_links"),
},
)
def test_event_retention(self):
"""Test tenant's event retention"""
tenant = Tenant.objects.create(
domain="foo",
default=True,
branding_title="custom",
event_retention="weeks=3",
)
factory = RequestFactory()
request = factory.get("/")
request.tenant = tenant
event = Event.new(
action=EventAction.SYSTEM_EXCEPTION, message="test"
).from_http(request)
self.assertEqual(
event.expires.day, (event.created + timedelta_from_string("weeks=3")).day
)
self.assertEqual(
event.expires.month,
(event.created + timedelta_from_string("weeks=3")).month,
)
self.assertEqual(
event.expires.year, (event.created + timedelta_from_string("weeks=3")).year
)

View File

@ -25902,6 +25902,9 @@ components:
type: string
format: uuid
nullable: true
event_retention:
type: string
description: 'Events will be deleted after this duration.(Format: weeks=3;days=2;hours=3,seconds=2).'
PatchedTokenRequest:
type: object
description: Token Serializer
@ -27977,6 +27980,9 @@ components:
type: string
format: uuid
nullable: true
event_retention:
type: string
description: 'Events will be deleted after this duration.(Format: weeks=3;days=2;hours=3,seconds=2).'
required:
- domain
- tenant_uuid
@ -28012,6 +28018,9 @@ components:
type: string
format: uuid
nullable: true
event_retention:
type: string
description: 'Events will be deleted after this duration.(Format: weeks=3;days=2;hours=3,seconds=2).'
required:
- domain
Token:

View File

@ -1230,6 +1230,10 @@ msgstr "Duo activation"
msgid "Duo push-notifications"
msgstr "Duo push-notifications"
#: src/pages/tenants/TenantForm.ts
msgid "Duration after which events will be deleted from the database."
msgstr "Duration after which events will be deleted from the database."
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
msgid "Each provider has a different issuer, based on the application slug."
msgstr "Each provider has a different issuer, based on the application slug."
@ -1408,6 +1412,10 @@ msgstr "Event Log"
msgid "Event info"
msgstr "Event info"
#: src/pages/tenants/TenantForm.ts
msgid "Event retention"
msgstr "Event retention"
#: src/pages/events/EventInfoPage.ts
msgid "Event {0}"
msgstr "Event {0}"
@ -1666,6 +1674,10 @@ msgstr "Forgot username or password?"
msgid "Form didn't return a promise for submitting"
msgstr "Form didn't return a promise for submitting"
#: src/pages/tenants/TenantForm.ts
msgid "Format: \"weeks=3;days=2;hours=3,seconds=2\"."
msgstr "Format: \"weeks=3;days=2;hours=3,seconds=2\"."
#: src/pages/providers/proxy/ProxyProviderForm.ts
msgid "Forward auth (domain level)"
msgstr "Forward auth (domain level)"
@ -2643,6 +2655,10 @@ msgstr "Optionally set this to your parent domain, if you want authentication an
msgid "Order"
msgstr "Order"
#: src/pages/tenants/TenantForm.ts
msgid "Other global settings"
msgstr "Other global settings"
#: src/pages/admin-overview/charts/OutpostStatusChart.ts
msgid "Outdated outposts"
msgstr "Outdated outposts"
@ -4659,6 +4675,10 @@ msgstr "When selected, incoming assertion's Signatures will be validated against
msgid "When this option is enabled, all executions of this policy will be logged. By default, only execution errors are logged."
msgstr "When this option is enabled, all executions of this policy will be logged. By default, only execution errors are logged."
#: src/pages/tenants/TenantForm.ts
msgid "When using an external logging solution for archiving, this can be set to \"minutes=5\"."
msgstr "When using an external logging solution for archiving, this can be set to \"minutes=5\"."
#: src/flows/FlowExecutor.ts
msgid "Whoops!"
msgstr "Whoops!"

View File

@ -1222,6 +1222,10 @@ msgstr ""
msgid "Duo push-notifications"
msgstr ""
#: src/pages/tenants/TenantForm.ts
msgid "Duration after which events will be deleted from the database."
msgstr ""
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
msgid "Each provider has a different issuer, based on the application slug."
msgstr ""
@ -1400,6 +1404,10 @@ msgstr ""
msgid "Event info"
msgstr ""
#: src/pages/tenants/TenantForm.ts
msgid "Event retention"
msgstr ""
#: src/pages/events/EventInfoPage.ts
msgid "Event {0}"
msgstr ""
@ -1658,6 +1666,10 @@ msgstr ""
msgid "Form didn't return a promise for submitting"
msgstr ""
#: src/pages/tenants/TenantForm.ts
msgid "Format: \"weeks=3;days=2;hours=3,seconds=2\"."
msgstr ""
#: src/pages/providers/proxy/ProxyProviderForm.ts
msgid "Forward auth (domain level)"
msgstr ""
@ -2635,6 +2647,10 @@ msgstr ""
msgid "Order"
msgstr ""
#: src/pages/tenants/TenantForm.ts
msgid "Other global settings"
msgstr ""
#: src/pages/admin-overview/charts/OutpostStatusChart.ts
msgid "Outdated outposts"
msgstr ""
@ -4644,6 +4660,10 @@ msgstr ""
msgid "When this option is enabled, all executions of this policy will be logged. By default, only execution errors are logged."
msgstr ""
#: src/pages/tenants/TenantForm.ts
msgid "When using an external logging solution for archiving, this can be set to \"minutes=5\"."
msgstr ""
#: src/flows/FlowExecutor.ts
msgid "Whoops!"
msgstr ""

View File

@ -162,6 +162,26 @@ export class TenantForm extends ModelForm<Tenant, string> {
</ak-form-element-horizontal>
</div>
</ak-form-group>
<ak-form-group>
<span slot="header">
${t`Other global settings`}
</span>
<div slot="body" class="pf-c-form">
<ak-form-element-horizontal
label=${t`Event retention`}
?required=${true}
name="eventRetention">
<input type="text" value="${first(this.instance?.eventRetention, "days=365")}" class="pf-c-form-control" required>
<p class="pf-c-form__helper-text">
${t`Duration after which events will be deleted from the database.`}
</p>
<p class="pf-c-form__helper-text">
${t`When using an external logging solution for archiving, this can be set to "minutes=5".`}
</p>
<p class="pf-c-form__helper-text">${t`Format: "weeks=3;days=2;hours=3,seconds=2".`}</p>
</ak-form-element-horizontal>
</div>
</ak-form-group>
</form>`;
}