make --schema-name default to public in mgmt commands

Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
This commit is contained in:
Marc 'risson' Schmitt 2023-12-07 09:26:44 +01:00
parent b151e27689
commit 1db9038830
No known key found for this signature in database
GPG Key ID: 9C3FA22FABF1AA8D
15 changed files with 82 additions and 95 deletions

View File

@ -1,24 +1,18 @@
"""Export blueprint of current authentik install""" """Export blueprint of current authentik install"""
from django.core.management.base import BaseCommand, no_translations from django.core.management.base import no_translations
from django_tenants.management.commands import TenantWrappedCommand
from structlog.stdlib import get_logger from structlog.stdlib import get_logger
from authentik.blueprints.v1.exporter import Exporter from authentik.blueprints.v1.exporter import Exporter
from authentik.tenants.management import TenantCommand
LOGGER = get_logger() LOGGER = get_logger()
class TCommand(BaseCommand): class Command(TenantCommand):
"""Export blueprint of current authentik install""" """Export blueprint of current authentik install"""
@no_translations @no_translations
def handle(self, *args, **options): def handle_per_tenant(self, *args, **options):
"""Export blueprint of current authentik install""" """Export blueprint of current authentik install"""
exporter = Exporter() exporter = Exporter()
self.stdout.write(exporter.export_to_string()) self.stdout.write(exporter.export_to_string())
class Command(TenantWrappedCommand):
"""Export blueprint of current authentik install"""
COMMAND = TCommand

View File

@ -1,22 +1,22 @@
"""Import certificate""" """Import certificate"""
from sys import exit as sys_exit from sys import exit as sys_exit
from django.core.management.base import BaseCommand, no_translations from django.core.management.base import no_translations
from django_tenants.management.commands import TenantWrappedCommand
from rest_framework.exceptions import ValidationError from rest_framework.exceptions import ValidationError
from structlog.stdlib import get_logger from structlog.stdlib import get_logger
from authentik.crypto.api import CertificateKeyPairSerializer from authentik.crypto.api import CertificateKeyPairSerializer
from authentik.crypto.models import CertificateKeyPair from authentik.crypto.models import CertificateKeyPair
from authentik.tenants.management import TenantCommand
LOGGER = get_logger() LOGGER = get_logger()
class TCommand(BaseCommand): class Command(TenantCommand):
"""Import certificate""" """Import certificate"""
@no_translations @no_translations
def handle(self, *args, **options): def handle_per_tenant(self, *args, **options):
"""Import certificate""" """Import certificate"""
keypair = CertificateKeyPair.objects.filter(name=options["name"]).first() keypair = CertificateKeyPair.objects.filter(name=options["name"]).first()
dirty = False dirty = False
@ -50,9 +50,3 @@ class TCommand(BaseCommand):
parser.add_argument("--certificate", type=str, required=True) parser.add_argument("--certificate", type=str, required=True)
parser.add_argument("--private-key", type=str, required=False) parser.add_argument("--private-key", type=str, required=False)
parser.add_argument("--name", type=str, required=True) parser.add_argument("--name", type=str, required=True)
class Command(TenantWrappedCommand):
"""Import certificate"""
COMMAND = TCommand

View File

@ -1,30 +1,23 @@
"""SCIM Sync""" """SCIM Sync"""
from django.core.management.base import BaseCommand
from django_tenants.management.commands import TenantWrappedCommand
from structlog.stdlib import get_logger from structlog.stdlib import get_logger
from authentik.providers.scim.models import SCIMProvider from authentik.providers.scim.models import SCIMProvider
from authentik.providers.scim.tasks import scim_sync from authentik.providers.scim.tasks import scim_sync
from authentik.tenants.management import TenantCommand
LOGGER = get_logger() LOGGER = get_logger()
class TCommand(BaseCommand): class Command(TenantCommand):
"""Run sync for an SCIM Provider""" """Run sync for an SCIM Provider"""
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument("providers", nargs="+", type=str) parser.add_argument("providers", nargs="+", type=str)
def handle(self, **options): def handle_per_tenant(self, **options):
for provider_name in options["providers"]: for provider_name in options["providers"]:
provider = SCIMProvider.objects.filter(name=provider_name).first() provider = SCIMProvider.objects.filter(name=provider_name).first()
if not provider: if not provider:
LOGGER.warning("Provider does not exist", name=provider_name) LOGGER.warning("Provider does not exist", name=provider_name)
continue continue
scim_sync.delay(provider.pk).get() scim_sync.delay(provider.pk).get()
class Command(TenantWrappedCommand):
"""Run sync for an SCIM Provider"""
COMMAND = TCommand

View File

@ -1,12 +1,11 @@
"""authentik recovery create_admin_group""" """authentik recovery create_admin_group"""
from django.core.management.base import BaseCommand
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from django_tenants.management.commands import TenantWrappedCommand
from authentik.core.models import Group, User from authentik.core.models import Group, User
from authentik.tenants.management import TenantCommand
class TCommand(BaseCommand): class Command(TenantCommand):
"""Create admin group if the default group gets deleted""" """Create admin group if the default group gets deleted"""
help = _("Create admin group if the default group gets deleted.") help = _("Create admin group if the default group gets deleted.")
@ -14,7 +13,7 @@ class TCommand(BaseCommand):
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument("user", action="store", help="User to add to the admin group.") parser.add_argument("user", action="store", help="User to add to the admin group.")
def handle(self, *args, **options): def handle_per_tenant(self, *args, **options):
"""Create admin group if the default group gets deleted""" """Create admin group if the default group gets deleted"""
username = options.get("user") username = options.get("user")
user = User.objects.filter(username=username).first() user = User.objects.filter(username=username).first()
@ -29,9 +28,3 @@ class TCommand(BaseCommand):
) )
group.users.add(user) group.users.add(user)
self.stdout.write(f"User '{username}' successfully added to the group 'authentik Admins'.") self.stdout.write(f"User '{username}' successfully added to the group 'authentik Admins'.")
class Command(TenantWrappedCommand):
"""Create admin group if the default group gets deleted"""
COMMAND = TCommand

View File

@ -2,17 +2,16 @@
from datetime import timedelta from datetime import timedelta
from getpass import getuser from getpass import getuser
from django.core.management.base import BaseCommand
from django.urls import reverse from django.urls import reverse
from django.utils.text import slugify from django.utils.text import slugify
from django.utils.timezone import now from django.utils.timezone import now
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from django_tenants.management.commands import TenantWrappedCommand
from authentik.core.models import Token, TokenIntents, User from authentik.core.models import Token, TokenIntents, User
from authentik.tenants.management import TenantCommand
class TCommand(BaseCommand): class Command(TenantCommand):
"""Create Token used to recover access""" """Create Token used to recover access"""
help = _("Create a Key which can be used to restore access to authentik.") help = _("Create a Key which can be used to restore access to authentik.")
@ -30,7 +29,7 @@ class TCommand(BaseCommand):
"""Get full recovery link""" """Get full recovery link"""
return reverse("authentik_recovery:use-token", kwargs={"key": str(token.key)}) return reverse("authentik_recovery:use-token", kwargs={"key": str(token.key)})
def handle(self, *args, **options): def handle_per_tenant(self, *args, **options):
"""Create Token used to recover access""" """Create Token used to recover access"""
duration = int(options.get("duration", 1)) duration = int(options.get("duration", 1))
_now = now() _now = now()
@ -51,9 +50,3 @@ class TCommand(BaseCommand):
f"Store this link safely, as it will allow anyone to access authentik as {user}." f"Store this link safely, as it will allow anyone to access authentik as {user}."
) )
self.stdout.write(self.get_url(token)) self.stdout.write(self.get_url(token))
class Command(TenantWrappedCommand):
"""Create Token used to recover access"""
COMMAND = TCommand

View File

@ -1,31 +1,24 @@
"""LDAP Connection check""" """LDAP Connection check"""
from json import dumps from json import dumps
from django.core.management.base import BaseCommand
from django_tenants.management.commands import TenantWrappedCommand
from structlog.stdlib import get_logger from structlog.stdlib import get_logger
from authentik.sources.ldap.models import LDAPSource from authentik.sources.ldap.models import LDAPSource
from authentik.tenants.management import TenantCommand
LOGGER = get_logger() LOGGER = get_logger()
class TCommand(BaseCommand): class Command(TenantCommand):
"""Check connectivity to LDAP servers for a source""" """Check connectivity to LDAP servers for a source"""
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument("source_slugs", nargs="?", type=str) parser.add_argument("source_slugs", nargs="?", type=str)
def handle(self, **options): def handle_per_tenant(self, **options):
sources = LDAPSource.objects.filter(enabled=True) sources = LDAPSource.objects.filter(enabled=True)
if options["source_slugs"]: if options["source_slugs"]:
sources = LDAPSource.objects.filter(slug__in=options["source_slugs"]) sources = LDAPSource.objects.filter(slug__in=options["source_slugs"])
for source in sources.order_by("slug"): for source in sources.order_by("slug"):
status = source.check_connection() status = source.check_connection()
self.stdout.write(dumps(status, indent=4)) self.stdout.write(dumps(status, indent=4))
class Command(TenantWrappedCommand):
"""Check connectivity to LDAP servers for a source"""
COMMAND = TCommand

View File

@ -1,6 +1,4 @@
"""LDAP Sync""" """LDAP Sync"""
from django.core.management.base import BaseCommand
from django_tenants.management.commands import TenantWrappedCommand
from structlog.stdlib import get_logger from structlog.stdlib import get_logger
from authentik.sources.ldap.models import LDAPSource from authentik.sources.ldap.models import LDAPSource
@ -8,17 +6,18 @@ from authentik.sources.ldap.sync.groups import GroupLDAPSynchronizer
from authentik.sources.ldap.sync.membership import MembershipLDAPSynchronizer from authentik.sources.ldap.sync.membership import MembershipLDAPSynchronizer
from authentik.sources.ldap.sync.users import UserLDAPSynchronizer from authentik.sources.ldap.sync.users import UserLDAPSynchronizer
from authentik.sources.ldap.tasks import ldap_sync_paginator from authentik.sources.ldap.tasks import ldap_sync_paginator
from authentik.tenants.management import TenantCommand
LOGGER = get_logger() LOGGER = get_logger()
class TCommand(BaseCommand): class Command(TenantCommand):
"""Run sync for an LDAP Source""" """Run sync for an LDAP Source"""
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument("source_slugs", nargs="+", type=str) parser.add_argument("source_slugs", nargs="+", type=str)
def handle(self, **options): def handle_per_tenant(self, **options):
for source_slug in options["source_slugs"]: for source_slug in options["source_slugs"]:
source = LDAPSource.objects.filter(slug=source_slug).first() source = LDAPSource.objects.filter(slug=source_slug).first()
if not source: if not source:
@ -31,9 +30,3 @@ class TCommand(BaseCommand):
) )
for task in tasks: for task in tasks:
task() task()
class Command(TenantWrappedCommand):
"""Run sync for an LDAP Source"""
COMMAND = TCommand

View File

@ -1,19 +1,19 @@
"""Send a test-email with global settings""" """Send a test-email with global settings"""
from uuid import uuid4 from uuid import uuid4
from django.core.management.base import BaseCommand, no_translations from django.core.management.base import no_translations
from django_tenants.management.commands import TenantWrappedCommand
from authentik.stages.email.models import EmailStage from authentik.stages.email.models import EmailStage
from authentik.stages.email.tasks import send_mail from authentik.stages.email.tasks import send_mail
from authentik.stages.email.utils import TemplateEmailMessage from authentik.stages.email.utils import TemplateEmailMessage
from authentik.tenants.management import TenantCommand
class TCommand(BaseCommand): class Command(TenantCommand):
"""Send a test-email with global settings""" """Send a test-email with global settings"""
@no_translations @no_translations
def handle(self, *args, **options): def handle_per_tenant(self, *args, **options):
"""Send a test-email with global settings""" """Send a test-email with global settings"""
delete_stage = False delete_stage = False
if options["stage"]: if options["stage"]:
@ -42,9 +42,3 @@ class TCommand(BaseCommand):
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument("to", type=str) parser.add_argument("to", type=str)
parser.add_argument("-S", "--stage", type=str) parser.add_argument("-S", "--stage", type=str)
class Command(TenantWrappedCommand):
"""Send a test-email with global settings"""
COMMAND = TCommand

View File

@ -0,0 +1,40 @@
from django.core.management.base import BaseCommand
from django.db import connection
from django_tenants.utils import get_public_schema_name
from authentik.tenants.models import Tenant
class TenantCommand(BaseCommand):
"""Generic command class useful for running any existing command
on a particular tenant."""
def create_parser(self, prog_name, subcommand, **kwargs):
parser = super().create_parser(prog_name, subcommand, **kwargs)
self.add_base_argument(
parser,
"-s",
"--schema",
default=get_public_schema_name(),
help="Tenant schema name.",
dest="schema_name",
)
return parser
def handle(self, *args, **options):
verbosity = int(options.get("verbosity"))
schema_name = options["schema_name"] or self.schema_name
connection.set_schema_to_public()
if verbosity >= 1:
self.stderr.write(
self.style.NOTICE("Switching to schema '")
+ self.style.SQL_TABLE(schema_name)
+ self.style.NOTICE("'")
)
connection.set_tenant(Tenant.objects.get(schema_name=schema_name))
self.handle_per_tenant(*args, **options)
def handle_per_tenant(self, *args, **options):
raise NotImplementedError(
"subclasses of TenantCommand must provide a handle_per_tenant() method"
)

View File

@ -8,7 +8,7 @@ title: Export
Requires authentik 2022.8.2 Requires authentik 2022.8.2
::: :::
To migrate existing configurations to blueprints, run `ak export_blueprint --schema public` within any authentik Worker container. This will output a blueprint for most currently created objects. Some objects will not be exported as they might have dependencies on other things. To migrate existing configurations to blueprints, run `ak export_blueprint` within any authentik Worker container. This will output a blueprint for most currently created objects. Some objects will not be exported as they might have dependencies on other things.
Exported blueprints don't use any of the YAML Tags, they just contain a list of entries as they are in the database. Exported blueprints don't use any of the YAML Tags, they just contain a list of entries as they are in the database.

View File

@ -62,9 +62,9 @@ Files are checked every 5 minutes, and will trigger an Outpost refresh if the fi
Starting with authentik 2022.9, you can also import certificates with any folder structure directly. To do this, run the following command within the worker container: Starting with authentik 2022.9, you can also import certificates with any folder structure directly. To do this, run the following command within the worker container:
```shell ```shell
ak import_certificate --schema public --certificate /certs/mycert.pem --private-key /certs/something.pem --name test ak import_certificate --certificate /certs/mycert.pem --private-key /certs/something.pem --name test
# --private-key can be omitted to only import a certificate, i.e. to trust other connections # --private-key can be omitted to only import a certificate, i.e. to trust other connections
# ak import_certificate --schema public --certificate /certs/othercert.pem --name test2 # ak import_certificate --certificate /certs/othercert.pem --name test2
``` ```
This will import the certificate into authentik under the given name. This command is idempotent, meaning you can run it via a cron-job and authentik will only update the certificate when it changes. This will import the certificate into authentik under the given name. This command is idempotent, meaning you can run it via a cron-job and authentik will only update the certificate when it changes.

View File

@ -9,7 +9,7 @@ Some hosting providers block outgoing SMTP ports, in which case you'll have to h
To test if an email stage, or the global email settings are configured correctly, you can run the following command: To test if an email stage, or the global email settings are configured correctly, you can run the following command:
``` ```
ak test_email --schema public <to address> [-S <stage name>] ak test_email <to address> [-S <stage name>]
``` ```
If you omit the `-S` parameter, the email will be sent using the global settings. Otherwise, the settings of the specified stage will be used. If you omit the `-S` parameter, the email will be sent using the global settings. Otherwise, the settings of the specified stage will be used.
@ -17,11 +17,11 @@ If you omit the `-S` parameter, the email will be sent using the global settings
To run this command with docker-compose, use To run this command with docker-compose, use
``` ```
docker-compose exec worker ak test_email --schema public [...] docker-compose exec worker ak test_email [...]
``` ```
To run this command with Kubernetes, use To run this command with Kubernetes, use
``` ```
kubectl exec -it deployment/authentik-worker -c authentik -- ak test_email --schema public [...] kubectl exec -it deployment/authentik-worker -c authentik -- ak test_email [...]
``` ```

View File

@ -5,23 +5,23 @@ title: Troubleshooting LDAP Synchronization
To troubleshoot LDAP sources, you can run the command below to run a synchronization in the foreground and see any errors or warnings that might happen directly To troubleshoot LDAP sources, you can run the command below to run a synchronization in the foreground and see any errors or warnings that might happen directly
``` ```
docker-compose run --rm worker ldap_sync --schema public *slug of the source* docker-compose run --rm worker ldap_sync *slug of the source*
``` ```
or, for Kubernetes, run or, for Kubernetes, run
``` ```
kubectl exec -it deployment/authentik-worker -c authentik -- ak ldap_sync --schema public *slug of the source* kubectl exec -it deployment/authentik-worker -c authentik -- ak ldap_sync *slug of the source*
``` ```
Starting with authentik 2023.10, you can also run command below to explicitly check the connectivity to the configured LDAP Servers: Starting with authentik 2023.10, you can also run command below to explicitly check the connectivity to the configured LDAP Servers:
``` ```
docker-compose run --rm worker ldap_check_connection --schema public *slug of the source* docker-compose run --rm worker ldap_check_connection *slug of the source*
``` ```
or, for Kubernetes, run or, for Kubernetes, run
``` ```
kubectl exec -it deployment/authentik-worker -c authentik -- ak ldap_check_connection --schema public *slug of the source* kubectl exec -it deployment/authentik-worker -c authentik -- ak ldap_check_connection *slug of the source*
``` ```

View File

@ -11,19 +11,19 @@ This recovery key will give whoever has the link direct access to your instances
To create the key, run the following command: To create the key, run the following command:
``` ```
docker-compose run --rm server create_recovery_key --schema public 10 akadmin docker-compose run --rm server create_recovery_key 10 akadmin
``` ```
For Kubernetes, run For Kubernetes, run
``` ```
kubectl exec -it deployment/authentik-worker -c authentik -- ak create_recovery_key --schema public 10 akadmin kubectl exec -it deployment/authentik-worker -c authentik -- ak create_recovery_key 10 akadmin
``` ```
or, for CLI, run or, for CLI, run
``` ```
ak create_recovery_key 10 --schema public akadmin ak create_recovery_key 10 akadmin
``` ```
This will output a link, that can be used to instantly gain access to authentik as the user specified above. The link is valid for amount of years specified above, in this case, 10 years. This will output a link, that can be used to instantly gain access to authentik as the user specified above. The link is valid for amount of years specified above, in this case, 10 years.

View File

@ -7,11 +7,11 @@ If all of the Admin groups have been deleted, or misconfigured during sync, you
Run the following command, where _username_ is the user you want to add to the newly created group: Run the following command, where _username_ is the user you want to add to the newly created group:
``` ```
docker-compose run --rm server create_admin_group --schema public username docker-compose run --rm server create_admin_group username
``` ```
or, for Kubernetes, run or, for Kubernetes, run
``` ```
kubectl exec -it deployment/authentik-worker -c authentik -- ak create_admin_group --schema public username kubectl exec -it deployment/authentik-worker -c authentik -- ak create_admin_group username
``` ```