snapshot of https://github.com/mattermost/mattermost.git (master, 2026-09-16; blobs > 131072B omitted)
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 Nightly Race / Build Environment (push) Failing after 1s
Server CI Cache Warm / Warm Go Module and Build Cache (push) Failing after 1s

This commit is contained in:
upstream-mirror
2026-09-16 00:29:55 +05:00
commit 240db4e2a7
15309 changed files with 2173406 additions and 0 deletions

View File

@@ -0,0 +1,316 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. #. Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @enterprise @saml
// Skip: @headless @electron @firefox // run on Chrome (headed) only
import type {UserCollection} from '@/support/okta_commands';
import users from '@/fixtures/saml_users.json';
//Manual Setup required: Follow the instructions mentioned in the mattermost/platform-private/config/saml-okta-setup.txt file
context('Okta', () => {
const loginButtonText = 'SAML';
const regular1 = users.regulars['samluser-1'];
const guest1 = users.guests['samlguest-1'];
const guest2 = users.guests['samlguest-2'];
const admin1 = users.admins['samladmin-1'];
const admin2 = users.admins['samladmin-2'];
const {
oktaBaseUrl,
oktaMMAppName,
oktaMMEntityId,
} = Cypress.expose();
const idpUrl = `${oktaBaseUrl}/app/${oktaMMAppName}/${oktaMMEntityId}/sso/saml`;
const idpMetadataUrl = `${oktaBaseUrl}/app/${oktaMMEntityId}/sso/saml/metadata`;
const newConfig = {
SamlSettings: {
Enable: true,
EnableSyncWithLdap: false,
EnableSyncWithLdapIncludeAuth: false,
Verify: true,
Encrypt: true,
SignRequest: true,
IdpURL: idpUrl,
IdpDescriptorURL: `http://www.okta.com/${oktaMMEntityId}`,
IdpMetadataURL: idpMetadataUrl,
ServiceProviderIdentifier: `${Cypress.config('baseUrl')}/login/sso/saml`,
AssertionConsumerServiceURL: `${Cypress.config('baseUrl')}/login/sso/saml`,
SignatureAlgorithm: 'RSAwithSHA1',
CanonicalAlgorithm: 'Canonical1.0',
IdpCertificateFile: 'saml-idp.crt',
PublicCertificateFile: 'saml-public.crt',
PrivateKeyFile: 'saml-private.key',
IdAttribute: '',
GuestAttribute: '',
EnableAdminAttribute: false,
AdminAttribute: '',
FirstNameAttribute: '',
LastNameAttribute: '',
EmailAttribute: 'Email',
UsernameAttribute: 'Username',
LoginButtonText: loginButtonText,
},
GuestAccountsSettings: {
Enable: true,
},
};
// TestSettings type is not exported from saml_commands; uses SAMLUser | null for user field
let testSettings: any;
//Note: the assumption is that this test suite runs on a clean setup (empty DB) which would ensure that the users are not present in the Mattermost instance beforehand
describe('SAML Login flow', () => {
before(() => {
// * Check if server has license for SAML
cy.apiRequireLicenseForFeature('SAML');
// # Get certificates status and upload as necessary
cy.apiGetSAMLCertificateStatus().then((resp) => {
const data = resp.body;
if (!data.idp_certificate_file) {
cy.apiUploadSAMLIDPCert('saml-idp.crt');
}
if (!data.public_certificate_file) {
cy.apiUploadSAMLPublicCert('saml-public.crt');
}
if (!data.private_key_file) {
cy.apiUploadSAMLPrivateKey('saml-private.key');
}
});
// # Check SAML metadata if working properly
cy.apiGetMetadataFromIdp(idpMetadataUrl);
cy.oktaAddUsers(users as unknown as UserCollection);
cy.apiUpdateConfig(newConfig).then(({config}) => {
cy.setTestSettings(loginButtonText, config).then((_response) => {
testSettings = _response;
});
});
});
it('Saml login new and existing MM regular user', () => {
cy.apiAdminLogin();
testSettings.user = regular1;
//login new user
cy.oktaGetOrCreateUser(testSettings.user).then((oktaUserId) => {
cy.oktaDeleteSession(oktaUserId);
cy.doSamlLogin(testSettings).then(() => {
cy.doOktaLogin(testSettings.user).then(() => {
cy.skipOrCreateTeam(testSettings, oktaUserId).then(() => {
cy.doSamlLogout(testSettings).then(() => {
cy.oktaDeleteSession(oktaUserId);
});
});
});
});
});
//login existing user
cy.oktaGetOrCreateUser(testSettings.user).then((oktaUserId) => {
cy.oktaDeleteSession(oktaUserId);
cy.doSamlLogin(testSettings).then(() => {
cy.doOktaLogin(testSettings.user).then(() => {
cy.doSamlLogout(testSettings).then(() => {
cy.oktaDeleteSession(oktaUserId);
});
});
});
});
});
it('Saml login new and existing MM guest user(userType=Guest)', () => {
cy.apiAdminLogin();
testSettings.user = guest1;
newConfig.SamlSettings.GuestAttribute = 'UserType=Guest';
cy.apiUpdateConfig(newConfig).then(() => {
//login new user
cy.oktaGetOrCreateUser(testSettings.user).then((oktaUserId) => {
cy.oktaDeleteSession(oktaUserId);
cy.doSamlLogin(testSettings).then(() => {
cy.doOktaLogin(testSettings.user).then(() => {
cy.skipOrCreateTeam(testSettings, oktaUserId).then(() => {
cy.doLogoutFromSignUp().then(() => {
cy.oktaDeleteSession(oktaUserId);
});
});
});
});
});
//login existing user
cy.oktaGetOrCreateUser(testSettings.user).then((oktaUserId) => {
cy.oktaDeleteSession(oktaUserId);
cy.doSamlLogin(testSettings).then(() => {
cy.doOktaLogin(testSettings.user).then(() => {
cy.doLogoutFromSignUp().then(() => {
cy.oktaDeleteSession(oktaUserId);
});
});
});
});
});
});
it('Saml login new and existing MM guest(isGuest=true)', () => {
cy.apiAdminLogin();
testSettings.user = guest2;
newConfig.SamlSettings.GuestAttribute = 'IsGuest=true';
cy.apiUpdateConfig(newConfig).then(() => {
//login new user
cy.oktaGetOrCreateUser(testSettings.user).then((oktaUserId) => {
cy.oktaDeleteSession(oktaUserId);
cy.doSamlLogin(testSettings).then(() => {
cy.doOktaLogin(testSettings.user).then(() => {
cy.skipOrCreateTeam(testSettings, oktaUserId).then(() => {
cy.doLogoutFromSignUp().then(() => {
cy.oktaDeleteSession(oktaUserId);
});
});
});
});
});
//login existing user
cy.oktaGetOrCreateUser(testSettings.user).then((oktaUserId) => {
cy.oktaDeleteSession(oktaUserId);
cy.doSamlLogin(testSettings).then(() => {
cy.doOktaLogin(testSettings.user).then(() => {
cy.doLogoutFromSignUp().then(() => {
cy.oktaDeleteSession(oktaUserId);
});
});
});
});
});
});
it('Saml login new and existing MM admin(userType=Admin)', () => {
cy.apiAdminLogin();
testSettings.user = admin1;
newConfig.SamlSettings.EnableAdminAttribute = true;
newConfig.SamlSettings.AdminAttribute = 'UserType=Admin';
cy.apiUpdateConfig(newConfig).then(() => {
//login new user
cy.oktaGetOrCreateUser(testSettings.user).then((oktaUserId) => {
cy.oktaDeleteSession(oktaUserId);
cy.doSamlLogin(testSettings).then(() => {
cy.doOktaLogin(testSettings.user).then(() => {
cy.skipOrCreateTeam(testSettings, oktaUserId).then(() => {
cy.doSamlLogout(testSettings).then(() => {
cy.oktaDeleteSession(oktaUserId);
});
});
});
});
});
//login existing user
cy.oktaGetOrCreateUser(testSettings.user).then((oktaUserId) => {
cy.oktaDeleteSession(oktaUserId);
cy.doSamlLogin(testSettings).then(() => {
cy.doOktaLogin(testSettings.user).then(() => {
cy.doSamlLogout(testSettings).then(() => {
cy.oktaDeleteSession(oktaUserId);
});
});
});
});
});
});
it('Saml login new and existing MM admin(isAdmin=true)', () => {
cy.apiAdminLogin();
testSettings.user = admin2;
newConfig.SamlSettings.EnableAdminAttribute = true;
newConfig.SamlSettings.AdminAttribute = 'IsAdmin=true';
cy.apiUpdateConfig(newConfig).then(() => {
//login new user
cy.oktaGetOrCreateUser(testSettings.user).then((oktaUserId) => {
cy.oktaDeleteSession(oktaUserId);
cy.doSamlLogin(testSettings).then(() => {
cy.doOktaLogin(testSettings.user).then(() => {
cy.skipOrCreateTeam(testSettings, oktaUserId).then(() => {
cy.doSamlLogout(testSettings).then(() => {
cy.oktaDeleteSession(oktaUserId);
});
});
});
});
});
cy.oktaGetOrCreateUser(testSettings.user).then((oktaUserId) => {
cy.oktaDeleteSession(oktaUserId);
cy.doSamlLogin(testSettings).then(() => {
cy.doOktaLogin(testSettings.user).then(() => {
cy.doSamlLogout(testSettings).then(() => {
cy.oktaDeleteSession(oktaUserId);
});
});
});
});
});
});
it('Saml login invited Guest user to a team', () => {
cy.apiAdminLogin();
testSettings.user = regular1;
//login as a regular user - generate an invite link
cy.oktaGetOrCreateUser(testSettings.user).then((oktaUserId) => {
cy.oktaDeleteSession(oktaUserId);
cy.doSamlLogin(testSettings).then(() => {
cy.doOktaLogin(testSettings.user).then(() => {
cy.skipOrCreateTeam(testSettings, oktaUserId).then((teamName: string) => {
testSettings.teamName = teamName;
//get invite link
cy.getInvitePeopleLink(testSettings).then((inviteUrl) => {
//logout regular1
cy.oktaDeleteSession(oktaUserId);
cy.doSamlLogout(testSettings).then(() => {
testSettings.user = guest1;
cy.oktaGetOrCreateUser(testSettings.user).then((_oktaUserId) => {
cy.visit(inviteUrl as unknown as string).then(() => {
cy.oktaDeleteSession(_oktaUserId);
//login the guest
cy.doSamlLogin(testSettings).then(() => {
cy.doOktaLogin(testSettings.user).then(() => {
cy.doLogoutFromSignUp();
cy.oktaDeleteSession(_oktaUserId);
});
});
});
});
});
});
});
});
});
});
});
});
});

View File

@@ -0,0 +1,196 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. #. Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @enterprise @saml
// Skip: @headless @electron @firefox // run on Chrome (headed) only
import type {UserCollection} from '@/support/okta_commands';
import users from '@/fixtures/saml_users.json';
//Manual Setup required: Follow the instructions mentioned in the mattermost/platform-private/config/saml-okta-setup.txt file
context('LDAP SAML - Automated Tests (SAML TESTS)', () => {
const loginButtonText = 'SAML';
const regular1 = users.regulars['samluser-1'];
const {
oktaBaseUrl,
oktaMMAppName,
oktaMMEntityId,
} = Cypress.expose();
const idpUrl = `${oktaBaseUrl}/app/${oktaMMAppName}/${oktaMMEntityId}/sso/saml`;
const idpMetadataUrl = `${oktaBaseUrl}/app/${oktaMMEntityId}/sso/saml/metadata`;
const newConfig = {
SamlSettings: {
Enable: true,
EnableSyncWithLdap: false,
EnableSyncWithLdapIncludeAuth: false,
Verify: true,
Encrypt: true,
SignRequest: true,
IdpURL: idpUrl,
IdpDescriptorURL: `http://www.okta.com/${oktaMMEntityId}`,
IdpMetadataURL: idpMetadataUrl,
ServiceProviderIdentifier: `${Cypress.config('baseUrl')}/login/sso/saml`,
AssertionConsumerServiceURL: `${Cypress.config('baseUrl')}/login/sso/saml`,
SignatureAlgorithm: 'RSAwithSHA1',
CanonicalAlgorithm: 'Canonical1.0',
IdpCertificateFile: 'saml-idp.crt',
PublicCertificateFile: 'saml-public.crt',
PrivateKeyFile: 'saml-private.key',
IdAttribute: '',
GuestAttribute: '',
EnableAdminAttribute: false,
AdminAttribute: '',
FirstNameAttribute: '',
LastNameAttribute: '',
EmailAttribute: 'Email',
UsernameAttribute: 'Username',
LoginButtonText: loginButtonText,
},
GuestAccountsSettings: {
Enable: true,
},
};
// TestSettings type is not exported from saml_commands; uses SAMLUser | null for user field
let testSettings: any;
//Note: the assumption is that this test suite runs on a clean setup (empty DB) which would ensure that the users are not present in the Mattermost instance beforehand
describe('LDAP SAML - Automated Tests (SAML TESTS)', () => {
before(() => {
// * Check if server has license for SAML
cy.apiRequireLicenseForFeature('SAML');
// # Get certificates status and upload as necessary
cy.apiGetSAMLCertificateStatus().then((resp) => {
const data = resp.body;
if (!data.idp_certificate_file) {
cy.apiUploadSAMLIDPCert('saml-idp.crt');
}
if (!data.public_certificate_file) {
cy.apiUploadSAMLPublicCert('saml-public.crt');
}
if (!data.private_key_file) {
cy.apiUploadSAMLPrivateKey('saml-private.key');
}
});
// # Check SAML metadata if working properly
cy.apiGetMetadataFromIdp(idpMetadataUrl);
cy.oktaAddUsers(users as unknown as UserCollection);
cy.apiUpdateConfig(newConfig).then(({config}) => {
cy.setTestSettings(loginButtonText, config).then((_response) => {
testSettings = _response;
});
});
});
it('MM-T3012 - Check SAML Metadata without Enable Encryption', () => {
cy.apiAdminLogin();
const test1Settings = {
...newConfig,
SamlSettings: {
...newConfig.SamlSettings,
Encrypt: false,
PublicCertificateFile: '',
PrivateKeyFile: '',
},
};
cy.apiUpdateConfig(test1Settings).then(() => {
const baseUrl = Cypress.config('baseUrl');
cy.request(`${baseUrl}/api/v4/saml/metadata`).then((resp) => {
expect(resp.status).to.eq(200);
expect(resp.headers['content-type']).to.eq('application/xml');
expect(resp.body).to.contain('<?xml version');
});
});
});
it('MM-T3280 - SAML Login Audit', () => {
cy.apiAdminLogin();
cy.apiUpdateConfig(newConfig).then(() => {
testSettings.user = regular1;
cy.oktaGetOrCreateUser(testSettings.user).then((oktaUserId) => {
cy.oktaDeleteSession(oktaUserId);
cy.doSamlLogin(testSettings).then(() => {
cy.doOktaLogin(testSettings.user).then(() => {
cy.skipOrCreateTeam(testSettings, oktaUserId).then(() => {
cy.uiOpenProfileModal('Security');
cy.findByTestId('viewAccessHistory').click();
cy.findByTestId('auditTableBody').find('td').
each(($el) => {
cy.wrap($el).
invoke('text').
then((text) => {
if (text.includes('Saml obtained user')) {
expect(text).to.contains('Saml obtained user');
}
});
});
});
});
});
});
});
});
it('MM-T3281 - SAML Signature Algorithm using RSAwithSHA256', () => {
cy.apiAdminLogin();
const test1Settings = {
...newConfig,
SamlSettings: {
...newConfig.SamlSettings,
SignatureAlgorithm: 'RSAwithSHA256',
},
};
cy.apiUpdateConfig(test1Settings).then(() => {
testSettings.user = regular1;
cy.oktaGetOrCreateUser(testSettings.user).then((oktaUserId) => {
cy.oktaDeleteSession(oktaUserId);
cy.doSamlLogin(testSettings).then(() => {
cy.doOktaLogin(testSettings.user).then(() => {
cy.skipOrCreateTeam(testSettings, oktaUserId);
cy.oktaDeleteSession(oktaUserId);
});
});
});
});
});
it('SAML Signature Algorithm using RSAwithSHA512', () => {
cy.apiAdminLogin();
const test1Settings = {
...newConfig,
SamlSettings: {
...newConfig.SamlSettings,
SignatureAlgorithm: 'RSAwithSHA512',
},
};
cy.apiUpdateConfig(test1Settings).then(() => {
testSettings.user = regular1;
cy.oktaGetOrCreateUser(testSettings.user).then((oktaUserId) => {
cy.oktaDeleteSession(oktaUserId);
cy.doSamlLogin(testSettings).then(() => {
cy.doOktaLogin(testSettings.user).then(() => {
cy.skipOrCreateTeam(testSettings, oktaUserId);
});
});
});
});
});
});
});

View File

@@ -0,0 +1,212 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Group: @channels @enterprise @saml
import * as TIMEOUTS from '@/fixtures/timeouts';
import {getRandomId} from '@/utils';
// assumes that E20 license is uploaded
// Update config.mk to make sure docker images for openldap and keycloak
// - assumes openldap docker available on config default http://localhost:389
// - assumes keycloak docker - uses api to update
// assumes the CYPRESS_* variables are set (CYPRESS_keycloakBaseUrl / CYPRESS_keycloakAppName)
// requires {"chromeWebSecurity": false}
// copy ./mattermost-server/build/docker/keycloak/keycloak.crt -> ./mattermost-webapp/e2e/cypress/tests/fixtures/keycloak.crt
describe('SAML Guest', () => {
const loginButtonText = 'SAML';
const guestUser = {
username: 'guest.test',
password: 'Password1',
email: 'guest.test@mmtest.com',
firstname: 'Guest',
lastname: 'OneSaml',
ldapfirstname: 'Guest',
ldaplastname: 'OneSaml',
keycloakId: '',
};
const userFilter = `username=${guestUser.username}`;
const keycloakBaseUrl = Cypress.expose('keycloakBaseUrl') || 'http://localhost:8484';
const keycloakAppName = Cypress.expose('keycloakAppName') || 'mattermost';
const idpUrl = `${keycloakBaseUrl}/auth/realms/${keycloakAppName}/protocol/saml`;
const idpDescriptorUrl = `${keycloakBaseUrl}/auth/realms/${keycloakAppName}`;
const newConfig = {
GuestAccountsSettings: {
Enable: true,
},
SamlSettings: {
Enable: true,
EnableSyncWithLdap: false,
EnableSyncWithLdapIncludeAuth: false,
Verify: true,
Encrypt: false,
SignRequest: false,
IdpURL: idpUrl,
IdpDescriptorURL: idpDescriptorUrl,
IdpMetadataURL: '',
ServiceProviderIdentifier: `${Cypress.config('baseUrl')}/login/sso/saml`,
AssertionConsumerServiceURL: `${Cypress.config('baseUrl')}/login/sso/saml`,
SignatureAlgorithm: 'RSAwithSHA256',
CanonicalAlgorithm: 'Canonical1.0',
IdpCertificateFile: 'saml-idp.crt',
PublicCertificateFile: '',
PrivateKeyFile: '',
IdAttribute: 'username',
GuestAttribute: '',
EnableAdminAttribute: false,
AdminAttribute: '',
FirstNameAttribute: 'firstName',
LastNameAttribute: 'lastName',
EmailAttribute: 'email',
UsernameAttribute: 'username',
LoginButtonText: loginButtonText,
},
};
// TestSettings type is not exported from saml_commands; uses SAMLUser | null for user field
let testSettings: any;
before(() => {
// * Check if server has license for SAML
cy.apiRequireLicenseForFeature('SAML');
// # Upload certificate, overwrite existing
cy.apiUploadSAMLIDPCert('keycloak.crt');
// # Update Configs
cy.apiUpdateConfig(newConfig).then(({config}) => {
cy.setTestSettings(loginButtonText, config).then((_response) => {
testSettings = _response;
cy.keycloakResetUsers([guestUser]);
});
});
});
it('MM-T1423_1 - SAML Guest Setting disabled if Guest Access is turned off', () => {
// # Visit saml settings
cy.visit('/admin_console/authentication/saml');
// # Turn on Guest Attribute Filter
cy.findByTestId('SamlSettings.GuestAttributeinput').clear().type('username=e2etest.one');
// # Save SAML Settings
cy.findByText('Save').click().wait(TIMEOUTS.ONE_SEC);
// # Visit Guest Access settings
cy.visit('/admin_console/authentication/guest_access');
// # Turn off Guest Access
cy.findByTestId('GuestAccountsSettings.Enablefalse').check();
// # Save Guest Access Settings
cy.findByText('Save').click().wait(TIMEOUTS.ONE_SEC);
// # Handle confirmation model
cy.findByText('Save and Disable Guest Access').click().wait(TIMEOUTS.ONE_SEC);
// # Visit saml settings
cy.visit('/admin_console/authentication/saml');
// * verify Guest Attribute is disabled.
cy.findByTestId('SamlSettings.GuestAttributeinput').should('be.disabled');
});
it('MM-T1423_2 - SAML User will login as member', () => {
const testConfig = {
...newConfig,
GuestAccountsSettings: {
Enable: false,
},
};
cy.apiAdminLogin().then(() => {
cy.apiUpdateConfig(testConfig);
});
testSettings.user = guestUser;
// # MM Login via SAML
cy.doSamlLogin(testSettings).then(() => {
// # Login to Keycloak
cy.doKeycloakLogin(testSettings.user).then(() => {
// # Create team if no membership
cy.skipOrCreateTeam(testSettings, getRandomId()).then(() => {
// * check the user is member, if can create public channel
cy.get('#SidebarContainer .AddChannelDropdown_dropdownButton').click();
cy.get('#showNewChannel button').should('exist');
});
});
});
});
it('MM-T1426_1 - User logged in as member, filter does not match', () => {
const testConfig = {
...newConfig,
GuestAccountsSettings: {
...newConfig.GuestAccountsSettings,
Enable: true,
},
SamlSettings: {
...newConfig.SamlSettings,
GuestAttribute: 'username=Wrong',
},
};
cy.apiAdminLogin().then(() => {
cy.apiUpdateConfig(testConfig);
});
testSettings.user = guestUser;
// # MM Login via SAML
cy.doSamlLogin(testSettings).then(() => {
// # Login to Keycloak
cy.doKeycloakLogin(testSettings.user).then(() => {
// # Create team if no membership
cy.skipOrCreateTeam(testSettings, getRandomId()).then(() => {
// * check the user is member, if can create public channel
cy.get('#SidebarContainer .AddChannelDropdown_dropdownButton').click();
cy.get('#showNewChannel button').should('exist');
});
});
});
});
it('MM-T1426_2 - User logged in as guest, correct filter', () => {
const testConfig = {
...newConfig,
GuestAccountsSettings: {
...newConfig.GuestAccountsSettings,
Enable: true,
},
SamlSettings: {
...newConfig.SamlSettings,
GuestAttribute: userFilter,
},
};
cy.apiAdminLogin().then(() => {
cy.apiUpdateConfig(testConfig);
});
testSettings.user = guestUser;
// # MM Login via SAML
cy.doSamlLogin(testSettings).then(() => {
// # Login to Keycloak
cy.doKeycloakLogin(testSettings.user).then(() => {
// # Create team if no membership
cy.skipOrCreateTeam(testSettings, getRandomId()).then(() => {
// * check the user is guest, cannot create public channel
cy.get('#SidebarContainer .AddChannelDropdown_dropdownButton').should('not.exist');
});
});
});
});
});

View File

@@ -0,0 +1,144 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import type {AdminConfig} from '@mattermost/types/config';
// ***************************************************************
// - [#] indicates a test step (e.g. # Go to a page)
// - [*] indicates an assertion (e.g. * Check the title)
// - Use element ID when selecting an element. Create one if none.
// ***************************************************************
// Stage: @prod
// Group: @channels @enterprise @saml
/**
* Note: This test requires Enterprise license to be uploaded
*/
const testSamlMetadataUrl = 'http://test_saml_metadata_url';
const testSamlMetadataSuccessUrl = 'http://test_saml_metadata_success_url';
const testIdpURL = 'http://test_idp_url';
const testIdpDescriptorURL = 'http://test_idp_descriptor_url';
const testFetchedIdpURL = 'http://test_fetched_idp_url';
const testFetchedIdpDescriptorURL = 'http://test_fetched_idp_descriptor_url';
const testIdpPublicCertificate = 'MIICozCCAYsCBgGNzWfMwjANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQDDAptYXR0ZXJtb3N0';
const getSamlMetadataErrorMessage = 'SAML Metadata URL did not connect and pull data successfully';
const getSamlMetadataSuccessMessage = 'SAML Metadata retrieved successfully. Two fields and one certificate have been updated';
let config: AdminConfig;
describe('SystemConsole->SAML 2.0 - Get Metadata from Idp Flow', () => {
before(() => {
// * Check if server has license for SAML
cy.apiRequireLicenseForFeature('SAML');
cy.apiUpdateConfig({
SamlSettings: {
Enable: true,
AssertionConsumerServiceURL: Cypress.config('baseUrl') + '/login/sso/saml',
ServiceProviderIdentifier: Cypress.config('baseUrl') + '/login/sso/saml',
IdpMetadataURL: '',
IdpURL: testIdpURL,
IdpDescriptorURL: testIdpDescriptorURL,
},
}).then((data) => {
({config} = data);
});
//make sure we can navigate to SAML settings
cy.visit('/admin_console/authentication/saml');
cy.get('.admin-console__header').should('be.visible').and('have.text', 'SAML 2.0');
});
it('fail to fetch metadata from Idp Metadata Url', () => {
// * Verify that the metadata Url textbox is enabled and empty
cy.findByTestId('SamlSettings.IdpMetadataURLinput').
scrollIntoView().should('be.visible').and('be.enabled').and('have.text', '');
// * Verify that the Get Metadata Url fetch button is disabled
cy.get('#getSamlMetadataFromIDPButton').find('button').should('be.visible').and('be.disabled');
// # Type in the metadata Url in the metadata Url textbox
cy.findByTestId('SamlSettings.IdpMetadataURLinput').
scrollIntoView().should('be.visible').
focus().type(testSamlMetadataUrl);
// # Click on the Get SAML Metadata Button
cy.get('#getSamlMetadataFromIDPButton button').click();
// * Verify that we get the right error message
cy.get('#getSamlMetadataFromIDPButton').should('be.visible').contains(getSamlMetadataErrorMessage);
// * Verify that the IdpURL textbox content has not been updated
cy.findByTestId('SamlSettings.IdpURLinput').then((elem) => {
Cypress.$(elem).val() === config.SamlSettings.IdpURL;
});
// * Verify that the IdpDescriptorURL textbox content has not been updated
cy.findByTestId('SamlSettings.IdpDescriptorURL').then((elem) => {
Cypress.$(elem).val() === config.SamlSettings.IdpDescriptorURL;
});
// * Verify that the IdpDescriptorURL textbox content has been updated
cy.findByTestId('SamlSettings.ServiceProviderIdentifier').then((elem) => {
Cypress.$(elem).val() === config.SamlSettings.ServiceProviderIdentifier;
});
// * Verify that we can successfully save the settings (we have not affected previous state)
cy.get('#saveSetting').click();
});
it('fetches metadata and sets the IdP certificate from Idp Metadata Url', () => {
cy.apiUpdateConfig({
SamlSettings: {
Enable: true,
IdpMetadataURL: testSamlMetadataSuccessUrl,
IdpURL: testIdpURL,
IdpDescriptorURL: testIdpDescriptorURL,
AssertionConsumerServiceURL: Cypress.config('baseUrl') + '/login/sso/saml',
ServiceProviderIdentifier: Cypress.config('baseUrl') + '/login/sso/saml',
},
});
cy.visit('/admin_console/authentication/saml');
cy.intercept('POST', '**/api/v4/saml/metadatafromidp', (req) => {
req.reply({
statusCode: 200,
body: {
idp_url: testFetchedIdpURL,
idp_descriptor_url: testFetchedIdpDescriptorURL,
idp_public_certificate: testIdpPublicCertificate,
},
});
}).as('getSamlMetadataFromIdp');
cy.intercept('POST', '**/api/v4/saml/certificate/idp', (req) => {
expect(req.headers['content-type']).to.eq('application/x-pem-file');
expect(req.body).to.eq(testIdpPublicCertificate);
req.reply({
statusCode: 200,
body: {status: 'OK'},
});
}).as('setSamlIdpCertificateFromMetadata');
// # Click on the Get SAML Metadata Button
cy.get('#getSamlMetadataFromIDPButton button').scrollIntoView().should('be.visible').and('be.enabled').click();
// * Verify that the metadata and certificate endpoints are called
cy.wait('@getSamlMetadataFromIdp');
cy.wait('@setSamlIdpCertificateFromMetadata');
// * Verify that the IdP URL fields have been updated
cy.findByTestId('SamlSettings.IdpURLinput').should('have.value', testFetchedIdpURL);
cy.findByTestId('SamlSettings.IdpDescriptorURLinput').should('have.value', testFetchedIdpDescriptorURL);
// * Verify that the success message reflects the updated fields and certificate
cy.get('#getSamlMetadataFromIDPButton').should('be.visible').contains(getSamlMetadataSuccessMessage);
// * Verify that the IdP certificate row shows the remove certificate view
cy.contains('.remove-filename', 'saml-idp.crt').should('be.visible');
cy.contains('button', 'Remove Identity Provider Certificate').should('be.visible');
});
});