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.events.utils import cleanse_dict, get_user, model_to_dict, sanitize_dict
|
||||||
from authentik.lib.sentry import SentryIgnoredException
|
from authentik.lib.sentry import SentryIgnoredException
|
||||||
from authentik.lib.utils.http import get_client_ip
|
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.policies.models import PolicyBindingModel
|
||||||
from authentik.stages.email.utils import TemplateEmailMessage
|
from authentik.stages.email.utils import TemplateEmailMessage
|
||||||
|
from authentik.tenants.models import Tenant
|
||||||
from authentik.tenants.utils import DEFAULT_TENANT
|
from authentik.tenants.utils import DEFAULT_TENANT
|
||||||
|
|
||||||
LOGGER = get_logger("authentik.events")
|
LOGGER = get_logger("authentik.events")
|
||||||
|
@ -37,7 +39,8 @@ GAUGE_EVENTS = Gauge(
|
||||||
|
|
||||||
|
|
||||||
def default_event_duration():
|
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)
|
return now() + timedelta(days=365)
|
||||||
|
|
||||||
|
|
||||||
|
@ -147,7 +150,12 @@ class Event(ExpiringModel):
|
||||||
"method": request.method,
|
"method": request.method,
|
||||||
}
|
}
|
||||||
if hasattr(request, "tenant"):
|
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"):
|
if hasattr(request, "user"):
|
||||||
original_user = None
|
original_user = None
|
||||||
if hasattr(request, "session"):
|
if hasattr(request, "session"):
|
||||||
|
|
|
@ -5,12 +5,12 @@ from django.core.exceptions import ValidationError
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
ALLOWED_KEYS = (
|
ALLOWED_KEYS = (
|
||||||
"days",
|
|
||||||
"seconds",
|
|
||||||
"microseconds",
|
"microseconds",
|
||||||
"milliseconds",
|
"milliseconds",
|
||||||
|
"seconds",
|
||||||
"minutes",
|
"minutes",
|
||||||
"hours",
|
"hours",
|
||||||
|
"days",
|
||||||
"weeks",
|
"weeks",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,7 @@ class TenantSerializer(ModelSerializer):
|
||||||
"flow_invalidation",
|
"flow_invalidation",
|
||||||
"flow_recovery",
|
"flow_recovery",
|
||||||
"flow_unenrollment",
|
"flow_unenrollment",
|
||||||
|
"event_retention",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
24
authentik/tenants/migrations/0004_tenant_event_retention.py
Normal file
24
authentik/tenants/migrations/0004_tenant_event_retention.py
Normal 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],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
|
@ -5,6 +5,7 @@ from django.db import models
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from authentik.flows.models import Flow
|
from authentik.flows.models import Flow
|
||||||
|
from authentik.lib.utils.time import timedelta_string_validator
|
||||||
|
|
||||||
|
|
||||||
class Tenant(models.Model):
|
class Tenant(models.Model):
|
||||||
|
@ -22,6 +23,7 @@ class Tenant(models.Model):
|
||||||
)
|
)
|
||||||
|
|
||||||
branding_title = models.TextField(default="authentik")
|
branding_title = models.TextField(default="authentik")
|
||||||
|
|
||||||
branding_logo = models.TextField(
|
branding_logo = models.TextField(
|
||||||
default="/static/dist/assets/icons/icon_left_brand.svg"
|
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"
|
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:
|
def __str__(self) -> str:
|
||||||
if self.default:
|
if self.default:
|
||||||
return "Default tenant"
|
return "Default tenant"
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
"""Test tenants"""
|
"""Test tenants"""
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
from django.test.client import RequestFactory
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.encoding import force_str
|
from django.utils.encoding import force_str
|
||||||
|
|
||||||
|
from authentik.events.models import Event, EventAction
|
||||||
from authentik.lib.config import CONFIG
|
from authentik.lib.config import CONFIG
|
||||||
|
from authentik.lib.utils.time import timedelta_from_string
|
||||||
from authentik.tenants.models import Tenant
|
from authentik.tenants.models import Tenant
|
||||||
|
|
||||||
|
|
||||||
|
@ -57,3 +60,28 @@ class TestTenants(TestCase):
|
||||||
"ui_footer_links": CONFIG.y("footer_links"),
|
"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
|
type: string
|
||||||
format: uuid
|
format: uuid
|
||||||
nullable: true
|
nullable: true
|
||||||
|
event_retention:
|
||||||
|
type: string
|
||||||
|
description: 'Events will be deleted after this duration.(Format: weeks=3;days=2;hours=3,seconds=2).'
|
||||||
PatchedTokenRequest:
|
PatchedTokenRequest:
|
||||||
type: object
|
type: object
|
||||||
description: Token Serializer
|
description: Token Serializer
|
||||||
|
@ -27977,6 +27980,9 @@ components:
|
||||||
type: string
|
type: string
|
||||||
format: uuid
|
format: uuid
|
||||||
nullable: true
|
nullable: true
|
||||||
|
event_retention:
|
||||||
|
type: string
|
||||||
|
description: 'Events will be deleted after this duration.(Format: weeks=3;days=2;hours=3,seconds=2).'
|
||||||
required:
|
required:
|
||||||
- domain
|
- domain
|
||||||
- tenant_uuid
|
- tenant_uuid
|
||||||
|
@ -28012,6 +28018,9 @@ components:
|
||||||
type: string
|
type: string
|
||||||
format: uuid
|
format: uuid
|
||||||
nullable: true
|
nullable: true
|
||||||
|
event_retention:
|
||||||
|
type: string
|
||||||
|
description: 'Events will be deleted after this duration.(Format: weeks=3;days=2;hours=3,seconds=2).'
|
||||||
required:
|
required:
|
||||||
- domain
|
- domain
|
||||||
Token:
|
Token:
|
||||||
|
|
|
@ -1230,6 +1230,10 @@ msgstr "Duo activation"
|
||||||
msgid "Duo push-notifications"
|
msgid "Duo push-notifications"
|
||||||
msgstr "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
|
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
|
||||||
msgid "Each provider has a different issuer, based on the application slug."
|
msgid "Each provider has a different issuer, based on the application slug."
|
||||||
msgstr "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"
|
msgid "Event info"
|
||||||
msgstr "Event info"
|
msgstr "Event info"
|
||||||
|
|
||||||
|
#: src/pages/tenants/TenantForm.ts
|
||||||
|
msgid "Event retention"
|
||||||
|
msgstr "Event retention"
|
||||||
|
|
||||||
#: src/pages/events/EventInfoPage.ts
|
#: src/pages/events/EventInfoPage.ts
|
||||||
msgid "Event {0}"
|
msgid "Event {0}"
|
||||||
msgstr "Event {0}"
|
msgstr "Event {0}"
|
||||||
|
@ -1666,6 +1674,10 @@ msgstr "Forgot username or password?"
|
||||||
msgid "Form didn't return a promise for submitting"
|
msgid "Form didn't return a promise for submitting"
|
||||||
msgstr "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
|
#: src/pages/providers/proxy/ProxyProviderForm.ts
|
||||||
msgid "Forward auth (domain level)"
|
msgid "Forward auth (domain level)"
|
||||||
msgstr "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"
|
msgid "Order"
|
||||||
msgstr "Order"
|
msgstr "Order"
|
||||||
|
|
||||||
|
#: src/pages/tenants/TenantForm.ts
|
||||||
|
msgid "Other global settings"
|
||||||
|
msgstr "Other global settings"
|
||||||
|
|
||||||
#: src/pages/admin-overview/charts/OutpostStatusChart.ts
|
#: src/pages/admin-overview/charts/OutpostStatusChart.ts
|
||||||
msgid "Outdated outposts"
|
msgid "Outdated outposts"
|
||||||
msgstr "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."
|
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."
|
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
|
#: src/flows/FlowExecutor.ts
|
||||||
msgid "Whoops!"
|
msgid "Whoops!"
|
||||||
msgstr "Whoops!"
|
msgstr "Whoops!"
|
||||||
|
|
|
@ -1222,6 +1222,10 @@ msgstr ""
|
||||||
msgid "Duo push-notifications"
|
msgid "Duo push-notifications"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/tenants/TenantForm.ts
|
||||||
|
msgid "Duration after which events will be deleted from the database."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
|
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
|
||||||
msgid "Each provider has a different issuer, based on the application slug."
|
msgid "Each provider has a different issuer, based on the application slug."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -1400,6 +1404,10 @@ msgstr ""
|
||||||
msgid "Event info"
|
msgid "Event info"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/tenants/TenantForm.ts
|
||||||
|
msgid "Event retention"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/events/EventInfoPage.ts
|
#: src/pages/events/EventInfoPage.ts
|
||||||
msgid "Event {0}"
|
msgid "Event {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -1658,6 +1666,10 @@ msgstr ""
|
||||||
msgid "Form didn't return a promise for submitting"
|
msgid "Form didn't return a promise for submitting"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/tenants/TenantForm.ts
|
||||||
|
msgid "Format: \"weeks=3;days=2;hours=3,seconds=2\"."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/providers/proxy/ProxyProviderForm.ts
|
#: src/pages/providers/proxy/ProxyProviderForm.ts
|
||||||
msgid "Forward auth (domain level)"
|
msgid "Forward auth (domain level)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -2635,6 +2647,10 @@ msgstr ""
|
||||||
msgid "Order"
|
msgid "Order"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/tenants/TenantForm.ts
|
||||||
|
msgid "Other global settings"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/admin-overview/charts/OutpostStatusChart.ts
|
#: src/pages/admin-overview/charts/OutpostStatusChart.ts
|
||||||
msgid "Outdated outposts"
|
msgid "Outdated outposts"
|
||||||
msgstr ""
|
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."
|
msgid "When this option is enabled, all executions of this policy will be logged. By default, only execution errors are logged."
|
||||||
msgstr ""
|
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
|
#: src/flows/FlowExecutor.ts
|
||||||
msgid "Whoops!"
|
msgid "Whoops!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -162,6 +162,26 @@ export class TenantForm extends ModelForm<Tenant, string> {
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
</div>
|
</div>
|
||||||
</ak-form-group>
|
</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>`;
|
</form>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Reference in a new issue