Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
46a3e3b
Add OIDC authentication support with Arctic library
jmorton Dec 8, 2025
5c16379
Replace PageData.user with reactive userStore across application
jmorton Dec 8, 2025
be6e135
Add server-side rule enforcement infrastructure
jmorton Dec 8, 2025
47959b4
Add E2E tests for OIDC authentication flow
jmorton Dec 8, 2025
48790cc
Update non-OIDC auth routes to use event-based cookie handling
jmorton Dec 8, 2025
2dba59a
Fix race condition in OIDC well-known configuration fetch
jmorton Dec 8, 2025
7e958b8
Add OIDC nonce parameter for replay attack protection
jmorton Dec 8, 2025
34d49f1
Add audience claim validation to JWT verification
jmorton Dec 8, 2025
4848409
Validate audience only on ID token per OIDC spec
jmorton Dec 9, 2025
684a9df
Fix open redirect vulnerability in back parameter
jmorton Dec 9, 2025
216a19b
Add secure flag to all authentication cookies
jmorton Dec 9, 2025
623b39e
Add SameSite=Lax to all authentication cookies
jmorton Dec 9, 2025
5148894
Add configurable JWT signing algorithms via OIDC_ALGORITHMS env var
jmorton Dec 9, 2025
10f35c9
Remove sensitive data from OIDC logs
jmorton Dec 9, 2025
d9f266e
Standardize OIDC logging and fix additional sensitive data leaks
jmorton Dec 9, 2025
b4b1beb
Add Content Security Policy headers (report-only mode)
jmorton Dec 9, 2025
da15bd8
Verify ID token before using as logout hint
jmorton Dec 9, 2025
96f8604
Add configurable JWT claim paths for OIDC
jmorton Dec 9, 2025
23c109c
Use dynamically loaded env vars for OIDC related values set at launch…
jmorton Dec 10, 2025
6bf7260
Fix WebSocket lifecycle and token refresh for OIDC
AaronPlave Feb 17, 2026
7e56f90
Linting, fixes, and small cleanup
AaronPlave Feb 17, 2026
0f45665
Handle expired refresh tokens gracefully instead of infinite retry loop
AaronPlave Feb 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,17 @@ PUBLIC_LIBRARY_SEQUENCES_ENABLED=false
PUBLIC_COMMAND_EXPANSION_MODE=typescript
# VITE_HOST=localhost.jpl.nasa.gov
# VITE_HTTPS=true

PUBLIC_AUTH_OIDC_ENABLED=false
OIDC_WELL_KNOWN_URL=
OIDC_AUTHORIZATION_URL=
OIDC_TOKEN_URL=
OIDC_LOGOUT_URL=
OIDC_JWKS_URL=
OIDC_SCOPES=
OIDC_CLIENT_ID=
OIDC_CLIENT_SECRET=
OIDC_REDIRECT_URI=
OIDC_AUDIENCE=
OIDC_ISSUER=
OIDC_ALGORITHMS=
6 changes: 6 additions & 0 deletions e2e-tests/fixtures/AppNav.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ export class AppNav {
await this.pageLoadingLocator.waitFor({ state: 'detached' });
}

async show() {
await this.appMenuButton.click();
await this.appMenu.waitFor({ state: 'attached' });
await this.appMenu.waitFor({ state: 'visible' });
}

updatePage(page: Page): void {
this.aboutModal = page.locator(`.modal:has-text("About")`);
this.aboutModalCloseButton = page.locator(`.modal:has-text("About") >> button:has-text("Close")`);
Expand Down
213 changes: 213 additions & 0 deletions e2e-tests/fixtures/OIDC.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
import { expect, Locator, Page } from '@playwright/test';
import { decode, JwtPayload } from 'jsonwebtoken';
import { AppNav } from './AppNav';

type HasuraToken = JwtPayload & {
'https://hasura.io/jwt/claims': {
'x-hasura-allowed-roles': string[];
'x-hasura-default-role': string;
'x-hasura-user-id': string;
};
};

// OIDC spans several pages.
// As such, we will define a class for each of the pages,
// and then incorporate them as members into an overall
// OIDC class.
class AerieLogin {
loginButton: Locator;

constructor(public page: Page) {
this.updatePage(page);
}

async login() {
await this.page.goto('/plans', { waitUntil: 'load' });
const loginButton = this.page.getByText('Login Using OIDC');

await loginButton.waitFor();

Check failure on line 28 in e2e-tests/fixtures/OIDC.ts

View workflow job for this annotation

GitHub Actions / e2e-test

[oidc tests] › e2e-tests/tests/oidc.test.ts:52:3 › Different Logins › Login as user

2) [oidc tests] › e2e-tests/tests/oidc.test.ts:52:3 › Different Logins › Login as user ─────────── Retry #1 ─────────────────────────────────────────────────────────────────────────────────────── Error: locator.waitFor: Target page, context or browser has been closed Call log: - waiting for getByText('Login Using OIDC') to be visible at fixtures/OIDC.ts:28 26 | const loginButton = this.page.getByText('Login Using OIDC'); 27 | > 28 | await loginButton.waitFor(); | ^ 29 | 30 | let buttonClicked: boolean = false; 31 | await loginButton.click(); at AerieLogin.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:28:23) at OIDC.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:158:5) at /home/runner/work/***-ui/***-ui/e2e-tests/tests/oidc.test.ts:56:5

Check failure on line 28 in e2e-tests/fixtures/OIDC.ts

View workflow job for this annotation

GitHub Actions / e2e-test

[oidc tests] › e2e-tests/tests/oidc.test.ts:52:3 › Different Logins › Login as user

2) [oidc tests] › e2e-tests/tests/oidc.test.ts:52:3 › Different Logins › Login as user ─────────── Error: locator.waitFor: Target page, context or browser has been closed Call log: - waiting for getByText('Login Using OIDC') to be visible at fixtures/OIDC.ts:28 26 | const loginButton = this.page.getByText('Login Using OIDC'); 27 | > 28 | await loginButton.waitFor(); | ^ 29 | 30 | let buttonClicked: boolean = false; 31 | await loginButton.click(); at AerieLogin.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:28:23) at OIDC.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:158:5) at /home/runner/work/***-ui/***-ui/e2e-tests/tests/oidc.test.ts:56:5

Check failure on line 28 in e2e-tests/fixtures/OIDC.ts

View workflow job for this annotation

GitHub Actions / e2e-test

[oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin

1) [oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin ────────── Retry #2 ─────────────────────────────────────────────────────────────────────────────────────── Error: locator.waitFor: Target page, context or browser has been closed Call log: - waiting for getByText('Login Using OIDC') to be visible at fixtures/OIDC.ts:28 26 | const loginButton = this.page.getByText('Login Using OIDC'); 27 | > 28 | await loginButton.waitFor(); | ^ 29 | 30 | let buttonClicked: boolean = false; 31 | await loginButton.click(); at AerieLogin.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:28:23) at OIDC.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:158:5) at /home/runner/work/***-ui/***-ui/e2e-tests/tests/oidc.test.ts:48:5

Check failure on line 28 in e2e-tests/fixtures/OIDC.ts

View workflow job for this annotation

GitHub Actions / e2e-test

[oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin

1) [oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin ────────── Retry #1 ─────────────────────────────────────────────────────────────────────────────────────── Error: locator.waitFor: Target page, context or browser has been closed Call log: - waiting for getByText('Login Using OIDC') to be visible at fixtures/OIDC.ts:28 26 | const loginButton = this.page.getByText('Login Using OIDC'); 27 | > 28 | await loginButton.waitFor(); | ^ 29 | 30 | let buttonClicked: boolean = false; 31 | await loginButton.click(); at AerieLogin.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:28:23) at OIDC.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:158:5) at /home/runner/work/***-ui/***-ui/e2e-tests/tests/oidc.test.ts:48:5

Check failure on line 28 in e2e-tests/fixtures/OIDC.ts

View workflow job for this annotation

GitHub Actions / e2e-test

[oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin

1) [oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin ────────── Error: locator.waitFor: Target page, context or browser has been closed Call log: - waiting for getByText('Login Using OIDC') to be visible at fixtures/OIDC.ts:28 26 | const loginButton = this.page.getByText('Login Using OIDC'); 27 | > 28 | await loginButton.waitFor(); | ^ 29 | 30 | let buttonClicked: boolean = false; 31 | await loginButton.click(); at AerieLogin.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:28:23) at OIDC.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:158:5) at /home/runner/work/***-ui/***-ui/e2e-tests/tests/oidc.test.ts:48:5

Check failure on line 28 in e2e-tests/fixtures/OIDC.ts

View workflow job for this annotation

GitHub Actions / e2e-test

[oidc tests] › e2e-tests/tests/oidc.test.ts:52:3 › Different Logins › Login as user

2) [oidc tests] › e2e-tests/tests/oidc.test.ts:52:3 › Different Logins › Login as user ─────────── Retry #1 ─────────────────────────────────────────────────────────────────────────────────────── Error: locator.waitFor: Target page, context or browser has been closed Call log: - waiting for getByText('Login Using OIDC') to be visible at fixtures/OIDC.ts:28 26 | const loginButton = this.page.getByText('Login Using OIDC'); 27 | > 28 | await loginButton.waitFor(); | ^ 29 | 30 | let buttonClicked: boolean = false; 31 | await loginButton.click(); at AerieLogin.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:28:23) at OIDC.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:158:5) at /home/runner/work/***-ui/***-ui/e2e-tests/tests/oidc.test.ts:56:5

Check failure on line 28 in e2e-tests/fixtures/OIDC.ts

View workflow job for this annotation

GitHub Actions / e2e-test

[oidc tests] › e2e-tests/tests/oidc.test.ts:52:3 › Different Logins › Login as user

2) [oidc tests] › e2e-tests/tests/oidc.test.ts:52:3 › Different Logins › Login as user ─────────── Error: locator.waitFor: Target page, context or browser has been closed Call log: - waiting for getByText('Login Using OIDC') to be visible at fixtures/OIDC.ts:28 26 | const loginButton = this.page.getByText('Login Using OIDC'); 27 | > 28 | await loginButton.waitFor(); | ^ 29 | 30 | let buttonClicked: boolean = false; 31 | await loginButton.click(); at AerieLogin.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:28:23) at OIDC.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:158:5) at /home/runner/work/***-ui/***-ui/e2e-tests/tests/oidc.test.ts:56:5

Check failure on line 28 in e2e-tests/fixtures/OIDC.ts

View workflow job for this annotation

GitHub Actions / e2e-test

[oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin

1) [oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin ────────── Retry #2 ─────────────────────────────────────────────────────────────────────────────────────── Error: locator.waitFor: Target page, context or browser has been closed Call log: - waiting for getByText('Login Using OIDC') to be visible at fixtures/OIDC.ts:28 26 | const loginButton = this.page.getByText('Login Using OIDC'); 27 | > 28 | await loginButton.waitFor(); | ^ 29 | 30 | let buttonClicked: boolean = false; 31 | await loginButton.click(); at AerieLogin.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:28:23) at OIDC.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:158:5) at /home/runner/work/***-ui/***-ui/e2e-tests/tests/oidc.test.ts:48:5

Check failure on line 28 in e2e-tests/fixtures/OIDC.ts

View workflow job for this annotation

GitHub Actions / e2e-test

[oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin

1) [oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin ────────── Retry #1 ─────────────────────────────────────────────────────────────────────────────────────── Error: locator.waitFor: Target page, context or browser has been closed Call log: - waiting for getByText('Login Using OIDC') to be visible at fixtures/OIDC.ts:28 26 | const loginButton = this.page.getByText('Login Using OIDC'); 27 | > 28 | await loginButton.waitFor(); | ^ 29 | 30 | let buttonClicked: boolean = false; 31 | await loginButton.click(); at AerieLogin.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:28:23) at OIDC.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:158:5) at /home/runner/work/***-ui/***-ui/e2e-tests/tests/oidc.test.ts:48:5

Check failure on line 28 in e2e-tests/fixtures/OIDC.ts

View workflow job for this annotation

GitHub Actions / e2e-test

[oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin

1) [oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin ────────── Error: locator.waitFor: Target page, context or browser has been closed Call log: - waiting for getByText('Login Using OIDC') to be visible at fixtures/OIDC.ts:28 26 | const loginButton = this.page.getByText('Login Using OIDC'); 27 | > 28 | await loginButton.waitFor(); | ^ 29 | 30 | let buttonClicked: boolean = false; 31 | await loginButton.click(); at AerieLogin.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:28:23) at OIDC.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:158:5) at /home/runner/work/***-ui/***-ui/e2e-tests/tests/oidc.test.ts:48:5

Check failure on line 28 in e2e-tests/fixtures/OIDC.ts

View workflow job for this annotation

GitHub Actions / e2e-test

[oidc tests] › e2e-tests/tests/oidc.test.ts:52:3 › Different Logins › Login as user

2) [oidc tests] › e2e-tests/tests/oidc.test.ts:52:3 › Different Logins › Login as user ─────────── Retry #1 ─────────────────────────────────────────────────────────────────────────────────────── Error: locator.waitFor: Target page, context or browser has been closed Call log: - waiting for getByText('Login Using OIDC') to be visible at fixtures/OIDC.ts:28 26 | const loginButton = this.page.getByText('Login Using OIDC'); 27 | > 28 | await loginButton.waitFor(); | ^ 29 | 30 | let buttonClicked: boolean = false; 31 | await loginButton.click(); at AerieLogin.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:28:23) at OIDC.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:158:5) at /home/runner/work/***-ui/***-ui/e2e-tests/tests/oidc.test.ts:56:5

Check failure on line 28 in e2e-tests/fixtures/OIDC.ts

View workflow job for this annotation

GitHub Actions / e2e-test

[oidc tests] › e2e-tests/tests/oidc.test.ts:52:3 › Different Logins › Login as user

2) [oidc tests] › e2e-tests/tests/oidc.test.ts:52:3 › Different Logins › Login as user ─────────── Error: locator.waitFor: Target page, context or browser has been closed Call log: - waiting for getByText('Login Using OIDC') to be visible at fixtures/OIDC.ts:28 26 | const loginButton = this.page.getByText('Login Using OIDC'); 27 | > 28 | await loginButton.waitFor(); | ^ 29 | 30 | let buttonClicked: boolean = false; 31 | await loginButton.click(); at AerieLogin.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:28:23) at OIDC.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:158:5) at /home/runner/work/***-ui/***-ui/e2e-tests/tests/oidc.test.ts:56:5

Check failure on line 28 in e2e-tests/fixtures/OIDC.ts

View workflow job for this annotation

GitHub Actions / e2e-test

[oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin

1) [oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin ────────── Retry #2 ─────────────────────────────────────────────────────────────────────────────────────── Error: locator.waitFor: Target page, context or browser has been closed Call log: - waiting for getByText('Login Using OIDC') to be visible at fixtures/OIDC.ts:28 26 | const loginButton = this.page.getByText('Login Using OIDC'); 27 | > 28 | await loginButton.waitFor(); | ^ 29 | 30 | let buttonClicked: boolean = false; 31 | await loginButton.click(); at AerieLogin.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:28:23) at OIDC.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:158:5) at /home/runner/work/***-ui/***-ui/e2e-tests/tests/oidc.test.ts:48:5

Check failure on line 28 in e2e-tests/fixtures/OIDC.ts

View workflow job for this annotation

GitHub Actions / e2e-test

[oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin

1) [oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin ────────── Retry #1 ─────────────────────────────────────────────────────────────────────────────────────── Error: locator.waitFor: Target page, context or browser has been closed Call log: - waiting for getByText('Login Using OIDC') to be visible at fixtures/OIDC.ts:28 26 | const loginButton = this.page.getByText('Login Using OIDC'); 27 | > 28 | await loginButton.waitFor(); | ^ 29 | 30 | let buttonClicked: boolean = false; 31 | await loginButton.click(); at AerieLogin.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:28:23) at OIDC.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:158:5) at /home/runner/work/***-ui/***-ui/e2e-tests/tests/oidc.test.ts:48:5

Check failure on line 28 in e2e-tests/fixtures/OIDC.ts

View workflow job for this annotation

GitHub Actions / e2e-test

[oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin

1) [oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin ────────── Error: locator.waitFor: Target page, context or browser has been closed Call log: - waiting for getByText('Login Using OIDC') to be visible at fixtures/OIDC.ts:28 26 | const loginButton = this.page.getByText('Login Using OIDC'); 27 | > 28 | await loginButton.waitFor(); | ^ 29 | 30 | let buttonClicked: boolean = false; 31 | await loginButton.click(); at AerieLogin.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:28:23) at OIDC.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:158:5) at /home/runner/work/***-ui/***-ui/e2e-tests/tests/oidc.test.ts:48:5

Check failure on line 28 in e2e-tests/fixtures/OIDC.ts

View workflow job for this annotation

GitHub Actions / e2e-test

[oidc tests] › e2e-tests/tests/oidc.test.ts:52:3 › Different Logins › Login as user

2) [oidc tests] › e2e-tests/tests/oidc.test.ts:52:3 › Different Logins › Login as user ─────────── Retry #1 ─────────────────────────────────────────────────────────────────────────────────────── Error: locator.waitFor: Target page, context or browser has been closed Call log: - waiting for getByText('Login Using OIDC') to be visible at fixtures/OIDC.ts:28 26 | const loginButton = this.page.getByText('Login Using OIDC'); 27 | > 28 | await loginButton.waitFor(); | ^ 29 | 30 | let buttonClicked: boolean = false; 31 | await loginButton.click(); at AerieLogin.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:28:23) at OIDC.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:158:5) at /home/runner/work/***-ui/***-ui/e2e-tests/tests/oidc.test.ts:56:5

Check failure on line 28 in e2e-tests/fixtures/OIDC.ts

View workflow job for this annotation

GitHub Actions / e2e-test

[oidc tests] › e2e-tests/tests/oidc.test.ts:52:3 › Different Logins › Login as user

2) [oidc tests] › e2e-tests/tests/oidc.test.ts:52:3 › Different Logins › Login as user ─────────── Error: locator.waitFor: Target page, context or browser has been closed Call log: - waiting for getByText('Login Using OIDC') to be visible at fixtures/OIDC.ts:28 26 | const loginButton = this.page.getByText('Login Using OIDC'); 27 | > 28 | await loginButton.waitFor(); | ^ 29 | 30 | let buttonClicked: boolean = false; 31 | await loginButton.click(); at AerieLogin.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:28:23) at OIDC.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:158:5) at /home/runner/work/***-ui/***-ui/e2e-tests/tests/oidc.test.ts:56:5

Check failure on line 28 in e2e-tests/fixtures/OIDC.ts

View workflow job for this annotation

GitHub Actions / e2e-test

[oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin

1) [oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin ────────── Retry #2 ─────────────────────────────────────────────────────────────────────────────────────── Error: locator.waitFor: Target page, context or browser has been closed Call log: - waiting for getByText('Login Using OIDC') to be visible at fixtures/OIDC.ts:28 26 | const loginButton = this.page.getByText('Login Using OIDC'); 27 | > 28 | await loginButton.waitFor(); | ^ 29 | 30 | let buttonClicked: boolean = false; 31 | await loginButton.click(); at AerieLogin.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:28:23) at OIDC.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:158:5) at /home/runner/work/***-ui/***-ui/e2e-tests/tests/oidc.test.ts:48:5

Check failure on line 28 in e2e-tests/fixtures/OIDC.ts

View workflow job for this annotation

GitHub Actions / e2e-test

[oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin

1) [oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin ────────── Retry #1 ─────────────────────────────────────────────────────────────────────────────────────── Error: locator.waitFor: Target page, context or browser has been closed Call log: - waiting for getByText('Login Using OIDC') to be visible at fixtures/OIDC.ts:28 26 | const loginButton = this.page.getByText('Login Using OIDC'); 27 | > 28 | await loginButton.waitFor(); | ^ 29 | 30 | let buttonClicked: boolean = false; 31 | await loginButton.click(); at AerieLogin.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:28:23) at OIDC.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:158:5) at /home/runner/work/***-ui/***-ui/e2e-tests/tests/oidc.test.ts:48:5

Check failure on line 28 in e2e-tests/fixtures/OIDC.ts

View workflow job for this annotation

GitHub Actions / e2e-test

[oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin

1) [oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin ────────── Error: locator.waitFor: Target page, context or browser has been closed Call log: - waiting for getByText('Login Using OIDC') to be visible at fixtures/OIDC.ts:28 26 | const loginButton = this.page.getByText('Login Using OIDC'); 27 | > 28 | await loginButton.waitFor(); | ^ 29 | 30 | let buttonClicked: boolean = false; 31 | await loginButton.click(); at AerieLogin.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:28:23) at OIDC.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:158:5) at /home/runner/work/***-ui/***-ui/e2e-tests/tests/oidc.test.ts:48:5

Check failure on line 28 in e2e-tests/fixtures/OIDC.ts

View workflow job for this annotation

GitHub Actions / e2e-test

[oidc tests] › e2e-tests/tests/oidc.test.ts:52:3 › Different Logins › Login as user

2) [oidc tests] › e2e-tests/tests/oidc.test.ts:52:3 › Different Logins › Login as user ─────────── Retry #1 ─────────────────────────────────────────────────────────────────────────────────────── Error: locator.waitFor: Target page, context or browser has been closed Call log: - waiting for getByText('Login Using OIDC') to be visible at fixtures/OIDC.ts:28 26 | const loginButton = this.page.getByText('Login Using OIDC'); 27 | > 28 | await loginButton.waitFor(); | ^ 29 | 30 | let buttonClicked: boolean = false; 31 | await loginButton.click(); at AerieLogin.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:28:23) at OIDC.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:158:5) at /home/runner/work/***-ui/***-ui/e2e-tests/tests/oidc.test.ts:56:5

Check failure on line 28 in e2e-tests/fixtures/OIDC.ts

View workflow job for this annotation

GitHub Actions / e2e-test

[oidc tests] › e2e-tests/tests/oidc.test.ts:52:3 › Different Logins › Login as user

2) [oidc tests] › e2e-tests/tests/oidc.test.ts:52:3 › Different Logins › Login as user ─────────── Error: locator.waitFor: Target page, context or browser has been closed Call log: - waiting for getByText('Login Using OIDC') to be visible at fixtures/OIDC.ts:28 26 | const loginButton = this.page.getByText('Login Using OIDC'); 27 | > 28 | await loginButton.waitFor(); | ^ 29 | 30 | let buttonClicked: boolean = false; 31 | await loginButton.click(); at AerieLogin.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:28:23) at OIDC.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:158:5) at /home/runner/work/***-ui/***-ui/e2e-tests/tests/oidc.test.ts:56:5

Check failure on line 28 in e2e-tests/fixtures/OIDC.ts

View workflow job for this annotation

GitHub Actions / e2e-test

[oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin

1) [oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin ────────── Retry #2 ─────────────────────────────────────────────────────────────────────────────────────── Error: locator.waitFor: Target page, context or browser has been closed Call log: - waiting for getByText('Login Using OIDC') to be visible at fixtures/OIDC.ts:28 26 | const loginButton = this.page.getByText('Login Using OIDC'); 27 | > 28 | await loginButton.waitFor(); | ^ 29 | 30 | let buttonClicked: boolean = false; 31 | await loginButton.click(); at AerieLogin.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:28:23) at OIDC.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:158:5) at /home/runner/work/***-ui/***-ui/e2e-tests/tests/oidc.test.ts:48:5

Check failure on line 28 in e2e-tests/fixtures/OIDC.ts

View workflow job for this annotation

GitHub Actions / e2e-test

[oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin

1) [oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin ────────── Retry #1 ─────────────────────────────────────────────────────────────────────────────────────── Error: locator.waitFor: Target page, context or browser has been closed Call log: - waiting for getByText('Login Using OIDC') to be visible at fixtures/OIDC.ts:28 26 | const loginButton = this.page.getByText('Login Using OIDC'); 27 | > 28 | await loginButton.waitFor(); | ^ 29 | 30 | let buttonClicked: boolean = false; 31 | await loginButton.click(); at AerieLogin.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:28:23) at OIDC.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:158:5) at /home/runner/work/***-ui/***-ui/e2e-tests/tests/oidc.test.ts:48:5

Check failure on line 28 in e2e-tests/fixtures/OIDC.ts

View workflow job for this annotation

GitHub Actions / e2e-test

[oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin

1) [oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin ────────── Error: locator.waitFor: Target page, context or browser has been closed Call log: - waiting for getByText('Login Using OIDC') to be visible at fixtures/OIDC.ts:28 26 | const loginButton = this.page.getByText('Login Using OIDC'); 27 | > 28 | await loginButton.waitFor(); | ^ 29 | 30 | let buttonClicked: boolean = false; 31 | await loginButton.click(); at AerieLogin.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:28:23) at OIDC.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:158:5) at /home/runner/work/***-ui/***-ui/e2e-tests/tests/oidc.test.ts:48:5

Check failure on line 28 in e2e-tests/fixtures/OIDC.ts

View workflow job for this annotation

GitHub Actions / e2e-test

[oidc tests] › e2e-tests/tests/oidc.test.ts:52:3 › Different Logins › Login as user

2) [oidc tests] › e2e-tests/tests/oidc.test.ts:52:3 › Different Logins › Login as user ─────────── Retry #1 ─────────────────────────────────────────────────────────────────────────────────────── Error: locator.waitFor: Target page, context or browser has been closed Call log: - waiting for getByText('Login Using OIDC') to be visible at fixtures/OIDC.ts:28 26 | const loginButton = this.page.getByText('Login Using OIDC'); 27 | > 28 | await loginButton.waitFor(); | ^ 29 | 30 | let buttonClicked: boolean = false; 31 | await loginButton.click(); at AerieLogin.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:28:23) at OIDC.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:158:5) at /home/runner/work/***-ui/***-ui/e2e-tests/tests/oidc.test.ts:56:5

Check failure on line 28 in e2e-tests/fixtures/OIDC.ts

View workflow job for this annotation

GitHub Actions / e2e-test

[oidc tests] › e2e-tests/tests/oidc.test.ts:52:3 › Different Logins › Login as user

2) [oidc tests] › e2e-tests/tests/oidc.test.ts:52:3 › Different Logins › Login as user ─────────── Error: locator.waitFor: Target page, context or browser has been closed Call log: - waiting for getByText('Login Using OIDC') to be visible at fixtures/OIDC.ts:28 26 | const loginButton = this.page.getByText('Login Using OIDC'); 27 | > 28 | await loginButton.waitFor(); | ^ 29 | 30 | let buttonClicked: boolean = false; 31 | await loginButton.click(); at AerieLogin.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:28:23) at OIDC.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:158:5) at /home/runner/work/***-ui/***-ui/e2e-tests/tests/oidc.test.ts:56:5

Check failure on line 28 in e2e-tests/fixtures/OIDC.ts

View workflow job for this annotation

GitHub Actions / e2e-test

[oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin

1) [oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin ────────── Retry #2 ─────────────────────────────────────────────────────────────────────────────────────── Error: locator.waitFor: Target page, context or browser has been closed Call log: - waiting for getByText('Login Using OIDC') to be visible at fixtures/OIDC.ts:28 26 | const loginButton = this.page.getByText('Login Using OIDC'); 27 | > 28 | await loginButton.waitFor(); | ^ 29 | 30 | let buttonClicked: boolean = false; 31 | await loginButton.click(); at AerieLogin.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:28:23) at OIDC.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:158:5) at /home/runner/work/***-ui/***-ui/e2e-tests/tests/oidc.test.ts:48:5

Check failure on line 28 in e2e-tests/fixtures/OIDC.ts

View workflow job for this annotation

GitHub Actions / e2e-test

[oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin

1) [oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin ────────── Retry #1 ─────────────────────────────────────────────────────────────────────────────────────── Error: locator.waitFor: Target page, context or browser has been closed Call log: - waiting for getByText('Login Using OIDC') to be visible at fixtures/OIDC.ts:28 26 | const loginButton = this.page.getByText('Login Using OIDC'); 27 | > 28 | await loginButton.waitFor(); | ^ 29 | 30 | let buttonClicked: boolean = false; 31 | await loginButton.click(); at AerieLogin.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:28:23) at OIDC.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:158:5) at /home/runner/work/***-ui/***-ui/e2e-tests/tests/oidc.test.ts:48:5

Check failure on line 28 in e2e-tests/fixtures/OIDC.ts

View workflow job for this annotation

GitHub Actions / e2e-test

[oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin

1) [oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin ────────── Error: locator.waitFor: Target page, context or browser has been closed Call log: - waiting for getByText('Login Using OIDC') to be visible at fixtures/OIDC.ts:28 26 | const loginButton = this.page.getByText('Login Using OIDC'); 27 | > 28 | await loginButton.waitFor(); | ^ 29 | 30 | let buttonClicked: boolean = false; 31 | await loginButton.click(); at AerieLogin.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:28:23) at OIDC.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:158:5) at /home/runner/work/***-ui/***-ui/e2e-tests/tests/oidc.test.ts:48:5

Check failure on line 28 in e2e-tests/fixtures/OIDC.ts

View workflow job for this annotation

GitHub Actions / e2e-test

[oidc tests] › e2e-tests/tests/oidc.test.ts:52:3 › Different Logins › Login as user

2) [oidc tests] › e2e-tests/tests/oidc.test.ts:52:3 › Different Logins › Login as user ─────────── Retry #1 ─────────────────────────────────────────────────────────────────────────────────────── Error: locator.waitFor: Target page, context or browser has been closed Call log: - waiting for getByText('Login Using OIDC') to be visible at fixtures/OIDC.ts:28 26 | const loginButton = this.page.getByText('Login Using OIDC'); 27 | > 28 | await loginButton.waitFor(); | ^ 29 | 30 | let buttonClicked: boolean = false; 31 | await loginButton.click(); at AerieLogin.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:28:23) at OIDC.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:158:5) at /home/runner/work/***-ui/***-ui/e2e-tests/tests/oidc.test.ts:56:5

Check failure on line 28 in e2e-tests/fixtures/OIDC.ts

View workflow job for this annotation

GitHub Actions / e2e-test

[oidc tests] › e2e-tests/tests/oidc.test.ts:52:3 › Different Logins › Login as user

2) [oidc tests] › e2e-tests/tests/oidc.test.ts:52:3 › Different Logins › Login as user ─────────── Error: locator.waitFor: Target page, context or browser has been closed Call log: - waiting for getByText('Login Using OIDC') to be visible at fixtures/OIDC.ts:28 26 | const loginButton = this.page.getByText('Login Using OIDC'); 27 | > 28 | await loginButton.waitFor(); | ^ 29 | 30 | let buttonClicked: boolean = false; 31 | await loginButton.click(); at AerieLogin.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:28:23) at OIDC.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:158:5) at /home/runner/work/***-ui/***-ui/e2e-tests/tests/oidc.test.ts:56:5

Check failure on line 28 in e2e-tests/fixtures/OIDC.ts

View workflow job for this annotation

GitHub Actions / e2e-test

[oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin

1) [oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin ────────── Retry #2 ─────────────────────────────────────────────────────────────────────────────────────── Error: locator.waitFor: Target page, context or browser has been closed Call log: - waiting for getByText('Login Using OIDC') to be visible at fixtures/OIDC.ts:28 26 | const loginButton = this.page.getByText('Login Using OIDC'); 27 | > 28 | await loginButton.waitFor(); | ^ 29 | 30 | let buttonClicked: boolean = false; 31 | await loginButton.click(); at AerieLogin.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:28:23) at OIDC.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:158:5) at /home/runner/work/***-ui/***-ui/e2e-tests/tests/oidc.test.ts:48:5

Check failure on line 28 in e2e-tests/fixtures/OIDC.ts

View workflow job for this annotation

GitHub Actions / e2e-test

[oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin

1) [oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin ────────── Retry #1 ─────────────────────────────────────────────────────────────────────────────────────── Error: locator.waitFor: Target page, context or browser has been closed Call log: - waiting for getByText('Login Using OIDC') to be visible at fixtures/OIDC.ts:28 26 | const loginButton = this.page.getByText('Login Using OIDC'); 27 | > 28 | await loginButton.waitFor(); | ^ 29 | 30 | let buttonClicked: boolean = false; 31 | await loginButton.click(); at AerieLogin.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:28:23) at OIDC.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:158:5) at /home/runner/work/***-ui/***-ui/e2e-tests/tests/oidc.test.ts:48:5

Check failure on line 28 in e2e-tests/fixtures/OIDC.ts

View workflow job for this annotation

GitHub Actions / e2e-test

[oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin

1) [oidc tests] › e2e-tests/tests/oidc.test.ts:44:3 › Different Logins › Login as admin ────────── Error: locator.waitFor: Target page, context or browser has been closed Call log: - waiting for getByText('Login Using OIDC') to be visible at fixtures/OIDC.ts:28 26 | const loginButton = this.page.getByText('Login Using OIDC'); 27 | > 28 | await loginButton.waitFor(); | ^ 29 | 30 | let buttonClicked: boolean = false; 31 | await loginButton.click(); at AerieLogin.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:28:23) at OIDC.login (/home/runner/work/***-ui/***-ui/e2e-tests/fixtures/OIDC.ts:158:5) at /home/runner/work/***-ui/***-ui/e2e-tests/tests/oidc.test.ts:48:5

let buttonClicked: boolean = false;
await loginButton.click();
while (!buttonClicked) {
// this button has required variable numbers of tries
try {
await this.page.waitForURL('**/realms/aerie-dev/**', { timeout: 2000 });
buttonClicked = true;
} catch {
// means it timed out, no new page
await loginButton.click();
}
}
}

updatePage(page: Page) {
this.loginButton = page.getByText('Login Using OIDC');
}
}

class IdPLogin {
passwordSlot: Locator;
signInButton: Locator;
usernameSlot: Locator;

constructor(public page: Page) {
this.updatePage(page);
}

async login(username: string, password: string) {
await this.usernameSlot.waitFor();
await this.passwordSlot.waitFor();
await this.signInButton.waitFor();

await this.usernameSlot.fill(username);
await this.passwordSlot.fill(password);

await this.signInButton.click();

await this.page.waitForURL('**/plans');
}

updatePage(page: Page) {
this.usernameSlot = page.locator('#username');
this.passwordSlot = page.locator('#password');
this.signInButton = page.getByText('Sign In').last();
}
}

export class OIDC {
expectedDefaultRole: string;
expectedRoles: string[];

constructor(
public page: Page,
public username: string,
public password: string,
) {
switch (username) {
case 'AerieAdmin':
this.expectedRoles = ['1-aerie_admin', '2-user', '3-viewer'];
break;
case 'AerieUser':
this.expectedRoles = ['2-user', '3-viewer'];
break;
default: // AerieViewer
this.expectedRoles = ['3-viewer'];
}
this.expectedDefaultRole = this.expectedRoles[0];
}

async checkCookieRoles() {
const { accessToken } = await this.extractTokens();

if (accessToken) {
// otherwise it is considered potentailly undefined despite the above expect
const decoded = decode(accessToken); // TODO: extract this into its own method ?

const allowedRoles = (decoded as HasuraToken)['https://hasura.io/jwt/claims']['x-hasura-allowed-roles'];
for (const expectedRole of this.expectedRoles) {
expect(allowedRoles.includes(expectedRole));
}
}
}

async checkCurrentRole() {
// while this element shows up in Plan.ts, it is too cumbersome to define that object here.
// if it would make things more consistent and clean, a local class for the plans page for
// just elements like this (and cookies too?) can be created.
const currentRole = this.page.getByRole('combobox').filter({ hasText: '-' });
await expect(currentRole).toBeVisible();
await expect(currentRole).toHaveText(this.expectedDefaultRole);
}

async expectNoCookies() {
const cookies = await this.page.context().cookies();

console.log(cookies.map(c => c.name));

const cookieNames = cookies.map(c => c.name);
expect(cookieNames.includes('accessToken')).toBeFalsy();
expect(cookieNames.includes('idToken')).toBeFalsy();
expect(cookieNames.includes('refreshToken')).toBeFalsy();
}

async extractTokens() {
const cookies = await this.page.context().cookies();

// check presence of accessToken, idToken, and refreshToken
const cookieNames = cookies.map(c => c.name);
expect(cookieNames.includes('accessToken')).toBeTruthy();
expect(cookieNames.includes('idToken')).toBeTruthy();
expect(cookieNames.includes('refreshToken')).toBeTruthy();

// then pull them out
const accessToken = cookies.find(c => c.name === 'accessToken')?.value;
const idToken = cookies.find(c => c.name === 'idToken')?.value;
const refreshToken = cookies.find(c => c.name === 'refreshToken')?.value;

return {
accessToken,
idToken,
refreshToken,
};
}

async login() {
// log in on AERIE end of things
const aerieLogin = new AerieLogin(this.page);
await aerieLogin.login();

// then, IdP Login
const idpLogin = new IdPLogin(this.page);
await idpLogin.login(this.username, this.password);
}

async logout() {
const appNav = new AppNav(this.page);

await appNav.show();
await appNav.appMenuItemLogout.click();

await this.page.waitForURL('**/login');

await this.expectNoCookies();
}

// should run this iff already logged in.
async refresh() {
// get old cookies
const {
accessToken: oldAccessToken,
idToken: oldIdToken,
refreshToken: oldRefreshToken,
} = await this.extractTokens();

// wait for timeout (set to 600 seconds by default in our Keycloak deployment)
// NOTE: since the timer is set in the UI, the token needn't actually expire
// to prompt a refresh. we just need to skip that time HERE and it'll know to refresh.
// It pre-emptively refreshes 10 seconds before refresh time, so we will
// skip to 1 second before that, i.e. we will timeskip 589 seconds.
// await this.page.clock.fastForward(1 * 1000);
// TURNS OUT MESSING WITH PAGE TIMER SERIOUSLY THROWS OFF DELAYS AND RESULTS IN A REFRESH LOOP!

// now it'll refresh, so we want this test itself to wait for 5 seconds
await this.page.waitForTimeout(11000);

// get new cookies
const {
accessToken: newAccessToken,
idToken: newIdToken,
refreshToken: newRefreshToken,
} = await this.extractTokens();

console.log('OLD ACCESS TOKEN, NEW ACCESS TOKEN', oldAccessToken, newAccessToken);
console.log('OLD ID TOKEN, NEW ID TOKEN', oldIdToken, newIdToken);
console.log('OLD REFRESH TOKEN, NEW REFRESH TOKEN', oldRefreshToken, newRefreshToken);

expect(oldAccessToken).not.toEqual(newAccessToken);
expect(oldIdToken).not.toEqual(newIdToken);
expect(oldRefreshToken).not.toEqual(newRefreshToken);

await this.checkCookieRoles(); // should still be right!
}
}
100 changes: 100 additions & 0 deletions e2e-tests/tests/oidc.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import test, { type BrowserContext, type Page } from '@playwright/test';
import { OIDC } from '../fixtures/OIDC';

let context: BrowserContext;
let page: Page;

const users = [
{
password: 'password',
username: 'AerieAdmin',
},
{
password: 'password',
username: 'AerieUser',
},
{
password: 'password',
username: 'AerieViewer',
},
];

test.beforeAll(async ({ browser }) => {
context = await browser.newContext();
page = await context.newPage();
});

test.afterAll(async () => {
await page.close();
await context.close();
});

test.describe('Different Logins', () => {
// need to destroy everything between test runs
test.beforeAll(async ({ browser }) => {
context = await browser.newContext();
page = await context.newPage();
});

test.afterAll(async () => {
await page.close();
await context.close();
});

test('Login as admin', async () => {
const { username, password } = users[0];

const oidc = new OIDC(page, username, password);
await oidc.login();
await oidc.checkCookieRoles();
await oidc.checkCurrentRole();
});
test('Login as user', async () => {
const { username, password } = users[1];

const oidc = new OIDC(page, username, password);
await oidc.login();
await oidc.checkCookieRoles();
await oidc.checkCurrentRole();
});
test('Login as viewer', async () => {
const { username, password } = users[2];

const oidc = new OIDC(page, username, password);
await oidc.login();
await oidc.checkCookieRoles();

// the current role box/option won't be visible
});
});

test.describe('Refresh Functionality', () => {
test('Refresh as any user', async () => {
// user doesn't matter, so pick randomly
const { username, password } = users[Math.floor(Math.random() * 3)];

const oidc = new OIDC(page, username, password);

// you might be thinking - why essentially re-test login? why not just inject an access token?
// the reason is that the logic required to get an access token that always works
// requires a fair bit of extra work and logic to make sure it always works, which would
// require forging a token from scratch to ensure time properties and all were correct (requiring
// experimentation here AS WELL AS some modification of the keycloak configuration itself to
// ensure there is a fixed, predictable JWT key...simply re-logging in seems like the easier
// option implementationwise but we can explore the other option if this is too cumbersome)
await oidc.login();
await oidc.refresh();
});
});

test.describe('Logout Functionality', () => {
test('Logout as any user', async () => {
// user doesn't matter, so pick randomly
const { username, password } = users[Math.floor(Math.random() * 3)];

const oidc = new OIDC(page, username, password);
await oidc.login();
await page.waitForTimeout(2000); // wait for a sec
await oidc.logout();
});
});
3 changes: 3 additions & 0 deletions e2e-tests/utilities/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import { Cookie, Locator, Page } from '@playwright/test';
import { adjectives, animals, colors, uniqueNamesGenerator } from 'unique-names-generator';

export function getUserCookieValue(cookies: Cookie[]): string | undefined {
if (process.env.PUBLIC_AUTH_OIDC_ENABLED === 'true') {
return cookies.find(cookie => cookie.name === 'accessToken')?.value;
}
for (const cookie of cookies) {
if (cookie.name === 'user') {
return JSON.parse(atob(cookie.value)).token;
Expand Down
Loading
Loading