Repository navigation
Add full-flow behat for GSSP service name #95
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 2 commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
a0c1c0b
Add full-flow behat coverage for GSSP service name from AuthnRequest …
kayjoosten b8904f0
Add playwright coverage and GSSP registration-page step for service name
kayjoosten fa374f0
Drop local sp.php override now that the fix moved upstream to devssp
kayjoosten 983e49c
Add SSO-flow coverage and fix service_name shape, per review feedback
kayjoosten bb1f635
fix(behat): update stale Yubikey OTP field/button ids
kayjoosten b5f3269
docs: fix stale references in gssp_service_name docs
kayjoosten d86182b
Remove Playwright suite from this PR
kayjoosten File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| # Tagged SKIP until Stepup-Gateway PR #624 is merged and released in the test image | ||
| # with enable_service_name_from_saml_authnrequest enabled, and the mdui-capable | ||
| # sp.php is available. Run locally with: | ||
| # ./start-dev-env.sh gateway:<Stepup-Gateway checkout> demogssp:<Stepup-gssp-example checkout> | ||
| # docker compose exec behat ./vendor/bin/behat --config config/behat.yml features/gssp_service_name.feature | ||
| @SKIP | ||
| Feature: The GSSP shows the name of the service the user is authenticating for | ||
| In order to know which service I am authenticating for | ||
| As a user | ||
| I want the GSSP authentication page to show the service name from the AuthnRequest | ||
|
|
||
| # Covers the cross-repo flow of the mdui:UIInfo service name: | ||
| # the SP sends an AuthnRequest with an mdui:UIInfo/mdui:DisplayName extension, | ||
| # the Stepup-Gateway (feature flag enable_service_name_from_saml_authnrequest) | ||
| # reads it and forwards it in the proxy AuthnRequest to the GSSP, where the | ||
| # GSSP (Stepup-gssp-example via Stepup-gssp-bundle and Stepup-saml-bundle) | ||
| # displays it on the authentication page. | ||
| Scenario: Service name from the AuthnRequest mdui:UIInfo is shown on the GSSP authentication page | ||
| Given a service provider configured for second-factor-only | ||
| And a user "jane-a-ra" identified by "urn:collab:person:institution-a.example.com:jane-a-ra" from institution "institution-a.example.com" with UUID "00000000-0000-4000-8000-000000000001" | ||
| And the user "urn:collab:person:institution-a.example.com:jane-a-ra" has a vetted "demo-gssp" with identifier "gssp-identifier123" | ||
| When I start an SFO authentication for "urn:collab:person:institution-a.example.com:jane-a-ra" with service name "Behat Test Service" | ||
| Then I see service name "Behat Test Service" on the GSSP authentication page | ||
| When I verify the "demo-gssp" second factor | ||
| Then I am logged on the service provider | ||
|
|
||
| # Reuses the identity vetted in the previous scenario, like sfo.feature does. | ||
| Scenario: No service name is shown when the AuthnRequest carries no mdui:UIInfo | ||
| Given a service provider configured for second-factor-only | ||
| When I start an SFO authentication for "urn:collab:person:institution-a.example.com:jane-a-ra" | ||
| Then I should not see "Behat Test Service" | ||
| When I verify the "demo-gssp" second factor | ||
| Then I am logged on the service provider | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| node_modules/ | ||
| test-results/ | ||
| playwright-report/ | ||
| .playwright-mcp/ | ||
| *.png |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| # Service name e2e tests (Playwright) | ||
|
|
||
| Cross-repo browser test for the "show service name during authentication" feature: | ||
| Stepup-Middleware#589, Stepup-Gateway#624, Stepup-saml-bundle#137, | ||
| Stepup-gssp-bundle#49, Stepup-gssp-example#141. | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| 1. Start the devconf stepup environment (see `../../README.md`), pointing | ||
| `middleware` / `gateway` / `demogssp` at your local checkouts if you're | ||
| testing branches that aren't in the `test` images yet: | ||
|
|
||
| ```bash | ||
| cd ../.. | ||
| ./start-dev-env.sh -d \ | ||
| middleware:/path/to/Stepup-Middleware \ | ||
| gateway:/path/to/Stepup-Gateway \ | ||
| demogssp:/path/to/Stepup-gssp-example | ||
| ``` | ||
|
|
||
| 2. `.env` must have `APP_ENV=smoketest` (routes the apps to `*_test` DBs). | ||
|
|
||
| 3. Run the Behat suite at least once against this stack so the `jane-a-ra` | ||
| identity (vetted `demo-gssp` second factor) exists — this test reuses | ||
| that fixture data rather than duplicating the bootstrap: | ||
|
|
||
| ```bash | ||
| docker compose exec behat ./vendor/bin/behat --config config/behat.yml \ | ||
| --tags='~@wip' features/gssp_service_name.feature | ||
| ``` | ||
|
|
||
| 4. In `Stepup-Gateway`, `enable_service_name_from_saml_authnrequest: true` | ||
| must be set (already the case in the devconf parameters). | ||
|
|
||
| ## Install & run | ||
|
|
||
| ```bash | ||
| npm install | ||
| npx playwright install chromium # first time only | ||
| NODE_TLS_REJECT_UNAUTHORIZED=0 npx playwright test | ||
| ``` | ||
|
|
||
| `NODE_TLS_REJECT_UNAUTHORIZED=0` is needed because the devconf stack uses a | ||
| self-signed cert and `lib/middleware.ts` pushes config over `fetch()` | ||
| directly (not through Playwright's browser context, which is configured with | ||
| `ignoreHTTPSErrors` separately). | ||
|
|
||
| ## What it does | ||
|
|
||
| Each test pushes a config change to Middleware for the `second-sp` SP entity | ||
| (`lib/middleware.ts`), then drives the SP debug page | ||
| (`https://ssp.dev.openconext.local/simplesaml/sp.php`) through an SFO login | ||
| to `demogssp`, asserting on what service name is shown: | ||
|
|
||
| - No Middleware `service_name` → the SP's own `mdui:DisplayName` is shown. | ||
| - Middleware `service_name` set → it wins, regardless of what the SP sends. | ||
| - Neither present → no service name section renders, no error. | ||
|
|
||
| Each test resets `second-sp`'s `service_name` back to unset in `afterEach`, | ||
| so the shared environment is left as found. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| import fs from 'node:fs'; | ||
| import path from 'node:path'; | ||
|
|
||
| const MIDDLEWARE_CONFIG_URL = 'https://middleware.dev.openconext.local/management/configuration'; | ||
| const MIDDLEWARE_CONFIG_PATH = path.resolve(__dirname, '../../../middleware/middleware-config.json'); | ||
| const MANAGEMENT_USER = 'management'; | ||
| const MANAGEMENT_PASSWORD = 'secret'; | ||
|
|
||
| type ServiceProvider = { entity_id: string; service_name?: string | null; [key: string]: unknown }; | ||
| type MiddlewareConfig = { gateway: { service_providers: ServiceProvider[]; [key: string]: unknown }; [key: string]: unknown }; | ||
|
|
||
| function loadBaseConfig(): MiddlewareConfig { | ||
| const raw = fs.readFileSync(MIDDLEWARE_CONFIG_PATH, 'utf-8'); | ||
| return JSON.parse(raw) as MiddlewareConfig; | ||
| } | ||
|
|
||
| /** | ||
| * Pushes the devconf baseline middleware-config.json, optionally overriding | ||
| * `service_name` on one SP entity. Pass `serviceName: null` to push the | ||
| * baseline unmodified (no service_name key on that entity). | ||
| */ | ||
| export async function pushServiceName(entityId: string, serviceName: string | null): Promise<void> { | ||
| const config = loadBaseConfig(); | ||
| const sp = config.gateway.service_providers.find((s) => s.entity_id === entityId); | ||
| if (!sp) { | ||
| throw new Error(`No service provider with entity_id "${entityId}" found in ${MIDDLEWARE_CONFIG_PATH}`); | ||
| } | ||
| if (serviceName === null) { | ||
| delete sp.service_name; | ||
| } else { | ||
| sp.service_name = serviceName; | ||
| } | ||
|
|
||
| const auth = Buffer.from(`${MANAGEMENT_USER}:${MANAGEMENT_PASSWORD}`).toString('base64'); | ||
| const response = await fetch(MIDDLEWARE_CONFIG_URL, { | ||
| method: 'POST', | ||
| headers: { | ||
| Accept: 'application/json', | ||
| 'Content-Type': 'application/json', | ||
| Authorization: `Basic ${auth}`, | ||
| }, | ||
| body: JSON.stringify(config), | ||
| // devconf uses a self-signed cert; Node's fetch needs this at the process level, | ||
| // see NODE_TLS_REJECT_UNAUTHORIZED=0 in the npm script / CI invocation. | ||
| }); | ||
|
|
||
| if (!response.ok) { | ||
| throw new Error(`Middleware config push failed: HTTP ${response.status} ${await response.text()}`); | ||
| } | ||
| const body = (await response.json()) as { status?: string }; | ||
| if (body.status !== 'OK') { | ||
| throw new Error(`Middleware config push did not return status OK: ${JSON.stringify(body)}`); | ||
| } | ||
| } |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| { | ||
| "name": "stepup-service-name-e2e", | ||
| "private": true, | ||
| "scripts": { | ||
| "test": "playwright test" | ||
| }, | ||
| "devDependencies": { | ||
| "@playwright/test": "^1.48.0" | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| import { defineConfig } from '@playwright/test'; | ||
|
|
||
| // Requires the stepup devconf environment running with the `smoketest` .env profile | ||
| // (see ../../README.md) so the app containers use *_test databases and the | ||
| // hosts file entries for *.dev.openconext.local resolve to 127.0.0.1. | ||
| export default defineConfig({ | ||
| testDir: './tests', | ||
| timeout: 30_000, | ||
| fullyParallel: false, | ||
| reporter: 'list', | ||
| use: { | ||
| ignoreHTTPSErrors: true, | ||
| baseURL: 'https://ssp.dev.openconext.local', | ||
| screenshot: 'only-on-failure', | ||
| trace: 'retain-on-failure', | ||
| }, | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| import { test, expect, type Page } from '@playwright/test'; | ||
| import { pushServiceName } from '../lib/middleware'; | ||
|
|
||
| /** | ||
| * Cross-repo e2e coverage for the "service name during authentication" feature | ||
| * (Stepup-Middleware#589, Stepup-Gateway#624, Stepup-saml-bundle#137, | ||
| * Stepup-gssp-bundle#49, Stepup-gssp-example#141). | ||
| * | ||
| * Flow under test: SP (ssp debug SP) --AuthnRequest w/ mdui:UIInfo--> Gateway | ||
| * (SFO) --proxy AuthnRequest--> GSSP (demogssp) authentication page. | ||
| * | ||
| * Priority rule under test (see REFINEMENT_SERVICE_NAME.md): | ||
| * Middleware `service_name`, when configured for the SP, always wins over | ||
| * any mdui:DisplayName sent by the SP in the AuthnRequest. | ||
| * | ||
| * Prerequisites: | ||
| * - devconf-service-name/stepup environment running (./start-dev-env.sh -d | ||
| * with gateway/demogssp/middleware pointed at your local checkouts if you | ||
| * want to test in-progress branches). | ||
| * - APP_ENV=smoketest in .env (routes the apps to the *_test databases). | ||
| * - The Behat suite must have been run at least once against this stack | ||
| * (docker compose exec behat ./vendor/bin/behat --config config/behat.yml) | ||
| * so the "jane-a-ra" identity with a vetted demo-gssp second factor | ||
| * exists — that fixture setup lives in the Behat suite's @BeforeSuite | ||
| * hook, not duplicated here. | ||
| * | ||
| * Run: NODE_TLS_REJECT_UNAUTHORIZED=0 npx playwright test | ||
| */ | ||
|
|
||
| const SECOND_SP_ENTITY_ID = 'https://ssp.dev.openconext.local/simplesaml/module.php/saml/sp/metadata.php/second-sp'; | ||
| const VETTED_SUBJECT = 'urn:collab:person:institution-a.example.com:jane-a-ra'; | ||
|
|
||
| async function startSfoAuthentication(page: Page, mduiDisplayName?: string): Promise<void> { | ||
| await page.goto('/simplesaml/sp.php'); | ||
| await page.locator('#idp').selectOption('OpenConext Stepup Gateway - gateway.dev.openconext.local - SFO'); | ||
| await page.locator('#sp').selectOption('second-sp'); | ||
| await page.locator('#loa').selectOption('2'); | ||
| await page.locator('#subject').fill(VETTED_SUBJECT); | ||
| if (mduiDisplayName) { | ||
| await page.locator('#mdui_displayname').fill(mduiDisplayName); | ||
| } else { | ||
| await page.locator('#mdui_displayname').fill(''); | ||
| } | ||
| await page.getByRole('button', { name: 'Login' }).first().click(); | ||
| await expect(page).toHaveURL('https://demogssp.dev.openconext.local/authentication'); | ||
| } | ||
|
|
||
| test.describe('Service name during authentication', () => { | ||
| test.afterEach(async () => { | ||
| // Leave the shared devconf environment as we found it. | ||
| await pushServiceName(SECOND_SP_ENTITY_ID, null); | ||
| }); | ||
|
|
||
| test('shows the AuthnRequest mdui:DisplayName when Middleware has no service_name configured', async ({ page }) => { | ||
| await pushServiceName(SECOND_SP_ENTITY_ID, null); | ||
|
|
||
| await startSfoAuthentication(page, 'Behat Test Service'); | ||
|
|
||
| await expect(page.getByText('Behat Test Service')).toBeVisible(); | ||
| await page.screenshot({ path: 'screenshots/01-authnrequest-mdui-shown.png', fullPage: true }); | ||
| }); | ||
|
|
||
| test('Middleware service_name overrides the AuthnRequest mdui:DisplayName', async ({ page }) => { | ||
| await pushServiceName(SECOND_SP_ENTITY_ID, 'Middleware Configured Name'); | ||
|
|
||
| await startSfoAuthentication(page, 'Behat Test Service'); | ||
|
|
||
| await expect(page.getByText('Middleware Configured Name')).toBeVisible(); | ||
| await expect(page.getByText('Behat Test Service')).not.toBeVisible(); | ||
| await page.screenshot({ path: 'screenshots/02-middleware-overrides-authnrequest.png', fullPage: true }); | ||
| }); | ||
|
|
||
| test('renders without error when neither Middleware service_name nor mdui:DisplayName is present', async ({ page }) => { | ||
| await pushServiceName(SECOND_SP_ENTITY_ID, null); | ||
|
|
||
| await startSfoAuthentication(page); | ||
|
|
||
| await expect(page.getByText('Service name')).not.toBeVisible(); | ||
| await page.screenshot({ path: 'screenshots/03-no-service-name-no-error.png', fullPage: true }); | ||
| }); | ||
| }); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What i expect to see here: All 3 of the LoginService::singleSignOn methods should be triggered from here to see if the gateway applies (or discards????) the mdui information.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
stepup/tests/behat/features/sfo.featurestepup/tests/behat/features/sfo_gssp_fallback.feature