Skip to content

Commit

Permalink
tests/e2e: add forward auth e2e test (goauthentik#11374)
Browse files Browse the repository at this point in the history
* add nginx forward_auth e2e tests

Signed-off-by: Jens Langhammer <[email protected]>

* add envoy

Signed-off-by: Jens Langhammer <[email protected]>

* cleanup

Signed-off-by: Jens Langhammer <[email protected]>

* remove even more duplicate code

Signed-off-by: Jens Langhammer <[email protected]>

* cleanup more

Signed-off-by: Jens Langhammer <[email protected]>

* add traefik static config

Signed-off-by: Jens Langhammer <[email protected]>

* more cleanup, don't generate dex config cause they support env variables

Signed-off-by: Jens Langhammer <[email protected]>

* use default dex entrypoint to use templating

Signed-off-by: Jens Langhammer <[email protected]>

* remove options that are always set as default

Signed-off-by: Jens Langhammer <[email protected]>

* fix

Signed-off-by: Jens Langhammer <[email protected]>

* fix compose flag

Signed-off-by: Jens Langhammer <[email protected]>

* add caddy

Signed-off-by: Jens Langhammer <[email protected]>

* merge python files

Signed-off-by: Jens Langhammer <[email protected]>

* use whoami api to check better

Signed-off-by: Jens Langhammer <[email protected]>

* fix envoy config

Signed-off-by: Jens Langhammer <[email protected]>

* set invalidation flow

Signed-off-by: Jens Langhammer <[email protected]>

* fix logout checks

Signed-off-by: Jens Langhammer <[email protected]>

---------

Signed-off-by: Jens Langhammer <[email protected]>
  • Loading branch information
BeryJu authored Oct 16, 2024
1 parent c4caef4 commit 89f251d
Show file tree
Hide file tree
Showing 24 changed files with 678 additions and 302 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci-main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ jobs:
uses: ./.github/actions/setup
- name: Setup e2e env (chrome, etc)
run: |
docker compose -f tests/e2e/docker-compose.yml up -d
docker compose -f tests/e2e/docker-compose.yml up -d --quiet-pull
- id: cache-web
uses: actions/cache@v4
with:
Expand Down
21 changes: 21 additions & 0 deletions tests/e2e/proxy_forward_auth/caddy_single/Caddyfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
http://localhost {
# directive execution order is only as stated if enclosed with route.
route {
# always forward outpost path to actual outpost
reverse_proxy /outpost.goauthentik.io/* http://ak-test-outpost:9000

# forward authentication to outpost
forward_auth http://ak-test-outpost:9000 {
uri /outpost.goauthentik.io/auth/caddy

# capitalization of the headers is important, otherwise they will be empty
copy_headers X-Authentik-Username X-Authentik-Groups X-Authentik-Email X-Authentik-Name X-Authentik-Uid X-Authentik-Jwt X-Authentik-Meta-Jwks X-Authentik-Meta-Outpost X-Authentik-Meta-Provider X-Authentik-Meta-App X-Authentik-Meta-Version

# optional, in this config trust all private ranges, should probably be set to the outposts IP
trusted_proxies private_ranges
}

# actual site configuration below, for example
reverse_proxy ak-whoami
}
}
99 changes: 99 additions & 0 deletions tests/e2e/proxy_forward_auth/envoy_single/envoy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# yaml-language-server: $schema=https://github.com/jcchavezs/envoy-config-schema/releases/download/v1.21.0/v3_Bootstrap.json
static_resources:
listeners:
- name: main_listener
address:
socket_address:
address: 0.0.0.0
port_value: 10000
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
upgrade_configs:
- upgrade_type: websocket
access_log:
- name: envoy.access_loggers.stdout
typed_config:
"@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog
http_filters:
- name: envoy.filters.http.ext_authz
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz
transport_api_version: V3
http_service:
path_prefix: /outpost.goauthentik.io/auth/envoy
server_uri:
uri: http://ak-test-outpost:9000
cluster: authentik_outpost
timeout: 0.25s
authorization_request:
allowed_headers:
patterns:
- exact: "cookie"
ignore_case: true
authorization_response:
allowed_upstream_headers:
patterns:
- exact: "set-cookie"
ignore_case: true
- prefix: "x-authentik-"
ignore_case: true
allowed_client_headers_on_success:
patterns:
- exact: "cookie"
ignore_case: true
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["localhost"]
routes:
- match:
prefix: "/outpost.goauthentik.io"
route:
cluster: authentik_outpost
- match:
prefix: "/"
route:
cluster: whoami
- name: local_service
domains: ["*"]
typed_per_filter_config:
envoy.filters.http.ext_authz:
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute
disabled: true
routes:
- match:
prefix: "/"
route:
cluster: authentik_outpost

clusters:
- name: authentik_outpost
type: LOGICAL_DNS
load_assignment:
cluster_name: authentik_outpost
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: ak-test-outpost
port_value: 9000
- name: whoami
type: LOGICAL_DNS
load_assignment:
cluster_name: whoami
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: ak-whoami
port_value: 80
59 changes: 59 additions & 0 deletions tests/e2e/proxy_forward_auth/nginx_single/nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
server {
listen 80;
server_name _;

# Increase buffer size for large headers
# This is needed only if you get 'upstream sent too big header while reading response
# header from upstream' error when trying to access an application protected by goauthentik
proxy_buffers 8 16k;
proxy_buffer_size 32k;

location / {
proxy_pass http://ak-whoami;
proxy_set_header Host $host;

##############################
# authentik-specific config
##############################
auth_request /outpost.goauthentik.io/auth/nginx;
error_page 401 = @goauthentik_proxy_signin;
auth_request_set $auth_cookie $upstream_http_set_cookie;
add_header Set-Cookie $auth_cookie;

# translate headers from the outposts back to the actual upstream
auth_request_set $authentik_username $upstream_http_x_authentik_username;
auth_request_set $authentik_groups $upstream_http_x_authentik_groups;
auth_request_set $authentik_email $upstream_http_x_authentik_email;
auth_request_set $authentik_name $upstream_http_x_authentik_name;
auth_request_set $authentik_uid $upstream_http_x_authentik_uid;

proxy_set_header X-authentik-username $authentik_username;
proxy_set_header X-authentik-groups $authentik_groups;
proxy_set_header X-authentik-email $authentik_email;
proxy_set_header X-authentik-name $authentik_name;
proxy_set_header X-authentik-uid $authentik_uid;
}

# all requests to /outpost.goauthentik.io must be accessible without authentication
location /outpost.goauthentik.io {
proxy_pass http://ak-test-outpost:9000/outpost.goauthentik.io;
# ensure the host of this vserver matches your external URL you've configured
# in authentik
proxy_set_header Host $host;
proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
add_header Set-Cookie $auth_cookie;
auth_request_set $auth_cookie $upstream_http_set_cookie;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
}

# Special location for when the /auth endpoint returns a 401,
# redirect to the /start URL which initiates SSO
location @goauthentik_proxy_signin {
internal;
add_header Set-Cookie $auth_cookie;
return 302 /outpost.goauthentik.io/start?rd=$request_uri;
# For domain level, use the below error_page to redirect to your authentik server with the full redirect path
# return 302 https://localhost/outpost.goauthentik.io/start?rd=$scheme://$http_host$request_uri;
}
}
57 changes: 57 additions & 0 deletions tests/e2e/proxy_forward_auth/traefik_single/config-static.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# yaml-language-server: $schema=https://json.schemastore.org/traefik-v2.json
api:
insecure: true
debug: true

log:
level: debug
accessLog:
filePath: /dev/stdout

entryPoints:
web:
address: ":80"

# Re-use the same config file to define everything
providers:
file:
filename: /etc/traefik/traefik.yml

http:
middlewares:
authentik:
forwardAuth:
address: http://ak-test-outpost:9000/outpost.goauthentik.io/auth/traefik
trustForwardHeader: true
authResponseHeaders:
- X-authentik-username
- X-authentik-groups
- X-authentik-email
- X-authentik-name
- X-authentik-uid
- X-authentik-jwt
- X-authentik-meta-jwks
- X-authentik-meta-outpost
- X-authentik-meta-provider
- X-authentik-meta-app
- X-authentik-meta-version
routers:
default-router:
rule: "Host(`localhost`)"
middlewares:
- authentik
priority: 10
service: app
default-router-auth:
rule: "Host(`localhost`) && PathPrefix(`/outpost.goauthentik.io/`)"
priority: 15
service: authentik
services:
app:
loadBalancer:
servers:
- url: http://ak-whoami
authentik:
loadBalancer:
servers:
- url: http://ak-test-outpost:9000/outpost.goauthentik.io
23 changes: 23 additions & 0 deletions tests/e2e/sources_oauth2_dex/dex.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
enablePasswordDB: true
issuer: http://127.0.0.1:5556/dex
logger:
level: debug
staticClients:
- id: example-app
name: Example App
redirectURIs:
- {{ .Env.AK_REDIRECT_URL }}
secret: {{ .Env.AK_CLIENT_SECRET }}
staticPasswords:
- email: [email protected]
# hash for 'password', for testing
hash: "$2a$10$2b2cU8CPhOTaGrs1HRQuAueS7JTT5ZHsHSzYiFPm1leZck7Mc8T4W"
userID: "08a8684b-db88-4b73-90a9-3cd1661f5466"
username: admin
storage:
config:
file: "/tmp/dex.db"
type: sqlite3
web:
http: 0.0.0.0:5556
19 changes: 3 additions & 16 deletions tests/e2e/test_provider_ldap.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
from dataclasses import asdict
from time import sleep

from docker.client import DockerClient, from_env
from docker.models.containers import Container
from guardian.shortcuts import assign_perm
from ldap3 import ALL, ALL_ATTRIBUTES, ALL_OPERATIONAL_ATTRIBUTES, SUBTREE, Connection, Server
from ldap3.core.exceptions import LDAPInvalidCredentialsResult
Expand All @@ -24,29 +22,18 @@
class TestProviderLDAP(SeleniumTestCase):
"""LDAP and Outpost e2e tests"""

ldap_container: Container

def tearDown(self) -> None:
super().tearDown()
self.output_container_logs(self.ldap_container)
self.ldap_container.kill()

def start_ldap(self, outpost: Outpost) -> Container:
def start_ldap(self, outpost: Outpost):
"""Start ldap container based on outpost created"""
client: DockerClient = from_env()
container = client.containers.run(
self.run_container(
image=self.get_container_image("ghcr.io/goauthentik/dev-ldap"),
detach=True,
ports={
"3389": "3389",
"6636": "6636",
},
environment={
"AUTHENTIK_HOST": self.live_server_url,
"AUTHENTIK_TOKEN": outpost.token.key,
},
)
return container

def _prepare(self) -> User:
"""prepare user, provider, app and container"""
Expand All @@ -68,7 +55,7 @@ def _prepare(self) -> User:
)
outpost.providers.add(ldap)

self.ldap_container = self.start_ldap(outpost)
self.start_ldap(outpost)

# Wait until outpost healthcheck succeeds
healthcheck_retries = 0
Expand Down
18 changes: 6 additions & 12 deletions tests/e2e/test_provider_oauth2_github.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"""test OAuth Provider flow"""

from time import sleep
from typing import Any

from docker.types import Healthcheck
from selenium.webdriver.common.by import By
Expand All @@ -24,22 +23,17 @@ def setUp(self):
self.client_id = generate_id()
self.client_secret = generate_key()
super().setUp()

def get_container_specs(self) -> dict[str, Any] | None:
"""Setup client grafana container which we test OAuth against"""
return {
"image": "grafana/grafana:7.1.0",
"detach": True,
"ports": {
self.run_container(
image="grafana/grafana:7.1.0",
ports={
"3000": "3000",
},
"auto_remove": True,
"healthcheck": Healthcheck(
healthcheck=Healthcheck(
test=["CMD", "wget", "--spider", "http://localhost:3000"],
interval=5 * 1_000 * 1_000_000,
start_period=1 * 1_000 * 1_000_000,
),
"environment": {
environment={
"GF_AUTH_GITHUB_ENABLED": "true",
"GF_AUTH_GITHUB_ALLOW_SIGN_UP": "true",
"GF_AUTH_GITHUB_CLIENT_ID": self.client_id,
Expand All @@ -54,7 +48,7 @@ def get_container_specs(self) -> dict[str, Any] | None:
"GF_AUTH_GITHUB_API_URL": self.url("authentik_providers_oauth2_root:github-user"),
"GF_LOG_LEVEL": "debug",
},
}
)

@retry()
@apply_blueprint(
Expand Down
Loading

0 comments on commit 89f251d

Please sign in to comment.