From 27398f88f503a6a494ca5f58ae74905060aee70a Mon Sep 17 00:00:00 2001 From: Arne Gnisa Date: Wed, 4 Oct 2023 14:29:55 +0200 Subject: [PATCH 01/13] N21-1219 adds isExternalUser field to ICurrentUser --- .../authentication/interface/jwt-payload.ts | 1 + .../modules/authentication/interface/user.ts | 2 + .../mapper/current-user.mapper.spec.ts | 62 ++++++++++++++++++- .../mapper/current-user.mapper.ts | 10 ++- .../strategy/oauth2.strategy.spec.ts | 1 + .../strategy/oauth2.strategy.ts | 9 ++- .../src/modules/oauth/uc/oauth.uc.spec.ts | 2 +- apps/server/src/modules/oauth/uc/oauth.uc.ts | 7 +++ 8 files changed, 88 insertions(+), 6 deletions(-) diff --git a/apps/server/src/modules/authentication/interface/jwt-payload.ts b/apps/server/src/modules/authentication/interface/jwt-payload.ts index ed69630ccde..9b6d8ce65d0 100644 --- a/apps/server/src/modules/authentication/interface/jwt-payload.ts +++ b/apps/server/src/modules/authentication/interface/jwt-payload.ts @@ -5,6 +5,7 @@ export interface CreateJwtPayload { roles: string[]; systemId?: string; // without this the user needs to change his PW during first login support?: boolean; + isExternalUser?: boolean; } export interface JwtPayload extends CreateJwtPayload { diff --git a/apps/server/src/modules/authentication/interface/user.ts b/apps/server/src/modules/authentication/interface/user.ts index 1baa64d192b..164e8f4024e 100644 --- a/apps/server/src/modules/authentication/interface/user.ts +++ b/apps/server/src/modules/authentication/interface/user.ts @@ -39,4 +39,6 @@ export interface ICurrentUser { /** True if a support member impersonates the user */ impersonated?: boolean; + + isExternalUser: boolean; } diff --git a/apps/server/src/modules/authentication/mapper/current-user.mapper.spec.ts b/apps/server/src/modules/authentication/mapper/current-user.mapper.spec.ts index c89d1e3a037..df2510e26c2 100644 --- a/apps/server/src/modules/authentication/mapper/current-user.mapper.spec.ts +++ b/apps/server/src/modules/authentication/mapper/current-user.mapper.spec.ts @@ -61,6 +61,7 @@ describe('CurrentUserMapper', () => { describe('when userDO has no ID', () => { it('should throw error', () => { const user: UserDO = userDoFactory.build({ createdAt: new Date(), updatedAt: new Date() }); + expect(() => CurrentUserMapper.userDoToICurrentUser(accountId, user)).toThrow(ValidationError); }); }); @@ -68,7 +69,9 @@ describe('CurrentUserMapper', () => { describe('when userDO is valid', () => { it('should return valid ICurrentUser instance', () => { const user: UserDO = userDoFactory.buildWithId({ id: userId, createdAt: new Date(), updatedAt: new Date() }); + const currentUser = CurrentUserMapper.userDoToICurrentUser(accountId, user); + expect(currentUser).toMatchObject({ accountId, systemId: undefined, @@ -80,10 +83,21 @@ describe('CurrentUserMapper', () => { }); describe('when userDO is valid and a systemId is provided', () => { - it('should return valid ICurrentUser instance with systemId', () => { + const setup = () => { const user: UserDO = userDoFactory.buildWithId({ id: userId, createdAt: new Date(), updatedAt: new Date() }); const systemId = 'mockSystemId'; + + return { + user, + systemId, + }; + }; + + it('should return valid ICurrentUser instance with systemId', () => { + const { user, systemId } = setup(); + const currentUser = CurrentUserMapper.userDoToICurrentUser(accountId, user, systemId); + expect(currentUser).toMatchObject({ accountId, systemId, @@ -132,7 +146,7 @@ describe('CurrentUserMapper', () => { describe('jwtToICurrentUser', () => { describe('when JWT is provided with all claims', () => { - it('should return current user', () => { + const setup = () => { const jwtPayload: JwtPayload = { accountId: 'dummyAccountId', systemId: 'dummySystemId', @@ -140,6 +154,7 @@ describe('CurrentUserMapper', () => { schoolId: 'dummySchoolId', userId: 'dummyUserId', support: true, + isExternalUser: true, sub: 'dummyAccountId', jti: 'random string', aud: 'some audience', @@ -147,7 +162,17 @@ describe('CurrentUserMapper', () => { iat: Math.floor(new Date().getTime() / 1000), exp: Math.floor(new Date().getTime() / 1000) + 3600, }; + + return { + jwtPayload, + }; + }; + + it('should return current user', () => { + const { jwtPayload } = setup(); + const currentUser = CurrentUserMapper.jwtToICurrentUser(jwtPayload); + expect(currentUser).toMatchObject({ accountId: jwtPayload.accountId, systemId: jwtPayload.systemId, @@ -157,9 +182,20 @@ describe('CurrentUserMapper', () => { impersonated: jwtPayload.support, }); }); + + it('should return current user with default for isExternalUser', () => { + const { jwtPayload } = setup(); + + const currentUser = CurrentUserMapper.jwtToICurrentUser(jwtPayload); + + expect(currentUser).toMatchObject({ + isExternalUser: false, + }); + }); }); + describe('when JWT is provided without optional claims', () => { - it('should return current user', () => { + const setup = () => { const jwtPayload: JwtPayload = { accountId: 'dummyAccountId', roles: ['mockRoleId'], @@ -172,7 +208,17 @@ describe('CurrentUserMapper', () => { iat: Math.floor(new Date().getTime() / 1000), exp: Math.floor(new Date().getTime() / 1000) + 3600, }; + + return { + jwtPayload, + }; + }; + + it('should return current user', () => { + const { jwtPayload } = setup(); + const currentUser = CurrentUserMapper.jwtToICurrentUser(jwtPayload); + expect(currentUser).toMatchObject({ accountId: jwtPayload.accountId, roles: [jwtPayload.roles[0]], @@ -180,6 +226,16 @@ describe('CurrentUserMapper', () => { userId: jwtPayload.userId, }); }); + + it('should return current user with default for isExternalUser', () => { + const { jwtPayload } = setup(); + + const currentUser = CurrentUserMapper.jwtToICurrentUser(jwtPayload); + + expect(currentUser).toMatchObject({ + isExternalUser: false, + }); + }); }); }); }); diff --git a/apps/server/src/modules/authentication/mapper/current-user.mapper.ts b/apps/server/src/modules/authentication/mapper/current-user.mapper.ts index d4eb31fbede..f52a989c8f3 100644 --- a/apps/server/src/modules/authentication/mapper/current-user.mapper.ts +++ b/apps/server/src/modules/authentication/mapper/current-user.mapper.ts @@ -13,10 +13,16 @@ export class CurrentUserMapper { roles: user.roles.getItems().map((role: Role) => role.id), schoolId: user.school.id, userId: user.id, + isExternalUser: false, }; } - static userDoToICurrentUser(accountId: string, user: UserDO, systemId?: string): ICurrentUser { + static userDoToICurrentUser( + accountId: string, + user: UserDO, + systemId?: string, + isExternalUser = false + ): ICurrentUser { if (!user.id) { throw new ValidationError('user has no ID'); } @@ -27,6 +33,7 @@ export class CurrentUserMapper { roles: user.roles.map((roleRef: RoleReference) => roleRef.id), schoolId: user.schoolId, userId: user.id, + isExternalUser, }; } @@ -38,6 +45,7 @@ export class CurrentUserMapper { schoolId: jwtPayload.schoolId, userId: jwtPayload.userId, impersonated: jwtPayload.support, + isExternalUser: false, }; } } diff --git a/apps/server/src/modules/authentication/strategy/oauth2.strategy.spec.ts b/apps/server/src/modules/authentication/strategy/oauth2.strategy.spec.ts index 01feb93b044..8f6b4dc9710 100644 --- a/apps/server/src/modules/authentication/strategy/oauth2.strategy.spec.ts +++ b/apps/server/src/modules/authentication/strategy/oauth2.strategy.spec.ts @@ -86,6 +86,7 @@ describe('Oauth2Strategy', () => { roles: [user.roles[0].id], schoolId: user.schoolId, accountId: account.id, + isExternalUser: true, }); }); }); diff --git a/apps/server/src/modules/authentication/strategy/oauth2.strategy.ts b/apps/server/src/modules/authentication/strategy/oauth2.strategy.ts index 2d774594a3d..352e47bd1a2 100644 --- a/apps/server/src/modules/authentication/strategy/oauth2.strategy.ts +++ b/apps/server/src/modules/authentication/strategy/oauth2.strategy.ts @@ -37,7 +37,14 @@ export class Oauth2Strategy extends PassportStrategy(Strategy, 'oauth2') { throw new UnauthorizedException('no account found'); } - const currentUser: ICurrentUser = CurrentUserMapper.userDoToICurrentUser(account.id, user, systemId); + const isExternalUser = true; + + const currentUser: ICurrentUser = CurrentUserMapper.userDoToICurrentUser( + account.id, + user, + systemId, + isExternalUser + ); return currentUser; } diff --git a/apps/server/src/modules/oauth/uc/oauth.uc.spec.ts b/apps/server/src/modules/oauth/uc/oauth.uc.spec.ts index dba6cca003c..5d894e1f5f2 100644 --- a/apps/server/src/modules/oauth/uc/oauth.uc.spec.ts +++ b/apps/server/src/modules/oauth/uc/oauth.uc.spec.ts @@ -254,7 +254,7 @@ describe('OAuthUc', () => { externalId: 'mockExternalId', }); - const currentUser: ICurrentUser = { userId: 'userId' } as ICurrentUser; + const currentUser: ICurrentUser = { userId: 'userId', isExternalUser: true } as ICurrentUser; const testSystem: SystemDto = new SystemDto({ id: 'mockSystemId', type: 'mock', diff --git a/apps/server/src/modules/oauth/uc/oauth.uc.ts b/apps/server/src/modules/oauth/uc/oauth.uc.ts index e4dd7e68264..9d2fd9bb1de 100644 --- a/apps/server/src/modules/oauth/uc/oauth.uc.ts +++ b/apps/server/src/modules/oauth/uc/oauth.uc.ts @@ -63,6 +63,9 @@ export class OauthUc { return authenticationUrl; } + /** + * @deprecated Please use the oauth2 strategy instead. + */ async processOAuthLogin(cachedState: OauthLoginStateDto, code?: string, error?: string): Promise { const { state, systemId, postLoginRedirect, userLoginMigration } = cachedState; @@ -139,8 +142,12 @@ export class OauthUc { return migrationDto; } + /** + * @deprecated Please use the {@link ICurrentUser} from the specific stragegy instead. + */ private async getJwtForUser(userId: EntityId): Promise { const currentUser: ICurrentUser = await this.userService.getResolvedUser(userId); + currentUser.isExternalUser = true; const { accessToken } = await this.authenticationService.generateJwt(currentUser); From d71c4142effae64e925ea7372f062bafa355a773 Mon Sep 17 00:00:00 2001 From: Arne Gnisa Date: Wed, 4 Oct 2023 15:24:48 +0200 Subject: [PATCH 02/13] N21-1219 add doc --- apps/server/src/modules/authentication/interface/user.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/server/src/modules/authentication/interface/user.ts b/apps/server/src/modules/authentication/interface/user.ts index 164e8f4024e..5331d225505 100644 --- a/apps/server/src/modules/authentication/interface/user.ts +++ b/apps/server/src/modules/authentication/interface/user.ts @@ -40,5 +40,6 @@ export interface ICurrentUser { /** True if a support member impersonates the user */ impersonated?: boolean; + /** True if the user is an external user which could be e.g. a ldap or oauth user */ isExternalUser: boolean; } From bfcc5afd3369c9d891a4c98b0de0c5abaf42ef65 Mon Sep 17 00:00:00 2001 From: Arne Gnisa Date: Thu, 5 Oct 2023 09:24:56 +0200 Subject: [PATCH 03/13] N21-1219 changes test --- apps/server/src/modules/authentication/interface/user.ts | 2 +- apps/server/src/shared/testing/map-user-to-current-user.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/server/src/modules/authentication/interface/user.ts b/apps/server/src/modules/authentication/interface/user.ts index 5331d225505..4b758b7dd84 100644 --- a/apps/server/src/modules/authentication/interface/user.ts +++ b/apps/server/src/modules/authentication/interface/user.ts @@ -40,6 +40,6 @@ export interface ICurrentUser { /** True if a support member impersonates the user */ impersonated?: boolean; - /** True if the user is an external user which could be e.g. a ldap or oauth user */ + /** True if the user is an external user e.g. an oauth user */ isExternalUser: boolean; } diff --git a/apps/server/src/shared/testing/map-user-to-current-user.ts b/apps/server/src/shared/testing/map-user-to-current-user.ts index 1d77d8d2bb3..221db6e322b 100644 --- a/apps/server/src/shared/testing/map-user-to-current-user.ts +++ b/apps/server/src/shared/testing/map-user-to-current-user.ts @@ -15,6 +15,7 @@ export const mapUserToCurrentUser = ( accountId: account ? account.id : new ObjectId().toHexString(), systemId, impersonated, + isExternalUser: false, }; return currentUser; From 70147de90f6c0a5fa97e36cfc4a5dbf8b488f08a Mon Sep 17 00:00:00 2001 From: Arne Gnisa Date: Thu, 5 Oct 2023 10:02:00 +0200 Subject: [PATCH 04/13] N21-1219 review changes --- .../src/modules/authentication/interface/jwt-payload.ts | 2 +- .../modules/authentication/mapper/current-user.mapper.spec.ts | 4 +++- .../src/modules/authentication/mapper/current-user.mapper.ts | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/server/src/modules/authentication/interface/jwt-payload.ts b/apps/server/src/modules/authentication/interface/jwt-payload.ts index 9b6d8ce65d0..4892a217e57 100644 --- a/apps/server/src/modules/authentication/interface/jwt-payload.ts +++ b/apps/server/src/modules/authentication/interface/jwt-payload.ts @@ -5,7 +5,7 @@ export interface CreateJwtPayload { roles: string[]; systemId?: string; // without this the user needs to change his PW during first login support?: boolean; - isExternalUser?: boolean; + isExternalUser: boolean; } export interface JwtPayload extends CreateJwtPayload { diff --git a/apps/server/src/modules/authentication/mapper/current-user.mapper.spec.ts b/apps/server/src/modules/authentication/mapper/current-user.mapper.spec.ts index df2510e26c2..72964c71301 100644 --- a/apps/server/src/modules/authentication/mapper/current-user.mapper.spec.ts +++ b/apps/server/src/modules/authentication/mapper/current-user.mapper.spec.ts @@ -189,7 +189,7 @@ describe('CurrentUserMapper', () => { const currentUser = CurrentUserMapper.jwtToICurrentUser(jwtPayload); expect(currentUser).toMatchObject({ - isExternalUser: false, + isExternalUser: jwtPayload.isExternalUser, }); }); }); @@ -201,6 +201,7 @@ describe('CurrentUserMapper', () => { roles: ['mockRoleId'], schoolId: 'dummySchoolId', userId: 'dummyUserId', + isExternalUser: false, sub: 'dummyAccountId', jti: 'random string', aud: 'some audience', @@ -224,6 +225,7 @@ describe('CurrentUserMapper', () => { roles: [jwtPayload.roles[0]], schoolId: jwtPayload.schoolId, userId: jwtPayload.userId, + isExternalUser: false, }); }); diff --git a/apps/server/src/modules/authentication/mapper/current-user.mapper.ts b/apps/server/src/modules/authentication/mapper/current-user.mapper.ts index f52a989c8f3..ee2ac987f69 100644 --- a/apps/server/src/modules/authentication/mapper/current-user.mapper.ts +++ b/apps/server/src/modules/authentication/mapper/current-user.mapper.ts @@ -45,7 +45,7 @@ export class CurrentUserMapper { schoolId: jwtPayload.schoolId, userId: jwtPayload.userId, impersonated: jwtPayload.support, - isExternalUser: false, + isExternalUser: jwtPayload.isExternalUser, }; } } From 0ca003ac36f4932428254868b1a130e9d4cd1ccb Mon Sep 17 00:00:00 2001 From: Arne Gnisa Date: Thu, 5 Oct 2023 10:06:26 +0200 Subject: [PATCH 05/13] N21-1219 fix test --- apps/server/src/modules/user/service/user.service.spec.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/server/src/modules/user/service/user.service.spec.ts b/apps/server/src/modules/user/service/user.service.spec.ts index ea29891cee7..98a70092ede 100644 --- a/apps/server/src/modules/user/service/user.service.spec.ts +++ b/apps/server/src/modules/user/service/user.service.spec.ts @@ -163,6 +163,7 @@ describe('UserService', () => { schoolId: user.school.id, accountId: account.id, roles: [role.id], + isExternalUser: false, }); }); }); From e840a288d2e77f0fd03443f6ef94320b750dfd37 Mon Sep 17 00:00:00 2001 From: Arne Gnisa Date: Thu, 5 Oct 2023 10:26:18 +0200 Subject: [PATCH 06/13] N21-1219 fix test 2 --- .../services/authentication.service.spec.ts | 1 + .../server/src/modules/authentication/uc/login.uc.spec.ts | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/server/src/modules/authentication/services/authentication.service.spec.ts b/apps/server/src/modules/authentication/services/authentication.service.spec.ts index 461fe0e7246..d2cb12de653 100644 --- a/apps/server/src/modules/authentication/services/authentication.service.spec.ts +++ b/apps/server/src/modules/authentication/services/authentication.service.spec.ts @@ -99,6 +99,7 @@ describe('AuthenticationService', () => { roles: ['student'], schoolId: 'mockSchoolId', userId: 'mockUserId', + isExternalUser: false, }; await authenticationService.generateJwt(mockCurrentUser); expect(jwtService.sign).toBeCalledWith( diff --git a/apps/server/src/modules/authentication/uc/login.uc.spec.ts b/apps/server/src/modules/authentication/uc/login.uc.spec.ts index 2a6b3ab12b9..9f40a92ca35 100644 --- a/apps/server/src/modules/authentication/uc/login.uc.spec.ts +++ b/apps/server/src/modules/authentication/uc/login.uc.spec.ts @@ -29,7 +29,13 @@ describe('LoginUc', () => { describe('getLoginData', () => { describe('when userInfo is given', () => { const setup = () => { - const userInfo: CreateJwtPayload = { accountId: '', roles: [], schoolId: '', userId: '' }; + const userInfo: CreateJwtPayload = { + accountId: '', + roles: [], + schoolId: '', + userId: '', + isExternalUser: false, + }; const loginDto: LoginDto = new LoginDto({ accessToken: 'accessToken' }); authenticationService.generateJwt.mockResolvedValue(loginDto); From cdafe64a495459947e59c9586356f8e4b3fed66e Mon Sep 17 00:00:00 2001 From: Arne Gnisa Date: Thu, 5 Oct 2023 11:14:49 +0200 Subject: [PATCH 07/13] N21-1219 fix test 3 --- .../src/modules/authentication/strategy/ldap.strategy.spec.ts | 2 ++ .../video-conference/uc/video-conference-deprecated.uc.spec.ts | 1 + 2 files changed, 3 insertions(+) diff --git a/apps/server/src/modules/authentication/strategy/ldap.strategy.spec.ts b/apps/server/src/modules/authentication/strategy/ldap.strategy.spec.ts index db4a1a60878..2c11d41db65 100644 --- a/apps/server/src/modules/authentication/strategy/ldap.strategy.spec.ts +++ b/apps/server/src/modules/authentication/strategy/ldap.strategy.spec.ts @@ -436,6 +436,7 @@ describe('LdapStrategy', () => { schoolId: school.id, systemId: system.id, accountId: account.id, + isExternalUser: false, }); }); }); @@ -500,6 +501,7 @@ describe('LdapStrategy', () => { schoolId: school.id, systemId: system.id, accountId: account.id, + isExternalUser: false, }); }); }); diff --git a/apps/server/src/modules/video-conference/uc/video-conference-deprecated.uc.spec.ts b/apps/server/src/modules/video-conference/uc/video-conference-deprecated.uc.spec.ts index 3680c4519da..10f77aac378 100644 --- a/apps/server/src/modules/video-conference/uc/video-conference-deprecated.uc.spec.ts +++ b/apps/server/src/modules/video-conference/uc/video-conference-deprecated.uc.spec.ts @@ -170,6 +170,7 @@ describe('VideoConferenceUc', () => { roles: [], schoolId: 'schoolId', accountId: 'accountId', + isExternalUser: false, }; defaultOptions = { everybodyJoinsAsModerator: false, From 1f4fc89c36b5779e0958c47012b52c42c75f53e9 Mon Sep 17 00:00:00 2001 From: Arne Gnisa Date: Wed, 1 Nov 2023 11:31:07 +0100 Subject: [PATCH 08/13] N21-1219 changes after merge --- .../authentication/interface/jwt-payload.ts | 1 - .../modules/authentication/interface/user.ts | 6 ++-- .../mapper/current-user.mapper.spec.ts | 16 ++++----- .../mapper/current-user.mapper.ts | 7 ++-- .../services/authentication.service.spec.ts | 1 - .../strategy/oauth2.strategy.ts | 3 +- .../src/modules/oauth/uc/oauth.uc.spec.ts | 22 ++++++------ apps/server/src/modules/oauth/uc/oauth.uc.ts | 10 ++---- .../modules/user/service/user.service.spec.ts | 36 +++++++++++-------- .../src/modules/user/service/user.service.ts | 9 ++--- .../testing/map-user-to-current-user.ts | 1 - 11 files changed, 54 insertions(+), 58 deletions(-) diff --git a/apps/server/src/modules/authentication/interface/jwt-payload.ts b/apps/server/src/modules/authentication/interface/jwt-payload.ts index ca46acbe761..aad11700e60 100644 --- a/apps/server/src/modules/authentication/interface/jwt-payload.ts +++ b/apps/server/src/modules/authentication/interface/jwt-payload.ts @@ -6,7 +6,6 @@ export interface CreateJwtPayload { systemId?: string; // without this the user needs to change his PW during first login support?: boolean; // support UserId is missed see featherJS - isExternalUser: boolean; } export interface JwtPayload extends CreateJwtPayload { diff --git a/apps/server/src/modules/authentication/interface/user.ts b/apps/server/src/modules/authentication/interface/user.ts index cc8423f69b7..1283a550dd8 100644 --- a/apps/server/src/modules/authentication/interface/user.ts +++ b/apps/server/src/modules/authentication/interface/user.ts @@ -15,12 +15,12 @@ export interface ICurrentUser { /** True if a support member impersonates the user */ impersonated?: boolean; - - /** True if the user is an external user e.g. an oauth user */ - isExternalUser: boolean; } export interface OauthCurrentUser extends ICurrentUser { /** Contains the idToken of the external idp. Will be set during oAuth2 login and used for rp initiated logout */ externalIdToken?: string; + + /** True if the user is an external user e.g. an oauth user */ + isExternalUser: true; } diff --git a/apps/server/src/modules/authentication/mapper/current-user.mapper.spec.ts b/apps/server/src/modules/authentication/mapper/current-user.mapper.spec.ts index dfc51da6231..cf76a0da1d4 100644 --- a/apps/server/src/modules/authentication/mapper/current-user.mapper.spec.ts +++ b/apps/server/src/modules/authentication/mapper/current-user.mapper.spec.ts @@ -62,7 +62,7 @@ describe('CurrentUserMapper', () => { it('should throw error', () => { const user: UserDO = userDoFactory.build({ createdAt: new Date(), updatedAt: new Date() }); - expect(() => CurrentUserMapper.mapToOauthCurrentUser(accountId, user, undefined, 'idToken')).toThrow( + expect(() => CurrentUserMapper.mapToOauthCurrentUser(accountId, user, undefined, 'idToken')).toThrow( ValidationError ); }); @@ -101,6 +101,7 @@ describe('CurrentUserMapper', () => { schoolId: user.schoolId, userId, externalIdToken: idToken, + isExternalUser: true, }); }); }); @@ -140,6 +141,7 @@ describe('CurrentUserMapper', () => { schoolId: user.schoolId, userId, externalIdToken: idToken, + isExternalUser: true, }); }); }); @@ -190,7 +192,6 @@ describe('CurrentUserMapper', () => { schoolId: 'dummySchoolId', userId: 'dummyUserId', support: true, - isExternalUser: true, sub: 'dummyAccountId', jti: 'random string', aud: 'some audience', @@ -219,7 +220,7 @@ describe('CurrentUserMapper', () => { }); }); - it('should return current user with default for isExternalUser', () => { + /* it('should return current user with default for isExternalUser', () => { const { jwtPayload } = setup(); const currentUser = CurrentUserMapper.jwtToICurrentUser(jwtPayload); @@ -227,7 +228,7 @@ describe('CurrentUserMapper', () => { expect(currentUser).toMatchObject({ isExternalUser: jwtPayload.isExternalUser, }); - }); + }); */ }); describe('when JWT is provided without optional claims', () => { @@ -237,7 +238,7 @@ describe('CurrentUserMapper', () => { roles: ['mockRoleId'], schoolId: 'dummySchoolId', userId: 'dummyUserId', - isExternalUser: false, + // isExternalUser: false, sub: 'dummyAccountId', jti: 'random string', aud: 'some audience', @@ -261,11 +262,10 @@ describe('CurrentUserMapper', () => { roles: [jwtPayload.roles[0]], schoolId: jwtPayload.schoolId, userId: jwtPayload.userId, - isExternalUser: false, }); }); - it('should return current user with default for isExternalUser', () => { + /* it('should return current user with default for isExternalUser', () => { const { jwtPayload } = setup(); const currentUser = CurrentUserMapper.jwtToICurrentUser(jwtPayload); @@ -273,7 +273,7 @@ describe('CurrentUserMapper', () => { expect(currentUser).toMatchObject({ isExternalUser: false, }); - }); + }); */ }); }); diff --git a/apps/server/src/modules/authentication/mapper/current-user.mapper.ts b/apps/server/src/modules/authentication/mapper/current-user.mapper.ts index 51b4961c38c..bbb2633d606 100644 --- a/apps/server/src/modules/authentication/mapper/current-user.mapper.ts +++ b/apps/server/src/modules/authentication/mapper/current-user.mapper.ts @@ -13,7 +13,6 @@ export class CurrentUserMapper { roles: user.roles.getItems().map((role: Role) => role.id), schoolId: user.school.id, userId: user.id, - isExternalUser: false, }; } @@ -21,8 +20,7 @@ export class CurrentUserMapper { accountId: string, user: UserDO, systemId?: string, - externalIdToken?: string, - isExternalUser = false + externalIdToken?: string ): OauthCurrentUser { if (!user.id) { throw new ValidationError('user has no ID'); @@ -35,7 +33,7 @@ export class CurrentUserMapper { schoolId: user.schoolId, userId: user.id, externalIdToken, - isExternalUser, + isExternalUser: true, }; } @@ -58,7 +56,6 @@ export class CurrentUserMapper { schoolId: jwtPayload.schoolId, userId: jwtPayload.userId, impersonated: jwtPayload.support, - isExternalUser: jwtPayload.isExternalUser, }; } } diff --git a/apps/server/src/modules/authentication/services/authentication.service.spec.ts b/apps/server/src/modules/authentication/services/authentication.service.spec.ts index 1e5c69ecfb1..3d5b6d3a1b7 100644 --- a/apps/server/src/modules/authentication/services/authentication.service.spec.ts +++ b/apps/server/src/modules/authentication/services/authentication.service.spec.ts @@ -99,7 +99,6 @@ describe('AuthenticationService', () => { roles: ['student'], schoolId: 'mockSchoolId', userId: 'mockUserId', - isExternalUser: false, }; await authenticationService.generateJwt(mockCurrentUser); expect(jwtService.sign).toBeCalledWith( diff --git a/apps/server/src/modules/authentication/strategy/oauth2.strategy.ts b/apps/server/src/modules/authentication/strategy/oauth2.strategy.ts index 598f8633396..599744cc1a7 100644 --- a/apps/server/src/modules/authentication/strategy/oauth2.strategy.ts +++ b/apps/server/src/modules/authentication/strategy/oauth2.strategy.ts @@ -41,8 +41,7 @@ export class Oauth2Strategy extends PassportStrategy(Strategy, 'oauth2') { account.id, user, systemId, - tokenDto.idToken, - true, + tokenDto.idToken ); return currentUser; diff --git a/apps/server/src/modules/oauth/uc/oauth.uc.spec.ts b/apps/server/src/modules/oauth/uc/oauth.uc.spec.ts index c1f32062046..1e888abd5f1 100644 --- a/apps/server/src/modules/oauth/uc/oauth.uc.spec.ts +++ b/apps/server/src/modules/oauth/uc/oauth.uc.spec.ts @@ -1,17 +1,9 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; -import { UnauthorizedException, UnprocessableEntityException } from '@nestjs/common'; -import { Test, TestingModule } from '@nestjs/testing'; -import { LegacySchoolDo, UserDO } from '@shared/domain'; -import { SystemProvisioningStrategy } from '@shared/domain/interface/system-provisioning.strategy'; -import { ISession } from '@shared/domain/types/session'; -import { legacySchoolDoFactory, setupEntities } from '@shared/testing'; -import { LegacyLogger } from '@src/core/logger'; -import { ICurrentUser } from '@modules/authentication'; import { AuthenticationService } from '@modules/authentication/services/authentication.service'; +import { LegacySchoolService } from '@modules/legacy-school'; import { OauthUc } from '@modules/oauth/uc/oauth.uc'; import { ProvisioningService } from '@modules/provisioning'; import { ExternalUserDto, OauthDataDto, ProvisioningSystemDto } from '@modules/provisioning/dto'; -import { LegacySchoolService } from '@modules/legacy-school'; import { SystemService } from '@modules/system'; import { OauthConfigDto, SystemDto } from '@modules/system/service'; import { UserService } from '@modules/user'; @@ -19,9 +11,17 @@ import { UserMigrationService } from '@modules/user-login-migration'; import { OAuthMigrationError } from '@modules/user-login-migration/error/oauth-migration.error'; import { SchoolMigrationService } from '@modules/user-login-migration/service'; import { MigrationDto } from '@modules/user-login-migration/service/dto'; -import { OAuthSSOError } from '../loggable/oauth-sso.error'; +import { UnauthorizedException, UnprocessableEntityException } from '@nestjs/common'; +import { Test, TestingModule } from '@nestjs/testing'; +import { LegacySchoolDo, UserDO } from '@shared/domain'; +import { SystemProvisioningStrategy } from '@shared/domain/interface/system-provisioning.strategy'; +import { ISession } from '@shared/domain/types/session'; +import { legacySchoolDoFactory, setupEntities } from '@shared/testing'; +import { LegacyLogger } from '@src/core/logger'; +import { OauthCurrentUser } from '@modules/authentication/interface'; import { AuthorizationParams } from '../controller/dto'; import { OAuthTokenDto } from '../interface'; +import { OAuthSSOError } from '../loggable/oauth-sso.error'; import { OAuthProcessDto } from '../service/dto'; import { OAuthService } from '../service/oauth.service'; import { OauthLoginStateDto } from './dto/oauth-login-state.dto'; @@ -254,7 +254,7 @@ describe('OAuthUc', () => { externalId: 'mockExternalId', }); - const currentUser: ICurrentUser = { userId: 'userId', isExternalUser: true } as ICurrentUser; + const currentUser: OauthCurrentUser = { userId: 'userId', isExternalUser: true } as OauthCurrentUser; const testSystem: SystemDto = new SystemDto({ id: 'mockSystemId', type: 'mock', diff --git a/apps/server/src/modules/oauth/uc/oauth.uc.ts b/apps/server/src/modules/oauth/uc/oauth.uc.ts index cef5ad04307..f3540879953 100644 --- a/apps/server/src/modules/oauth/uc/oauth.uc.ts +++ b/apps/server/src/modules/oauth/uc/oauth.uc.ts @@ -2,7 +2,6 @@ import { Injectable, UnauthorizedException, UnprocessableEntityException } from import { EntityId, LegacySchoolDo, UserDO } from '@shared/domain'; import { ISession } from '@shared/domain/types/session'; import { LegacyLogger } from '@src/core/logger'; -import { ICurrentUser } from '@modules/authentication'; import { AuthenticationService } from '@modules/authentication/services/authentication.service'; import { ProvisioningService } from '@modules/provisioning'; import { OauthDataDto } from '@modules/provisioning/dto'; @@ -13,6 +12,7 @@ import { UserMigrationService } from '@modules/user-login-migration'; import { SchoolMigrationService } from '@modules/user-login-migration/service'; import { MigrationDto } from '@modules/user-login-migration/service/dto'; import { nanoid } from 'nanoid'; +import { OauthCurrentUser } from '../../authentication/interface'; import { AuthorizationParams } from '../controller/dto'; import { OAuthTokenDto } from '../interface'; import { OAuthProcessDto } from '../service/dto'; @@ -142,14 +142,10 @@ export class OauthUc { return migrationDto; } - /** - * @deprecated Please use the {@link ICurrentUser} from the specific stragegy instead. - */ private async getJwtForUser(userId: EntityId): Promise { - const currentUser: ICurrentUser = await this.userService.getResolvedUser(userId); - currentUser.isExternalUser = true; + const oauthCurrentUser: OauthCurrentUser = await this.userService.getResolvedUser(userId); - const { accessToken } = await this.authenticationService.generateJwt(currentUser); + const { accessToken } = await this.authenticationService.generateJwt(oauthCurrentUser); return accessToken; } diff --git a/apps/server/src/modules/user/service/user.service.spec.ts b/apps/server/src/modules/user/service/user.service.spec.ts index 23384bc494c..223fa1f0c88 100644 --- a/apps/server/src/modules/user/service/user.service.spec.ts +++ b/apps/server/src/modules/user/service/user.service.spec.ts @@ -9,10 +9,10 @@ import { UserDORepo } from '@shared/repo/user/user-do.repo'; import { roleFactory, setupEntities, userDoFactory, userFactory } from '@shared/testing'; import { AccountService } from '@modules/account/services/account.service'; import { AccountDto } from '@modules/account/services/dto'; -import { ICurrentUser } from '@modules/authentication'; import { RoleService } from '@modules/role/service/role.service'; import { UserService } from '@modules/user/service/user.service'; import { UserDto } from '@modules/user/uc/dto/user.dto'; +import { OauthCurrentUser } from '@modules/authentication/interface'; import { UserQuery } from './user-query.type'; describe('UserService', () => { @@ -136,13 +136,13 @@ describe('UserService', () => { describe('getResolvedUser is called', () => { describe('when a resolved user is requested', () => { - it('should return an ICurrentUser', async () => { + const setup = () => { const systemId = 'systemId'; const role: Role = roleFactory.buildWithId({ name: RoleName.STUDENT, permissions: [Permission.DASHBOARD_VIEW], }); - const user: User = userFactory.buildWithId({ roles: [role] }); + const user: UserDO = userDoFactory.buildWithId({ roles: [role] }); const account: AccountDto = new AccountDto({ id: 'accountId', systemId, @@ -152,18 +152,30 @@ describe('UserService', () => { activated: true, }); - userRepo.findById.mockResolvedValue(user); + userDORepo.findById.mockResolvedValue(user); accountService.findByUserIdOrFail.mockResolvedValue(account); - const result: ICurrentUser = await service.getResolvedUser(user.id); + return { + userId: user.id as string, + user, + account, + role, + systemId, + }; + }; + + it('should return the current user', async () => { + const { userId, user, account, role, systemId } = setup(); - expect(result).toEqual({ - userId: user.id, + const result: OauthCurrentUser = await service.getResolvedUser(userId); + + expect(result).toEqual({ + userId, systemId, - schoolId: user.school.id, + schoolId: user.schoolId, accountId: account.id, roles: [role.id], - isExternalUser: false, + isExternalUser: true, }); }); }); @@ -178,30 +190,24 @@ describe('UserService', () => { }); it('should return only the last name when the user has a protected role', async () => { - // Arrange const user: UserDO = userDoFactory.withRoles([{ id: role.id, name: RoleName.STUDENT }]).buildWithId({ lastName: 'lastName', }); - // Act const result: string = await service.getDisplayName(user); - // Assert expect(result).toEqual(user.lastName); expect(roleService.getProtectedRoles).toHaveBeenCalled(); }); it('should return the first name and last name when the user has no protected role', async () => { - // Arrange const user: UserDO = userDoFactory.withRoles([{ id: 'unprotectedId', name: RoleName.STUDENT }]).buildWithId({ lastName: 'lastName', firstName: 'firstName', }); - // Act const result: string = await service.getDisplayName(user); - // Assert expect(result).toEqual(`${user.firstName} ${user.lastName}`); expect(roleService.getProtectedRoles).toHaveBeenCalled(); }); diff --git a/apps/server/src/modules/user/service/user.service.ts b/apps/server/src/modules/user/service/user.service.ts index cc15404fc63..e8b9f4e7fb9 100644 --- a/apps/server/src/modules/user/service/user.service.ts +++ b/apps/server/src/modules/user/service/user.service.ts @@ -11,6 +11,7 @@ import { CurrentUserMapper } from '@modules/authentication/mapper'; import { RoleDto } from '@modules/role/service/dto/role.dto'; import { RoleService } from '@modules/role/service/role.service'; import { BadRequestException, Injectable } from '@nestjs/common'; +import { OauthCurrentUser } from '../../authentication/interface'; import { IUserConfig } from '../interfaces'; import { UserMapper } from '../mapper/user.mapper'; import { UserDto } from '../uc/dto/user.dto'; @@ -34,7 +35,7 @@ export class UserService { } /** - * @deprecated + * @deprecated use {@link UserService.findById} instead */ async getUser(id: string): Promise { const userEntity = await this.userRepo.findById(id, true); @@ -43,11 +44,11 @@ export class UserService { return userDto; } - async getResolvedUser(userId: EntityId): Promise { - const user: User = await this.userRepo.findById(userId, true); + async getResolvedUser(userId: EntityId): Promise { + const user: UserDO = await this.findById(userId); const account: AccountDto = await this.accountService.findByUserIdOrFail(userId); - const resolvedUser: ICurrentUser = CurrentUserMapper.userToICurrentUser(account.id, user, account.systemId); + const resolvedUser: OauthCurrentUser = CurrentUserMapper.mapToOauthCurrentUser(account.id, user, account.systemId); return resolvedUser; } diff --git a/apps/server/src/shared/testing/map-user-to-current-user.ts b/apps/server/src/shared/testing/map-user-to-current-user.ts index b8c975f125d..d835c822066 100644 --- a/apps/server/src/shared/testing/map-user-to-current-user.ts +++ b/apps/server/src/shared/testing/map-user-to-current-user.ts @@ -15,7 +15,6 @@ export const mapUserToCurrentUser = ( accountId: account ? account.id : new ObjectId().toHexString(), systemId, impersonated, - isExternalUser: false, }; return currentUser; From c5af33e99aa5305738fa05aa600db37bf5fe17e2 Mon Sep 17 00:00:00 2001 From: Arne Gnisa Date: Wed, 1 Nov 2023 11:35:04 +0100 Subject: [PATCH 09/13] N21-1219 adds adjustments --- .../mapper/current-user.mapper.spec.ts | 21 ------------------- apps/server/src/modules/oauth/uc/oauth.uc.ts | 3 --- .../src/modules/user/service/user.service.ts | 13 ++++++------ .../uc/video-conference-deprecated.uc.spec.ts | 1 - 4 files changed, 6 insertions(+), 32 deletions(-) diff --git a/apps/server/src/modules/authentication/mapper/current-user.mapper.spec.ts b/apps/server/src/modules/authentication/mapper/current-user.mapper.spec.ts index cf76a0da1d4..c0f833ad48f 100644 --- a/apps/server/src/modules/authentication/mapper/current-user.mapper.spec.ts +++ b/apps/server/src/modules/authentication/mapper/current-user.mapper.spec.ts @@ -219,16 +219,6 @@ describe('CurrentUserMapper', () => { impersonated: jwtPayload.support, }); }); - - /* it('should return current user with default for isExternalUser', () => { - const { jwtPayload } = setup(); - - const currentUser = CurrentUserMapper.jwtToICurrentUser(jwtPayload); - - expect(currentUser).toMatchObject({ - isExternalUser: jwtPayload.isExternalUser, - }); - }); */ }); describe('when JWT is provided without optional claims', () => { @@ -238,7 +228,6 @@ describe('CurrentUserMapper', () => { roles: ['mockRoleId'], schoolId: 'dummySchoolId', userId: 'dummyUserId', - // isExternalUser: false, sub: 'dummyAccountId', jti: 'random string', aud: 'some audience', @@ -264,16 +253,6 @@ describe('CurrentUserMapper', () => { userId: jwtPayload.userId, }); }); - - /* it('should return current user with default for isExternalUser', () => { - const { jwtPayload } = setup(); - - const currentUser = CurrentUserMapper.jwtToICurrentUser(jwtPayload); - - expect(currentUser).toMatchObject({ - isExternalUser: false, - }); - }); */ }); }); diff --git a/apps/server/src/modules/oauth/uc/oauth.uc.ts b/apps/server/src/modules/oauth/uc/oauth.uc.ts index f3540879953..e7004142daa 100644 --- a/apps/server/src/modules/oauth/uc/oauth.uc.ts +++ b/apps/server/src/modules/oauth/uc/oauth.uc.ts @@ -63,9 +63,6 @@ export class OauthUc { return authenticationUrl; } - /** - * @deprecated Please use the oauth2 strategy instead. - */ async processOAuthLogin(cachedState: OauthLoginStateDto, code?: string, error?: string): Promise { const { state, systemId, postLoginRedirect, userLoginMigration } = cachedState; diff --git a/apps/server/src/modules/user/service/user.service.ts b/apps/server/src/modules/user/service/user.service.ts index e8b9f4e7fb9..2cc95991f96 100644 --- a/apps/server/src/modules/user/service/user.service.ts +++ b/apps/server/src/modules/user/service/user.service.ts @@ -1,17 +1,16 @@ -import { ConfigService } from '@nestjs/config'; -import { EntityId, IFindOptions, LanguageType, User } from '@shared/domain'; -import { RoleReference, Page, UserDO } from '@shared/domain/domainobject'; -import { UserRepo } from '@shared/repo'; -import { UserDORepo } from '@shared/repo/user/user-do.repo'; import { AccountService } from '@modules/account'; import { AccountDto } from '@modules/account/services/dto'; -import { ICurrentUser } from '@modules/authentication'; // invalid import import { CurrentUserMapper } from '@modules/authentication/mapper'; import { RoleDto } from '@modules/role/service/dto/role.dto'; import { RoleService } from '@modules/role/service/role.service'; import { BadRequestException, Injectable } from '@nestjs/common'; -import { OauthCurrentUser } from '../../authentication/interface'; +import { ConfigService } from '@nestjs/config'; +import { EntityId, IFindOptions, LanguageType, User } from '@shared/domain'; +import { Page, RoleReference, UserDO } from '@shared/domain/domainobject'; +import { UserRepo } from '@shared/repo'; +import { UserDORepo } from '@shared/repo/user/user-do.repo'; +import { OauthCurrentUser } from '@modules/authentication/interface'; import { IUserConfig } from '../interfaces'; import { UserMapper } from '../mapper/user.mapper'; import { UserDto } from '../uc/dto/user.dto'; diff --git a/apps/server/src/modules/video-conference/uc/video-conference-deprecated.uc.spec.ts b/apps/server/src/modules/video-conference/uc/video-conference-deprecated.uc.spec.ts index 994c8042a6d..4d15397548b 100644 --- a/apps/server/src/modules/video-conference/uc/video-conference-deprecated.uc.spec.ts +++ b/apps/server/src/modules/video-conference/uc/video-conference-deprecated.uc.spec.ts @@ -172,7 +172,6 @@ describe('VideoConferenceUc', () => { roles: [], schoolId: 'schoolId', accountId: 'accountId', - isExternalUser: false, }; defaultOptions = { everybodyJoinsAsModerator: false, From b1ed486e70ca27c96f6cf27c8bbed0180c1c214d Mon Sep 17 00:00:00 2001 From: Arne Gnisa Date: Wed, 1 Nov 2023 11:38:05 +0100 Subject: [PATCH 10/13] N21-1219 fixes import --- apps/server/src/modules/oauth/uc/oauth.uc.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/server/src/modules/oauth/uc/oauth.uc.ts b/apps/server/src/modules/oauth/uc/oauth.uc.ts index e7004142daa..c495e7be05d 100644 --- a/apps/server/src/modules/oauth/uc/oauth.uc.ts +++ b/apps/server/src/modules/oauth/uc/oauth.uc.ts @@ -12,7 +12,7 @@ import { UserMigrationService } from '@modules/user-login-migration'; import { SchoolMigrationService } from '@modules/user-login-migration/service'; import { MigrationDto } from '@modules/user-login-migration/service/dto'; import { nanoid } from 'nanoid'; -import { OauthCurrentUser } from '../../authentication/interface'; +import { OauthCurrentUser } from '@modules/authentication/interface'; import { AuthorizationParams } from '../controller/dto'; import { OAuthTokenDto } from '../interface'; import { OAuthProcessDto } from '../service/dto'; From 8b903fdaf7ef6d7c595f8bd07f9e76d5416ef1df Mon Sep 17 00:00:00 2001 From: Arne Gnisa Date: Wed, 1 Nov 2023 12:03:59 +0100 Subject: [PATCH 11/13] N21-1219 adds isExternalUser to current user --- .../authentication/interface/jwt-payload.ts | 1 + .../modules/authentication/interface/user.ts | 6 ++--- .../mapper/current-user.mapper.spec.ts | 25 +++++++++++++++++++ .../mapper/current-user.mapper.ts | 3 +++ .../services/authentication.service.spec.ts | 1 + .../testing/map-user-to-current-user.ts | 1 + 6 files changed, 34 insertions(+), 3 deletions(-) diff --git a/apps/server/src/modules/authentication/interface/jwt-payload.ts b/apps/server/src/modules/authentication/interface/jwt-payload.ts index aad11700e60..ca46acbe761 100644 --- a/apps/server/src/modules/authentication/interface/jwt-payload.ts +++ b/apps/server/src/modules/authentication/interface/jwt-payload.ts @@ -6,6 +6,7 @@ export interface CreateJwtPayload { systemId?: string; // without this the user needs to change his PW during first login support?: boolean; // support UserId is missed see featherJS + isExternalUser: boolean; } export interface JwtPayload extends CreateJwtPayload { diff --git a/apps/server/src/modules/authentication/interface/user.ts b/apps/server/src/modules/authentication/interface/user.ts index 1283a550dd8..cc8423f69b7 100644 --- a/apps/server/src/modules/authentication/interface/user.ts +++ b/apps/server/src/modules/authentication/interface/user.ts @@ -15,12 +15,12 @@ export interface ICurrentUser { /** True if a support member impersonates the user */ impersonated?: boolean; + + /** True if the user is an external user e.g. an oauth user */ + isExternalUser: boolean; } export interface OauthCurrentUser extends ICurrentUser { /** Contains the idToken of the external idp. Will be set during oAuth2 login and used for rp initiated logout */ externalIdToken?: string; - - /** True if the user is an external user e.g. an oauth user */ - isExternalUser: true; } diff --git a/apps/server/src/modules/authentication/mapper/current-user.mapper.spec.ts b/apps/server/src/modules/authentication/mapper/current-user.mapper.spec.ts index c0f833ad48f..d06bea6d080 100644 --- a/apps/server/src/modules/authentication/mapper/current-user.mapper.spec.ts +++ b/apps/server/src/modules/authentication/mapper/current-user.mapper.spec.ts @@ -192,6 +192,7 @@ describe('CurrentUserMapper', () => { schoolId: 'dummySchoolId', userId: 'dummyUserId', support: true, + isExternalUser: true, sub: 'dummyAccountId', jti: 'random string', aud: 'some audience', @@ -219,6 +220,16 @@ describe('CurrentUserMapper', () => { impersonated: jwtPayload.support, }); }); + + it('should return current user with default for isExternalUser', () => { + const { jwtPayload } = setup(); + + const currentUser = CurrentUserMapper.jwtToICurrentUser(jwtPayload); + + expect(currentUser).toMatchObject({ + isExternalUser: jwtPayload.isExternalUser, + }); + }); }); describe('when JWT is provided without optional claims', () => { @@ -228,6 +239,7 @@ describe('CurrentUserMapper', () => { roles: ['mockRoleId'], schoolId: 'dummySchoolId', userId: 'dummyUserId', + isExternalUser: false, sub: 'dummyAccountId', jti: 'random string', aud: 'some audience', @@ -251,6 +263,17 @@ describe('CurrentUserMapper', () => { roles: [jwtPayload.roles[0]], schoolId: jwtPayload.schoolId, userId: jwtPayload.userId, + isExternalUser: false, + }); + }); + + it('should return current user with default for isExternalUser', () => { + const { jwtPayload } = setup(); + + const currentUser = CurrentUserMapper.jwtToICurrentUser(jwtPayload); + + expect(currentUser).toMatchObject({ + isExternalUser: false, }); }); }); @@ -265,6 +288,7 @@ describe('CurrentUserMapper', () => { schoolId: 'dummySchoolId', userId: 'dummyUserId', impersonated: true, + isExternalUser: false, }; const createJwtPayload: CreateJwtPayload = CurrentUserMapper.mapCurrentUserToCreateJwtPayload(currentUser); @@ -276,6 +300,7 @@ describe('CurrentUserMapper', () => { schoolId: currentUser.schoolId, userId: currentUser.userId, support: currentUser.impersonated, + isExternalUser: false, }); }); }); diff --git a/apps/server/src/modules/authentication/mapper/current-user.mapper.ts b/apps/server/src/modules/authentication/mapper/current-user.mapper.ts index bbb2633d606..ab832b70d8c 100644 --- a/apps/server/src/modules/authentication/mapper/current-user.mapper.ts +++ b/apps/server/src/modules/authentication/mapper/current-user.mapper.ts @@ -13,6 +13,7 @@ export class CurrentUserMapper { roles: user.roles.getItems().map((role: Role) => role.id), schoolId: user.school.id, userId: user.id, + isExternalUser: false, }; } @@ -45,6 +46,7 @@ export class CurrentUserMapper { roles: currentUser.roles, systemId: currentUser.systemId, support: currentUser.impersonated, + isExternalUser: currentUser.isExternalUser, }; } @@ -56,6 +58,7 @@ export class CurrentUserMapper { schoolId: jwtPayload.schoolId, userId: jwtPayload.userId, impersonated: jwtPayload.support, + isExternalUser: jwtPayload.isExternalUser, }; } } diff --git a/apps/server/src/modules/authentication/services/authentication.service.spec.ts b/apps/server/src/modules/authentication/services/authentication.service.spec.ts index 3d5b6d3a1b7..1e5c69ecfb1 100644 --- a/apps/server/src/modules/authentication/services/authentication.service.spec.ts +++ b/apps/server/src/modules/authentication/services/authentication.service.spec.ts @@ -99,6 +99,7 @@ describe('AuthenticationService', () => { roles: ['student'], schoolId: 'mockSchoolId', userId: 'mockUserId', + isExternalUser: false, }; await authenticationService.generateJwt(mockCurrentUser); expect(jwtService.sign).toBeCalledWith( diff --git a/apps/server/src/shared/testing/map-user-to-current-user.ts b/apps/server/src/shared/testing/map-user-to-current-user.ts index d835c822066..b8c975f125d 100644 --- a/apps/server/src/shared/testing/map-user-to-current-user.ts +++ b/apps/server/src/shared/testing/map-user-to-current-user.ts @@ -15,6 +15,7 @@ export const mapUserToCurrentUser = ( accountId: account ? account.id : new ObjectId().toHexString(), systemId, impersonated, + isExternalUser: false, }; return currentUser; From 089ffe0b695f788ca54f5cb4a2cdebeb68600cfe Mon Sep 17 00:00:00 2001 From: Arne Gnisa Date: Wed, 1 Nov 2023 12:41:31 +0100 Subject: [PATCH 12/13] N21-1219 fixes test --- apps/server/src/modules/authentication/uc/login.uc.spec.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/server/src/modules/authentication/uc/login.uc.spec.ts b/apps/server/src/modules/authentication/uc/login.uc.spec.ts index 2e0ea8d1d7a..c0f1d924876 100644 --- a/apps/server/src/modules/authentication/uc/login.uc.spec.ts +++ b/apps/server/src/modules/authentication/uc/login.uc.spec.ts @@ -35,7 +35,7 @@ describe('LoginUc', () => { userId: '', systemId: '', impersonated: false, - isExternalUser: false, + isExternalUser: false, someProperty: 'shouldNotBeMapped', }; const loginDto: LoginDto = new LoginDto({ accessToken: 'accessToken' }); @@ -59,6 +59,7 @@ describe('LoginUc', () => { roles: userInfo.roles, systemId: userInfo.systemId, support: userInfo.impersonated, + isExternalUser: userInfo.isExternalUser, }); }); From 35a4dee4b5189724f21f6afaec890a4ceca55b0c Mon Sep 17 00:00:00 2001 From: Arne Gnisa Date: Wed, 1 Nov 2023 13:43:59 +0100 Subject: [PATCH 13/13] N21-1219 fixes test --- .../video-conference/uc/video-conference-deprecated.uc.spec.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/server/src/modules/video-conference/uc/video-conference-deprecated.uc.spec.ts b/apps/server/src/modules/video-conference/uc/video-conference-deprecated.uc.spec.ts index 4d15397548b..994c8042a6d 100644 --- a/apps/server/src/modules/video-conference/uc/video-conference-deprecated.uc.spec.ts +++ b/apps/server/src/modules/video-conference/uc/video-conference-deprecated.uc.spec.ts @@ -172,6 +172,7 @@ describe('VideoConferenceUc', () => { roles: [], schoolId: 'schoolId', accountId: 'accountId', + isExternalUser: false, }; defaultOptions = { everybodyJoinsAsModerator: false,