mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 10:59:59 +00:00
108 lines
4.4 KiB
JavaScript
108 lines
4.4 KiB
JavaScript
/**
|
|
* Keycloak user provisioning through the admin console.
|
|
*
|
|
* `provisionKeycloakUser(browser, options)`
|
|
* Signs the master-realm administrator into the admin console, creates
|
|
* `options.user` in `options.realm` when it is missing, and sets
|
|
* `options.password` as its permanent password either way, so a user
|
|
* left on a reused stack always ends up on the inventory's value.
|
|
*
|
|
* Args:
|
|
* browser: Playwright `Browser`; the flow runs in its own context.
|
|
* options.baseUrl: Keycloak base URL (no trailing slash).
|
|
* options.realm: realm the user belongs to.
|
|
* options.adminUsername / options.adminPassword: master-realm admin.
|
|
* options.user: `{ username, firstName, lastName, email }`.
|
|
* options.password: password to set on the user.
|
|
*/
|
|
|
|
const { expect } = require("@playwright/test");
|
|
const { performKeycloakLoginForm, gotoOnion } = require("./personas");
|
|
const { resolveTimeout } = require("./timeouts");
|
|
|
|
async function openUser(page, username) {
|
|
const search = page.getByPlaceholder(/search user/i).first();
|
|
await search.waitFor({ state: "visible", timeout: resolveTimeout(60_000) });
|
|
await search.fill(username);
|
|
await search.press("Enter");
|
|
const link = page.getByRole("link", { name: username, exact: true }).first();
|
|
const exists = await link
|
|
.waitFor({ state: "visible", timeout: resolveTimeout(10_000) })
|
|
.then(() => true)
|
|
.catch(() => false);
|
|
if (exists) {
|
|
await link.click({ timeout: resolveTimeout(30_000) });
|
|
}
|
|
return exists;
|
|
}
|
|
|
|
async function createUser(page, user) {
|
|
await page
|
|
.getByRole("button", { name: /add user|create new user/i })
|
|
.or(page.getByRole("link", { name: /add user|create new user/i }))
|
|
.first()
|
|
.click({ timeout: resolveTimeout(30_000) });
|
|
await page.getByLabel(/^username/i).first().fill(user.username);
|
|
await page.getByLabel(/^email$/i).first().fill(user.email);
|
|
await page.getByLabel(/^first name/i).first().fill(user.firstName);
|
|
await page.getByLabel(/^last name/i).first().fill(user.lastName);
|
|
await page.getByRole("button", { name: /^create$/i }).click({ timeout: resolveTimeout(30_000) });
|
|
await expect(
|
|
page.getByText(/the user has been created/i).first(),
|
|
`Keycloak must confirm that ${user.username} was created`,
|
|
).toBeVisible({ timeout: resolveTimeout(60_000) });
|
|
}
|
|
|
|
async function setPassword(page, username, password) {
|
|
await page.getByRole("tab", { name: /credentials/i }).click({ timeout: resolveTimeout(30_000) });
|
|
await page
|
|
.getByRole("button", { name: /^(set|reset) password$/i })
|
|
.first()
|
|
.click({ timeout: resolveTimeout(30_000) });
|
|
const dialog = page.getByRole("dialog");
|
|
const passwordFields = dialog.locator("input[type='password']");
|
|
await passwordFields.first().waitFor({ state: "visible", timeout: resolveTimeout(30_000) });
|
|
await passwordFields.nth(0).fill(password);
|
|
await passwordFields.nth(1).fill(password);
|
|
await dialog
|
|
.locator("input[type='checkbox']")
|
|
.first()
|
|
.setChecked(false, { force: true, timeout: resolveTimeout(30_000) });
|
|
await dialog.getByRole("button", { name: /^save$/i }).click({ timeout: resolveTimeout(30_000) });
|
|
const confirm = page.getByRole("dialog").getByRole("button", { name: /^(save|reset) password$/i });
|
|
const confirmShown = await confirm
|
|
.waitFor({ state: "visible", timeout: resolveTimeout(5_000) })
|
|
.then(() => true)
|
|
.catch(() => false);
|
|
if (confirmShown) {
|
|
await confirm.click({ timeout: resolveTimeout(30_000) });
|
|
}
|
|
await expect(
|
|
page.getByText(/password has been (set|reset) successfully/i).first(),
|
|
`Keycloak must confirm the new password of ${username}`,
|
|
).toBeVisible({ timeout: resolveTimeout(60_000) });
|
|
}
|
|
|
|
async function provisionKeycloakUser(browser, options) {
|
|
const { baseUrl, realm, adminUsername, adminPassword, user, password } = options;
|
|
const context = await browser.newContext({ ignoreHTTPSErrors: true });
|
|
const page = await context.newPage();
|
|
try {
|
|
await gotoOnion(page, `${baseUrl}/admin/master/console/#/${realm}/users`);
|
|
await performKeycloakLoginForm(page, adminUsername, adminPassword);
|
|
if (!(await openUser(page, user.username))) {
|
|
await createUser(page, user);
|
|
}
|
|
await setPassword(page, user.username, password);
|
|
await page
|
|
.goto(`${baseUrl}/realms/master/protocol/openid-connect/logout`, { waitUntil: "commit" })
|
|
.catch(() => {});
|
|
} finally {
|
|
await context.close();
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
provisionKeycloakUser,
|
|
};
|