e2e: refactor oidc server from dex to tinyauth (#754)
This commit is contained in:
parent
f11e3b7f82
commit
ad8a83e60e
9 changed files with 168 additions and 85 deletions
14
.github/workflows/e2e.yml
vendored
14
.github/workflows/e2e.yml
vendored
|
|
@ -46,12 +46,14 @@ jobs:
|
||||||
mkdir -p data
|
mkdir -p data
|
||||||
mkdir -p playwright/temp
|
mkdir -p playwright/temp
|
||||||
mkdir -p playwright/data
|
mkdir -p playwright/data
|
||||||
|
mkdir -p playwright/tinyauth/app-data
|
||||||
|
mkdir -p playwright/tinyauth/caddy-data
|
||||||
chmod -R 777 playwright/temp
|
chmod -R 777 playwright/temp
|
||||||
touch .env.local
|
touch .env.local
|
||||||
echo "SERVER_IP=localhost" >> .env.local
|
echo "SERVER_IP=localhost" >> .env.local
|
||||||
echo "ZEROBYTE_DATABASE_URL=./data/zerobyte.db" >> .env.local
|
echo "ZEROBYTE_DATABASE_URL=./data/zerobyte.db" >> .env.local
|
||||||
echo "BASE_URL=http://localhost:4096" >> .env.local
|
echo "BASE_URL=http://localhost:4096" >> .env.local
|
||||||
echo "E2E_DEX_ORIGIN=http://dex:5557" >> .env.local
|
echo "E2E_TINYAUTH_ORIGIN=https://tinyauth.example.com:5557" >> .env.local
|
||||||
echo "TZ=Europe/Zurich" >> .env.local
|
echo "TZ=Europe/Zurich" >> .env.local
|
||||||
|
|
||||||
- name: Start zerobyte-e2e service
|
- name: Start zerobyte-e2e service
|
||||||
|
|
@ -68,13 +70,13 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
timeout 30s bash -c 'until curl -f http://localhost:4096/api/healthcheck; do echo "Waiting for server..." && sleep 2; done'
|
timeout 30s bash -c 'until curl -f http://localhost:4096/api/healthcheck; do echo "Waiting for server..." && sleep 2; done'
|
||||||
|
|
||||||
- name: Wait for Dex to be ready
|
- name: Wait for Tinyauth to be ready
|
||||||
run: |
|
run: |
|
||||||
timeout 30s bash -c 'until curl -sf http://localhost:5557/dex/.well-known/openid-configuration; do echo "Waiting for Dex..." && sleep 2; done'
|
timeout 30s bash -c 'until curl -skf https://localhost:5557/.well-known/openid-configuration; do echo "Waiting for Tinyauth..." && sleep 2; done'
|
||||||
|
|
||||||
- name: Print docker logs if failed to start
|
- name: Print docker logs if failed to start
|
||||||
if: failure()
|
if: failure()
|
||||||
run: docker compose logs zerobyte-e2e dex || true
|
run: docker compose logs zerobyte-e2e tinyauth tinyauth-app || true
|
||||||
|
|
||||||
- name: Make playwright directory writable
|
- name: Make playwright directory writable
|
||||||
run: sudo chmod 777 playwright/data/zerobyte.db
|
run: sudo chmod 777 playwright/data/zerobyte.db
|
||||||
|
|
@ -85,9 +87,9 @@ jobs:
|
||||||
- name: Dump container logs in playwright-report folder
|
- name: Dump container logs in playwright-report folder
|
||||||
if: always()
|
if: always()
|
||||||
run: |
|
run: |
|
||||||
tree playwright
|
tree playwright || true
|
||||||
docker compose logs zerobyte-e2e > playwright-report/container-logs.txt || true
|
docker compose logs zerobyte-e2e > playwright-report/container-logs.txt || true
|
||||||
docker compose logs dex > playwright-report/dex-logs.txt || true
|
docker compose logs tinyauth tinyauth-app > playwright-report/tinyauth-logs.txt || true
|
||||||
|
|
||||||
- name: Debug - print content of /test-data in container
|
- name: Debug - print content of /test-data in container
|
||||||
if: failure()
|
if: failure()
|
||||||
|
|
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -29,6 +29,8 @@ node_modules/
|
||||||
/playwright/.cache/
|
/playwright/.cache/
|
||||||
/playwright/.auth/
|
/playwright/.auth/
|
||||||
/playwright/*.pass
|
/playwright/*.pass
|
||||||
|
/playwright/tinyauth/app-data/
|
||||||
|
/playwright/tinyauth/caddy-data/
|
||||||
|
|
||||||
playwright/.auth
|
playwright/.auth
|
||||||
playwright/temp
|
playwright/temp
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,9 @@ services:
|
||||||
- DISABLE_RATE_LIMITING=true
|
- DISABLE_RATE_LIMITING=true
|
||||||
- APP_SECRET=94bad4678ce84a60b9789bd2114a6bf780aeb38df426f7352c941c66e25d5c2b
|
- APP_SECRET=94bad4678ce84a60b9789bd2114a6bf780aeb38df426f7352c941c66e25d5c2b
|
||||||
- BASE_URL=http://localhost:4096
|
- BASE_URL=http://localhost:4096
|
||||||
- TRUSTED_ORIGINS=http://dex:5557,http://localhost:5557
|
- TRUSTED_ORIGINS=https://tinyauth.example.com:5557,https://localhost:5557
|
||||||
|
- NODE_EXTRA_CA_CERTS=/tinyauth-ca/caddy/pki/authorities/local/root.crt
|
||||||
|
- SSL_CERT_FILE=/tinyauth-ca/caddy/pki/authorities/local/root.crt
|
||||||
devices:
|
devices:
|
||||||
- /dev/fuse:/dev/fuse
|
- /dev/fuse:/dev/fuse
|
||||||
cap_add:
|
cap_add:
|
||||||
|
|
@ -69,17 +71,56 @@ services:
|
||||||
ports:
|
ports:
|
||||||
- "4096:4096"
|
- "4096:4096"
|
||||||
depends_on:
|
depends_on:
|
||||||
- dex
|
tinyauth:
|
||||||
|
condition: service_healthy
|
||||||
volumes:
|
volumes:
|
||||||
- /etc/localtime:/etc/localtime:ro
|
- /etc/localtime:/etc/localtime:ro
|
||||||
- ./playwright/data:/var/lib/zerobyte/data
|
- ./playwright/data:/var/lib/zerobyte/data
|
||||||
- ./playwright/temp:/test-data
|
- ./playwright/temp:/test-data
|
||||||
|
- ./playwright/tinyauth/caddy-data:/tinyauth-ca:ro
|
||||||
|
|
||||||
dex:
|
tinyauth-app:
|
||||||
image: ghcr.io/dexidp/dex:latest
|
image: ghcr.io/steveiliop56/tinyauth:v5
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- TINYAUTH_APPURL=https://tinyauth.example.com:5557
|
||||||
|
- TINYAUTH_SERVER_PORT=3000
|
||||||
|
- TINYAUTH_SERVER_ADDRESS=0.0.0.0
|
||||||
|
- TINYAUTH_DATABASE_PATH=/data/tinyauth.db
|
||||||
|
- TINYAUTH_AUTH_USERSFILE=/config/users.txt
|
||||||
|
- TINYAUTH_OIDC_PRIVATEKEYPATH=/data/tinyauth_oidc_key
|
||||||
|
- TINYAUTH_OIDC_PUBLICKEYPATH=/data/tinyauth_oidc_key.pub
|
||||||
|
- TINYAUTH_OIDC_CLIENTS_ZEROBYTE_CLIENTID=zerobyte-test
|
||||||
|
- TINYAUTH_OIDC_CLIENTS_ZEROBYTE_CLIENTSECRET=test-secret-12345
|
||||||
|
- TINYAUTH_OIDC_CLIENTS_ZEROBYTE_TRUSTEDREDIRECTURIS=http://localhost:4096/api/auth/sso/callback/test-oidc-register,http://localhost:4096/api/auth/sso/callback/test-oidc-uninvited,http://localhost:4096/api/auth/sso/callback/test-oidc-invited,http://localhost:4096/api/auth/sso/callback/test-oidc-autolink
|
||||||
|
- TINYAUTH_OIDC_CLIENTS_ZEROBYTE_NAME=Zerobyte Test
|
||||||
|
- TINYAUTH_LOG_LEVEL=debug
|
||||||
|
- TINYAUTH_LOG_JSON=true
|
||||||
|
volumes:
|
||||||
|
- ./playwright/tinyauth/users.txt:/config/users.txt:ro
|
||||||
|
- ./playwright/tinyauth/app-data:/data
|
||||||
|
|
||||||
|
tinyauth:
|
||||||
|
image: caddy:2-alpine
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
- tinyauth-app
|
||||||
ports:
|
ports:
|
||||||
- "5557:5557"
|
- "5557:5557"
|
||||||
volumes:
|
volumes:
|
||||||
- ./playwright/dex-config.yaml:/etc/dex/cfg.yaml:ro
|
- ./playwright/tinyauth/caddy.json:/etc/caddy/caddy.json:ro
|
||||||
command: dex serve /etc/dex/cfg.yaml
|
- ./playwright/tinyauth/caddy-data:/data
|
||||||
|
command: caddy run --config /etc/caddy/caddy.json
|
||||||
|
healthcheck:
|
||||||
|
test:
|
||||||
|
[
|
||||||
|
"CMD-SHELL",
|
||||||
|
"test -f /data/caddy/pki/authorities/local/root.crt && wget -qO- --no-check-certificate https://localhost:5557/.well-known/openid-configuration >/dev/null",
|
||||||
|
]
|
||||||
|
interval: 1s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 30
|
||||||
|
networks:
|
||||||
|
default:
|
||||||
|
aliases:
|
||||||
|
- tinyauth.example.com
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,11 @@ import { expect, test } from "./test";
|
||||||
import { trackBrowserErrors } from "./helpers/browser-errors";
|
import { trackBrowserErrors } from "./helpers/browser-errors";
|
||||||
import { gotoAndWaitForAppReady, waitForAppReady } from "./helpers/page";
|
import { gotoAndWaitForAppReady, waitForAppReady } from "./helpers/page";
|
||||||
|
|
||||||
const dexOrigin = process.env.E2E_DEX_ORIGIN ?? "http://dex:5557";
|
const tinyauthOrigin = process.env.E2E_TINYAUTH_ORIGIN ?? "https://tinyauth.example.com:5557";
|
||||||
const issuer = `${dexOrigin}/dex`;
|
const issuer = tinyauthOrigin;
|
||||||
const discoveryEndpoint = `${issuer}/.well-known/openid-configuration`;
|
const discoveryEndpoint = `${issuer}/.well-known/openid-configuration`;
|
||||||
const appBaseUrl = `http://${process.env.SERVER_IP ?? "localhost"}:4096`;
|
const appBaseUrl = `http://${process.env.SERVER_IP ?? "localhost"}:4096`;
|
||||||
|
const appOrigin = new URL(appBaseUrl).origin;
|
||||||
const setupAuthFile = path.join(process.cwd(), "playwright", ".auth", "user.json");
|
const setupAuthFile = path.join(process.cwd(), "playwright", ".auth", "user.json");
|
||||||
|
|
||||||
const providerIds = {
|
const providerIds = {
|
||||||
|
|
@ -17,7 +18,7 @@ const providerIds = {
|
||||||
autoLink: "test-oidc-autolink",
|
autoLink: "test-oidc-autolink",
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
const dexPassword = "password";
|
const tinyauthPassword = "password";
|
||||||
const uninvitedUserEmail = "admin@example.com";
|
const uninvitedUserEmail = "admin@example.com";
|
||||||
const invitedUserEmail = "user@example.com";
|
const invitedUserEmail = "user@example.com";
|
||||||
const autoLinkUninvitedLocalEmail = "linkguard@example.com";
|
const autoLinkUninvitedLocalEmail = "linkguard@example.com";
|
||||||
|
|
@ -49,6 +50,8 @@ type SsoSignInResponse = {
|
||||||
url?: string;
|
url?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type OidcUiState = "app" | "authorize" | "loading" | "login";
|
||||||
|
|
||||||
async function openSsoSettings(page: Page) {
|
async function openSsoSettings(page: Page) {
|
||||||
await gotoAndWaitForAppReady(page, "/settings?tab=organization");
|
await gotoAndWaitForAppReady(page, "/settings?tab=organization");
|
||||||
await expect(page.getByText("Single Sign-On")).toBeVisible();
|
await expect(page.getByText("Single Sign-On")).toBeVisible();
|
||||||
|
|
@ -98,7 +101,7 @@ async function createLocalUser(browser: Browser, email: string, username: string
|
||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
email,
|
email,
|
||||||
password: dexPassword,
|
password: tinyauthPassword,
|
||||||
name: "SSO Link Target",
|
name: "SSO Link Target",
|
||||||
role: "user",
|
role: "user",
|
||||||
data: {
|
data: {
|
||||||
|
|
@ -206,10 +209,45 @@ async function startSsoLogin(page: Page, providerId: string) {
|
||||||
return body.url;
|
return body.url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getOidcUiState(page: Page) {
|
||||||
|
const currentUrl = new URL(page.url());
|
||||||
|
|
||||||
|
if (currentUrl.origin === appOrigin) {
|
||||||
|
return "app" satisfies OidcUiState;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tinyauthLoginInput = page.locator('input[name="username"]');
|
||||||
|
if (await tinyauthLoginInput.isVisible().catch(() => false)) {
|
||||||
|
return "login" satisfies OidcUiState;
|
||||||
|
}
|
||||||
|
|
||||||
|
const authorizeButton = page.getByRole("button", { name: /authorize|allow/i });
|
||||||
|
if (await authorizeButton.isVisible().catch(() => false)) {
|
||||||
|
return "authorize" satisfies OidcUiState;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "loading" satisfies OidcUiState;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function waitForOidcUiState(page: Page, expectedStates: OidcUiState[], timeout = 15000) {
|
||||||
|
const expectedPattern = new RegExp(`^(?:${expectedStates.join("|")})$`);
|
||||||
|
|
||||||
|
await expect
|
||||||
|
.poll(
|
||||||
|
async () => {
|
||||||
|
return getOidcUiState(page);
|
||||||
|
},
|
||||||
|
{ timeout },
|
||||||
|
)
|
||||||
|
.toMatch(expectedPattern);
|
||||||
|
|
||||||
|
return getOidcUiState(page);
|
||||||
|
}
|
||||||
|
|
||||||
async function withOidcLoginAttempt(
|
async function withOidcLoginAttempt(
|
||||||
browser: Browser,
|
browser: Browser,
|
||||||
providerId: string,
|
providerId: string,
|
||||||
dexLogin: string,
|
tinyauthLogin: string,
|
||||||
assertions: (page: Page) => Promise<void>,
|
assertions: (page: Page) => Promise<void>,
|
||||||
) {
|
) {
|
||||||
const context = await browser.newContext({
|
const context = await browser.newContext({
|
||||||
|
|
@ -229,13 +267,19 @@ async function withOidcLoginAttempt(
|
||||||
const ssoUrl = await startSsoLogin(page, providerId);
|
const ssoUrl = await startSsoLogin(page, providerId);
|
||||||
await page.goto(ssoUrl);
|
await page.goto(ssoUrl);
|
||||||
|
|
||||||
const dexLoginInput = page.locator('input[name="login"]');
|
let oidcUiState = await waitForOidcUiState(page, ["app", "authorize", "login"]);
|
||||||
const dexLoginIsVisible = await dexLoginInput.isVisible({ timeout: 5000 }).catch(() => false);
|
|
||||||
|
|
||||||
if (dexLoginIsVisible) {
|
if (oidcUiState === "login") {
|
||||||
await dexLoginInput.fill(dexLogin);
|
const tinyauthLoginInput = page.locator('input[name="username"]');
|
||||||
await page.locator('input[name="password"]').fill(dexPassword);
|
await tinyauthLoginInput.fill(tinyauthLogin);
|
||||||
|
await page.locator('input[name="password"]').fill(tinyauthPassword);
|
||||||
await page.locator('button[type="submit"]').click();
|
await page.locator('button[type="submit"]').click();
|
||||||
|
|
||||||
|
oidcUiState = await waitForOidcUiState(page, ["app", "authorize"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oidcUiState === "authorize") {
|
||||||
|
await page.getByRole("button", { name: /authorize|allow/i }).click();
|
||||||
}
|
}
|
||||||
|
|
||||||
await assertions(page);
|
await assertions(page);
|
||||||
|
|
@ -246,12 +290,13 @@ async function withOidcLoginAttempt(
|
||||||
}
|
}
|
||||||
|
|
||||||
function isLoginPath(url: string): boolean {
|
function isLoginPath(url: string): boolean {
|
||||||
const pathname = new URL(url).pathname;
|
const parsedUrl = new URL(url);
|
||||||
return pathname === "/login" || pathname === "/login/error";
|
return parsedUrl.origin === appOrigin && (parsedUrl.pathname === "/login" || parsedUrl.pathname === "/login/error");
|
||||||
}
|
}
|
||||||
|
|
||||||
function isSsoCallbackPath(url: string): boolean {
|
function isSsoCallbackPath(url: string): boolean {
|
||||||
return new URL(url).pathname.startsWith("/api/auth/sso/callback/");
|
const parsedUrl = new URL(url);
|
||||||
|
return parsedUrl.origin === appOrigin && parsedUrl.pathname.startsWith("/api/auth/sso/callback/");
|
||||||
}
|
}
|
||||||
|
|
||||||
async function expectInviteOnlyLoginError(page: Page) {
|
async function expectInviteOnlyLoginError(page: Page) {
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
"tsc": "tsc --noEmit && turbo run tsc",
|
"tsc": "tsc --noEmit && turbo run tsc",
|
||||||
"start:dev": "docker compose down && docker compose up --build zerobyte-dev",
|
"start:dev": "docker compose down && docker compose up --build zerobyte-dev",
|
||||||
"start:prod": "docker compose down && docker compose up --build zerobyte-prod",
|
"start:prod": "docker compose down && docker compose up --build zerobyte-prod",
|
||||||
"start:e2e": "docker compose down && rm -rf playwright/data/* playwright/.auth/user.json playwright/restic.pass && mkdir -p playwright/temp && rm -rf playwright/temp/* && docker compose up --build zerobyte-e2e",
|
"start:e2e": "docker compose down && mkdir -p playwright/data playwright/temp playwright/tinyauth/app-data playwright/tinyauth/caddy-data && rm -rf playwright/data/* playwright/.auth/user.json playwright/restic.pass playwright/temp/* playwright/tinyauth/app-data/* && docker compose up --build zerobyte-e2e",
|
||||||
"start:distroless": "docker compose down && docker compose up --build zerobyte-distroless",
|
"start:distroless": "docker compose down && docker compose up --build zerobyte-distroless",
|
||||||
"gen:api-client": "dotenv -e .env.local -- openapi-ts",
|
"gen:api-client": "dotenv -e .env.local -- openapi-ts",
|
||||||
"gen:migrations": "dotenv -e .env.local -- drizzle-kit generate",
|
"gen:migrations": "dotenv -e .env.local -- drizzle-kit generate",
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ export default defineConfig({
|
||||||
baseURL: `http://${process.env.SERVER_IP}:4096`,
|
baseURL: `http://${process.env.SERVER_IP}:4096`,
|
||||||
video: "retain-on-failure",
|
video: "retain-on-failure",
|
||||||
trace: "retain-on-failure",
|
trace: "retain-on-failure",
|
||||||
|
ignoreHTTPSErrors: true,
|
||||||
},
|
},
|
||||||
projects: [
|
projects: [
|
||||||
{
|
{
|
||||||
|
|
@ -24,7 +25,7 @@ export default defineConfig({
|
||||||
use: {
|
use: {
|
||||||
...devices["Desktop Chrome"],
|
...devices["Desktop Chrome"],
|
||||||
launchOptions: {
|
launchOptions: {
|
||||||
args: ["--host-rules=MAP dex 127.0.0.1"],
|
args: ["--host-rules=MAP tinyauth.example.com 127.0.0.1"],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
dependencies: ["setup"],
|
dependencies: ["setup"],
|
||||||
|
|
|
||||||
|
|
@ -1,58 +0,0 @@
|
||||||
issuer: http://dex:5557/dex
|
|
||||||
|
|
||||||
storage:
|
|
||||||
type: sqlite3
|
|
||||||
config:
|
|
||||||
file: /tmp/dex.db
|
|
||||||
|
|
||||||
web:
|
|
||||||
http: 0.0.0.0:5557
|
|
||||||
|
|
||||||
enablePasswordDB: true
|
|
||||||
|
|
||||||
staticPasswords:
|
|
||||||
- email: "admin@example.com"
|
|
||||||
hash: "$2a$10$2b2cU8CPhOTaGrs1HRQuAueS7JTT5ZHsHSzYiFPm1leZck7Mc8T4W"
|
|
||||||
username: "admin"
|
|
||||||
userID: "001"
|
|
||||||
- email: "user@example.com"
|
|
||||||
hash: "$2a$10$2b2cU8CPhOTaGrs1HRQuAueS7JTT5ZHsHSzYiFPm1leZck7Mc8T4W"
|
|
||||||
username: "user"
|
|
||||||
userID: "002"
|
|
||||||
- email: "test@example.com"
|
|
||||||
hash: "$2a$10$2b2cU8CPhOTaGrs1HRQuAueS7JTT5ZHsHSzYiFPm1leZck7Mc8T4W"
|
|
||||||
username: "test"
|
|
||||||
userID: "003"
|
|
||||||
- email: "test@test.com"
|
|
||||||
hash: "$2a$10$2b2cU8CPhOTaGrs1HRQuAueS7JTT5ZHsHSzYiFPm1leZck7Mc8T4W"
|
|
||||||
username: "test-local"
|
|
||||||
userID: "004"
|
|
||||||
- email: "linkguard@example.com"
|
|
||||||
hash: "$2a$10$2b2cU8CPhOTaGrs1HRQuAueS7JTT5ZHsHSzYiFPm1leZck7Mc8T4W"
|
|
||||||
username: "linkguard"
|
|
||||||
userID: "005"
|
|
||||||
|
|
||||||
staticClients:
|
|
||||||
- id: zerobyte-test
|
|
||||||
name: Zerobyte Test
|
|
||||||
redirectURIs:
|
|
||||||
- "http://localhost:3000/api/auth/sso/callback/credential"
|
|
||||||
- "http://localhost:3000/api/auth/sso/callback/dex"
|
|
||||||
- "http://localhost:4096/api/auth/sso/callback/test-oidc"
|
|
||||||
- "http://localhost:4096/api/auth/sso/callback/test-oidc-register"
|
|
||||||
- "http://localhost:4096/api/auth/sso/callback/test-oidc-uninvited"
|
|
||||||
- "http://localhost:4096/api/auth/sso/callback/test-oidc-invited"
|
|
||||||
- "http://localhost:4096/api/auth/sso/callback/test-oidc-autolink"
|
|
||||||
secret: test-secret-12345
|
|
||||||
|
|
||||||
oauth2:
|
|
||||||
skipApprovalScreen: true
|
|
||||||
|
|
||||||
logger:
|
|
||||||
level: debug
|
|
||||||
format: json
|
|
||||||
|
|
||||||
# Issuer URL: http://dex:5557/dex
|
|
||||||
# Discovery URL: http://dex:5557/dex/.well-known/openid-configuration
|
|
||||||
# Client ID: zerobyte-test
|
|
||||||
# Client Secret: test-secret-12345
|
|
||||||
45
playwright/tinyauth/caddy.json
Normal file
45
playwright/tinyauth/caddy.json
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
{
|
||||||
|
"apps": {
|
||||||
|
"http": {
|
||||||
|
"servers": {
|
||||||
|
"srv0": {
|
||||||
|
"listen": [":5557"],
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"match": [
|
||||||
|
{
|
||||||
|
"host": ["tinyauth.example.com", "localhost"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"handle": [
|
||||||
|
{
|
||||||
|
"handler": "reverse_proxy",
|
||||||
|
"upstreams": [
|
||||||
|
{
|
||||||
|
"dial": "tinyauth-app:3000"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"terminal": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tls": {
|
||||||
|
"automation": {
|
||||||
|
"policies": [
|
||||||
|
{
|
||||||
|
"subjects": ["tinyauth.example.com", "localhost"],
|
||||||
|
"issuers": [
|
||||||
|
{
|
||||||
|
"module": "internal"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
5
playwright/tinyauth/users.txt
Normal file
5
playwright/tinyauth/users.txt
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
admin@example.com:$2a$10$2b2cU8CPhOTaGrs1HRQuAueS7JTT5ZHsHSzYiFPm1leZck7Mc8T4W
|
||||||
|
user@example.com:$2a$10$2b2cU8CPhOTaGrs1HRQuAueS7JTT5ZHsHSzYiFPm1leZck7Mc8T4W
|
||||||
|
test@example.com:$2a$10$2b2cU8CPhOTaGrs1HRQuAueS7JTT5ZHsHSzYiFPm1leZck7Mc8T4W
|
||||||
|
test@test.com:$2a$10$2b2cU8CPhOTaGrs1HRQuAueS7JTT5ZHsHSzYiFPm1leZck7Mc8T4W
|
||||||
|
linkguard@example.com:$2a$10$2b2cU8CPhOTaGrs1HRQuAueS7JTT5ZHsHSzYiFPm1leZck7Mc8T4W
|
||||||
Loading…
Reference in a new issue