Files
upstream-mattermost/e2e-tests/cypress/tests/support/keycloak_commands.ts
upstream-mirror 240db4e2a7
Some checks failed
Server CI / Postgres (shard 0) (push) Has been skipped
Server CI / Postgres (shard 3) (push) Has been skipped
BuildEnv Docker Image / build-image (push) Failing after 4s
BuildEnv Docker Image / build-image-fips (push) Failing after 4s
Migration Review & Release Notes / Generate migration review & release notes (push) Failing after 3s
Server CI / Build Environment (push) Failing after 3s
Server CI / Postgres (shard 1) (push) Has been skipped
Tools CI / check-style (mattermost-govet) (push) Failing after 4s
Server CI / Postgres (shard 2) (push) Has been skipped
Tools CI / check-style (mmgotool) (push) Failing after 3s
Server CI / Elasticsearch v8 Compatibility (push) Has been skipped
Server CI / OpenSearch v2 Compatibility (push) Has been skipped
Server CI / Postgres FIPS (shard 0) (push) Has been skipped
Tools CI / Test (mattermost-govet) (push) Failing after 3s
Server CI / Postgres FIPS (shard 1) (push) Has been skipped
Server CI / Postgres FIPS (shard 2) (push) Has been skipped
Tools CI / Test (mmgotool) (push) Failing after 3s
Server CI / Postgres FIPS (shard 3) (push) Has been skipped
Server CI / Run mmctl tests (push) Has been skipped
Server CI / Run mmctl tests (FIPS) (push) Has been skipped
Server CI / Merge Postgres Test Results (push) Has been skipped
Server CI / Merge Postgres FIPS Test Results (push) Has been skipped
Server CI / Check backport migrations (push) Has been skipped
Server CI / Check generated files (push) Has been skipped
Server CI / check-style (push) Has been skipped
Server CI / Vet API (push) Has been skipped
Server CI / Build mattermost server app (push) Has been skipped
Server CI / Server CI Complete (push) Failing after 2s
Server CI / Server CI Artifacts (push) Has been skipped
Server CI / Sentry Upload (push) Has been skipped
Server CI / Server CI Report (push) Failing after 5m1s
Server CI Nightly Race / Race Detector (push) Has been skipped
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Webapp CI Cache Warm / Warm Webapp node_modules Cache (push) Has been cancelled
E2E CI Cache Warm / Warm E2E npm Registry Cache (push) Has been cancelled
API / build (push) Has been cancelled
Web App CI / check-types (push) Has been cancelled
Web App CI / check-lint (push) Has been cancelled
Web App CI / check-i18n (push) Has been cancelled
Web App CI / check-external-links (push) Has been cancelled
Web App CI / test (platform) (push) Has been cancelled
Web App CI / test (mattermost-redux) (push) Has been cancelled
Web App CI / test (channels shard 1/4) (push) Has been cancelled
Web App CI / test (channels shard 2/4) (push) Has been cancelled
Web App CI / test (channels shard 3/4) (push) Has been cancelled
Web App CI / test (channels shard 4/4) (push) Has been cancelled
Web App CI / upload-coverage (push) Has been cancelled
Web App CI / build (push) Has been cancelled
YAML Lint / yamllint (push) Has been cancelled
Push mirrored docker images / cd/Push mirrored docker images (push) Has been cancelled
docs-cd / Build and deploy docs (push) Has been cancelled
Docs CI / build (push) Has been cancelled
E2E Cache Warm: Cypress deps / Warm Cypress deps cache (push) Has been cancelled
Scorecards supply-chain security / Scorecard analysis (push) Has been cancelled
Server CI Weekly / Postgres FIPS (push) Has been skipped
Server CI Weekly / Run mmctl tests (FIPS) (push) Has been skipped
Server CI Weekly / Postgres with binary parameters (push) Has been skipped
Server CI Weekly / Build Environment (push) Failing after 1s
Server CI Cache Warm / Warm Go Module and Build Cache (push) Failing after 2s
Server CI Nightly Race / Build Environment (push) Failing after 1s
snapshot of https://github.com/mattermost/mattermost.git (master, 2026-09-16; blobs > 131072B omitted)
2026-09-16 00:29:55 +05:00

446 lines
15 KiB
TypeScript

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import * as TIMEOUTS from '../fixtures/timeouts';
import type {LdapUser} from './ldap_server_commands';
import type {ChainableT} from '@/types';
const {
keycloakBaseUrl,
keycloakAppName,
} = Cypress.expose();
const baseUrl = `${keycloakBaseUrl}/auth/admin/realms/${keycloakAppName}`;
const loginUrl = `${keycloakBaseUrl}/auth/realms/master/protocol/openid-connect/token`;
function buildProfile(user: LdapUser) {
return {
firstName: user.firstname,
lastName: user.lastname,
email: user.email,
username: user.username,
enabled: true,
};
}
/**
* keycloakGetAccessTokenAPI is a task wrapped as command with post-verification
* that an Access Token is successfully retrieved
* @returns {string} - access token
*/
function keycloakGetAccessTokenAPI(): ChainableT<string> {
return cy.task('keycloakRequest', {
baseUrl: loginUrl,
path: '',
method: 'post',
headers: {'Content-type': 'application/x-www-form-urlencoded'},
data: 'grant_type=password&username=mmuser&password=mostest_password&client_id=admin-cli',
// cy.task() returns untyped data
}).then((response: any) => {
expect(response.status).to.equal(200);
const token: string = response.data.access_token;
return cy.wrap(token);
});
}
Cypress.Commands.add('keycloakGetAccessTokenAPI', keycloakGetAccessTokenAPI);
/**
* keycloakCreateUserAPI is a task wrapped as command with post-verification
* that a user is successfully created in keycloak
* @param {string} accessToken - a valid access token
* @param {object} user - a keycloak user object to create
*
* @example
* cy.keycloakCreateUserAPI('abcde', {firstName: 'test', lastName: 'test', email: 'test', username: 'test', enabled: true,});
*/
function keycloakCreateUserAPI(accessToken: string, user: LdapUser): ChainableT {
const profile = buildProfile(user);
return cy.task('keycloakRequest', {
baseUrl,
path: 'users',
method: 'post',
data: profile,
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${accessToken}`,
},
// cy.task() returns untyped data
}).then((response: any) => {
expect(response.status).to.equal(201);
});
}
Cypress.Commands.add('keycloakCreateUserAPI', keycloakCreateUserAPI);
/**
* keycloakResetPasswordAPI is a task wrapped as command with post-verification
* that a user password is successfully reset in keycloak
* @param {string} accessToken - a valid access token
* @param {string} userId - a keycloak userId
* @param {string} password - new password to set
*
* @example
* cy.keycloakResetPasswordAPI('abcde', '12345', 'password');
*/
function keycloakResetPasswordAPI(accessToken: string, userId: string, password: string): ChainableT {
return cy.task('keycloakRequest', {
baseUrl,
path: `users/${userId}/reset-password`,
method: 'put',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${accessToken}`,
},
data: {type: 'password', temporary: false, value: password},
// cy.task() returns untyped data
}).then((response: any) => {
if (response.status === 200 && response.data.length > 0) {
return cy.wrap(response.data[0].id);
}
return null;
});
}
Cypress.Commands.add('keycloakResetPasswordAPI', keycloakResetPasswordAPI);
/**
* keycloakGetUserAPI is a task wrapped as command with post-verification
* that a user is successfully found in keycloak
* @param {string} accessToken - a valid access token
* @param {string} email - an email to query
* @returns {string} - keycloak userId if found
*
* @example
* cy.keycloakGetUserAPI('abcde', 'test@mm.com');
*/
function keycloakGetUserAPI(accessToken: string, email: string): ChainableT<string> {
return cy.task('keycloakRequest', {
baseUrl,
path: 'users?email=' + email,
method: 'get',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${accessToken}`,
},
// cy.task() returns untyped data
}).then((response: any) => {
if (response.status === 200 && response.data.length > 0) {
return cy.wrap<string>(response.data[0].id);
}
return cy.wrap(null as unknown as string);
});
}
Cypress.Commands.add('keycloakGetUserAPI', keycloakGetUserAPI);
/**
* keycloakDeleteUserAPI is a task wrapped as command with post-verification
* that a user is successfully deleted in keycloak
* @param {string} accessToken - a valid access token
* @param {string} userId - keycloak user id to delete
*
* @example
* cy.keycloakDeleteUserAPI('abcde', '12345');
*/
function keycloakDeleteUserAPI(accessToken: string, userId: string): ChainableT {
return cy.task('keycloakRequest', {
baseUrl,
path: `users/${userId}`,
method: 'delete',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${accessToken}`,
},
// cy.task() returns untyped data
}).then((response: any) => {
expect(response.status).to.equal(204);
});
}
Cypress.Commands.add('keycloakDeleteUserAPI', keycloakDeleteUserAPI);
/**
* keycloakUpdateUserAPI is a task wrapped as command with post-verification
* that a user is successfully updated in keycloak
* @param {string} accessToken - a valid access token
* @param {string} userId - keycloak user id to delete
* @param {object} data - keycloak user object
*
* @example
* cy.keycloakUpdateUserAPI('abcde', '12345', {'enabled': false}});
*/
function keycloakUpdateUserAPI(accessToken: string, userId: string, data: Record<string, unknown>): ChainableT {
return cy.task('keycloakRequest', {
baseUrl,
path: 'users/' + userId,
method: 'put',
headers: {
Authorization: `Bearer ${accessToken}`,
},
data,
// cy.task() returns untyped data
}).then((response: any) => {
expect(response.status).to.equal(204);
});
}
Cypress.Commands.add('keycloakUpdateUserAPI', keycloakUpdateUserAPI);
/**
* keycloakDeleteSessionAPI is a task wrapped as command with post-verification
* that a users session is successfully deleted in keycloak
* @param {string} accessToken - a valid access token
* @param {string} sessionId- keycloak session id to delete
*
* @example
* cy.keycloakDeleteSessionAPI('abcde', '12345');
*/
function keycloakDeleteSessionAPI(accessToken: string, sessionId: string): ChainableT {
return cy.task('keycloakRequest', {
baseUrl,
path: `sessions/${sessionId}`,
method: 'delete',
headers: {
Authorization: `Bearer ${accessToken}`,
},
// cy.task() returns untyped data
}).then((delResponse: any) => {
expect(delResponse.status).to.equal(204);
});
}
Cypress.Commands.add('keycloakDeleteSessionAPI', keycloakDeleteSessionAPI);
/**
* keycloakGetUserSessionsAPI is a task wrapped as command with post-verification
* that a users sessions are successfully found
* @param {string} accessToken - a valid access token
* @param {string} userId - keycloak user id to find sessions
* @returns {string[]} - array of keycloak session ids
*
* @example
* cy.keycloakGetUserSessionsAPI('abcde', '12345');
*/
function keycloakGetUserSessionsAPI(accessToken: string, userId: string): ChainableT<string[]> {
return cy.task('keycloakRequest', {
baseUrl,
path: `users/${userId}/sessions`,
method: 'get',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${accessToken}`,
},
// cy.task() returns untyped data
}).then((response: any) => {
expect(response.status).to.equal(200);
expect(response.data);
return cy.wrap<string[]>(response.data);
});
}
Cypress.Commands.add('keycloakGetUserSessionsAPI', keycloakGetUserSessionsAPI);
/**
* keycloakDeleteUserSessions is a command that finds a user's sessions
* and deletes them.
* @param {string} accessToken - a valid access token
* @param {string} userId- keycloak user id to delete sessions
*
* @example
* cy.keycloakDeleteUserSessions('abcde', '12345');
*/
function keycloakDeleteUserSessions(accessToken: string, userId: string): ChainableT {
return cy.keycloakGetUserSessionsAPI(accessToken, userId).then((responseData) => {
if (responseData.length > 0) {
responseData.forEach((sessionId) => {
cy.keycloakDeleteSessionAPI(accessToken, sessionId);
});
// Ensure we clear out these specific cookies
['JSESSIONID'].forEach((cookie) => {
cy.clearCookie(cookie);
});
}
});
}
Cypress.Commands.add('keycloakDeleteUserSessions', keycloakDeleteUserSessions);
/**
* keycloakResetUsers is a command that "resets" (deletes and re-creates) the users.
* @param {object[]} users - an array of user objects
*
* @example
* cy.keycloakResetUsers([{firstName: 'test', lastName: 'test', email: 'test', username: 'test', enabled: true}]);
*/
function keycloakResetUsers(users: LdapUser[]): ChainableT {
return cy.keycloakGetAccessTokenAPI().then((accessToken) => {
users.forEach((_user) => {
cy.keycloakGetUserAPI(accessToken, _user.email).then((userId) => {
if (userId) {
cy.keycloakDeleteUserAPI(accessToken, userId);
}
}).then(() => {
cy.keycloakCreateUser(accessToken, _user).then((_id) => {
_user.keycloakId = _id;
});
});
});
});
}
Cypress.Commands.add('keycloakResetUsers', keycloakResetUsers);
/**
* keycloakCreateUser is a command that creates a keycloak user.
* @param {User} user - a user object
*
* @example
* cy.keycloakCreateUser({firstName: 'test', lastName: 'test', email: 'test', username: 'test', enabled: true});
*/
function keycloakCreateUser(accessToken: string, user: LdapUser): ChainableT {
return cy.keycloakCreateUserAPI(accessToken, user).then(() => {
cy.keycloakGetUserAPI(accessToken, user.email).then((newId) => {
cy.keycloakResetPasswordAPI(accessToken, newId, user.password).then(() => {
cy.keycloakDeleteUserSessions(accessToken, newId).then(() => {
return cy.wrap(newId);
});
});
});
});
}
Cypress.Commands.add('keycloakCreateUser', keycloakCreateUser);
/**
* keycloakCreateUsers is a command that creates keycloak users.
* @param {User[]} users - an array of users
*
* @example
* cy.keycloakCreateUsers(users);
*/
function keycloakCreateUsers(users: LdapUser[] = []) {
return cy.keycloakGetAccessTokenAPI().then((accessToken) => {
return users.forEach((user) => {
return cy.keycloakCreateUser(accessToken, user);
});
});
}
Cypress.Commands.add('keycloakCreateUsers', keycloakCreateUsers);
/**
* keycloakUpdateUser is a command that updates a keycloak user data.
* @param {string} userEmail - the user email
* @param {Record<string, unknown>} data - the user data to update
*
* @example
* cy.keycloakUpdateUser('user@example.com', {firstName: 'test', lastName: 'test'});
*/
function keycloakUpdateUser(userEmail: string, data: Record<string, unknown>) {
return cy.keycloakGetAccessTokenAPI().then((accessToken) => {
return cy.keycloakGetUserAPI(accessToken, userEmail).then((userId) => {
return cy.keycloakUpdateUserAPI(accessToken, userId, data);
});
});
}
Cypress.Commands.add('keycloakUpdateUser', keycloakUpdateUser);
/**
* keycloakSuspendUser is a command that suspends a user (enabled=false)
* @param {string} userEmail - email of keycloak user
*
* @example
* cy.keycloakSuspendUser('user@test.com');
*/
function keycloakSuspendUser(userEmail: string) {
const data = {enabled: false};
cy.keycloakUpdateUser(userEmail, data);
}
Cypress.Commands.add('keycloakSuspendUser', keycloakSuspendUser);
/**
* keycloakUnsuspendUser is a command that re-activates a user (enabled=true)
* @param {string} userEmail - email of keycloak user
*
* @example
* cy.keycloakUnsuspendUser('user@test.com');
*/
function keycloakUnsuspendUser(userEmail: string): ChainableT {
const data = {enabled: true};
return cy.keycloakUpdateUser(userEmail, data);
}
Cypress.Commands.add('keycloakUnsuspendUser', keycloakUnsuspendUser);
/**
* checkKeycloakLoginPage is a command that verifies the keycloak login page is displayed
*
* @example
* cy.checkKeycloakLoginPage();
*/
function checkKeycloakLoginPage() {
cy.findByText('Username or email', {timeout: TIMEOUTS.ONE_SEC}).should('be.visible');
cy.findByText('Password').should('be.visible');
cy.findAllByText('Log In').should('be.visible');
}
Cypress.Commands.add('checkKeycloakLoginPage', checkKeycloakLoginPage);
/**
* doKeycloakLogin is a command that attempts to log a user into keycloak.
*
* @example
* cy.doKeycloakLogin();
*/
function doKeycloakLogin(user: LdapUser) {
cy.apiLogout();
cy.visit('/login');
cy.findByText('SAML').click();
cy.findByText('Username or email').type(user.email);
cy.findByText('Password').type(user.password);
cy.findAllByText('Log In').last().click();
}
Cypress.Commands.add('doKeycloakLogin', doKeycloakLogin);
/**
* verifyKeycloakLoginFailed is a command that verifies a keycloak login failed.
*
* @example
* cy.verifyKeycloakLoginFailed();
*/
function verifyKeycloakLoginFailed() {
cy.findAllByText('Account is disabled, contact your administrator.').should('be.visible');
}
Cypress.Commands.add('verifyKeycloakLoginFailed', verifyKeycloakLoginFailed);
declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace Cypress {
interface Chainable {
keycloakCreateUsers: typeof keycloakCreateUsers;
keycloakUpdateUser: typeof keycloakUpdateUser;
keycloakGetAccessTokenAPI: typeof keycloakGetAccessTokenAPI;
keycloakCreateUserAPI: typeof keycloakCreateUserAPI;
keycloakResetPasswordAPI: typeof keycloakResetPasswordAPI;
keycloakGetUserAPI: typeof keycloakGetUserAPI;
keycloakDeleteUserAPI: typeof keycloakDeleteUserAPI;
keycloakUpdateUserAPI: typeof keycloakUpdateUserAPI;
keycloakDeleteSessionAPI: typeof keycloakDeleteSessionAPI;
keycloakGetUserSessionsAPI: typeof keycloakGetUserSessionsAPI;
keycloakDeleteUserSessions: typeof keycloakDeleteUserSessions;
keycloakResetUsers: typeof keycloakResetUsers;
keycloakCreateUser: typeof keycloakCreateUser;
keycloakSuspendUser(userEmail: string): ChainableT<void>;
keycloakUnsuspendUser: typeof keycloakUnsuspendUser;
checkKeycloakLoginPage: typeof checkKeycloakLoginPage;
doKeycloakLogin(user: LdapUser): ChainableT<void>;
verifyKeycloakLoginFailed: typeof verifyKeycloakLoginFailed;
}
}
}