Files
upstream-ory-kratos/test/e2e/playwright/tests/desktop/identifier_first/oidc.login.spec.ts
upstream-mirror c60cc7ca75
Some checks failed
CI / Run tests and lints (push) Failing after 29s
CI / Build CLI docs (push) Has been skipped
CI / Run Playwright end-to-end tests (mysql) (push) Failing after 3s
CI / Run Playwright end-to-end tests (postgres) (push) Failing after 2s
CI / Run Playwright end-to-end tests (sqlite) (push) Failing after 3s
CodeQL / Analyze (go) (push) Failing after 4s
CodeQL / Analyze (javascript) (push) Failing after 3s
Docker Image Scanners / scanners (push) Failing after 4s
Synchronize Issue Labels / Synchronize Issue Labels (push) Has been skipped
CI / Run end-to-end tests (postgres) (push) Failing after 19s
CI / Run end-to-end tests (sqlite) (push) Failing after 2s
CI / Run Playwright end-to-end tests (cockroach) (push) Failing after 2s
CI / Draft newsletter (push) Has been skipped
CI / Generate release (push) Has been skipped
CI / Pending approval Slack notification (push) Has been skipped
CI / Send newsletter (push) Has been skipped
snapshot of https://github.com/ory/kratos.git (master, 2026-09-15; blobs > 131072B omitted)
2026-09-15 21:19:12 +05:00

172 lines
5.1 KiB
TypeScript

// Copyright © 2024 Ory Corp
// SPDX-License-Identifier: Apache-2.0
import { faker } from "@faker-js/faker"
import { expect, Page } from "@playwright/test"
import { getSession, hasSession } from "../../../actions/session"
import { test } from "../../../fixtures"
import { toConfig } from "../../../lib/helper"
import { LoginPage } from "../../../models/elements/login"
import { OryKratosConfiguration } from "../../../../shared/config"
async function loginHydra(page: Page) {
return test.step("login with hydra", async () => {
await page
.locator("input[name=username]")
.fill(faker.internet.email({ provider: "ory.sh" }))
await page.locator("button[name=action][value=accept]").click()
await page.locator("#offline").check()
await page.locator("#openid").check()
await page.locator("input[name=website]").fill(faker.internet.url())
await page.locator("button[name=action][value=accept]").click()
})
}
async function registerWithHydra(
page: Page,
config: OryKratosConfiguration,
kratosPublicURL: string,
) {
return await test.step("register", async () => {
await page.goto("/registration")
await page.locator(`button[name=provider][value=hydra]`).click()
const email = faker.internet.email({ provider: "ory.sh" })
await page.locator("input[name=username]").fill(email)
await page.locator("#remember").check()
await page.locator("button[name=action][value=accept]").click()
await page.locator("#offline").check()
await page.locator("#openid").check()
await page.locator("input[name=website]").fill(faker.internet.url())
await page.locator("button[name=action][value=accept]").click()
await page.waitForURL(
new RegExp(config.selfservice.default_browser_return_url),
)
await page.context().clearCookies({
domain: new URL(kratosPublicURL).hostname,
})
await expect(
getSession(page.request, kratosPublicURL),
).rejects.toThrowError()
return email
})
}
for (const mitigateEnumeration of [true, false]) {
test.describe(`account enumeration protection ${
mitigateEnumeration ? "on" : "off"
}`, () => {
test.use({
configOverride: toConfig({
mitigateEnumeration,
selfservice: {
methods: {
password: {
enabled: true,
},
},
},
}),
})
test("login", async ({ page, config, kratosPublicURL }) => {
const login = new LoginPage(page, config)
await login.open()
await page.locator(`button[name=provider][value=hydra]`).click()
await loginHydra(page)
await page.waitForURL(
new RegExp(config.selfservice.default_browser_return_url),
)
await hasSession(page.request, kratosPublicURL)
})
test("oidc sign in on second step", async ({
page,
config,
kratosPublicURL,
}) => {
const email = await registerWithHydra(page, config, kratosPublicURL)
const login = new LoginPage(page, config)
await login.open()
await login.submitIdentifierFirst(email)
// If account enumeration is mitigated, we should see the password method,
// because the identity has not set up a password
await expect(
page.locator('button[name="method"][value="password"]'),
"hide the password method",
).toBeVisible({ visible: mitigateEnumeration })
await page.locator(`button[name=provider][value=hydra]`).click()
await loginHydra(page)
await page.waitForURL(
new RegExp(config.selfservice.default_browser_return_url),
)
const session = await getSession(page.request, kratosPublicURL)
expect(session).toBeDefined()
expect(session.active).toBe(true)
})
})
}
test("login with refresh", async ({ page, config, kratosPublicURL }) => {
await registerWithHydra(page, config, kratosPublicURL)
const login = new LoginPage(page, config)
const initialSession = await test.step("initial login", async () => {
await login.open()
await page.locator(`button[name=provider][value=hydra]`).click()
await loginHydra(page)
await page.waitForURL(
new RegExp(config.selfservice.default_browser_return_url),
)
return await getSession(page.request, kratosPublicURL)
})
// This is required, because OIDC issues a new session on refresh (TODO), and MySQL does not store sub second timestamps, so we need to wait a bit
await page.waitForTimeout(1000)
await test.step("refresh login", async () => {
await login.open({
refresh: true,
})
await expect(
page.locator('[data-testid="ui/message/1010003"]'),
"show the refresh message",
).toBeVisible()
await page.locator(`button[name=provider][value=hydra]`).click()
await loginHydra(page)
await page.waitForURL(
new RegExp(config.selfservice.default_browser_return_url),
)
const newSession = await getSession(page.request, kratosPublicURL)
// expect(newSession.authentication_methods).toHaveLength(
// initialSession.authentication_methods.length + 1,
// )
expect(newSession.authenticated_at).not.toBe(
initialSession.authenticated_at,
)
})
})