snapshot of https://github.com/ory/kratos.git (master, 2026-09-15; blobs > 131072B omitted)
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
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
This commit is contained in:
133
test/e2e/cypress/integration/profiles/import/import.spec.ts
Normal file
133
test/e2e/cypress/integration/profiles/import/import.spec.ts
Normal file
@@ -0,0 +1,133 @@
|
||||
// Copyright © 2023 Ory Corp
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { routes as express } from "../../../helpers/express"
|
||||
import { gen, KRATOS_ADMIN, website } from "../../../helpers"
|
||||
|
||||
context("Import Identities", () => {
|
||||
before(() => {
|
||||
cy.useConfigProfile("oidc")
|
||||
cy.proxy("express")
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
cy.clearAllCookies()
|
||||
})
|
||||
|
||||
const password = gen.password()
|
||||
for (const tc of [
|
||||
{
|
||||
name: "cleartext",
|
||||
config: {
|
||||
password,
|
||||
},
|
||||
checkPassword: password,
|
||||
},
|
||||
{
|
||||
name: "pbkdf2",
|
||||
config: {
|
||||
hashed_password:
|
||||
"$pbkdf2-sha256$i=1000,l=128$e8/arsEf4cvQihdNgqj0Nw$5xQQKNTyeTHx2Ld5/JDE7A",
|
||||
},
|
||||
checkPassword: "123456",
|
||||
},
|
||||
{
|
||||
name: "bcrypt",
|
||||
config: {
|
||||
hashed_password:
|
||||
"$2a$10$ZsCsoVQ3xfBG/K2z2XpBf.tm90GZmtOqtqWcB5.pYd5Eq8y7RlDyq",
|
||||
},
|
||||
checkPassword: "123456",
|
||||
},
|
||||
{
|
||||
name: "argon2id",
|
||||
config: {
|
||||
hashed_password:
|
||||
"$argon2id$v=19$m=16,t=2,p=1$bVI1aE1SaTV6SGQ3bzdXdw$fnjCcZYmEPOUOjYXsT92Cg",
|
||||
},
|
||||
checkPassword: "123456",
|
||||
},
|
||||
]) {
|
||||
// playwright:migrated
|
||||
it(`should be able to sign in using an imported password (${tc.name})`, () => {
|
||||
const email = gen.email()
|
||||
cy.request("POST", `${KRATOS_ADMIN}/identities`, {
|
||||
schema_id: "default",
|
||||
traits: {
|
||||
email,
|
||||
website,
|
||||
},
|
||||
credentials: {
|
||||
password: {
|
||||
config: tc.config,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
cy.visit(express.login)
|
||||
|
||||
// Try to sign in with an incorrect password
|
||||
cy.get('input[name="identifier"]').type(email)
|
||||
cy.get('input[name="password"]').type("invalid-password")
|
||||
cy.submitPasswordForm()
|
||||
cy.get('*[data-testid="ui/message/4000006"]').should(
|
||||
"contain.text",
|
||||
"credentials are invalid",
|
||||
)
|
||||
|
||||
// But with correct password it succeeds
|
||||
cy.get('input[name="password"]').type(tc.checkPassword)
|
||||
cy.submitPasswordForm()
|
||||
|
||||
cy.location("pathname").should("not.contain", "/login")
|
||||
cy.getSession().should((session) => {
|
||||
const { identity } = session
|
||||
expect(identity.id).to.not.be.empty
|
||||
expect(identity.traits.website).to.equal(website)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
it(`should be able to sign in using imported oidc credentials`, () => {
|
||||
const email = gen.email()
|
||||
const website = "https://" + gen.password() + ".com"
|
||||
cy.request("POST", `${KRATOS_ADMIN}/identities`, {
|
||||
schema_id: "default",
|
||||
traits: {
|
||||
email,
|
||||
website,
|
||||
},
|
||||
credentials: {
|
||||
oidc: {
|
||||
config: {
|
||||
providers: [
|
||||
{
|
||||
provider: "hydra",
|
||||
subject: email,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
cy.visit(express.login)
|
||||
cy.triggerOidc("express")
|
||||
|
||||
cy.get("#username").clear().type(email)
|
||||
cy.get("#remember").click()
|
||||
cy.get("#accept").click()
|
||||
cy.get('[name="scope"]').each(($el) => cy.wrap($el).click())
|
||||
cy.get("#remember").click()
|
||||
cy.get("#accept").click()
|
||||
|
||||
// Wait for the post-OIDC-consent redirect chain to settle so the session
|
||||
// cookie is in Cypress's jar before we hit /sessions/whoami.
|
||||
cy.location("pathname").should("not.contain", "/login")
|
||||
cy.getSession().should((session) => {
|
||||
const { identity } = session
|
||||
expect(identity.id).to.not.be.empty
|
||||
expect(identity.traits.website).to.equal(website)
|
||||
})
|
||||
})
|
||||
})
|
||||
131
test/e2e/cypress/integration/profiles/import/import_mfa.spec.ts
Normal file
131
test/e2e/cypress/integration/profiles/import/import_mfa.spec.ts
Normal file
@@ -0,0 +1,131 @@
|
||||
// Copyright © 2026 Ory Corp
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { TOTP } from "otpauth"
|
||||
|
||||
import { gen, KRATOS_ADMIN, website } from "../../../helpers"
|
||||
import { routes as express } from "../../../helpers/express"
|
||||
|
||||
// Regression coverage for https://github.com/ory/kratos/issues/4561.
|
||||
//
|
||||
// When TOTP or lookup-secret credentials are imported through the admin
|
||||
// identity API, the user must be able to use them to complete an AAL2
|
||||
// login. Previously the import wrote the credential row but not the
|
||||
// matching identity_credential_identifiers row, so AAL2 login would fail
|
||||
// with "You have no TOTP device set up." or "You have not configured
|
||||
// backup codes yet.".
|
||||
context("Import Identities with MFA credentials", () => {
|
||||
before(() => {
|
||||
cy.useConfigProfile("mfa")
|
||||
cy.proxy("express")
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
cy.clearAllCookies()
|
||||
cy.useConfig((builder) =>
|
||||
builder.longPrivilegedSessionTime().disableCodeMfa(),
|
||||
)
|
||||
})
|
||||
|
||||
// playwright:migrated
|
||||
it("should be able to complete AAL2 login using imported TOTP credentials", () => {
|
||||
const email = gen.email()
|
||||
const password = gen.password()
|
||||
|
||||
// Build the TOTP secret on the test side so we can both ship its
|
||||
// otpauth URL into the import payload and generate matching codes
|
||||
// later when we authenticate.
|
||||
const totp = new TOTP({
|
||||
issuer: "Ory",
|
||||
label: email,
|
||||
algorithm: "SHA1",
|
||||
digits: 6,
|
||||
period: 30,
|
||||
})
|
||||
|
||||
cy.request("POST", `${KRATOS_ADMIN}/identities`, {
|
||||
schema_id: "default",
|
||||
traits: { email, website },
|
||||
credentials: {
|
||||
password: { config: { password } },
|
||||
totp: { config: { totp_url: totp.toString() } },
|
||||
},
|
||||
})
|
||||
|
||||
// Force AAL2 on sign-in so we exercise the TOTP step-up path.
|
||||
cy.requireStrictAal()
|
||||
cy.visit(express.login)
|
||||
|
||||
cy.get('input[name="identifier"]').type(email)
|
||||
cy.get('input[name="password"]').type(password)
|
||||
cy.submitPasswordForm()
|
||||
|
||||
cy.shouldShow2FAScreen()
|
||||
|
||||
cy.get('input[name="totp_code"]').type(totp.generate())
|
||||
cy.get('*[name="method"][value="totp"]').click()
|
||||
|
||||
cy.location("pathname").should("not.contain", "/login")
|
||||
cy.getSession({
|
||||
expectAal: "aal2",
|
||||
expectMethods: ["password", "totp"],
|
||||
})
|
||||
})
|
||||
|
||||
// playwright:migrated
|
||||
it("should be able to complete AAL2 login using imported lookup-secret credentials", () => {
|
||||
const email = gen.email()
|
||||
const password = gen.password()
|
||||
|
||||
// Generate a few human-readable codes so failures in the test log
|
||||
// are easy to read; in production these would be opaque strings.
|
||||
const codes = [
|
||||
"imported-recovery-1",
|
||||
"imported-recovery-2",
|
||||
"imported-recovery-3",
|
||||
"imported-recovery-4",
|
||||
]
|
||||
|
||||
cy.request("POST", `${KRATOS_ADMIN}/identities`, {
|
||||
schema_id: "default",
|
||||
traits: { email, website },
|
||||
credentials: {
|
||||
password: { config: { password } },
|
||||
lookup_secret: {
|
||||
config: {
|
||||
codes: codes.map((code) => ({ code })),
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
cy.requireStrictAal()
|
||||
cy.visit(express.login)
|
||||
|
||||
cy.get('input[name="identifier"]').type(email)
|
||||
cy.get('input[name="password"]').type(password)
|
||||
cy.submitPasswordForm()
|
||||
|
||||
cy.shouldShow2FAScreen()
|
||||
|
||||
// Reject an invalid code first to make sure we are exercising the
|
||||
// lookup-secret branch and not silently bypassing it.
|
||||
cy.get('input[name="lookup_secret"]').type("not-a-real-code")
|
||||
cy.get('*[name="method"][value="lookup_secret"]').click()
|
||||
cy.get('[data-testid="ui/message/4000016"]').should(
|
||||
"contain.text",
|
||||
"The backup recovery code is not valid.",
|
||||
)
|
||||
|
||||
// The form clears between attempts; type one of the imported codes.
|
||||
cy.get('input[name="lookup_secret"]').should("have.value", "")
|
||||
cy.get('input[name="lookup_secret"]').type(codes[0])
|
||||
cy.get('*[name="method"][value="lookup_secret"]').click()
|
||||
|
||||
cy.location("pathname").should("not.contain", "/login")
|
||||
cy.getSession({
|
||||
expectAal: "aal2",
|
||||
expectMethods: ["password", "lookup_secret"],
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user