From 4c49f6b92d84cb70a974c3f0929f3de748a1aaa6 Mon Sep 17 00:00:00 2001 From: Kavita Gautam Date: Thu, 27 Aug 2026 16:34:17 +0545 Subject: [PATCH 1/2] test: cleanup otp credentials after mfa --- web/tests/e2e/environment/test.ts | 26 ++++++++++ web/tests/e2e/support/api/keycloak/user.ts | 56 ++++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/web/tests/e2e/environment/test.ts b/web/tests/e2e/environment/test.ts index f0df3d829d1..b3ff0685eb7 100644 --- a/web/tests/e2e/environment/test.ts +++ b/web/tests/e2e/environment/test.ts @@ -212,3 +212,29 @@ const storeKeycloakGroups = async (adminUser: User) => { } }) } + +test.beforeEach(async () => { + if (config.vaultMode || config.mfa) { + const adminUser = store.userStore.get(config.keycloakAdminUser.toLowerCase()) + + if (adminUser) { + await api.keycloak.setAccessTokenForKeycloakUser(adminUser) + + await api.keycloak.deleteUserTotpCredentials({ + user: adminUser + }) + } + } +}) + +test.afterEach(async () => { + if (config.vaultMode || config.mfa) { + const adminUser = store.userStore.get(config.keycloakAdminUser.toLowerCase()) + + if (adminUser) { + await api.keycloak.deleteUserTotpCredentials({ + user: adminUser + }) + } + } +}) diff --git a/web/tests/e2e/support/api/keycloak/user.ts b/web/tests/e2e/support/api/keycloak/user.ts index 71947f943e3..30c738f190e 100644 --- a/web/tests/e2e/support/api/keycloak/user.ts +++ b/web/tests/e2e/support/api/keycloak/user.ts @@ -168,3 +168,59 @@ export const getRealmRole = async (role: string, admin: User): Promise => { + const response = await request({ + method: 'GET', + path: join(realmBasePath, 'users'), + user + }) + checkResponseStatus(response, 'Failed while finding Keycloak user') + + const users = (await response.json()) as Array<{ + id: string + username: string + }> + + const keycloakUser = users.find( + (keycloakUser) => keycloakUser.username.toLowerCase() === user.id.toLowerCase() + ) + + if (!keycloakUser) { + throw new Error(`Keycloak user with username '${user.id}' not found`) + } + + return keycloakUser.id +} + +export const deleteUserTotpCredentials = async ({ user }: { user: User }): Promise => { + const keycloakUserId = await getKeycloakUserId({ user }) + + const response = await request({ + method: 'GET', + path: join(realmBasePath, 'users', keycloakUserId, 'credentials'), + user + }) + checkResponseStatus(response, 'Failed while listing Keycloak user credentials') + + const credentials = (await response.json()) as Array<{ + id: string + type: string + }> + + for (const credential of credentials) { + if (['otp', 'totp'].includes(credential.type)) { + const deleteResponse = await request({ + method: 'DELETE', + path: join(realmBasePath, 'users', keycloakUserId, 'credentials', credential.id), + user + }) + + if (deleteResponse.status !== 204) { + throw new Error( + `Failed to delete OTP/TOTP credential for user: ${user.id}, Status: ${deleteResponse.status}` + ) + } + } + } +} From 895d15a77b573db61d1b41a5c7d00fe704dbe904 Mon Sep 17 00:00:00 2001 From: Kavita Gautam Date: Wed, 2 Sep 2026 12:37:19 +0545 Subject: [PATCH 2/2] test: cleanup using globalBeforeHook and globalCleanup custom hooks Signed-off-by: Kavita Gautam --- web/tests/e2e/environment/test.ts | 40 ++++++++-------------- web/tests/e2e/support/api/keycloak/user.ts | 16 ++++----- 2 files changed, 21 insertions(+), 35 deletions(-) diff --git a/web/tests/e2e/environment/test.ts b/web/tests/e2e/environment/test.ts index b3ff0685eb7..94e91266e98 100644 --- a/web/tests/e2e/environment/test.ts +++ b/web/tests/e2e/environment/test.ts @@ -46,6 +46,12 @@ export const test = base.extend<{ } } + // Runs after each test has finished + if (config.keycloak && (config.mfa || config.vaultMode) && adminUser) { + await api.keycloak.setAccessTokenForKeycloakUser(adminUser) + await api.keycloak.deleteUserTotpCredentials({ user: adminUser }) + } + await cleanUpUser(store.createdUserStore, adminUser) await cleanUpGroup(adminUser) await cleanUpSpaces(adminUser) @@ -80,6 +86,14 @@ export const test = base.extend<{ } } } + + // Runs before each test, but after the world has been initialized. + const adminUser = world.usersEnvironment.getUser({ key: config.keycloakAdminUser }) + if (config.keycloak && (config.mfa || config.vaultMode) && adminUser) { + await api.keycloak.setAccessTokenForKeycloakUser(adminUser) + await api.keycloak.deleteUserTotpCredentials({ user: adminUser }) + } + await use() }, { auto: true } @@ -212,29 +226,3 @@ const storeKeycloakGroups = async (adminUser: User) => { } }) } - -test.beforeEach(async () => { - if (config.vaultMode || config.mfa) { - const adminUser = store.userStore.get(config.keycloakAdminUser.toLowerCase()) - - if (adminUser) { - await api.keycloak.setAccessTokenForKeycloakUser(adminUser) - - await api.keycloak.deleteUserTotpCredentials({ - user: adminUser - }) - } - } -}) - -test.afterEach(async () => { - if (config.vaultMode || config.mfa) { - const adminUser = store.userStore.get(config.keycloakAdminUser.toLowerCase()) - - if (adminUser) { - await api.keycloak.deleteUserTotpCredentials({ - user: adminUser - }) - } - } -}) diff --git a/web/tests/e2e/support/api/keycloak/user.ts b/web/tests/e2e/support/api/keycloak/user.ts index 30c738f190e..a7035abbff5 100644 --- a/web/tests/e2e/support/api/keycloak/user.ts +++ b/web/tests/e2e/support/api/keycloak/user.ts @@ -170,27 +170,25 @@ export const getRealmRole = async (role: string, admin: User): Promise => { + const username = user.originalId + const response = await request({ method: 'GET', - path: join(realmBasePath, 'users'), + path: `${join(realmBasePath, 'users')}?username=${encodeURIComponent(username)}&exact=true`, user }) checkResponseStatus(response, 'Failed while finding Keycloak user') - const users = (await response.json()) as Array<{ + const keycloakUsers = (await response.json()) as Array<{ id: string username: string }> - const keycloakUser = users.find( - (keycloakUser) => keycloakUser.username.toLowerCase() === user.id.toLowerCase() - ) - - if (!keycloakUser) { - throw new Error(`Keycloak user with username '${user.id}' not found`) + if (keycloakUsers.length === 0) { + throw new Error(`Keycloak user with username '${username}' not found`) } - return keycloakUser.id + return keycloakUsers[0].id } export const deleteUserTotpCredentials = async ({ user }: { user: User }): Promise => {