diff --git a/authentik/core/migrations/0046_session_and_more.py b/authentik/core/migrations/0046_session_and_more.py index 1a681ea1f5..1b52b1d65f 100644 --- a/authentik/core/migrations/0046_session_and_more.py +++ b/authentik/core/migrations/0046_session_and_more.py @@ -79,6 +79,7 @@ def _migrate_session( AuthenticatedSession.objects.using(db_alias).create( session=session, user=old_auth_session.user, + uuid=old_auth_session.uuid, ) diff --git a/authentik/core/migrations/0048_delete_oldauthenticatedsession_content_type.py b/authentik/core/migrations/0048_delete_oldauthenticatedsession_content_type.py index d79f14a74a..09a1027e39 100644 --- a/authentik/core/migrations/0048_delete_oldauthenticatedsession_content_type.py +++ b/authentik/core/migrations/0048_delete_oldauthenticatedsession_content_type.py @@ -1,10 +1,81 @@ # Generated by Django 5.1.9 on 2025-05-14 11:15 -from django.apps.registry import Apps +from django.apps.registry import Apps, apps as global_apps from django.db import migrations +from django.contrib.contenttypes.management import create_contenttypes +from django.contrib.auth.management import create_permissions from django.db.backends.base.schema import BaseDatabaseSchemaEditor +def migrate_authenticated_session_permissions(apps: Apps, schema_editor: BaseDatabaseSchemaEditor): + """Migrate permissions from OldAuthenticatedSession to AuthenticatedSession""" + db_alias = schema_editor.connection.alias + + # `apps` here is just an instance of `django.db.migrations.state.AppConfigStub`, we need the + # real config for creating permissions and content types + authentik_core_config = global_apps.get_app_config("authentik_core") + # These are only ran by django after all migrations, but we need them right now. + # `global_apps` is needed, + create_permissions(authentik_core_config, using=db_alias, verbosity=1) + create_contenttypes(authentik_core_config, using=db_alias, verbosity=1) + + # But from now on, this is just a regular migration, so use `apps` + Permission = apps.get_model("auth", "Permission") + ContentType = apps.get_model("contenttypes", "ContentType") + + try: + old_ct = ContentType.objects.using(db_alias).get( + app_label="authentik_core", model="oldauthenticatedsession" + ) + new_ct = ContentType.objects.using(db_alias).get( + app_label="authentik_core", model="authenticatedsession" + ) + except ContentType.DoesNotExist: + # This should exist at this point, but if not, let's cut our losses + return + + # Get all permissions for the old content type + old_perms = Permission.objects.using(db_alias).filter(content_type=old_ct) + + # Create equivalent permissions for the new content type + for old_perm in old_perms: + new_perm = ( + Permission.objects.using(db_alias) + .filter( + content_type=new_ct, + codename=old_perm.codename, + ) + .first() + ) + if not new_perm: + # This should exist at this point, but if not, let's cut our losses + continue + + # Global user permissions + User = apps.get_model("authentik_core", "User") + User.user_permissions.through.objects.using(db_alias).filter( + permission=old_perm + ).all().update(permission=new_perm) + + # Global role permissions + DjangoGroup = apps.get_model("auth", "Group") + DjangoGroup.permissions.through.objects.using(db_alias).filter( + permission=old_perm + ).all().update(permission=new_perm) + + # Object user permissions + UserObjectPermission = apps.get_model("guardian", "UserObjectPermission") + UserObjectPermission.objects.using(db_alias).filter(permission=old_perm).all().update( + permission=new_perm, content_type=new_ct + ) + + # Object role permissions + GroupObjectPermission = apps.get_model("guardian", "GroupObjectPermission") + GroupObjectPermission.objects.using(db_alias).filter(permission=old_perm).all().update( + permission=new_perm, content_type=new_ct + ) + + def remove_old_authenticated_session_content_type( apps: Apps, schema_editor: BaseDatabaseSchemaEditor ): @@ -21,7 +92,12 @@ class Migration(migrations.Migration): ] operations = [ + migrations.RunPython( + code=migrate_authenticated_session_permissions, + reverse_code=migrations.RunPython.noop, + ), migrations.RunPython( code=remove_old_authenticated_session_content_type, + reverse_code=migrations.RunPython.noop, ), ]