This repository has been archived on 2024-05-31. You can view files and clone it, but cannot push or open issues or pull requests.
authentik/tests/e2e/test_source_oauth_oauth2.py

196 lines
7.9 KiB
Python
Raw Permalink Normal View History

"""test OAuth Source"""
from pathlib import Path
from time import sleep
from typing import Any, Optional
from docker.models.containers import Container
from docker.types import Healthcheck
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as ec
2021-02-27 23:27:18 +00:00
from selenium.webdriver.support.wait import WebDriverWait
from yaml import safe_dump
2022-08-02 22:05:49 +00:00
from authentik.blueprints.tests import apply_blueprint
from authentik.core.models import User
2020-12-05 21:08:42 +00:00
from authentik.flows.models import Flow
from authentik.lib.generators import generate_id, generate_key
2020-12-05 21:08:42 +00:00
from authentik.sources.oauth.models import OAuthSource
from authentik.stages.identification.models import IdentificationStage
blueprints: migrate from managed (#3338) * test all bundled blueprints Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * fix empty title Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * fix default blueprints Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * add script to generate dev config Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * migrate managed to blueprints Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * add more to blueprint instance Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * migrated away from ObjectManager Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * fix lint errors Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * migrate things Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * migrate tests Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * fix some tests Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * fix a bit more Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * fix more tests Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * whops Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * fix missing name Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * *sigh* Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * fix more tests Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * add tasks Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * scheduled Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * run discovery on start Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * oops this test should stay Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-08-01 21:05:58 +00:00
from tests.e2e.utils import SeleniumTestCase, retry
CONFIG_PATH = "/tmp/dex.yml" # nosec
2020-09-26 15:44:05 +00:00
class TestSourceOAuth2(SeleniumTestCase):
"""test OAuth Source flow"""
container: Container
def setUp(self):
self.client_secret = generate_key()
2024-01-01 20:08:40 +00:00
self.slug = generate_id()
2020-09-11 21:21:11 +00:00
self.prepare_dex_config()
super().setUp()
def prepare_dex_config(self):
"""Since Dex does not document which environment
variables can be used to configure clients"""
2020-07-09 21:13:14 +00:00
config = {
"enablePasswordDB": True,
"issuer": "http://127.0.0.1:5556/dex",
"logger": {"level": "debug"},
"staticClients": [
{
"id": "example-app",
"name": "Example App",
"redirectURIs": [
self.url(
2020-12-05 21:08:42 +00:00
"authentik_sources_oauth:oauth-client-callback",
2024-01-01 20:08:40 +00:00
source_slug=self.slug,
2020-07-09 21:13:14 +00:00
)
],
"secret": self.client_secret,
}
],
"staticPasswords": [
{
"email": "admin@example.com",
# hash for password
"hash": "$2a$10$2b2cU8CPhOTaGrs1HRQuAueS7JTT5ZHsHSzYiFPm1leZck7Mc8T4W",
"userID": "08a8684b-db88-4b73-90a9-3cd1661f5466",
"username": "admin",
}
],
"storage": {"config": {"file": "/tmp/dex.db"}, "type": "sqlite3"}, # nosec
2020-07-09 21:13:14 +00:00
"web": {"http": "0.0.0.0:5556"},
}
with open(CONFIG_PATH, "w+", encoding="utf8") as _file:
safe_dump(config, _file)
def get_container_specs(self) -> Optional[dict[str, Any]]:
2020-09-11 21:21:11 +00:00
return {
"image": "ghcr.io/dexidp/dex:v2.28.1",
2020-09-11 21:21:11 +00:00
"detach": True,
2024-01-01 20:08:40 +00:00
"ports": {"5556": "5556"},
2020-09-11 21:21:11 +00:00
"auto_remove": True,
"command": "dex serve /config.yml",
2020-09-11 21:21:11 +00:00
"healthcheck": Healthcheck(
test=["CMD", "wget", "--spider", "http://localhost:5556/dex/healthz"],
interval=5 * 1_000 * 1_000_000,
start_period=1 * 1_000 * 1_000_000,
),
"volumes": {str(Path(CONFIG_PATH).absolute()): {"bind": "/config.yml", "mode": "ro"}},
2020-09-11 21:21:11 +00:00
}
2020-07-09 21:13:14 +00:00
def create_objects(self):
"""Create required objects"""
# Bootstrap all needed objects
authentication_flow = Flow.objects.get(slug="default-source-authentication")
enrollment_flow = Flow.objects.get(slug="default-source-enrollment")
source = OAuthSource.objects.create( # nosec
2024-01-01 20:08:40 +00:00
name=generate_id(),
slug=self.slug,
authentication_flow=authentication_flow,
enrollment_flow=enrollment_flow,
provider_type="openidconnect",
authorization_url="http://127.0.0.1:5556/dex/auth",
access_token_url="http://127.0.0.1:5556/dex/token",
profile_url="http://127.0.0.1:5556/dex/userinfo",
consumer_key="example-app",
2020-07-09 12:59:25 +00:00
consumer_secret=self.client_secret,
)
ident_stage = IdentificationStage.objects.first()
ident_stage.sources.set([source])
ident_stage.save()
@retry()
blueprints: migrate from managed (#3338) * test all bundled blueprints Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * fix empty title Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * fix default blueprints Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * add script to generate dev config Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * migrate managed to blueprints Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * add more to blueprint instance Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * migrated away from ObjectManager Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * fix lint errors Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * migrate things Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * migrate tests Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * fix some tests Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * fix a bit more Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * fix more tests Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * whops Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * fix missing name Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * *sigh* Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * fix more tests Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * add tasks Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * scheduled Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * run discovery on start Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * oops this test should stay Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-08-01 21:05:58 +00:00
@apply_blueprint(
"default/flow-default-authentication-flow.yaml",
"default/flow-default-invalidation-flow.yaml",
blueprints: migrate from managed (#3338) * test all bundled blueprints Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * fix empty title Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * fix default blueprints Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * add script to generate dev config Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * migrate managed to blueprints Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * add more to blueprint instance Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * migrated away from ObjectManager Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * fix lint errors Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * migrate things Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * migrate tests Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * fix some tests Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * fix a bit more Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * fix more tests Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * whops Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * fix missing name Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * *sigh* Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * fix more tests Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * add tasks Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * scheduled Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * run discovery on start Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * oops this test should stay Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-08-01 21:05:58 +00:00
)
@apply_blueprint(
"default/flow-default-source-authentication.yaml",
"default/flow-default-source-enrollment.yaml",
"default/flow-default-source-pre-authentication.yaml",
blueprints: migrate from managed (#3338) * test all bundled blueprints Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * fix empty title Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * fix default blueprints Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * add script to generate dev config Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * migrate managed to blueprints Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * add more to blueprint instance Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * migrated away from ObjectManager Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * fix lint errors Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * migrate things Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * migrate tests Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * fix some tests Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * fix a bit more Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * fix more tests Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * whops Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * fix missing name Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * *sigh* Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * fix more tests Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * add tasks Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * scheduled Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * run discovery on start Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * oops this test should stay Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2022-08-01 21:05:58 +00:00
)
2020-07-09 21:13:14 +00:00
def test_oauth_enroll(self):
"""test OAuth Source With With OIDC"""
self.create_objects()
self.driver.get(self.live_server_url)
2021-02-27 23:27:18 +00:00
flow_executor = self.get_shadow_root("ak-flow-executor")
identification_stage = self.get_shadow_root("ak-stage-identification", flow_executor)
2021-02-27 23:27:18 +00:00
wait = WebDriverWait(identification_stage, self.wait_timeout)
wait.until(
ec.presence_of_element_located(
(By.CSS_SELECTOR, ".pf-c-login__main-footer-links-item > button")
)
)
2021-02-27 23:27:18 +00:00
identification_stage.find_element(
By.CSS_SELECTOR, ".pf-c-login__main-footer-links-item > button"
).click()
# Now we should be at the IDP, wait for the login field
self.wait.until(ec.presence_of_element_located((By.ID, "login")))
self.driver.find_element(By.ID, "login").send_keys("admin@example.com")
self.driver.find_element(By.ID, "password").send_keys("password")
self.driver.find_element(By.ID, "password").send_keys(Keys.ENTER)
# Wait until we're logged in
self.wait.until(ec.presence_of_element_located((By.CSS_SELECTOR, "button[type=submit]")))
self.driver.find_element(By.CSS_SELECTOR, "button[type=submit]").click()
# At this point we've been redirected back
# and we're asked for the username
2021-02-27 23:27:18 +00:00
flow_executor = self.get_shadow_root("ak-flow-executor")
2021-02-27 23:30:33 +00:00
prompt_stage = self.get_shadow_root("ak-stage-prompt", flow_executor)
2021-02-27 23:27:18 +00:00
2021-02-27 23:30:33 +00:00
prompt_stage.find_element(By.CSS_SELECTOR, "input[name=username]").click()
prompt_stage.find_element(By.CSS_SELECTOR, "input[name=username]").send_keys("foo")
prompt_stage.find_element(By.CSS_SELECTOR, "input[name=username]").send_keys(Keys.ENTER)
2020-11-23 13:24:42 +00:00
# Wait until we've logged in
2021-09-16 15:30:16 +00:00
self.wait_for_url(self.if_user_url("/library"))
self.driver.get(self.if_user_url("/settings"))
self.assert_user(User(username="foo", name="admin", email="admin@example.com"))
@retry()
def test_oauth_enroll_auth(self):
"""test OAuth Source With With OIDC (enroll and authenticate again)"""
self.test_oauth_enroll()
# We're logged in at the end of this, log out and re-login
2020-12-05 21:08:42 +00:00
self.driver.get(self.url("authentik_flows:default-invalidation"))
2021-02-27 23:27:18 +00:00
sleep(1)
flow_executor = self.get_shadow_root("ak-flow-executor")
identification_stage = self.get_shadow_root("ak-stage-identification", flow_executor)
2021-02-27 23:27:18 +00:00
wait = WebDriverWait(identification_stage, self.wait_timeout)
2021-02-27 23:27:18 +00:00
wait.until(
ec.presence_of_element_located(
(By.CSS_SELECTOR, ".pf-c-login__main-footer-links-item > button")
)
)
2021-02-27 23:27:18 +00:00
identification_stage.find_element(
By.CSS_SELECTOR, ".pf-c-login__main-footer-links-item > button"
).click()
2021-02-27 23:27:18 +00:00
# Now we should be at the IDP, wait for the login field
self.wait.until(ec.presence_of_element_located((By.ID, "login")))
self.driver.find_element(By.ID, "login").send_keys("admin@example.com")
self.driver.find_element(By.ID, "password").send_keys("password")
self.driver.find_element(By.ID, "password").send_keys(Keys.ENTER)
# Wait until we're logged in
self.wait.until(ec.presence_of_element_located((By.CSS_SELECTOR, "button[type=submit]")))
self.driver.find_element(By.CSS_SELECTOR, "button[type=submit]").click()
2020-11-23 13:24:42 +00:00
# Wait until we've logged in
2021-09-16 15:30:16 +00:00
self.wait_for_url(self.if_user_url("/library"))
self.driver.get(self.if_user_url("/settings"))
self.assert_user(User(username="foo", name="admin", email="admin@example.com"))