@tomei/sso 0.66.1-test.3 → 0.66.1-test.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/__tests__/unit/components/login-user/login.spec.ts +271 -2
- package/__tests__/unit/components/login-user/password-expiry.spec.ts +87 -0
- package/dist/__tests__/unit/components/login-user/login.spec.js +199 -2
- package/dist/__tests__/unit/components/login-user/login.spec.js.map +1 -1
- package/dist/__tests__/unit/components/login-user/password-expiry.spec.d.ts +1 -0
- package/dist/__tests__/unit/components/login-user/password-expiry.spec.js +86 -0
- package/dist/__tests__/unit/components/login-user/password-expiry.spec.js.map +1 -0
- package/dist/src/components/login-user/interfaces/user-info.interface.d.ts +1 -0
- package/dist/src/components/login-user/user.d.ts +1 -0
- package/dist/src/components/login-user/user.js +7 -1
- package/dist/src/components/login-user/user.js.map +1 -1
- package/dist/src/components/system/system.d.ts +1 -0
- package/dist/src/components/system/system.js +1 -0
- package/dist/src/components/system/system.js.map +1 -1
- package/dist/src/components/system-privilege/system-privilege.d.ts +1 -0
- package/dist/src/components/system-privilege/system-privilege.js +2 -0
- package/dist/src/components/system-privilege/system-privilege.js.map +1 -1
- package/dist/src/interfaces/system-privilege.interface.d.ts +1 -0
- package/dist/src/interfaces/system.interface.d.ts +1 -0
- package/dist/src/models/group.entity.d.ts +1 -0
- package/dist/src/models/group.entity.js +8 -1
- package/dist/src/models/group.entity.js.map +1 -1
- package/dist/src/models/system-privilege.entity.d.ts +1 -0
- package/dist/src/models/system-privilege.entity.js +7 -0
- package/dist/src/models/system-privilege.entity.js.map +1 -1
- package/dist/src/models/system.entity.d.ts +1 -0
- package/dist/src/models/system.entity.js +7 -0
- package/dist/src/models/system.entity.js.map +1 -1
- package/dist/src/models/user.entity.d.ts +1 -0
- package/dist/src/models/user.entity.js +7 -0
- package/dist/src/models/user.entity.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/components/login-user/interfaces/user-info.interface.ts +1 -0
- package/src/components/login-user/user.ts +14 -2
- package/src/components/system/system.ts +2 -0
- package/src/components/system-privilege/system-privilege.ts +3 -0
- package/src/interfaces/system-privilege.interface.ts +1 -0
- package/src/interfaces/system.interface.ts +1 -0
- package/src/models/group.entity.ts +7 -1
- package/src/models/system-privilege.entity.ts +6 -0
- package/src/models/system.entity.ts +6 -0
- package/src/models/user.entity.ts +6 -0
|
@@ -71,7 +71,11 @@ describe('LoginUser', () => {
|
|
|
71
71
|
dbTransaction = null;
|
|
72
72
|
jest
|
|
73
73
|
.spyOn(ComponentConfig, 'getComponentConfigValue')
|
|
74
|
-
.
|
|
74
|
+
.mockImplementation((componentName: string, configKey: string) =>
|
|
75
|
+
configKey === 'useLoginApiYN'
|
|
76
|
+
? ('Y' as any)
|
|
77
|
+
: (mockLoginApiEndpoint as any),
|
|
78
|
+
);
|
|
75
79
|
});
|
|
76
80
|
|
|
77
81
|
it('should initialize LoginUser with valid userId', async () => {
|
|
@@ -136,6 +140,35 @@ describe('LoginUser', () => {
|
|
|
136
140
|
|
|
137
141
|
expect(axiosPostMock).toHaveBeenCalledTimes(1);
|
|
138
142
|
});
|
|
143
|
+
|
|
144
|
+
it('should initialize LoginUser via direct db query when useLoginApi is false', async () => {
|
|
145
|
+
jest
|
|
146
|
+
.spyOn(ComponentConfig, 'getComponentConfigValue')
|
|
147
|
+
.mockImplementation((componentName: string, configKey: string) => {
|
|
148
|
+
if (configKey === 'useLoginApiYN') return 'N' as any;
|
|
149
|
+
return mockLoginApiEndpoint as any;
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
const findOneMock = jest
|
|
153
|
+
.spyOn(LoginUser['_Repository'], 'findOne')
|
|
154
|
+
.mockResolvedValueOnce(mockUserData as any);
|
|
155
|
+
const axiosPostMock = jest.spyOn(axios, 'post');
|
|
156
|
+
|
|
157
|
+
const result = await LoginUser.init(
|
|
158
|
+
sessionService,
|
|
159
|
+
userId,
|
|
160
|
+
dbTransaction,
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
expect(findOneMock).toHaveBeenCalledWith({
|
|
164
|
+
where: { UserId: userId },
|
|
165
|
+
include: [{ model: expect.anything() }],
|
|
166
|
+
transaction: dbTransaction,
|
|
167
|
+
});
|
|
168
|
+
expect(axiosPostMock).not.toHaveBeenCalled();
|
|
169
|
+
expect(result).toBeInstanceOf(LoginUser);
|
|
170
|
+
expect(result.Email).toBe(mockUserData.Email);
|
|
171
|
+
});
|
|
139
172
|
});
|
|
140
173
|
|
|
141
174
|
// describe('checkSession', () => {
|
|
@@ -876,7 +909,11 @@ describe('LoginUser', () => {
|
|
|
876
909
|
.mockReturnValue('test-session' as any);
|
|
877
910
|
jest
|
|
878
911
|
.spyOn(ComponentConfig, 'getComponentConfigValue')
|
|
879
|
-
.
|
|
912
|
+
.mockImplementation((componentName: string, configKey: string) =>
|
|
913
|
+
configKey === 'useLoginApiYN'
|
|
914
|
+
? ('Y' as any)
|
|
915
|
+
: (mockLoginApiEndpoint as any),
|
|
916
|
+
);
|
|
880
917
|
});
|
|
881
918
|
|
|
882
919
|
it('should return true if user has the specified privilege', async () => {
|
|
@@ -941,6 +978,238 @@ describe('LoginUser', () => {
|
|
|
941
978
|
loginUser.checkPrivileges(systemCode, privilegeName),
|
|
942
979
|
).rejects.toThrow();
|
|
943
980
|
});
|
|
981
|
+
|
|
982
|
+
it('should check the session privileges directly when useLoginApi is false', async () => {
|
|
983
|
+
const systemCode = 'SS';
|
|
984
|
+
const privilegeName = 'Privilege 1';
|
|
985
|
+
jest
|
|
986
|
+
.spyOn(ComponentConfig, 'getComponentConfigValue')
|
|
987
|
+
.mockImplementation((componentName: string, configKey: string) => {
|
|
988
|
+
if (configKey === 'useLoginApiYN') return 'N' as any;
|
|
989
|
+
return mockLoginApiEndpoint as any;
|
|
990
|
+
});
|
|
991
|
+
|
|
992
|
+
const sessionService = await SessionService.init();
|
|
993
|
+
const loginUser = await LoginUser.init(sessionService);
|
|
994
|
+
loginUser.ObjectId = '1';
|
|
995
|
+
loginUser['_SessionService'].retrieveUserSession = jest
|
|
996
|
+
.fn()
|
|
997
|
+
.mockResolvedValue({
|
|
998
|
+
systemLogins: [{ code: systemCode, privileges: [privilegeName] }],
|
|
999
|
+
});
|
|
1000
|
+
|
|
1001
|
+
const axiosPostMock = jest.spyOn(axios, 'post');
|
|
1002
|
+
|
|
1003
|
+
const hasPrivilege = await loginUser.checkPrivileges(
|
|
1004
|
+
systemCode,
|
|
1005
|
+
privilegeName,
|
|
1006
|
+
);
|
|
1007
|
+
|
|
1008
|
+
expect(hasPrivilege).toBe(true);
|
|
1009
|
+
expect(axiosPostMock).not.toHaveBeenCalled();
|
|
1010
|
+
});
|
|
1011
|
+
});
|
|
1012
|
+
|
|
1013
|
+
describe('checkSession', () => {
|
|
1014
|
+
const mockLoginApiEndpoint = {
|
|
1015
|
+
baseUrl: 'http://sso-api',
|
|
1016
|
+
checkSession: '/check-session',
|
|
1017
|
+
apiKey: 'test-api-key',
|
|
1018
|
+
};
|
|
1019
|
+
|
|
1020
|
+
beforeEach(() => {
|
|
1021
|
+
jest
|
|
1022
|
+
.spyOn(ApplicationConfig, 'getComponentConfigValue')
|
|
1023
|
+
.mockReturnValue('test-session' as any);
|
|
1024
|
+
});
|
|
1025
|
+
|
|
1026
|
+
it('should call the login-api endpoint when useLoginApi is true', async () => {
|
|
1027
|
+
jest
|
|
1028
|
+
.spyOn(ComponentConfig, 'getComponentConfigValue')
|
|
1029
|
+
.mockImplementation((componentName: string, configKey: string) =>
|
|
1030
|
+
configKey === 'useLoginApiYN'
|
|
1031
|
+
? ('Y' as any)
|
|
1032
|
+
: (mockLoginApiEndpoint as any),
|
|
1033
|
+
);
|
|
1034
|
+
|
|
1035
|
+
const systemCode = 'SS';
|
|
1036
|
+
const sessionId = 'session-1';
|
|
1037
|
+
const userId = '1';
|
|
1038
|
+
const sessionService = await SessionService.init();
|
|
1039
|
+
const loginUser = await LoginUser.init(sessionService);
|
|
1040
|
+
|
|
1041
|
+
const mockSystemLogin = { code: systemCode, sessionId };
|
|
1042
|
+
const axiosPostMock = jest
|
|
1043
|
+
.spyOn(axios, 'post')
|
|
1044
|
+
.mockResolvedValueOnce({
|
|
1045
|
+
data: { systemLogin: mockSystemLogin },
|
|
1046
|
+
} as any);
|
|
1047
|
+
|
|
1048
|
+
const systemLogin = await loginUser.checkSession(
|
|
1049
|
+
systemCode,
|
|
1050
|
+
sessionId,
|
|
1051
|
+
userId,
|
|
1052
|
+
);
|
|
1053
|
+
|
|
1054
|
+
expect(systemLogin).toEqual(mockSystemLogin);
|
|
1055
|
+
expect(axiosPostMock).toHaveBeenCalledWith(
|
|
1056
|
+
`${mockLoginApiEndpoint.baseUrl}${mockLoginApiEndpoint.checkSession}`,
|
|
1057
|
+
{
|
|
1058
|
+
SystemCode: systemCode,
|
|
1059
|
+
SessionName: 'test-session',
|
|
1060
|
+
SessionId: sessionId,
|
|
1061
|
+
UserId: userId,
|
|
1062
|
+
},
|
|
1063
|
+
{
|
|
1064
|
+
headers: {
|
|
1065
|
+
'Content-Type': 'application/json',
|
|
1066
|
+
'x-api-key': mockLoginApiEndpoint.apiKey,
|
|
1067
|
+
},
|
|
1068
|
+
},
|
|
1069
|
+
);
|
|
1070
|
+
});
|
|
1071
|
+
|
|
1072
|
+
it('should validate the session directly against redis when useLoginApi is false', async () => {
|
|
1073
|
+
jest
|
|
1074
|
+
.spyOn(ComponentConfig, 'getComponentConfigValue')
|
|
1075
|
+
.mockImplementation((componentName: string, configKey: string) => {
|
|
1076
|
+
if (configKey === 'useLoginApiYN') return 'N' as any;
|
|
1077
|
+
return mockLoginApiEndpoint as any;
|
|
1078
|
+
});
|
|
1079
|
+
|
|
1080
|
+
const systemCode = 'SS';
|
|
1081
|
+
const sessionId = 'session-1';
|
|
1082
|
+
const userId = '1';
|
|
1083
|
+
const sessionService = await SessionService.init();
|
|
1084
|
+
const loginUser = await LoginUser.init(sessionService);
|
|
1085
|
+
|
|
1086
|
+
const mockSystemLogin = { code: systemCode, sessionId };
|
|
1087
|
+
loginUser['_SessionService'].retrieveUserSession = jest
|
|
1088
|
+
.fn()
|
|
1089
|
+
.mockResolvedValue({ systemLogins: [mockSystemLogin] });
|
|
1090
|
+
loginUser['_SessionService'].refreshDuration = jest.fn();
|
|
1091
|
+
|
|
1092
|
+
const axiosPostMock = jest.spyOn(axios, 'post');
|
|
1093
|
+
|
|
1094
|
+
const systemLogin = await loginUser.checkSession(
|
|
1095
|
+
systemCode,
|
|
1096
|
+
sessionId,
|
|
1097
|
+
userId,
|
|
1098
|
+
);
|
|
1099
|
+
|
|
1100
|
+
expect(systemLogin).toEqual(mockSystemLogin);
|
|
1101
|
+
expect(
|
|
1102
|
+
loginUser['_SessionService'].refreshDuration,
|
|
1103
|
+
).toHaveBeenCalledWith(userId, 'test-session');
|
|
1104
|
+
expect(axiosPostMock).not.toHaveBeenCalled();
|
|
1105
|
+
});
|
|
1106
|
+
|
|
1107
|
+
it('should throw "Session expired." when useLoginApi is false and the session is stale', async () => {
|
|
1108
|
+
jest
|
|
1109
|
+
.spyOn(ComponentConfig, 'getComponentConfigValue')
|
|
1110
|
+
.mockImplementation((componentName: string, configKey: string) => {
|
|
1111
|
+
if (configKey === 'useLoginApiYN') return 'N' as any;
|
|
1112
|
+
return mockLoginApiEndpoint as any;
|
|
1113
|
+
});
|
|
1114
|
+
|
|
1115
|
+
const sessionService = await SessionService.init();
|
|
1116
|
+
const loginUser = await LoginUser.init(sessionService);
|
|
1117
|
+
loginUser['_SessionService'].retrieveUserSession = jest
|
|
1118
|
+
.fn()
|
|
1119
|
+
.mockResolvedValue({ systemLogins: [] });
|
|
1120
|
+
|
|
1121
|
+
await expect(
|
|
1122
|
+
loginUser.checkSession('SS', 'session-1', '1'),
|
|
1123
|
+
).rejects.toThrow('Session expired.');
|
|
1124
|
+
});
|
|
1125
|
+
});
|
|
1126
|
+
|
|
1127
|
+
describe('setSession', () => {
|
|
1128
|
+
const mockLoginApiEndpoint = {
|
|
1129
|
+
baseUrl: 'http://sso-api',
|
|
1130
|
+
setSession: '/set-session',
|
|
1131
|
+
apiKey: 'test-api-key',
|
|
1132
|
+
};
|
|
1133
|
+
|
|
1134
|
+
beforeEach(() => {
|
|
1135
|
+
jest
|
|
1136
|
+
.spyOn(ApplicationConfig, 'getComponentConfigValue')
|
|
1137
|
+
.mockReturnValue('test-session' as any);
|
|
1138
|
+
});
|
|
1139
|
+
|
|
1140
|
+
it('should call the login-api endpoint when useLoginApi is true', async () => {
|
|
1141
|
+
jest
|
|
1142
|
+
.spyOn(ComponentConfig, 'getComponentConfigValue')
|
|
1143
|
+
.mockImplementation((componentName: string, configKey: string) =>
|
|
1144
|
+
configKey === 'useLoginApiYN'
|
|
1145
|
+
? ('Y' as any)
|
|
1146
|
+
: (mockLoginApiEndpoint as any),
|
|
1147
|
+
);
|
|
1148
|
+
|
|
1149
|
+
const systemCode = 'SS';
|
|
1150
|
+
const sessionId = 'session-1';
|
|
1151
|
+
const sessionService = await SessionService.init();
|
|
1152
|
+
const loginUser = await LoginUser.init(sessionService);
|
|
1153
|
+
loginUser.ObjectId = '1';
|
|
1154
|
+
|
|
1155
|
+
const axiosPostMock = jest
|
|
1156
|
+
.spyOn(axios, 'post')
|
|
1157
|
+
.mockResolvedValueOnce({ data: {} } as any);
|
|
1158
|
+
|
|
1159
|
+
await loginUser.setSession(systemCode, sessionId, null);
|
|
1160
|
+
|
|
1161
|
+
expect(axiosPostMock).toHaveBeenCalledWith(
|
|
1162
|
+
`${mockLoginApiEndpoint.baseUrl}${mockLoginApiEndpoint.setSession}`,
|
|
1163
|
+
{
|
|
1164
|
+
SystemCode: systemCode,
|
|
1165
|
+
SessionName: 'test-session',
|
|
1166
|
+
SessionId: sessionId,
|
|
1167
|
+
UserId: '1',
|
|
1168
|
+
},
|
|
1169
|
+
{
|
|
1170
|
+
headers: {
|
|
1171
|
+
'Content-Type': 'application/json',
|
|
1172
|
+
'x-api-key': mockLoginApiEndpoint.apiKey,
|
|
1173
|
+
},
|
|
1174
|
+
},
|
|
1175
|
+
);
|
|
1176
|
+
});
|
|
1177
|
+
|
|
1178
|
+
it('should persist the session directly to redis when useLoginApi is false', async () => {
|
|
1179
|
+
jest
|
|
1180
|
+
.spyOn(ComponentConfig, 'getComponentConfigValue')
|
|
1181
|
+
.mockImplementation((componentName: string, configKey: string) => {
|
|
1182
|
+
if (configKey === 'useLoginApiYN') return 'N' as any;
|
|
1183
|
+
return mockLoginApiEndpoint as any;
|
|
1184
|
+
});
|
|
1185
|
+
|
|
1186
|
+
const systemCode = 'SS';
|
|
1187
|
+
const sessionId = 'session-1';
|
|
1188
|
+
const sessionService = await SessionService.init();
|
|
1189
|
+
const loginUser = await LoginUser.init(sessionService);
|
|
1190
|
+
loginUser.ObjectId = '1';
|
|
1191
|
+
|
|
1192
|
+
jest.spyOn(loginUser, 'getPrivileges').mockResolvedValue(['privilege1']);
|
|
1193
|
+
loginUser['_SessionService'].retrieveUserSession = jest
|
|
1194
|
+
.fn()
|
|
1195
|
+
.mockResolvedValue({ systemLogins: [] });
|
|
1196
|
+
loginUser['_SessionService'].setUserSession = jest.fn();
|
|
1197
|
+
|
|
1198
|
+
const axiosPostMock = jest.spyOn(axios, 'post');
|
|
1199
|
+
|
|
1200
|
+
await loginUser.setSession(systemCode, sessionId, null);
|
|
1201
|
+
|
|
1202
|
+
expect(axiosPostMock).not.toHaveBeenCalled();
|
|
1203
|
+
expect(loginUser['_SessionService'].setUserSession).toHaveBeenCalledWith(
|
|
1204
|
+
'1',
|
|
1205
|
+
{
|
|
1206
|
+
systemLogins: [
|
|
1207
|
+
{ id: systemCode, code: systemCode, sessionId, privileges: ['privilege1'] },
|
|
1208
|
+
],
|
|
1209
|
+
},
|
|
1210
|
+
'test-session',
|
|
1211
|
+
);
|
|
1212
|
+
});
|
|
944
1213
|
});
|
|
945
1214
|
|
|
946
1215
|
describe('getObjectPrivileges', () => {
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { User } from '../../../../src/components/login-user/user';
|
|
2
|
+
import { UserPasswordHistory } from '../../../../src/components/user-password-history/user-password-history';
|
|
3
|
+
import { YN } from '../../../../src/enum/yn.enum';
|
|
4
|
+
|
|
5
|
+
// User and LoginUser import each other; this test exercises only User's expiry policy.
|
|
6
|
+
jest.mock('../../../../src/components/login-user/login-user', () => ({
|
|
7
|
+
LoginUser: class {},
|
|
8
|
+
}));
|
|
9
|
+
|
|
10
|
+
describe('User.getPasswordExpiryStatus', () => {
|
|
11
|
+
const originalExpiryMonths = process.env.PASSWORD_EXPIRY_MONTHS;
|
|
12
|
+
const originalWarningDays = process.env.PASSWORD_EXPIRY_WARNING_DAYS;
|
|
13
|
+
|
|
14
|
+
const user = (password: string | null) =>
|
|
15
|
+
Object.assign(Object.create(User.prototype), {
|
|
16
|
+
ObjectId: '123',
|
|
17
|
+
_Password: password,
|
|
18
|
+
_NeedToChangePasswordYN: YN.No,
|
|
19
|
+
}) as User;
|
|
20
|
+
|
|
21
|
+
beforeEach(() => {
|
|
22
|
+
process.env.PASSWORD_EXPIRY_MONTHS = '1';
|
|
23
|
+
process.env.PASSWORD_EXPIRY_WARNING_DAYS = '14';
|
|
24
|
+
jest.useFakeTimers().setSystemTime(new Date('2026-02-20T12:00:00Z'));
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
afterEach(() => {
|
|
28
|
+
jest.restoreAllMocks();
|
|
29
|
+
jest.useRealTimers();
|
|
30
|
+
if (originalExpiryMonths === undefined)
|
|
31
|
+
delete process.env.PASSWORD_EXPIRY_MONTHS;
|
|
32
|
+
else process.env.PASSWORD_EXPIRY_MONTHS = originalExpiryMonths;
|
|
33
|
+
if (originalWarningDays === undefined)
|
|
34
|
+
delete process.env.PASSWORD_EXPIRY_WARNING_DAYS;
|
|
35
|
+
else process.env.PASSWORD_EXPIRY_WARNING_DAYS = originalWarningDays;
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('disables expiry when the period is zero', async () => {
|
|
39
|
+
process.env.PASSWORD_EXPIRY_MONTHS = '0';
|
|
40
|
+
const lookup = jest.spyOn(UserPasswordHistory, 'getLatestByUserId');
|
|
41
|
+
|
|
42
|
+
expect(await user('hash').getPasswordExpiryStatus()).toEqual({
|
|
43
|
+
expired: false,
|
|
44
|
+
expiringSoon: false,
|
|
45
|
+
expiresInDays: null,
|
|
46
|
+
});
|
|
47
|
+
expect(lookup).not.toHaveBeenCalled();
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('skips an account without a local password', async () => {
|
|
51
|
+
const lookup = jest.spyOn(UserPasswordHistory, 'getLatestByUserId');
|
|
52
|
+
|
|
53
|
+
expect(await user(null).getPasswordExpiryStatus()).toEqual({
|
|
54
|
+
expired: false,
|
|
55
|
+
expiringSoon: false,
|
|
56
|
+
expiresInDays: null,
|
|
57
|
+
});
|
|
58
|
+
expect(lookup).not.toHaveBeenCalled();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('expires an account without password history', async () => {
|
|
62
|
+
jest
|
|
63
|
+
.spyOn(UserPasswordHistory, 'getLatestByUserId')
|
|
64
|
+
.mockResolvedValue(null);
|
|
65
|
+
|
|
66
|
+
expect(await user('hash').getPasswordExpiryStatus()).toEqual({
|
|
67
|
+
expired: true,
|
|
68
|
+
expiringSoon: false,
|
|
69
|
+
expiresInDays: null,
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('warns before expiry and clamps month-end dates', async () => {
|
|
74
|
+
jest.spyOn(UserPasswordHistory, 'getLatestByUserId').mockResolvedValue({
|
|
75
|
+
CreatedAt: new Date('2026-01-31T12:00:00Z'),
|
|
76
|
+
} as UserPasswordHistory);
|
|
77
|
+
|
|
78
|
+
expect(await user('hash').getPasswordExpiryStatus()).toEqual({
|
|
79
|
+
expired: false,
|
|
80
|
+
expiringSoon: true,
|
|
81
|
+
expiresInDays: 8,
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
jest.setSystemTime(new Date('2026-02-28T12:00:00Z'));
|
|
85
|
+
expect((await user('hash').getPasswordExpiryStatus()).expired).toBe(true);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
@@ -72,7 +72,9 @@ describe('LoginUser', () => {
|
|
|
72
72
|
dbTransaction = null;
|
|
73
73
|
jest
|
|
74
74
|
.spyOn(config_1.ComponentConfig, 'getComponentConfigValue')
|
|
75
|
-
.
|
|
75
|
+
.mockImplementation((componentName, configKey) => configKey === 'useLoginApiYN'
|
|
76
|
+
? 'Y'
|
|
77
|
+
: mockLoginApiEndpoint);
|
|
76
78
|
});
|
|
77
79
|
it('should initialize LoginUser with valid userId', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
78
80
|
const user = {
|
|
@@ -120,6 +122,28 @@ describe('LoginUser', () => {
|
|
|
120
122
|
yield expect(login_user_1.LoginUser.init(sessionService, userId, dbTransaction)).rejects.toThrow(Error);
|
|
121
123
|
expect(axiosPostMock).toHaveBeenCalledTimes(1);
|
|
122
124
|
}));
|
|
125
|
+
it('should initialize LoginUser via direct db query when useLoginApi is false', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
126
|
+
jest
|
|
127
|
+
.spyOn(config_1.ComponentConfig, 'getComponentConfigValue')
|
|
128
|
+
.mockImplementation((componentName, configKey) => {
|
|
129
|
+
if (configKey === 'useLoginApiYN')
|
|
130
|
+
return 'N';
|
|
131
|
+
return mockLoginApiEndpoint;
|
|
132
|
+
});
|
|
133
|
+
const findOneMock = jest
|
|
134
|
+
.spyOn(login_user_1.LoginUser['_Repository'], 'findOne')
|
|
135
|
+
.mockResolvedValueOnce(mockUserData);
|
|
136
|
+
const axiosPostMock = jest.spyOn(axios_1.default, 'post');
|
|
137
|
+
const result = yield login_user_1.LoginUser.init(sessionService, userId, dbTransaction);
|
|
138
|
+
expect(findOneMock).toHaveBeenCalledWith({
|
|
139
|
+
where: { UserId: userId },
|
|
140
|
+
include: [{ model: expect.anything() }],
|
|
141
|
+
transaction: dbTransaction,
|
|
142
|
+
});
|
|
143
|
+
expect(axiosPostMock).not.toHaveBeenCalled();
|
|
144
|
+
expect(result).toBeInstanceOf(login_user_1.LoginUser);
|
|
145
|
+
expect(result.Email).toBe(mockUserData.Email);
|
|
146
|
+
}));
|
|
123
147
|
});
|
|
124
148
|
describe('shouldReleaseLock', () => {
|
|
125
149
|
const minuteToAutoRelease = 5;
|
|
@@ -452,7 +476,9 @@ describe('LoginUser', () => {
|
|
|
452
476
|
.mockReturnValue('test-session');
|
|
453
477
|
jest
|
|
454
478
|
.spyOn(config_1.ComponentConfig, 'getComponentConfigValue')
|
|
455
|
-
.
|
|
479
|
+
.mockImplementation((componentName, configKey) => configKey === 'useLoginApiYN'
|
|
480
|
+
? 'Y'
|
|
481
|
+
: mockLoginApiEndpoint);
|
|
456
482
|
});
|
|
457
483
|
it('should return true if user has the specified privilege', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
458
484
|
const systemCode = 'SS';
|
|
@@ -487,6 +513,177 @@ describe('LoginUser', () => {
|
|
|
487
513
|
loginUser.ObjectId = null;
|
|
488
514
|
yield expect(loginUser.checkPrivileges(systemCode, privilegeName)).rejects.toThrow();
|
|
489
515
|
}));
|
|
516
|
+
it('should check the session privileges directly when useLoginApi is false', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
517
|
+
const systemCode = 'SS';
|
|
518
|
+
const privilegeName = 'Privilege 1';
|
|
519
|
+
jest
|
|
520
|
+
.spyOn(config_1.ComponentConfig, 'getComponentConfigValue')
|
|
521
|
+
.mockImplementation((componentName, configKey) => {
|
|
522
|
+
if (configKey === 'useLoginApiYN')
|
|
523
|
+
return 'N';
|
|
524
|
+
return mockLoginApiEndpoint;
|
|
525
|
+
});
|
|
526
|
+
const sessionService = yield session_service_1.SessionService.init();
|
|
527
|
+
const loginUser = yield login_user_1.LoginUser.init(sessionService);
|
|
528
|
+
loginUser.ObjectId = '1';
|
|
529
|
+
loginUser['_SessionService'].retrieveUserSession = jest
|
|
530
|
+
.fn()
|
|
531
|
+
.mockResolvedValue({
|
|
532
|
+
systemLogins: [{ code: systemCode, privileges: [privilegeName] }],
|
|
533
|
+
});
|
|
534
|
+
const axiosPostMock = jest.spyOn(axios_1.default, 'post');
|
|
535
|
+
const hasPrivilege = yield loginUser.checkPrivileges(systemCode, privilegeName);
|
|
536
|
+
expect(hasPrivilege).toBe(true);
|
|
537
|
+
expect(axiosPostMock).not.toHaveBeenCalled();
|
|
538
|
+
}));
|
|
539
|
+
});
|
|
540
|
+
describe('checkSession', () => {
|
|
541
|
+
const mockLoginApiEndpoint = {
|
|
542
|
+
baseUrl: 'http://sso-api',
|
|
543
|
+
checkSession: '/check-session',
|
|
544
|
+
apiKey: 'test-api-key',
|
|
545
|
+
};
|
|
546
|
+
beforeEach(() => {
|
|
547
|
+
jest
|
|
548
|
+
.spyOn(config_1.ApplicationConfig, 'getComponentConfigValue')
|
|
549
|
+
.mockReturnValue('test-session');
|
|
550
|
+
});
|
|
551
|
+
it('should call the login-api endpoint when useLoginApi is true', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
552
|
+
jest
|
|
553
|
+
.spyOn(config_1.ComponentConfig, 'getComponentConfigValue')
|
|
554
|
+
.mockImplementation((componentName, configKey) => configKey === 'useLoginApiYN'
|
|
555
|
+
? 'Y'
|
|
556
|
+
: mockLoginApiEndpoint);
|
|
557
|
+
const systemCode = 'SS';
|
|
558
|
+
const sessionId = 'session-1';
|
|
559
|
+
const userId = '1';
|
|
560
|
+
const sessionService = yield session_service_1.SessionService.init();
|
|
561
|
+
const loginUser = yield login_user_1.LoginUser.init(sessionService);
|
|
562
|
+
const mockSystemLogin = { code: systemCode, sessionId };
|
|
563
|
+
const axiosPostMock = jest
|
|
564
|
+
.spyOn(axios_1.default, 'post')
|
|
565
|
+
.mockResolvedValueOnce({
|
|
566
|
+
data: { systemLogin: mockSystemLogin },
|
|
567
|
+
});
|
|
568
|
+
const systemLogin = yield loginUser.checkSession(systemCode, sessionId, userId);
|
|
569
|
+
expect(systemLogin).toEqual(mockSystemLogin);
|
|
570
|
+
expect(axiosPostMock).toHaveBeenCalledWith(`${mockLoginApiEndpoint.baseUrl}${mockLoginApiEndpoint.checkSession}`, {
|
|
571
|
+
SystemCode: systemCode,
|
|
572
|
+
SessionName: 'test-session',
|
|
573
|
+
SessionId: sessionId,
|
|
574
|
+
UserId: userId,
|
|
575
|
+
}, {
|
|
576
|
+
headers: {
|
|
577
|
+
'Content-Type': 'application/json',
|
|
578
|
+
'x-api-key': mockLoginApiEndpoint.apiKey,
|
|
579
|
+
},
|
|
580
|
+
});
|
|
581
|
+
}));
|
|
582
|
+
it('should validate the session directly against redis when useLoginApi is false', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
583
|
+
jest
|
|
584
|
+
.spyOn(config_1.ComponentConfig, 'getComponentConfigValue')
|
|
585
|
+
.mockImplementation((componentName, configKey) => {
|
|
586
|
+
if (configKey === 'useLoginApiYN')
|
|
587
|
+
return 'N';
|
|
588
|
+
return mockLoginApiEndpoint;
|
|
589
|
+
});
|
|
590
|
+
const systemCode = 'SS';
|
|
591
|
+
const sessionId = 'session-1';
|
|
592
|
+
const userId = '1';
|
|
593
|
+
const sessionService = yield session_service_1.SessionService.init();
|
|
594
|
+
const loginUser = yield login_user_1.LoginUser.init(sessionService);
|
|
595
|
+
const mockSystemLogin = { code: systemCode, sessionId };
|
|
596
|
+
loginUser['_SessionService'].retrieveUserSession = jest
|
|
597
|
+
.fn()
|
|
598
|
+
.mockResolvedValue({ systemLogins: [mockSystemLogin] });
|
|
599
|
+
loginUser['_SessionService'].refreshDuration = jest.fn();
|
|
600
|
+
const axiosPostMock = jest.spyOn(axios_1.default, 'post');
|
|
601
|
+
const systemLogin = yield loginUser.checkSession(systemCode, sessionId, userId);
|
|
602
|
+
expect(systemLogin).toEqual(mockSystemLogin);
|
|
603
|
+
expect(loginUser['_SessionService'].refreshDuration).toHaveBeenCalledWith(userId, 'test-session');
|
|
604
|
+
expect(axiosPostMock).not.toHaveBeenCalled();
|
|
605
|
+
}));
|
|
606
|
+
it('should throw "Session expired." when useLoginApi is false and the session is stale', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
607
|
+
jest
|
|
608
|
+
.spyOn(config_1.ComponentConfig, 'getComponentConfigValue')
|
|
609
|
+
.mockImplementation((componentName, configKey) => {
|
|
610
|
+
if (configKey === 'useLoginApiYN')
|
|
611
|
+
return 'N';
|
|
612
|
+
return mockLoginApiEndpoint;
|
|
613
|
+
});
|
|
614
|
+
const sessionService = yield session_service_1.SessionService.init();
|
|
615
|
+
const loginUser = yield login_user_1.LoginUser.init(sessionService);
|
|
616
|
+
loginUser['_SessionService'].retrieveUserSession = jest
|
|
617
|
+
.fn()
|
|
618
|
+
.mockResolvedValue({ systemLogins: [] });
|
|
619
|
+
yield expect(loginUser.checkSession('SS', 'session-1', '1')).rejects.toThrow('Session expired.');
|
|
620
|
+
}));
|
|
621
|
+
});
|
|
622
|
+
describe('setSession', () => {
|
|
623
|
+
const mockLoginApiEndpoint = {
|
|
624
|
+
baseUrl: 'http://sso-api',
|
|
625
|
+
setSession: '/set-session',
|
|
626
|
+
apiKey: 'test-api-key',
|
|
627
|
+
};
|
|
628
|
+
beforeEach(() => {
|
|
629
|
+
jest
|
|
630
|
+
.spyOn(config_1.ApplicationConfig, 'getComponentConfigValue')
|
|
631
|
+
.mockReturnValue('test-session');
|
|
632
|
+
});
|
|
633
|
+
it('should call the login-api endpoint when useLoginApi is true', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
634
|
+
jest
|
|
635
|
+
.spyOn(config_1.ComponentConfig, 'getComponentConfigValue')
|
|
636
|
+
.mockImplementation((componentName, configKey) => configKey === 'useLoginApiYN'
|
|
637
|
+
? 'Y'
|
|
638
|
+
: mockLoginApiEndpoint);
|
|
639
|
+
const systemCode = 'SS';
|
|
640
|
+
const sessionId = 'session-1';
|
|
641
|
+
const sessionService = yield session_service_1.SessionService.init();
|
|
642
|
+
const loginUser = yield login_user_1.LoginUser.init(sessionService);
|
|
643
|
+
loginUser.ObjectId = '1';
|
|
644
|
+
const axiosPostMock = jest
|
|
645
|
+
.spyOn(axios_1.default, 'post')
|
|
646
|
+
.mockResolvedValueOnce({ data: {} });
|
|
647
|
+
yield loginUser.setSession(systemCode, sessionId, null);
|
|
648
|
+
expect(axiosPostMock).toHaveBeenCalledWith(`${mockLoginApiEndpoint.baseUrl}${mockLoginApiEndpoint.setSession}`, {
|
|
649
|
+
SystemCode: systemCode,
|
|
650
|
+
SessionName: 'test-session',
|
|
651
|
+
SessionId: sessionId,
|
|
652
|
+
UserId: '1',
|
|
653
|
+
}, {
|
|
654
|
+
headers: {
|
|
655
|
+
'Content-Type': 'application/json',
|
|
656
|
+
'x-api-key': mockLoginApiEndpoint.apiKey,
|
|
657
|
+
},
|
|
658
|
+
});
|
|
659
|
+
}));
|
|
660
|
+
it('should persist the session directly to redis when useLoginApi is false', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
661
|
+
jest
|
|
662
|
+
.spyOn(config_1.ComponentConfig, 'getComponentConfigValue')
|
|
663
|
+
.mockImplementation((componentName, configKey) => {
|
|
664
|
+
if (configKey === 'useLoginApiYN')
|
|
665
|
+
return 'N';
|
|
666
|
+
return mockLoginApiEndpoint;
|
|
667
|
+
});
|
|
668
|
+
const systemCode = 'SS';
|
|
669
|
+
const sessionId = 'session-1';
|
|
670
|
+
const sessionService = yield session_service_1.SessionService.init();
|
|
671
|
+
const loginUser = yield login_user_1.LoginUser.init(sessionService);
|
|
672
|
+
loginUser.ObjectId = '1';
|
|
673
|
+
jest.spyOn(loginUser, 'getPrivileges').mockResolvedValue(['privilege1']);
|
|
674
|
+
loginUser['_SessionService'].retrieveUserSession = jest
|
|
675
|
+
.fn()
|
|
676
|
+
.mockResolvedValue({ systemLogins: [] });
|
|
677
|
+
loginUser['_SessionService'].setUserSession = jest.fn();
|
|
678
|
+
const axiosPostMock = jest.spyOn(axios_1.default, 'post');
|
|
679
|
+
yield loginUser.setSession(systemCode, sessionId, null);
|
|
680
|
+
expect(axiosPostMock).not.toHaveBeenCalled();
|
|
681
|
+
expect(loginUser['_SessionService'].setUserSession).toHaveBeenCalledWith('1', {
|
|
682
|
+
systemLogins: [
|
|
683
|
+
{ id: systemCode, code: systemCode, sessionId, privileges: ['privilege1'] },
|
|
684
|
+
],
|
|
685
|
+
}, 'test-session');
|
|
686
|
+
}));
|
|
490
687
|
});
|
|
491
688
|
describe('getObjectPrivileges', () => {
|
|
492
689
|
it('should return an array of privileges', () => __awaiter(void 0, void 0, void 0, function* () {
|