mirror of
https://github.com/goauthentik/authentik
synced 2026-04-25 17:15:26 +02:00
tests/e2e: add endpoint tests (#19072)
* tests/e2e: add endpoint tests Signed-off-by: Jens Langhammer <jens@goauthentik.io> * dont rely on hostname Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
@@ -1,11 +1,13 @@
|
||||
services:
|
||||
chromium:
|
||||
image: docker.io/selenium/standalone-chromium:143.0
|
||||
image: ghcr.io/goauthentik/selenium:143.0-ak-0.35.3
|
||||
shm_size: 2g
|
||||
network_mode: host
|
||||
restart: always
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
labels:
|
||||
- io.goauthentik.tests=selenium
|
||||
mailpit:
|
||||
image: docker.io/axllent/mailpit:v1.28.0
|
||||
ports:
|
||||
|
||||
64
tests/e2e/test_endpoints_flow.py
Normal file
64
tests/e2e/test_endpoints_flow.py
Normal file
@@ -0,0 +1,64 @@
|
||||
"""test default login flow"""
|
||||
|
||||
from authentik.blueprints.tests import apply_blueprint, reconcile_app
|
||||
from authentik.crypto.apps import MANAGED_KEY
|
||||
from authentik.crypto.models import CertificateKeyPair
|
||||
from authentik.endpoints.connectors.agent.models import AgentConnector, EnrollmentToken
|
||||
from authentik.endpoints.models import Device, EndpointStage, StageMode
|
||||
from authentik.events.models import Event, EventAction
|
||||
from authentik.flows.models import Flow, FlowStageBinding
|
||||
from authentik.lib.generators import generate_id
|
||||
from tests.e2e.utils import SeleniumTestCase, retry
|
||||
|
||||
|
||||
class TestEndpointsFlow(SeleniumTestCase):
|
||||
"""test default login flow"""
|
||||
|
||||
@reconcile_app("authentik_crypto")
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.connector = AgentConnector.objects.create(
|
||||
name=generate_id(),
|
||||
challenge_key=CertificateKeyPair.objects.filter(managed=MANAGED_KEY).first(),
|
||||
)
|
||||
self.enrollment_token = EnrollmentToken.objects.create(
|
||||
name=generate_id(), connector=self.connector
|
||||
)
|
||||
|
||||
@retry()
|
||||
@apply_blueprint(
|
||||
"default/flow-default-authentication-flow.yaml",
|
||||
"default/flow-default-invalidation-flow.yaml",
|
||||
)
|
||||
def test_login(self):
|
||||
"""test default login flow"""
|
||||
rc, output = self.driver_container.exec_run(
|
||||
["ak-sysd", "domains", "join", "ak", "-a", self.live_server_url],
|
||||
user="root",
|
||||
environment={"AK_SYS_INSECURE_ENV_TOKEN": self.enrollment_token.key},
|
||||
)
|
||||
self.assertEqual(rc, 0, str(output))
|
||||
|
||||
dev = Device.objects.first()
|
||||
self.assertIsNotNone(dev)
|
||||
|
||||
stage = EndpointStage.objects.create(
|
||||
name=generate_id(), connector=self.connector, mode=StageMode.REQUIRED
|
||||
)
|
||||
FlowStageBinding.objects.create(
|
||||
target=Flow.objects.get(slug="default-authentication-flow"), stage=stage, order=0
|
||||
)
|
||||
|
||||
self.driver.get(
|
||||
self.url(
|
||||
"authentik_core:if-flow",
|
||||
flow_slug="default-authentication-flow",
|
||||
)
|
||||
)
|
||||
self.login()
|
||||
self.wait_for_url(self.if_user_url("/library"))
|
||||
self.assert_user(self.user)
|
||||
|
||||
login_evt = Event.objects.filter(action=EventAction.LOGIN).first()
|
||||
self.assertIsNotNone(login_evt)
|
||||
self.assertEqual(login_evt.context["device"]["pk"], dev.pk.hex)
|
||||
@@ -2,10 +2,12 @@
|
||||
|
||||
import socket
|
||||
from collections.abc import Callable
|
||||
from functools import lru_cache, wraps
|
||||
from functools import cached_property, lru_cache, wraps
|
||||
from json import JSONDecodeError, dumps, loads
|
||||
from os import environ, getenv
|
||||
from pathlib import Path
|
||||
from sys import stderr
|
||||
from tempfile import gettempdir
|
||||
from time import sleep
|
||||
from typing import Any
|
||||
from unittest.case import TestCase
|
||||
@@ -21,6 +23,7 @@ from docker import DockerClient, from_env
|
||||
from docker.errors import DockerException
|
||||
from docker.models.containers import Container
|
||||
from docker.models.networks import Network
|
||||
from requests import RequestException
|
||||
from selenium import webdriver
|
||||
from selenium.common.exceptions import (
|
||||
DetachedShadowRootException,
|
||||
@@ -43,6 +46,7 @@ from authentik.core.api.users import UserSerializer
|
||||
from authentik.core.models import User
|
||||
from authentik.core.tests.utils import create_test_admin_user
|
||||
from authentik.lib.generators import generate_id
|
||||
from authentik.lib.utils.http import get_http_session
|
||||
from authentik.root.test_runner import get_docker_tag
|
||||
|
||||
IS_CI = "CI" in environ
|
||||
@@ -179,6 +183,7 @@ class SeleniumTestCase(DockerTestCase, StaticLiveServerTestCase):
|
||||
opts = webdriver.ChromeOptions()
|
||||
opts.accept_insecure_certs = True
|
||||
opts.add_argument("--disable-search-engine-choice-screen")
|
||||
opts.add_extension(self._get_chrome_extension())
|
||||
# This breaks selenium when running remotely...?
|
||||
# opts.set_capability("goog:loggingPrefs", {"browser": "ALL"})
|
||||
opts.add_experimental_option(
|
||||
@@ -200,6 +205,31 @@ class SeleniumTestCase(DockerTestCase, StaticLiveServerTestCase):
|
||||
count += 1
|
||||
raise ValueError(f"Webdriver failed after {RETRIES}.")
|
||||
|
||||
def _get_chrome_extension(self):
|
||||
path = Path(gettempdir()) / "ak-chrome.crx"
|
||||
try:
|
||||
self.logger.info("Downloading chrome extension...", path=path)
|
||||
res = get_http_session().get(
|
||||
"https://pkg.goauthentik.io/packages/authentik_browser-ext/browser-ext/authentik_chrome.zip",
|
||||
stream=True,
|
||||
)
|
||||
with open(path, "w+b") as _ext:
|
||||
for chunk in res.iter_content(chunk_size=1024):
|
||||
if chunk:
|
||||
_ext.write(chunk)
|
||||
except RequestException as exc:
|
||||
if path.exists() and not IS_CI:
|
||||
self.logger.info(
|
||||
"Failed to download chrome extension, using cached copy", path=path
|
||||
)
|
||||
return path
|
||||
raise exc
|
||||
return path
|
||||
|
||||
@cached_property
|
||||
def driver_container(self) -> Container:
|
||||
return self.docker_client.containers.list(filters={"label": "io.goauthentik.tests"})[0]
|
||||
|
||||
def tearDown(self):
|
||||
if IS_CI:
|
||||
print("::endgroup::", file=stderr)
|
||||
|
||||
Reference in New Issue
Block a user