diff --git a/authentik/enterprise/providers/rac/api/connection_tokens.py b/authentik/enterprise/providers/rac/api/connection_tokens.py
new file mode 100644
index 0000000000..9b5ff10743
--- /dev/null
+++ b/authentik/enterprise/providers/rac/api/connection_tokens.py
@@ -0,0 +1,53 @@
+"""RAC Provider API Views"""
+
+from django_filters.rest_framework.backends import DjangoFilterBackend
+from rest_framework import mixins
+from rest_framework.filters import OrderingFilter, SearchFilter
+from rest_framework.serializers import ModelSerializer
+from rest_framework.viewsets import GenericViewSet
+
+from authentik.api.authorization import OwnerFilter, OwnerPermissions
+from authentik.core.api.groups import GroupMemberSerializer
+from authentik.core.api.used_by import UsedByMixin
+from authentik.enterprise.api import EnterpriseRequiredMixin
+from authentik.enterprise.providers.rac.api.endpoints import EndpointSerializer
+from authentik.enterprise.providers.rac.api.providers import RACProviderSerializer
+from authentik.enterprise.providers.rac.models import ConnectionToken, Endpoint
+
+
+class ConnectionTokenSerializer(EnterpriseRequiredMixin, ModelSerializer):
+ """ConnectionToken Serializer"""
+
+ provider_obj = RACProviderSerializer(source="provider", read_only=True)
+ endpoint_obj = EndpointSerializer(source="endpoint", read_only=True)
+ user = GroupMemberSerializer(source="session.user", read_only=True)
+
+ class Meta:
+ model = Endpoint
+ fields = [
+ "pk",
+ "provider",
+ "provider_obj",
+ "endpoint",
+ "endpoint_obj",
+ "user",
+ ]
+
+
+class ConnectionTokenViewSet(
+ mixins.RetrieveModelMixin,
+ mixins.UpdateModelMixin,
+ mixins.DestroyModelMixin,
+ UsedByMixin,
+ mixins.ListModelMixin,
+ GenericViewSet,
+):
+ """ConnectionToken Viewset"""
+
+ queryset = ConnectionToken.objects.all().select_related("session", "endpoint")
+ serializer_class = ConnectionTokenSerializer
+ filterset_fields = ["endpoint", "session__user", "provider"]
+ search_fields = ["endpoint__name", "provider__name"]
+ ordering = ["endpoint__name", "provider__name"]
+ permission_classes = [OwnerPermissions]
+ filter_backends = [OwnerFilter, DjangoFilterBackend, OrderingFilter, SearchFilter]
diff --git a/authentik/enterprise/providers/rac/api/providers.py b/authentik/enterprise/providers/rac/api/providers.py
index 25df75789c..892e081c96 100644
--- a/authentik/enterprise/providers/rac/api/providers.py
+++ b/authentik/enterprise/providers/rac/api/providers.py
@@ -16,7 +16,12 @@ class RACProviderSerializer(EnterpriseRequiredMixin, ProviderSerializer):
class Meta:
model = RACProvider
- fields = ProviderSerializer.Meta.fields + ["settings", "outpost_set", "connection_expiry"]
+ fields = ProviderSerializer.Meta.fields + [
+ "settings",
+ "outpost_set",
+ "connection_expiry",
+ "delete_token_on_disconnect",
+ ]
extra_kwargs = ProviderSerializer.Meta.extra_kwargs
diff --git a/authentik/enterprise/providers/rac/consumer_client.py b/authentik/enterprise/providers/rac/consumer_client.py
index 5bfc176b95..b6331ca563 100644
--- a/authentik/enterprise/providers/rac/consumer_client.py
+++ b/authentik/enterprise/providers/rac/consumer_client.py
@@ -43,6 +43,7 @@ class RACClientConsumer(AsyncWebsocketConsumer):
logger: BoundLogger
async def connect(self):
+ self.logger = get_logger()
await self.accept("guacamole")
await self.channel_layer.group_add(RAC_CLIENT_GROUP, self.channel_name)
await self.channel_layer.group_add(
@@ -64,9 +65,11 @@ class RACClientConsumer(AsyncWebsocketConsumer):
@database_sync_to_async
def init_outpost_connection(self):
"""Initialize guac connection settings"""
- self.token = ConnectionToken.filter_not_expired(
- token=self.scope["url_route"]["kwargs"]["token"]
- ).first()
+ self.token = (
+ ConnectionToken.filter_not_expired(token=self.scope["url_route"]["kwargs"]["token"])
+ .select_related("endpoint", "provider", "session", "session__user")
+ .first()
+ )
if not self.token:
raise DenyConnection()
self.provider = self.token.provider
@@ -107,6 +110,9 @@ class RACClientConsumer(AsyncWebsocketConsumer):
OUTPOST_GROUP_INSTANCE % {"outpost_pk": str(outpost.pk), "instance": states[0].uid},
msg,
)
+ if self.provider and self.provider.delete_token_on_disconnect:
+ self.logger.info("Deleting connection token to prevent reconnect", token=self.token)
+ self.token.delete()
async def receive(self, text_data=None, bytes_data=None):
"""Mirror data received from client to the dest_channel_id
diff --git a/authentik/enterprise/providers/rac/migrations/0001_squashed_0003_alter_connectiontoken_options_and_more.py b/authentik/enterprise/providers/rac/migrations/0001_squashed_0003_alter_connectiontoken_options_and_more.py
new file mode 100644
index 0000000000..3c6626f1a7
--- /dev/null
+++ b/authentik/enterprise/providers/rac/migrations/0001_squashed_0003_alter_connectiontoken_options_and_more.py
@@ -0,0 +1,181 @@
+# Generated by Django 5.0.1 on 2024-02-11 19:04
+
+import uuid
+
+import django.db.models.deletion
+from django.db import migrations, models
+
+import authentik.core.models
+import authentik.lib.utils.time
+
+
+class Migration(migrations.Migration):
+
+ replaces = [
+ ("authentik_providers_rac", "0001_initial"),
+ ("authentik_providers_rac", "0002_endpoint_maximum_connections"),
+ ("authentik_providers_rac", "0003_alter_connectiontoken_options_and_more"),
+ ]
+
+ initial = True
+
+ dependencies = [
+ ("authentik_core", "0032_group_roles"),
+ ("authentik_policies", "0011_policybinding_failure_result_and_more"),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name="RACPropertyMapping",
+ fields=[
+ (
+ "propertymapping_ptr",
+ models.OneToOneField(
+ auto_created=True,
+ on_delete=django.db.models.deletion.CASCADE,
+ parent_link=True,
+ primary_key=True,
+ serialize=False,
+ to="authentik_core.propertymapping",
+ ),
+ ),
+ ("static_settings", models.JSONField(default=dict)),
+ ],
+ options={
+ "verbose_name": "RAC Property Mapping",
+ "verbose_name_plural": "RAC Property Mappings",
+ },
+ bases=("authentik_core.propertymapping",),
+ ),
+ migrations.CreateModel(
+ name="RACProvider",
+ fields=[
+ (
+ "provider_ptr",
+ models.OneToOneField(
+ auto_created=True,
+ on_delete=django.db.models.deletion.CASCADE,
+ parent_link=True,
+ primary_key=True,
+ serialize=False,
+ to="authentik_core.provider",
+ ),
+ ),
+ ("settings", models.JSONField(default=dict)),
+ (
+ "auth_mode",
+ models.TextField(
+ choices=[("static", "Static"), ("prompt", "Prompt")], default="prompt"
+ ),
+ ),
+ (
+ "connection_expiry",
+ models.TextField(
+ default="hours=8",
+ help_text="Determines how long a session lasts. Default of 0 means that the sessions lasts until the browser is closed. (Format: hours=-1;minutes=-2;seconds=-3)",
+ validators=[authentik.lib.utils.time.timedelta_string_validator],
+ ),
+ ),
+ (
+ "delete_token_on_disconnect",
+ models.BooleanField(
+ default=False,
+ help_text="When set to true, connection tokens will be deleted upon disconnect.",
+ ),
+ ),
+ ],
+ options={
+ "verbose_name": "RAC Provider",
+ "verbose_name_plural": "RAC Providers",
+ },
+ bases=("authentik_core.provider",),
+ ),
+ migrations.CreateModel(
+ name="Endpoint",
+ fields=[
+ (
+ "policybindingmodel_ptr",
+ models.OneToOneField(
+ auto_created=True,
+ on_delete=django.db.models.deletion.CASCADE,
+ parent_link=True,
+ primary_key=True,
+ serialize=False,
+ to="authentik_policies.policybindingmodel",
+ ),
+ ),
+ ("name", models.TextField()),
+ ("host", models.TextField()),
+ (
+ "protocol",
+ models.TextField(choices=[("rdp", "Rdp"), ("vnc", "Vnc"), ("ssh", "Ssh")]),
+ ),
+ ("settings", models.JSONField(default=dict)),
+ (
+ "auth_mode",
+ models.TextField(choices=[("static", "Static"), ("prompt", "Prompt")]),
+ ),
+ (
+ "property_mappings",
+ models.ManyToManyField(
+ blank=True, default=None, to="authentik_core.propertymapping"
+ ),
+ ),
+ (
+ "provider",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.CASCADE,
+ to="authentik_providers_rac.racprovider",
+ ),
+ ),
+ ("maximum_connections", models.IntegerField(default=1)),
+ ],
+ options={
+ "verbose_name": "RAC Endpoint",
+ "verbose_name_plural": "RAC Endpoints",
+ },
+ bases=("authentik_policies.policybindingmodel", models.Model),
+ ),
+ migrations.CreateModel(
+ name="ConnectionToken",
+ fields=[
+ (
+ "expires",
+ models.DateTimeField(default=authentik.core.models.default_token_duration),
+ ),
+ ("expiring", models.BooleanField(default=True)),
+ (
+ "connection_token_uuid",
+ models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False),
+ ),
+ ("token", models.TextField(default=authentik.core.models.default_token_key)),
+ ("settings", models.JSONField(default=dict)),
+ (
+ "endpoint",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.CASCADE,
+ to="authentik_providers_rac.endpoint",
+ ),
+ ),
+ (
+ "provider",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.CASCADE,
+ to="authentik_providers_rac.racprovider",
+ ),
+ ),
+ (
+ "session",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.CASCADE,
+ to="authentik_core.authenticatedsession",
+ ),
+ ),
+ ],
+ options={
+ "abstract": False,
+ "verbose_name": "RAC Connection token",
+ "verbose_name_plural": "RAC Connection tokens",
+ },
+ ),
+ ]
diff --git a/authentik/enterprise/providers/rac/migrations/0003_alter_connectiontoken_options_and_more.py b/authentik/enterprise/providers/rac/migrations/0003_alter_connectiontoken_options_and_more.py
new file mode 100644
index 0000000000..c333fedadd
--- /dev/null
+++ b/authentik/enterprise/providers/rac/migrations/0003_alter_connectiontoken_options_and_more.py
@@ -0,0 +1,28 @@
+# Generated by Django 5.0.1 on 2024-02-11 19:04
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("authentik_providers_rac", "0002_endpoint_maximum_connections"),
+ ]
+
+ operations = [
+ migrations.AlterModelOptions(
+ name="connectiontoken",
+ options={
+ "verbose_name": "RAC Connection token",
+ "verbose_name_plural": "RAC Connection tokens",
+ },
+ ),
+ migrations.AddField(
+ model_name="racprovider",
+ name="delete_token_on_disconnect",
+ field=models.BooleanField(
+ default=False,
+ help_text="When set to true, connection tokens will be deleted upon disconnect.",
+ ),
+ ),
+ ]
diff --git a/authentik/enterprise/providers/rac/models.py b/authentik/enterprise/providers/rac/models.py
index d354617739..c5f866bfd6 100644
--- a/authentik/enterprise/providers/rac/models.py
+++ b/authentik/enterprise/providers/rac/models.py
@@ -52,6 +52,10 @@ class RACProvider(Provider):
"(Format: hours=-1;minutes=-2;seconds=-3)"
),
)
+ delete_token_on_disconnect = models.BooleanField(
+ default=False,
+ help_text=_("When set to true, connection tokens will be deleted upon disconnect."),
+ )
@property
def launch_url(self) -> Optional[str]:
@@ -195,3 +199,13 @@ class ConnectionToken(ExpiringModel):
continue
settings[key] = str(value)
return settings
+
+ def __str__(self):
+ return (
+ f"RAC Connection token {self.session.user} to "
+ f"{self.endpoint.provider.name}/{self.endpoint.name}"
+ )
+
+ class Meta:
+ verbose_name = _("RAC Connection token")
+ verbose_name_plural = _("RAC Connection tokens")
diff --git a/authentik/enterprise/providers/rac/signals.py b/authentik/enterprise/providers/rac/signals.py
index 20e967ddb3..28cece00ab 100644
--- a/authentik/enterprise/providers/rac/signals.py
+++ b/authentik/enterprise/providers/rac/signals.py
@@ -45,8 +45,8 @@ def pre_delete_connection_token_disconnect(sender, instance: ConnectionToken, **
@receiver(post_save, sender=Endpoint)
-def post_save_application(sender: type[Model], instance, created: bool, **_):
- """Clear user's application cache upon application creation"""
+def post_save_endpoint(sender: type[Model], instance, created: bool, **_):
+ """Clear user's endpoint cache upon endpoint creation"""
if not created: # pragma: no cover
return
diff --git a/authentik/enterprise/providers/rac/tests/test_endpoints_api.py b/authentik/enterprise/providers/rac/tests/test_endpoints_api.py
index 3000b345ce..1ad9b70daf 100644
--- a/authentik/enterprise/providers/rac/tests/test_endpoints_api.py
+++ b/authentik/enterprise/providers/rac/tests/test_endpoints_api.py
@@ -70,6 +70,7 @@ class TestEndpointsAPI(APITestCase):
"authorization_flow": None,
"property_mappings": [],
"connection_expiry": "hours=8",
+ "delete_token_on_disconnect": False,
"component": "ak-provider-rac-form",
"assigned_application_slug": self.app.slug,
"assigned_application_name": self.app.name,
@@ -124,6 +125,7 @@ class TestEndpointsAPI(APITestCase):
"assigned_application_slug": self.app.slug,
"assigned_application_name": self.app.name,
"connection_expiry": "hours=8",
+ "delete_token_on_disconnect": False,
"verbose_name": "RAC Provider",
"verbose_name_plural": "RAC Providers",
"meta_model_name": "authentik_providers_rac.racprovider",
@@ -152,6 +154,7 @@ class TestEndpointsAPI(APITestCase):
"assigned_application_slug": self.app.slug,
"assigned_application_name": self.app.name,
"connection_expiry": "hours=8",
+ "delete_token_on_disconnect": False,
"verbose_name": "RAC Provider",
"verbose_name_plural": "RAC Providers",
"meta_model_name": "authentik_providers_rac.racprovider",
diff --git a/authentik/enterprise/providers/rac/urls.py b/authentik/enterprise/providers/rac/urls.py
index b36eb998d5..8ee5e32089 100644
--- a/authentik/enterprise/providers/rac/urls.py
+++ b/authentik/enterprise/providers/rac/urls.py
@@ -6,6 +6,7 @@ from django.urls import path
from django.views.decorators.csrf import ensure_csrf_cookie
from authentik.core.channels import TokenOutpostMiddleware
+from authentik.enterprise.providers.rac.api.connection_tokens import ConnectionTokenViewSet
from authentik.enterprise.providers.rac.api.endpoints import EndpointViewSet
from authentik.enterprise.providers.rac.api.property_mappings import RACPropertyMappingViewSet
from authentik.enterprise.providers.rac.api.providers import RACProviderViewSet
@@ -45,4 +46,5 @@ api_urlpatterns = [
("providers/rac", RACProviderViewSet),
("propertymappings/rac", RACPropertyMappingViewSet),
("rac/endpoints", EndpointViewSet),
+ ("rac/connection_tokens", ConnectionTokenViewSet),
]
diff --git a/authentik/events/migrations/0005_remove_systemtask_finish_timestamp_and_more.py b/authentik/events/migrations/0005_remove_systemtask_finish_timestamp_and_more.py
index b42fb252fc..8871965b7f 100644
--- a/authentik/events/migrations/0005_remove_systemtask_finish_timestamp_and_more.py
+++ b/authentik/events/migrations/0005_remove_systemtask_finish_timestamp_and_more.py
@@ -23,18 +23,15 @@ class Migration(migrations.Migration):
model_name="systemtask",
name="duration",
field=models.FloatField(default=0),
- preserve_default=False,
),
migrations.AddField(
model_name="systemtask",
name="finish_timestamp",
field=models.DateTimeField(default=django.utils.timezone.now),
- preserve_default=False,
),
migrations.AddField(
model_name="systemtask",
name="start_timestamp",
field=models.DateTimeField(default=django.utils.timezone.now),
- preserve_default=False,
),
]
diff --git a/authentik/events/models.py b/authentik/events/models.py
index 179d9edf29..3bb2ff1458 100644
--- a/authentik/events/models.py
+++ b/authentik/events/models.py
@@ -620,9 +620,9 @@ class SystemTask(SerializerModel, ExpiringModel):
name = models.TextField()
uid = models.TextField(null=True)
- start_timestamp = models.DateTimeField()
- finish_timestamp = models.DateTimeField()
- duration = models.FloatField()
+ start_timestamp = models.DateTimeField(default=now)
+ finish_timestamp = models.DateTimeField(default=now)
+ duration = models.FloatField(default=0)
status = models.TextField(choices=TaskStatus.choices)
diff --git a/blueprints/schema.json b/blueprints/schema.json
index 6a745cebb1..bd3c1cd29f 100644
--- a/blueprints/schema.json
+++ b/blueprints/schema.json
@@ -7924,6 +7924,11 @@
"minLength": 1,
"title": "Connection expiry",
"description": "Determines how long a session lasts. Default of 0 means that the sessions lasts until the browser is closed. (Format: hours=-1;minutes=-2;seconds=-3)"
+ },
+ "delete_token_on_disconnect": {
+ "type": "boolean",
+ "title": "Delete token on disconnect",
+ "description": "When set to true, connection tokens will be deleted upon disconnect."
}
},
"required": []
diff --git a/blueprints/system/providers-rac.yaml b/blueprints/system/providers-rac.yaml
index 63a568673f..ef530cea20 100644
--- a/blueprints/system/providers-rac.yaml
+++ b/blueprints/system/providers-rac.yaml
@@ -23,6 +23,8 @@ entries:
enable-full-window-drag: "true"
enable-desktop-composition: "true"
enable-menu-animations: "true"
+ enable-wallpaper: "true"
+ enable-font-smoothing: "true"
- identifiers:
managed: goauthentik.io/providers/rac/ssh-default
model: authentik_providers_rac.racpropertymapping
diff --git a/schema.yml b/schema.yml
index 97214b0055..4c7a433d00 100644
--- a/schema.yml
+++ b/schema.yml
@@ -17818,6 +17818,252 @@ paths:
schema:
$ref: '#/components/schemas/GenericError'
description: ''
+ /rac/connection_tokens/:
+ get:
+ operationId: rac_connection_tokens_list
+ description: ConnectionToken Viewset
+ parameters:
+ - in: query
+ name: endpoint
+ schema:
+ type: string
+ format: uuid
+ - name: ordering
+ required: false
+ in: query
+ description: Which field to use when ordering the results.
+ schema:
+ type: string
+ - name: page
+ required: false
+ in: query
+ description: A page number within the paginated result set.
+ schema:
+ type: integer
+ - name: page_size
+ required: false
+ in: query
+ description: Number of results to return per page.
+ schema:
+ type: integer
+ - in: query
+ name: provider
+ schema:
+ type: integer
+ - name: search
+ required: false
+ in: query
+ description: A search term.
+ schema:
+ type: string
+ - in: query
+ name: session__user
+ schema:
+ type: integer
+ tags:
+ - rac
+ security:
+ - authentik: []
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/PaginatedConnectionTokenList'
+ description: ''
+ '400':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ValidationError'
+ description: ''
+ '403':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/GenericError'
+ description: ''
+ /rac/connection_tokens/{connection_token_uuid}/:
+ get:
+ operationId: rac_connection_tokens_retrieve
+ description: ConnectionToken Viewset
+ parameters:
+ - in: path
+ name: connection_token_uuid
+ schema:
+ type: string
+ format: uuid
+ description: A UUID string identifying this connection token.
+ required: true
+ tags:
+ - rac
+ security:
+ - authentik: []
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ConnectionToken'
+ description: ''
+ '400':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ValidationError'
+ description: ''
+ '403':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/GenericError'
+ description: ''
+ put:
+ operationId: rac_connection_tokens_update
+ description: ConnectionToken Viewset
+ parameters:
+ - in: path
+ name: connection_token_uuid
+ schema:
+ type: string
+ format: uuid
+ description: A UUID string identifying this connection token.
+ required: true
+ tags:
+ - rac
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ConnectionTokenRequest'
+ required: true
+ security:
+ - authentik: []
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ConnectionToken'
+ description: ''
+ '400':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ValidationError'
+ description: ''
+ '403':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/GenericError'
+ description: ''
+ patch:
+ operationId: rac_connection_tokens_partial_update
+ description: ConnectionToken Viewset
+ parameters:
+ - in: path
+ name: connection_token_uuid
+ schema:
+ type: string
+ format: uuid
+ description: A UUID string identifying this connection token.
+ required: true
+ tags:
+ - rac
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/PatchedConnectionTokenRequest'
+ security:
+ - authentik: []
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ConnectionToken'
+ description: ''
+ '400':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ValidationError'
+ description: ''
+ '403':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/GenericError'
+ description: ''
+ delete:
+ operationId: rac_connection_tokens_destroy
+ description: ConnectionToken Viewset
+ parameters:
+ - in: path
+ name: connection_token_uuid
+ schema:
+ type: string
+ format: uuid
+ description: A UUID string identifying this connection token.
+ required: true
+ tags:
+ - rac
+ security:
+ - authentik: []
+ responses:
+ '204':
+ description: No response body
+ '400':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ValidationError'
+ description: ''
+ '403':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/GenericError'
+ description: ''
+ /rac/connection_tokens/{connection_token_uuid}/used_by/:
+ get:
+ operationId: rac_connection_tokens_used_by_list
+ description: Get a list of all objects that use this object
+ parameters:
+ - in: path
+ name: connection_token_uuid
+ schema:
+ type: string
+ format: uuid
+ description: A UUID string identifying this connection token.
+ required: true
+ tags:
+ - rac
+ security:
+ - authentik: []
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/UsedBy'
+ description: ''
+ '400':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ValidationError'
+ description: ''
+ '403':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/GenericError'
+ description: ''
/rac/endpoints/:
get:
operationId: rac_endpoints_list
@@ -31248,6 +31494,48 @@ components:
- cache_timeout_reputation
- capabilities
- error_reporting
+ ConnectionToken:
+ type: object
+ description: ConnectionToken Serializer
+ properties:
+ pk:
+ type: string
+ format: uuid
+ readOnly: true
+ title: Pbm uuid
+ provider:
+ type: integer
+ provider_obj:
+ allOf:
+ - $ref: '#/components/schemas/RACProvider'
+ readOnly: true
+ endpoint:
+ type: string
+ format: uuid
+ readOnly: true
+ endpoint_obj:
+ allOf:
+ - $ref: '#/components/schemas/Endpoint'
+ readOnly: true
+ user:
+ allOf:
+ - $ref: '#/components/schemas/GroupMember'
+ readOnly: true
+ required:
+ - endpoint
+ - endpoint_obj
+ - pk
+ - provider
+ - provider_obj
+ - user
+ ConnectionTokenRequest:
+ type: object
+ description: ConnectionToken Serializer
+ properties:
+ provider:
+ type: integer
+ required:
+ - provider
ConsentChallenge:
type: object
description: Challenge info for consent screens
@@ -36268,6 +36556,18 @@ components:
required:
- pagination
- results
+ PaginatedConnectionTokenList:
+ type: object
+ properties:
+ pagination:
+ $ref: '#/components/schemas/Pagination'
+ results:
+ type: array
+ items:
+ $ref: '#/components/schemas/ConnectionToken'
+ required:
+ - pagination
+ - results
PaginatedConsentStageList:
type: object
properties:
@@ -37980,6 +38280,12 @@ components:
writeOnly: true
description: Optional Private Key. If this is set, you can use this keypair
for encryption.
+ PatchedConnectionTokenRequest:
+ type: object
+ description: ConnectionToken Serializer
+ properties:
+ provider:
+ type: integer
PatchedConsentStageRequest:
type: object
description: ConsentStage Serializer
@@ -39542,6 +39848,9 @@ components:
minLength: 1
description: 'Determines how long a session lasts. Default of 0 means that
the sessions lasts until the browser is closed. (Format: hours=-1;minutes=-2;seconds=-3)'
+ delete_token_on_disconnect:
+ type: boolean
+ description: When set to true, connection tokens will be deleted upon disconnect.
PatchedRadiusProviderRequest:
type: object
description: RadiusProvider Serializer
@@ -41615,6 +41924,9 @@ components:
type: string
description: 'Determines how long a session lasts. Default of 0 means that
the sessions lasts until the browser is closed. (Format: hours=-1;minutes=-2;seconds=-3)'
+ delete_token_on_disconnect:
+ type: boolean
+ description: When set to true, connection tokens will be deleted upon disconnect.
required:
- assigned_application_name
- assigned_application_slug
@@ -41656,6 +41968,9 @@ components:
minLength: 1
description: 'Determines how long a session lasts. Default of 0 means that
the sessions lasts until the browser is closed. (Format: hours=-1;minutes=-2;seconds=-3)'
+ delete_token_on_disconnect:
+ type: boolean
+ description: When set to true, connection tokens will be deleted upon disconnect.
required:
- authorization_flow
- name
diff --git a/web/src/admin/enterprise/EnterpriseLicenseForm.ts b/web/src/admin/enterprise/EnterpriseLicenseForm.ts
index ebce9938db..466a96aa71 100644
--- a/web/src/admin/enterprise/EnterpriseLicenseForm.ts
+++ b/web/src/admin/enterprise/EnterpriseLicenseForm.ts
@@ -1,3 +1,4 @@
+import { EVENT_REFRESH_ENTERPRISE } from "@goauthentik/app/common/constants";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import "@goauthentik/elements/CodeMirror";
import "@goauthentik/elements/forms/HorizontalFormElement";
@@ -34,14 +35,19 @@ export class EnterpriseLicenseForm extends ModelForm
+ ${msg( + "When enabled, connection authorizations will be deleted when a client disconnects. This will force clients with flaky internet connections to re-authorize the endpoint.", + )} +
+