|
@@ -0,0 +1,210 @@
|
|
|
|
|
+import { configManager } from '~/server/service/config-manager';
|
|
|
|
|
+
|
|
|
|
|
+import { KeycloakUserGroupSyncService } from './keycloak-user-group-sync';
|
|
|
|
|
+
|
|
|
|
|
+vi.mock('@keycloak/keycloak-admin-client', () => {
|
|
|
|
|
+ return {
|
|
|
|
|
+ default: class {
|
|
|
|
|
+
|
|
|
|
|
+ auth() {}
|
|
|
|
|
+
|
|
|
|
|
+ groups = {
|
|
|
|
|
+ // mock group search on Keycloak
|
|
|
|
|
+ find: () => {
|
|
|
|
|
+ return [
|
|
|
|
|
+ // root node
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'groupId1',
|
|
|
|
|
+ name: 'grandParentGroup',
|
|
|
|
|
+ subGroups: [
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'groupId2',
|
|
|
|
|
+ name: 'parentGroup',
|
|
|
|
|
+ subGroups: [
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'groupId3',
|
|
|
|
|
+ name: 'childGroup',
|
|
|
|
|
+ },
|
|
|
|
|
+ ],
|
|
|
|
|
+ },
|
|
|
|
|
+ ],
|
|
|
|
|
+ },
|
|
|
|
|
+ // another root node
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'groupId4',
|
|
|
|
|
+ name: 'rootGroup',
|
|
|
|
|
+ },
|
|
|
|
|
+ ];
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // mock group detail
|
|
|
|
|
+ findOne: (payload) => {
|
|
|
|
|
+ if (payload?.id === 'groupId1') {
|
|
|
|
|
+ return Promise.resolve(
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'groupId1',
|
|
|
|
|
+ name: 'grandParentGroup',
|
|
|
|
|
+ attributes: {
|
|
|
|
|
+ description: ['this is a grand parent group'],
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+ if (payload?.id === 'groupId2') {
|
|
|
|
|
+ return Promise.resolve(
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'groupId2',
|
|
|
|
|
+ name: 'parentGroup',
|
|
|
|
|
+ attributes: {
|
|
|
|
|
+ description: ['this is a parent group'],
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+ if (payload?.id === 'groupId3') {
|
|
|
|
|
+ return Promise.resolve(
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'groupId3',
|
|
|
|
|
+ name: 'childGroup',
|
|
|
|
|
+ attributes: {
|
|
|
|
|
+ description: ['this is a child group'],
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+ if (payload?.id === 'groupId4') {
|
|
|
|
|
+ return Promise.resolve(
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'groupId3',
|
|
|
|
|
+ name: 'childGroup',
|
|
|
|
|
+ attributes: {
|
|
|
|
|
+ description: ['this is a root group'],
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+ return Promise.reject(new Error('not found'));
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // mock group users
|
|
|
|
|
+ listMembers: (payload) => {
|
|
|
|
|
+ if (payload?.id === 'groupId1') {
|
|
|
|
|
+ return Promise.resolve([
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'userId1',
|
|
|
|
|
+ username: 'grandParentGroupUser',
|
|
|
|
|
+ email: 'user@grandParentGroup.com',
|
|
|
|
|
+ },
|
|
|
|
|
+ ]);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (payload?.id === 'groupId2') {
|
|
|
|
|
+ return Promise.resolve([
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'userId2',
|
|
|
|
|
+ username: 'parentGroupUser',
|
|
|
|
|
+ email: 'user@parentGroup.com',
|
|
|
|
|
+ },
|
|
|
|
|
+ ]);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (payload?.id === 'groupId3') {
|
|
|
|
|
+ return Promise.resolve([
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'userId3',
|
|
|
|
|
+ username: 'childGroupUser',
|
|
|
|
|
+ email: 'user@childGroup.com',
|
|
|
|
|
+ },
|
|
|
|
|
+ ]);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (payload?.id === 'groupId4') {
|
|
|
|
|
+ return Promise.resolve([
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 'userId4',
|
|
|
|
|
+ username: 'rootGroupUser',
|
|
|
|
|
+ email: 'user@rootGroup.com',
|
|
|
|
|
+ },
|
|
|
|
|
+ ]);
|
|
|
|
|
+ }
|
|
|
|
|
+ return Promise.reject(new Error('not found'));
|
|
|
|
|
+ },
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ },
|
|
|
|
|
+ };
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+describe('KeycloakUserGroupSyncService.generateExternalUserGroupTrees', () => {
|
|
|
|
|
+ let keycloakUserGroupSyncService: KeycloakUserGroupSyncService;
|
|
|
|
|
+
|
|
|
|
|
+ const configParams = {
|
|
|
|
|
+ 'external-user-group:keycloak:host': 'http://dummy-keycloak-host.com',
|
|
|
|
|
+ 'external-user-group:keycloak:groupRealm': 'myrealm',
|
|
|
|
|
+ 'external-user-group:keycloak:groupSyncClientRealm': 'myrealm',
|
|
|
|
|
+ 'external-user-group:keycloak:groupDescriptionAttribute': 'description',
|
|
|
|
|
+ 'external-user-group:keycloak:groupSyncClientID': 'admin-cli',
|
|
|
|
|
+ 'external-user-group:keycloak:groupSyncClientSecret': '123456',
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ beforeAll(async() => {
|
|
|
|
|
+ await configManager.updateConfigsInTheSameNamespace('crowi', configParams, true);
|
|
|
|
|
+ keycloakUserGroupSyncService = new KeycloakUserGroupSyncService(null, null);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ it('creates ExternalUserGroupTrees', async() => {
|
|
|
|
|
+
|
|
|
|
|
+ const rootNodes = await keycloakUserGroupSyncService?.generateExternalUserGroupTrees();
|
|
|
|
|
+
|
|
|
|
|
+ expect(rootNodes?.length).toBe(2);
|
|
|
|
|
+
|
|
|
|
|
+ // check grandParentGroup
|
|
|
|
|
+ const grandParentNode = rootNodes?.find(node => node.id === 'groupId1');
|
|
|
|
|
+ const expectedChildNode = {
|
|
|
|
|
+ id: 'groupId3',
|
|
|
|
|
+ userInfos: [{
|
|
|
|
|
+ id: 'userId3',
|
|
|
|
|
+ username: 'childGroupUser',
|
|
|
|
|
+ email: 'user@childGroup.com',
|
|
|
|
|
+ }],
|
|
|
|
|
+ childGroupNodes: [],
|
|
|
|
|
+ name: 'childGroup',
|
|
|
|
|
+ description: 'this is a child group',
|
|
|
|
|
+ };
|
|
|
|
|
+ const expectedParentNode = {
|
|
|
|
|
+ id: 'groupId2',
|
|
|
|
|
+ userInfos: [{
|
|
|
|
|
+ id: 'userId2',
|
|
|
|
|
+ username: 'parentGroupUser',
|
|
|
|
|
+ email: 'user@parentGroup.com',
|
|
|
|
|
+ }],
|
|
|
|
|
+ childGroupNodes: [expectedChildNode],
|
|
|
|
|
+ name: 'parentGroup',
|
|
|
|
|
+ description: 'this is a parent group',
|
|
|
|
|
+ };
|
|
|
|
|
+ const expectedGrandParentNode = {
|
|
|
|
|
+ id: 'groupId1',
|
|
|
|
|
+ userInfos: [{
|
|
|
|
|
+ id: 'userId1',
|
|
|
|
|
+ username: 'grandParentGroupUser',
|
|
|
|
|
+ email: 'user@grandParentGroup.com',
|
|
|
|
|
+ }],
|
|
|
|
|
+ childGroupNodes: [expectedParentNode],
|
|
|
|
|
+ name: 'grandParentGroup',
|
|
|
|
|
+ description: 'this is a grand parent group',
|
|
|
|
|
+ };
|
|
|
|
|
+ expect(grandParentNode).toStrictEqual(expectedGrandParentNode);
|
|
|
|
|
+
|
|
|
|
|
+ // check rootGroup
|
|
|
|
|
+ const rootNode = rootNodes?.find(node => node.id === 'groupId4');
|
|
|
|
|
+ const expectedRootNode = {
|
|
|
|
|
+ id: 'groupId4',
|
|
|
|
|
+ userInfos: [{
|
|
|
|
|
+ id: 'userId4',
|
|
|
|
|
+ username: 'rootGroupUser',
|
|
|
|
|
+ email: 'user@rootGroup.com',
|
|
|
|
|
+ }],
|
|
|
|
|
+ childGroupNodes: [],
|
|
|
|
|
+ name: 'rootGroup',
|
|
|
|
|
+ description: 'this is a root group',
|
|
|
|
|
+ };
|
|
|
|
|
+ expect(rootNode).toStrictEqual(expectedRootNode);
|
|
|
|
|
+ });
|
|
|
|
|
+});
|