Keycloak
120 строк · 4.3 Кб
1import ClientRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientRepresentation";
2import IdentityProviderRepresentation from "@keycloak/keycloak-admin-client/lib/defs/identityProviderRepresentation";
3import { expect, test } from "@playwright/test";
4import { randomUUID } from "node:crypto";
5
6import {
7createClient,
8createIdentityProvider,
9createRandomUserWithPassword,
10deleteClient,
11deleteIdentityProvider,
12deleteUser,
13findClientByClientId,
14inRealm,
15} from "../admin-client";
16import groupsIdPClient from "../realms/groups-idp.json" assert { type: "json" };
17import { getBaseUrl } from "../utils";
18
19const realm = "groups";
20
21test.describe("Account linking", () => {
22let groupIdPClientId: string;
23let user: string;
24// Tests for keycloak account console, section Account linking in Account security
25test.beforeAll(async () => {
26user = await createRandomUserWithPassword("user-" + randomUUID(), "pwd");
27
28const kcGroupsIdpId = await findClientByClientId("groups-idp");
29if (kcGroupsIdpId) {
30await deleteClient(kcGroupsIdpId);
31}
32groupIdPClientId = await createClient(
33groupsIdPClient as ClientRepresentation,
34);
35const baseUrl = getBaseUrl();
36const idp: IdentityProviderRepresentation = {
37alias: "master-idp",
38providerId: "oidc",
39enabled: true,
40config: {
41clientId: "groups-idp",
42clientSecret: "H0JaTc7VBu3HJR26vrzMxgidfJmgI5Dw",
43validateSignature: "false",
44tokenUrl: `${baseUrl}/realms/master/protocol/openid-connect/token`,
45jwksUrl: `${baseUrl}/realms/master/protocol/openid-connect/certs`,
46issuer: `${baseUrl}/realms/master`,
47authorizationUrl: `${baseUrl}/realms/master/protocol/openid-connect/auth`,
48logoutUrl: `${baseUrl}/realms/master/protocol/openid-connect/logout`,
49userInfoUrl: `${baseUrl}/realms/master/protocol/openid-connect/userinfo`,
50},
51};
52
53await inRealm(realm, () => createIdentityProvider(idp));
54});
55
56test.afterAll(async () => {
57await deleteUser(user);
58});
59test.afterAll(async () => {
60await deleteClient(groupIdPClientId);
61});
62test.afterAll(async () => {
63await inRealm(realm, () => deleteIdentityProvider("master-idp"));
64});
65
66test("Linking", async ({ page }) => {
67// If refactoring this, consider introduction of helper functions for individual pages - login, update profile etc.
68await page.goto(
69process.env.CI ? `/realms/${realm}/account` : `/?realm=${realm}`,
70);
71
72// Click the login via master-idp provider button
73await loginWithIdp(page, "master-idp");
74
75// Now the login at the master-idp should be visible
76await loginWithUsernamePassword(page, "admin", "admin");
77
78// Now the update-profile page should be visible
79await updateProfile(page, "test", "user", "testuser@keycloak.org");
80
81// Now the account console should be visible
82await page.getByTestId("accountSecurity").click();
83await expect(
84page.getByTestId("account-security/linked-accounts"),
85).toBeVisible();
86await page.getByTestId("account-security/linked-accounts").click();
87await expect(
88page
89.getByTestId("linked-accounts/master-idp")
90.getByRole("button", { name: "Unlink account" }),
91).toBeVisible();
92await page
93.getByTestId("linked-accounts/master-idp")
94.getByRole("button", { name: "Unlink account" })
95.click();
96
97// Expect an error shown that the account cannot be unlinked
98await expect(page.getByLabel("Danger Alert")).toBeVisible();
99});
100});
101
102async function updateProfile(page, firstName, lastName, email) {
103await expect(
104page.getByRole("heading", { name: "Update Account Information" }),
105).toBeVisible();
106await page.getByLabel("Email", { exact: true }).fill(email);
107await page.getByLabel("First name", { exact: true }).fill(firstName);
108await page.getByLabel("Last name", { exact: true }).fill(lastName);
109await page.getByRole("button", { name: "Submit" }).click();
110}
111
112async function loginWithUsernamePassword(page, username, password) {
113await page.getByLabel("Username").fill(username);
114await page.getByLabel("Password", { exact: true }).fill(password);
115await page.getByRole("button", { name: "Sign In" }).click();
116}
117
118async function loginWithIdp(page, idpAlias: string) {
119await page.getByRole("link", { name: idpAlias }).click();
120}
121