tenants: make event retention configurable on tenant level
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
parent
1e28a1e311
commit
1972464a20
|
@ -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"):
|
||||
|
|
|
@ -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",
|
||||
)
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ class TenantSerializer(ModelSerializer):
|
|||
"flow_invalidation",
|
||||
"flow_recovery",
|
||||
"flow_unenrollment",
|
||||
"event_retention",
|
||||
]
|
||||
|
||||
|
||||
|
|
|
@ -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],
|
||||
),
|
||||
),
|
||||
]
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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!"
|
||||
|
|
|
@ -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 ""
|
||||
|
|
|
@ -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>`;
|
||||
}
|
||||
|
||||
|
|
Reference in New Issue