Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/meteor/ee/server/configuration/saml.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ await License.onLicense('saml-enterprise', () => {

const savedRoles = await Roles.findInIdsOrNames(ensureArray<string>(value)).toArray();

userObject.roles = savedRoles.map((role) => role.name);
userObject.roles = savedRoles.map((role) => role._id);
}
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@
'eduPersonAffiliation' => array('group2'),
'email' => 'samluser3@example.com',
),
'samluser4:password' => array(
'uid' => array('4'),
'username' => 'samluser4',
'cn' => 'Saml User 4',
'eduPersonAffiliation' => array('group4'),
'email' => 'samluser4@example.com',
'role' => 'saml-role',
),
),

);
1 change: 1 addition & 0 deletions apps/meteor/tests/e2e/fixtures/userStates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ export const Users = {
user3: generateContext('user3'),
samluser1: generateContext('samluser1'),
samluser2: generateContext('samluser2'),
samluser4: generateContext('samluser4'),
userForSamlMerge: generateContext('user_for_saml_merge'),
userForSamlMerge2: generateContext('user_for_saml_merge2'),
admin: generateContext('rocketchat.internal.admin.test'),
Expand Down
59 changes: 56 additions & 3 deletions apps/meteor/tests/e2e/saml.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,23 @@ import * as constants from './config/constants';
import { createUserFixture } from './fixtures/collections/users';
import { Users } from './fixtures/userStates';
import { Registration } from './page-objects';
import { createCustomRole, deleteCustomRole } from './utils/custom-role';
import { getUserInfo } from './utils/getUserInfo';
import { setSettingValueById } from './utils/setSettingValueById';
import { test, expect } from './utils/test';
import { test, expect, BaseTest } from './utils/test';

const resetTestData = async (cleanupOnly = false) => {
// Reset saml users' data on mongo in the beforeAll hook to allow re-running the tests within the same playwright session
// This is needed because those tests will modify this data and running them a second time would trigger different code paths
const connection = await MongoClient.connect(constants.URL_MONGODB);

const usernamesToDelete = [Users.userForSamlMerge, Users.userForSamlMerge2, Users.samluser1, Users.samluser2].map(({ data: { username }}) => username);
const usernamesToDelete = [
Users.userForSamlMerge,
Users.userForSamlMerge2,
Users.samluser1,
Users.samluser2,
Users.samluser4,
].map(({ data: { username } }) => username);
await connection
.db()
.collection('users')
Expand Down Expand Up @@ -57,6 +64,14 @@ const resetTestData = async (cleanupOnly = false) => {
_id: 'SAML_Custom_Default',
value: false,
},
{
_id: 'SAML_Custom_Default_role_attribute_sync',
value: true,
},
{
_id: 'SAML_Custom_Default_role_attribute_name',
value: 'role',
},
].map((setting) =>
connection
.db()
Expand All @@ -66,8 +81,17 @@ const resetTestData = async (cleanupOnly = false) => {
);
};

const setupCustomRole = async (api: BaseTest['api']) => {
const roleResponse = await createCustomRole(api, { name: 'saml-role' })
expect(roleResponse.status()).toBe(200);

const { role } = await roleResponse.json();
return role._id;
}

test.describe('SAML', () => {
let poRegistration: Registration;
let samlRoleId: string;

const containerPath = path.join(__dirname, 'containers', 'saml');

Expand All @@ -77,6 +101,11 @@ test.describe('SAML', () => {
// Only one setting updated through the API to avoid refreshing the service configurations several times
await expect((await setSettingValueById(api, 'SAML_Custom_Default', true)).status()).toBe(200);

// Create a new custom role
if (constants.IS_EE) {
samlRoleId = await setupCustomRole(api)
}

await compose.buildOne('testsamlidp_idp', {
cwd: containerPath,
});
Expand All @@ -86,7 +115,7 @@ test.describe('SAML', () => {
});
});

test.afterAll(async () => {
test.afterAll(async ({ api }) => {
await compose.down({
cwd: containerPath,
});
Expand All @@ -102,6 +131,11 @@ test.describe('SAML', () => {

// Remove saml test users so they don't interfere with other tests
await resetTestData(true);

// Remove created custom role
if (constants.IS_EE) {
expect((await deleteCustomRole(api, 'saml-role')).status()).toBe(200);
}
});

test.beforeEach(async ({ page }) => {
Expand Down Expand Up @@ -260,6 +294,25 @@ test.describe('SAML', () => {
});
});

test('User Mapping - Custom Role', async ({ page, api }) => {
test.skip(!constants.IS_EE);

await doLoginStep(page, 'samluser4');

await test.step('expect users role to have been mapped correctly', async () => {
const user = await getUserInfo(api, 'samluser4');

expect(user).toBeDefined();
expect(user?.username).toBe('samluser4');
expect(user?.name).toBe('Saml User 4');
expect(user?.emails).toBeDefined();
expect(user?.emails?.[0].address).toBe('samluser4@example.com');
expect(user?.roles).toBeDefined();
expect(user?.roles?.length).toBe(1);
expect(user?.roles).toContain(samlRoleId);
});
});

test.fixme('User Merge - By Custom Identifier', async () => {
// Test user merge with a custom identifier configured in the fieldmap
});
Expand Down
11 changes: 11 additions & 0 deletions apps/meteor/tests/e2e/utils/custom-role.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Endpoints } from '@rocket.chat/rest-typings';

import type { BaseTest } from './test';

export async function createCustomRole(api: BaseTest['api'], data: Parameters<Endpoints['/v1/roles.create']['POST']>[0]) {
return api.post('/roles.create', data);
}

export async function deleteCustomRole(api: BaseTest['api'], roleId: string) {
return api.post('/roles.delete', { roleId });
}