Compare commits
	
		
			10 Commits
		
	
	
		
			web/legibi
			...
			enterprise
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 60000812fd | |||
| 929e70669a | |||
| 36114284bf | |||
| a65ea0de94 | |||
| 2056b0cbee | |||
| af85ddf60b | |||
| e8e42261e3 | |||
| 9fda4e91ad | |||
| a11f1258e1 | |||
| a97578ac62 | 
							
								
								
									
										2
									
								
								.github/workflows/ci-main.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/ci-main.yml
									
									
									
									
										vendored
									
									
								
							@ -168,6 +168,8 @@ jobs:
 | 
				
			|||||||
            glob: tests/e2e/test_provider_saml* tests/e2e/test_source_saml*
 | 
					            glob: tests/e2e/test_provider_saml* tests/e2e/test_source_saml*
 | 
				
			||||||
          - name: ldap
 | 
					          - name: ldap
 | 
				
			||||||
            glob: tests/e2e/test_provider_ldap* tests/e2e/test_source_ldap*
 | 
					            glob: tests/e2e/test_provider_ldap* tests/e2e/test_source_ldap*
 | 
				
			||||||
 | 
					          - name: rac
 | 
				
			||||||
 | 
					            glob: tests/e2e/test_provider_rac*
 | 
				
			||||||
          - name: radius
 | 
					          - name: radius
 | 
				
			||||||
            glob: tests/e2e/test_provider_radius*
 | 
					            glob: tests/e2e/test_provider_radius*
 | 
				
			||||||
          - name: scim
 | 
					          - name: scim
 | 
				
			||||||
 | 
				
			|||||||
@ -31,6 +31,8 @@ class PytestTestRunner(DiscoverRunner):  # pragma: no cover
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        if kwargs.get("randomly_seed", None):
 | 
					        if kwargs.get("randomly_seed", None):
 | 
				
			||||||
            self.args.append(f"--randomly-seed={kwargs['randomly_seed']}")
 | 
					            self.args.append(f"--randomly-seed={kwargs['randomly_seed']}")
 | 
				
			||||||
 | 
					        if kwargs.get("no_capture"):
 | 
				
			||||||
 | 
					            self.args.append("-s")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        settings.TEST = True
 | 
					        settings.TEST = True
 | 
				
			||||||
        settings.CELERY["task_always_eager"] = True
 | 
					        settings.CELERY["task_always_eager"] = True
 | 
				
			||||||
@ -56,6 +58,10 @@ class PytestTestRunner(DiscoverRunner):  # pragma: no cover
 | 
				
			|||||||
    def add_arguments(cls, parser: ArgumentParser):
 | 
					    def add_arguments(cls, parser: ArgumentParser):
 | 
				
			||||||
        """Add more pytest-specific arguments"""
 | 
					        """Add more pytest-specific arguments"""
 | 
				
			||||||
        DiscoverRunner.add_arguments(parser)
 | 
					        DiscoverRunner.add_arguments(parser)
 | 
				
			||||||
 | 
					        parser.add_argument(
 | 
				
			||||||
 | 
					            "--no-capture",
 | 
				
			||||||
 | 
					            action="store_true",
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
        parser.add_argument(
 | 
					        parser.add_argument(
 | 
				
			||||||
            "--randomly-seed",
 | 
					            "--randomly-seed",
 | 
				
			||||||
            type=int,
 | 
					            type=int,
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										44
									
								
								tests/e2e/_process.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								tests/e2e/_process.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,44 @@
 | 
				
			|||||||
 | 
					"""authentik e2e testing utilities"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from datetime import timedelta
 | 
				
			||||||
 | 
					from time import mktime
 | 
				
			||||||
 | 
					from unittest.mock import MagicMock, patch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from daphne.testing import DaphneProcess
 | 
				
			||||||
 | 
					from django import setup as django_setup
 | 
				
			||||||
 | 
					from django.conf import settings
 | 
				
			||||||
 | 
					from django.utils.timezone import now
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from authentik.lib.config import CONFIG
 | 
				
			||||||
 | 
					from authentik.lib.generators import generate_id
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TestDatabaseProcess(DaphneProcess):
 | 
				
			||||||
 | 
					    """Channels does not correctly switch to the test database by default.
 | 
				
			||||||
 | 
					    https://github.com/django/channels/issues/2048"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def run(self):
 | 
				
			||||||
 | 
					        if not settings.configured:  # Fix For raise AppRegistryNotReady("Apps aren't loaded yet.")
 | 
				
			||||||
 | 
					            django_setup()  # Ensure Django is fully set up before using settings
 | 
				
			||||||
 | 
					        if not settings.DATABASES[list(settings.DATABASES.keys())[0]]["NAME"].startswith("test_"):
 | 
				
			||||||
 | 
					            for _, db_settings in settings.DATABASES.items():
 | 
				
			||||||
 | 
					                db_settings["NAME"] = f"test_{db_settings['NAME']}"
 | 
				
			||||||
 | 
					        settings.TEST = True
 | 
				
			||||||
 | 
					        from authentik.enterprise.license import LicenseKey
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        with (
 | 
				
			||||||
 | 
					            patch(
 | 
				
			||||||
 | 
					                "authentik.enterprise.license.LicenseKey.validate",
 | 
				
			||||||
 | 
					                MagicMock(
 | 
				
			||||||
 | 
					                    return_value=LicenseKey(
 | 
				
			||||||
 | 
					                        aud="",
 | 
				
			||||||
 | 
					                        exp=int(mktime((now() + timedelta(days=3000)).timetuple())),
 | 
				
			||||||
 | 
					                        name=generate_id(),
 | 
				
			||||||
 | 
					                        internal_users=100,
 | 
				
			||||||
 | 
					                        external_users=100,
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            CONFIG.patch("email.port", 1025),
 | 
				
			||||||
 | 
					        ):
 | 
				
			||||||
 | 
					            return super().run()
 | 
				
			||||||
@ -1,7 +1,6 @@
 | 
				
			|||||||
"""LDAP and Outpost e2e tests"""
 | 
					"""LDAP and Outpost e2e tests"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from dataclasses import asdict
 | 
					from dataclasses import asdict
 | 
				
			||||||
from time import sleep
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
from guardian.shortcuts import assign_perm
 | 
					from guardian.shortcuts import assign_perm
 | 
				
			||||||
from ldap3 import ALL, ALL_ATTRIBUTES, ALL_OPERATIONAL_ATTRIBUTES, SUBTREE, Connection, Server
 | 
					from ldap3 import ALL, ALL_ATTRIBUTES, ALL_OPERATIONAL_ATTRIBUTES, SUBTREE, Connection, Server
 | 
				
			||||||
@ -56,17 +55,7 @@ class TestProviderLDAP(SeleniumTestCase):
 | 
				
			|||||||
        outpost.providers.add(ldap)
 | 
					        outpost.providers.add(ldap)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.start_ldap(outpost)
 | 
					        self.start_ldap(outpost)
 | 
				
			||||||
 | 
					        self.wait_for_outpost(outpost)
 | 
				
			||||||
        # Wait until outpost healthcheck succeeds
 | 
					 | 
				
			||||||
        healthcheck_retries = 0
 | 
					 | 
				
			||||||
        while healthcheck_retries < 50:  # noqa: PLR2004
 | 
					 | 
				
			||||||
            if len(outpost.state) > 0:
 | 
					 | 
				
			||||||
                state = outpost.state[0]
 | 
					 | 
				
			||||||
                if state.last_seen:
 | 
					 | 
				
			||||||
                    break
 | 
					 | 
				
			||||||
            healthcheck_retries += 1
 | 
					 | 
				
			||||||
            sleep(0.5)
 | 
					 | 
				
			||||||
        sleep(5)
 | 
					 | 
				
			||||||
        return outpost
 | 
					        return outpost
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @retry()
 | 
					    @retry()
 | 
				
			||||||
 | 
				
			|||||||
@ -7,7 +7,6 @@ from sys import platform
 | 
				
			|||||||
from time import sleep
 | 
					from time import sleep
 | 
				
			||||||
from unittest.case import skip, skipUnless
 | 
					from unittest.case import skip, skipUnless
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from channels.testing import ChannelsLiveServerTestCase
 | 
					 | 
				
			||||||
from jwt import decode
 | 
					from jwt import decode
 | 
				
			||||||
from selenium.webdriver.common.by import By
 | 
					from selenium.webdriver.common.by import By
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -87,17 +86,7 @@ class TestProviderProxy(SeleniumTestCase):
 | 
				
			|||||||
        outpost.build_user_permissions(outpost.user)
 | 
					        outpost.build_user_permissions(outpost.user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.start_proxy(outpost)
 | 
					        self.start_proxy(outpost)
 | 
				
			||||||
 | 
					        self.wait_for_outpost(outpost)
 | 
				
			||||||
        # Wait until outpost healthcheck succeeds
 | 
					 | 
				
			||||||
        healthcheck_retries = 0
 | 
					 | 
				
			||||||
        while healthcheck_retries < 50:  # noqa: PLR2004
 | 
					 | 
				
			||||||
            if len(outpost.state) > 0:
 | 
					 | 
				
			||||||
                state = outpost.state[0]
 | 
					 | 
				
			||||||
                if state.last_seen:
 | 
					 | 
				
			||||||
                    break
 | 
					 | 
				
			||||||
            healthcheck_retries += 1
 | 
					 | 
				
			||||||
            sleep(0.5)
 | 
					 | 
				
			||||||
        sleep(5)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.driver.get("http://localhost:9000/api")
 | 
					        self.driver.get("http://localhost:9000/api")
 | 
				
			||||||
        self.login()
 | 
					        self.login()
 | 
				
			||||||
@ -168,17 +157,7 @@ class TestProviderProxy(SeleniumTestCase):
 | 
				
			|||||||
        outpost.build_user_permissions(outpost.user)
 | 
					        outpost.build_user_permissions(outpost.user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.start_proxy(outpost)
 | 
					        self.start_proxy(outpost)
 | 
				
			||||||
 | 
					        self.wait_for_outpost(outpost)
 | 
				
			||||||
        # Wait until outpost healthcheck succeeds
 | 
					 | 
				
			||||||
        healthcheck_retries = 0
 | 
					 | 
				
			||||||
        while healthcheck_retries < 50:  # noqa: PLR2004
 | 
					 | 
				
			||||||
            if len(outpost.state) > 0:
 | 
					 | 
				
			||||||
                state = outpost.state[0]
 | 
					 | 
				
			||||||
                if state.last_seen:
 | 
					 | 
				
			||||||
                    break
 | 
					 | 
				
			||||||
            healthcheck_retries += 1
 | 
					 | 
				
			||||||
            sleep(0.5)
 | 
					 | 
				
			||||||
        sleep(5)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.driver.get("http://localhost:9000/api")
 | 
					        self.driver.get("http://localhost:9000/api")
 | 
				
			||||||
        self.login()
 | 
					        self.login()
 | 
				
			||||||
@ -202,7 +181,7 @@ class TestProviderProxy(SeleniumTestCase):
 | 
				
			|||||||
# TODO: Fix flaky test
 | 
					# TODO: Fix flaky test
 | 
				
			||||||
@skip("Flaky test")
 | 
					@skip("Flaky test")
 | 
				
			||||||
@skipUnless(platform.startswith("linux"), "requires local docker")
 | 
					@skipUnless(platform.startswith("linux"), "requires local docker")
 | 
				
			||||||
class TestProviderProxyConnect(ChannelsLiveServerTestCase):
 | 
					class TestProviderProxyConnect(SeleniumTestCase):
 | 
				
			||||||
    """Test Proxy connectivity over websockets"""
 | 
					    """Test Proxy connectivity over websockets"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @retry(exceptions=[AssertionError])
 | 
					    @retry(exceptions=[AssertionError])
 | 
				
			||||||
@ -239,16 +218,7 @@ class TestProviderProxyConnect(ChannelsLiveServerTestCase):
 | 
				
			|||||||
        )
 | 
					        )
 | 
				
			||||||
        outpost.providers.add(proxy)
 | 
					        outpost.providers.add(proxy)
 | 
				
			||||||
        outpost.build_user_permissions(outpost.user)
 | 
					        outpost.build_user_permissions(outpost.user)
 | 
				
			||||||
 | 
					        self.wait_for_outpost(outpost)
 | 
				
			||||||
        # Wait until outpost healthcheck succeeds
 | 
					 | 
				
			||||||
        healthcheck_retries = 0
 | 
					 | 
				
			||||||
        while healthcheck_retries < 50:  # noqa: PLR2004
 | 
					 | 
				
			||||||
            if len(outpost.state) > 0:
 | 
					 | 
				
			||||||
                state = outpost.state[0]
 | 
					 | 
				
			||||||
                if state.last_seen and state.version:
 | 
					 | 
				
			||||||
                    break
 | 
					 | 
				
			||||||
            healthcheck_retries += 1
 | 
					 | 
				
			||||||
            sleep(0.5)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        state = outpost.state
 | 
					        state = outpost.state
 | 
				
			||||||
        self.assertGreaterEqual(len(state), 1)
 | 
					        self.assertGreaterEqual(len(state), 1)
 | 
				
			||||||
 | 
				
			|||||||
@ -76,17 +76,7 @@ class TestProviderProxyForward(SeleniumTestCase):
 | 
				
			|||||||
        outpost.build_user_permissions(outpost.user)
 | 
					        outpost.build_user_permissions(outpost.user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.start_outpost(outpost)
 | 
					        self.start_outpost(outpost)
 | 
				
			||||||
 | 
					        self.wait_for_outpost(outpost)
 | 
				
			||||||
        # Wait until outpost healthcheck succeeds
 | 
					 | 
				
			||||||
        healthcheck_retries = 0
 | 
					 | 
				
			||||||
        while healthcheck_retries < 50:  # noqa: PLR2004
 | 
					 | 
				
			||||||
            if len(outpost.state) > 0:
 | 
					 | 
				
			||||||
                state = outpost.state[0]
 | 
					 | 
				
			||||||
                if state.last_seen:
 | 
					 | 
				
			||||||
                    break
 | 
					 | 
				
			||||||
            healthcheck_retries += 1
 | 
					 | 
				
			||||||
            sleep(0.5)
 | 
					 | 
				
			||||||
        sleep(5)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @retry()
 | 
					    @retry()
 | 
				
			||||||
    def test_traefik(self):
 | 
					    def test_traefik(self):
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										126
									
								
								tests/e2e/test_provider_rac.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								tests/e2e/test_provider_rac.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,126 @@
 | 
				
			|||||||
 | 
					"""RAC e2e tests"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from datetime import timedelta
 | 
				
			||||||
 | 
					from time import mktime, sleep
 | 
				
			||||||
 | 
					from unittest.mock import MagicMock, patch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from django.utils.timezone import now
 | 
				
			||||||
 | 
					from selenium.webdriver.common.by import By
 | 
				
			||||||
 | 
					from selenium.webdriver.common.keys import Keys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from authentik.blueprints.tests import apply_blueprint, reconcile_app
 | 
				
			||||||
 | 
					from authentik.core.models import Application
 | 
				
			||||||
 | 
					from authentik.enterprise.license import LicenseKey
 | 
				
			||||||
 | 
					from authentik.enterprise.models import License
 | 
				
			||||||
 | 
					from authentik.enterprise.providers.rac.models import Endpoint, Protocols, RACProvider
 | 
				
			||||||
 | 
					from authentik.flows.models import Flow
 | 
				
			||||||
 | 
					from authentik.lib.generators import generate_id
 | 
				
			||||||
 | 
					from authentik.outposts.models import Outpost, OutpostType
 | 
				
			||||||
 | 
					from tests.e2e.utils import SeleniumTestCase, retry
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TestProviderRAC(SeleniumTestCase):
 | 
				
			||||||
 | 
					    """RAC e2e tests"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def setUp(self):
 | 
				
			||||||
 | 
					        super().setUp()
 | 
				
			||||||
 | 
					        self.password = generate_id()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def start_rac(self, outpost: Outpost):
 | 
				
			||||||
 | 
					        """Start rac container based on outpost created"""
 | 
				
			||||||
 | 
					        self.run_container(
 | 
				
			||||||
 | 
					            image=self.get_container_image("ghcr.io/goauthentik/dev-rac"),
 | 
				
			||||||
 | 
					            environment={
 | 
				
			||||||
 | 
					                "AUTHENTIK_TOKEN": outpost.token.key,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @patch(
 | 
				
			||||||
 | 
					        "authentik.enterprise.license.LicenseKey.validate",
 | 
				
			||||||
 | 
					        MagicMock(
 | 
				
			||||||
 | 
					            return_value=LicenseKey(
 | 
				
			||||||
 | 
					                aud="",
 | 
				
			||||||
 | 
					                exp=int(mktime((now() + timedelta(days=3000)).timetuple())),
 | 
				
			||||||
 | 
					                name=generate_id(),
 | 
				
			||||||
 | 
					                internal_users=100,
 | 
				
			||||||
 | 
					                external_users=100,
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    @retry()
 | 
				
			||||||
 | 
					    @apply_blueprint(
 | 
				
			||||||
 | 
					        "default/flow-default-authentication-flow.yaml",
 | 
				
			||||||
 | 
					        "default/flow-default-invalidation-flow.yaml",
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    @apply_blueprint(
 | 
				
			||||||
 | 
					        "default/flow-default-provider-authorization-implicit-consent.yaml",
 | 
				
			||||||
 | 
					        "default/flow-default-provider-invalidation.yaml",
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    @apply_blueprint(
 | 
				
			||||||
 | 
					        "system/providers-rac.yaml",
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    @reconcile_app("authentik_crypto")
 | 
				
			||||||
 | 
					    def test_rac_ssh(self):
 | 
				
			||||||
 | 
					        """Test SSH RAC"""
 | 
				
			||||||
 | 
					        License.objects.create(key=generate_id())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        test_ssh = self.run_container(
 | 
				
			||||||
 | 
					            image="lscr.io/linuxserver/openssh-server:latest",
 | 
				
			||||||
 | 
					            ports={
 | 
				
			||||||
 | 
					                "2222": "2222",
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            environment={
 | 
				
			||||||
 | 
					                "USER_NAME": "authentik",
 | 
				
			||||||
 | 
					                "USER_PASSWORD": self.password,
 | 
				
			||||||
 | 
					                "PASSWORD_ACCESS": "true",
 | 
				
			||||||
 | 
					                "SUDO_ACCESS": "true",
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        rac: RACProvider = RACProvider.objects.create(
 | 
				
			||||||
 | 
					            name=generate_id(),
 | 
				
			||||||
 | 
					            authorization_flow=Flow.objects.get(
 | 
				
			||||||
 | 
					                slug="default-provider-authorization-implicit-consent"
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        endpoint = Endpoint.objects.create(
 | 
				
			||||||
 | 
					            name=generate_id(),
 | 
				
			||||||
 | 
					            protocol=Protocols.SSH,
 | 
				
			||||||
 | 
					            host=f"{self.host}:2222",
 | 
				
			||||||
 | 
					            settings={
 | 
				
			||||||
 | 
					                "username": "authentik",
 | 
				
			||||||
 | 
					                "password": self.password,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            provider=rac,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        app = Application.objects.create(name=generate_id(), slug=generate_id(), provider=rac)
 | 
				
			||||||
 | 
					        outpost: Outpost = Outpost.objects.create(
 | 
				
			||||||
 | 
					            name=generate_id(),
 | 
				
			||||||
 | 
					            type=OutpostType.RAC,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        outpost.providers.add(rac)
 | 
				
			||||||
 | 
					        outpost.build_user_permissions(outpost.user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.start_rac(outpost)
 | 
				
			||||||
 | 
					        self.wait_for_outpost(outpost)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.driver.get(
 | 
				
			||||||
 | 
					            self.url("authentik_providers_rac:start", app=app.slug, endpoint=endpoint.pk)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.login()
 | 
				
			||||||
 | 
					        sleep(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        iface = self.driver.find_element(By.CSS_SELECTOR, "ak-rac")
 | 
				
			||||||
 | 
					        sleep(5)
 | 
				
			||||||
 | 
					        state = self.driver.execute_script("return arguments[0].clientState", iface)
 | 
				
			||||||
 | 
					        self.assertEqual(state, 3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        uid = generate_id()
 | 
				
			||||||
 | 
					        self.driver.find_element(By.CSS_SELECTOR, "body").send_keys(
 | 
				
			||||||
 | 
					            f'echo "{uid}" > /tmp/test' + Keys.ENTER
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        sleep(2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        _, output = test_ssh.exec_run("cat /tmp/test")
 | 
				
			||||||
 | 
					        self.assertEqual(output, f"{uid}\n".encode())
 | 
				
			||||||
@ -1,7 +1,6 @@
 | 
				
			|||||||
"""Radius e2e tests"""
 | 
					"""Radius e2e tests"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from dataclasses import asdict
 | 
					from dataclasses import asdict
 | 
				
			||||||
from time import sleep
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
from pyrad.client import Client
 | 
					from pyrad.client import Client
 | 
				
			||||||
from pyrad.dictionary import Dictionary
 | 
					from pyrad.dictionary import Dictionary
 | 
				
			||||||
@ -50,17 +49,7 @@ class TestProviderRadius(SeleniumTestCase):
 | 
				
			|||||||
        outpost.providers.add(radius)
 | 
					        outpost.providers.add(radius)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.start_radius(outpost)
 | 
					        self.start_radius(outpost)
 | 
				
			||||||
 | 
					        self.wait_for_outpost(outpost)
 | 
				
			||||||
        # Wait until outpost healthcheck succeeds
 | 
					 | 
				
			||||||
        healthcheck_retries = 0
 | 
					 | 
				
			||||||
        while healthcheck_retries < 50:  # noqa: PLR2004
 | 
					 | 
				
			||||||
            if len(outpost.state) > 0:
 | 
					 | 
				
			||||||
                state = outpost.state[0]
 | 
					 | 
				
			||||||
                if state.last_seen:
 | 
					 | 
				
			||||||
                    break
 | 
					 | 
				
			||||||
            healthcheck_retries += 1
 | 
					 | 
				
			||||||
            sleep(0.5)
 | 
					 | 
				
			||||||
        sleep(5)
 | 
					 | 
				
			||||||
        return outpost
 | 
					        return outpost
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @retry()
 | 
					    @retry()
 | 
				
			||||||
 | 
				
			|||||||
@ -419,7 +419,6 @@ class TestSourceSAML(SeleniumTestCase):
 | 
				
			|||||||
        # Wait until we're logged in
 | 
					        # Wait until we're logged in
 | 
				
			||||||
        self.wait_for_url(self.if_user_url())
 | 
					        self.wait_for_url(self.if_user_url())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # sleep(999999)
 | 
					 | 
				
			||||||
        self.assert_user(
 | 
					        self.assert_user(
 | 
				
			||||||
            User.objects.exclude(username="akadmin")
 | 
					            User.objects.exclude(username="akadmin")
 | 
				
			||||||
            .exclude(username__startswith="ak-outpost")
 | 
					            .exclude(username__startswith="ak-outpost")
 | 
				
			||||||
 | 
				
			|||||||
@ -12,8 +12,8 @@ from typing import Any
 | 
				
			|||||||
from unittest.case import TestCase
 | 
					from unittest.case import TestCase
 | 
				
			||||||
from urllib.parse import urlencode
 | 
					from urllib.parse import urlencode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from channels.testing import ChannelsLiveServerTestCase
 | 
				
			||||||
from django.apps import apps
 | 
					from django.apps import apps
 | 
				
			||||||
from django.contrib.staticfiles.testing import StaticLiveServerTestCase
 | 
					 | 
				
			||||||
from django.db import connection
 | 
					from django.db import connection
 | 
				
			||||||
from django.db.migrations.loader import MigrationLoader
 | 
					from django.db.migrations.loader import MigrationLoader
 | 
				
			||||||
from django.test.testcases import TransactionTestCase
 | 
					from django.test.testcases import TransactionTestCase
 | 
				
			||||||
@ -35,6 +35,8 @@ from authentik.core.api.users import UserSerializer
 | 
				
			|||||||
from authentik.core.models import User
 | 
					from authentik.core.models import User
 | 
				
			||||||
from authentik.core.tests.utils import create_test_admin_user
 | 
					from authentik.core.tests.utils import create_test_admin_user
 | 
				
			||||||
from authentik.lib.generators import generate_id
 | 
					from authentik.lib.generators import generate_id
 | 
				
			||||||
 | 
					from authentik.outposts.models import Outpost
 | 
				
			||||||
 | 
					from tests.e2e._process import TestDatabaseProcess
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RETRIES = int(environ.get("RETRIES", "3"))
 | 
					RETRIES = int(environ.get("RETRIES", "3"))
 | 
				
			||||||
IS_CI = "CI" in environ
 | 
					IS_CI = "CI" in environ
 | 
				
			||||||
@ -58,10 +60,13 @@ def get_local_ip() -> str:
 | 
				
			|||||||
    return ip_addr
 | 
					    return ip_addr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ContainerException(Exception): ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DockerTestCase(TestCase):
 | 
					class DockerTestCase(TestCase):
 | 
				
			||||||
    """Mixin for dealing with containers"""
 | 
					    """Mixin for dealing with containers"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    max_healthcheck_attempts = 30
 | 
					    max_healthcheck_attempts = 50
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    __client: DockerClient
 | 
					    __client: DockerClient
 | 
				
			||||||
    __network: Network
 | 
					    __network: Network
 | 
				
			||||||
@ -95,7 +100,7 @@ class DockerTestCase(TestCase):
 | 
				
			|||||||
            sleep(1)
 | 
					            sleep(1)
 | 
				
			||||||
            attempt += 1
 | 
					            attempt += 1
 | 
				
			||||||
            if attempt >= self.max_healthcheck_attempts:
 | 
					            if attempt >= self.max_healthcheck_attempts:
 | 
				
			||||||
                self.failureException("Container failed to start")
 | 
					                raise ContainerException("Container failed to start")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_container_image(self, base: str) -> str:
 | 
					    def get_container_image(self, base: str) -> str:
 | 
				
			||||||
        """Try to pull docker image based on git branch, fallback to main if not found."""
 | 
					        """Try to pull docker image based on git branch, fallback to main if not found."""
 | 
				
			||||||
@ -152,13 +157,17 @@ class DockerTestCase(TestCase):
 | 
				
			|||||||
        self.__network.remove()
 | 
					        self.__network.remove()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SeleniumTestCase(DockerTestCase, StaticLiveServerTestCase):
 | 
					class SeleniumTestCase(DockerTestCase, ChannelsLiveServerTestCase):
 | 
				
			||||||
    """StaticLiveServerTestCase which automatically creates a Webdriver instance"""
 | 
					    """ChannelsLiveServerTestCase which automatically creates a Webdriver instance"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ProtocolServerProcess = TestDatabaseProcess
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    host = get_local_ip()
 | 
					    host = get_local_ip()
 | 
				
			||||||
    wait_timeout: int
 | 
					    wait_timeout: int
 | 
				
			||||||
    user: User
 | 
					    user: User
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    serve_static = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def setUp(self):
 | 
					    def setUp(self):
 | 
				
			||||||
        if IS_CI:
 | 
					        if IS_CI:
 | 
				
			||||||
            print("::group::authentik Logs", file=stderr)
 | 
					            print("::group::authentik Logs", file=stderr)
 | 
				
			||||||
@ -265,6 +274,18 @@ class SeleniumTestCase(DockerTestCase, StaticLiveServerTestCase):
 | 
				
			|||||||
        self.assertEqual(user["name"].value, expected_user.name)
 | 
					        self.assertEqual(user["name"].value, expected_user.name)
 | 
				
			||||||
        self.assertEqual(user["email"].value, expected_user.email)
 | 
					        self.assertEqual(user["email"].value, expected_user.email)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def wait_for_outpost(self, outpost: Outpost, tries=50):
 | 
				
			||||||
 | 
					        """Wait until outpost healthcheck succeeds"""
 | 
				
			||||||
 | 
					        healthcheck_retries = 0
 | 
				
			||||||
 | 
					        while healthcheck_retries < tries:
 | 
				
			||||||
 | 
					            if len(outpost.state) > 0:
 | 
				
			||||||
 | 
					                state = outpost.state[0]
 | 
				
			||||||
 | 
					                if state.last_seen:
 | 
				
			||||||
 | 
					                    return
 | 
				
			||||||
 | 
					            healthcheck_retries += 1
 | 
				
			||||||
 | 
					            sleep(0.5)
 | 
				
			||||||
 | 
					        raise ContainerException("Outpost failed to become healthy")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@lru_cache
 | 
					@lru_cache
 | 
				
			||||||
def get_loader():
 | 
					def get_loader():
 | 
				
			||||||
@ -277,7 +298,12 @@ def retry(max_retires=RETRIES, exceptions=None):
 | 
				
			|||||||
    """Retry test multiple times. Default to catching Selenium Timeout Exception"""
 | 
					    """Retry test multiple times. Default to catching Selenium Timeout Exception"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if not exceptions:
 | 
					    if not exceptions:
 | 
				
			||||||
        exceptions = [WebDriverException, TimeoutException, NoSuchElementException]
 | 
					        exceptions = [
 | 
				
			||||||
 | 
					            WebDriverException,
 | 
				
			||||||
 | 
					            TimeoutException,
 | 
				
			||||||
 | 
					            NoSuchElementException,
 | 
				
			||||||
 | 
					            ContainerException,
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    logger = get_logger()
 | 
					    logger = get_logger()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user