@soapjs/soap-auth 0.3.3 → 0.4.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/.claude/settings.local.json +20 -0
- package/build/errors.d.ts +1 -1
- package/build/errors.js +2 -2
- package/build/index.d.ts +1 -0
- package/build/index.js +1 -0
- package/build/services/auth-throttle.service.d.ts +2 -2
- package/build/services/auth-throttle.service.js +2 -2
- package/build/services/index.d.ts +1 -0
- package/build/services/index.js +1 -0
- package/build/services/password.service.d.ts +7 -5
- package/build/services/password.service.js +76 -18
- package/build/services/totp.service.d.ts +16 -0
- package/build/services/totp.service.js +96 -0
- package/build/session/session-handler.d.ts +1 -0
- package/build/session/session-handler.js +39 -6
- package/build/soap-auth.d.ts +13 -6
- package/build/soap-auth.js +132 -5
- package/build/strategies/api-key/api-key.strategy.d.ts +4 -4
- package/build/strategies/api-key/api-key.strategy.js +3 -2
- package/build/strategies/base-auth.strategy.d.ts +5 -4
- package/build/strategies/basic/basic.strategy.d.ts +2 -1
- package/build/strategies/basic/basic.strategy.js +1 -0
- package/build/strategies/credential-auth.strategy.d.ts +7 -7
- package/build/strategies/credential-auth.strategy.js +9 -14
- package/build/strategies/index.d.ts +1 -0
- package/build/strategies/index.js +1 -0
- package/build/strategies/jwt/jwt.strategy.d.ts +3 -1
- package/build/strategies/jwt/jwt.strategy.js +41 -9
- package/build/strategies/jwt/jwt.tools.js +16 -14
- package/build/strategies/local/local.strategy.d.ts +6 -3
- package/build/strategies/local/local.strategy.js +83 -2
- package/build/strategies/oauth2/hybrid.oauth2.strategy.d.ts +3 -3
- package/build/strategies/oauth2/hybrid.oauth2.strategy.js +1 -6
- package/build/strategies/oauth2/oauth2.errors.d.ts +1 -0
- package/build/strategies/oauth2/oauth2.errors.js +4 -0
- package/build/strategies/oauth2/oauth2.strategy.d.ts +6 -4
- package/build/strategies/oauth2/oauth2.strategy.js +114 -46
- package/build/strategies/oauth2/oauth2.tools.js +2 -2
- package/build/strategies/oauth2/oauth2.types.d.ts +2 -2
- package/build/strategies/oauth2/providers/facebook.strategy.d.ts +11 -0
- package/build/strategies/oauth2/providers/facebook.strategy.js +58 -0
- package/build/strategies/oauth2/providers/github.strategy.d.ts +11 -0
- package/build/strategies/oauth2/providers/github.strategy.js +56 -0
- package/build/strategies/oauth2/providers/google.strategy.d.ts +11 -0
- package/build/strategies/oauth2/providers/google.strategy.js +52 -0
- package/build/strategies/oauth2/providers/http-oauth2.strategy.d.ts +16 -0
- package/build/strategies/oauth2/providers/http-oauth2.strategy.js +49 -0
- package/build/strategies/oauth2/providers/index.d.ts +5 -0
- package/build/strategies/oauth2/providers/index.js +21 -0
- package/build/strategies/oauth2/providers/provider.types.d.ts +7 -0
- package/build/strategies/oauth2/providers/provider.types.js +2 -0
- package/build/strategies/token-auth.strategy.d.ts +4 -4
- package/build/strategies/token-auth.strategy.js +2 -3
- package/build/tools/tools.js +1 -2
- package/build/types.d.ts +31 -32
- package/build/utils/validation.d.ts +23 -0
- package/build/utils/validation.js +139 -0
- package/package.json +8 -7
- package/build/__tests__/soap-auth.test.d.ts +0 -1
- package/build/__tests__/soap-auth.test.js +0 -42
- package/build/services/__tests__/account-lock.service.test.d.ts +0 -1
- package/build/services/__tests__/account-lock.service.test.js +0 -55
- package/build/services/__tests__/auth-throttle.service.test.d.ts +0 -1
- package/build/services/__tests__/auth-throttle.service.test.js +0 -48
- package/build/services/__tests__/jwks.service.test.d.ts +0 -1
- package/build/services/__tests__/jwks.service.test.js +0 -39
- package/build/services/__tests__/mfa.service.test.d.ts +0 -1
- package/build/services/__tests__/mfa.service.test.js +0 -66
- package/build/services/__tests__/password.service.test.d.ts +0 -1
- package/build/services/__tests__/password.service.test.js +0 -66
- package/build/services/__tests__/pkce.service.test.d.ts +0 -1
- package/build/services/__tests__/pkce.service.test.js +0 -77
- package/build/services/__tests__/rate-limit.service.test.d.ts +0 -1
- package/build/services/__tests__/rate-limit.service.test.js +0 -37
- package/build/services/__tests__/role.service.test.d.ts +0 -1
- package/build/services/__tests__/role.service.test.js +0 -31
- package/build/session/__tests__/file.session-store.test.d.ts +0 -1
- package/build/session/__tests__/file.session-store.test.js +0 -117
- package/build/session/__tests__/memory.session-store.test.d.ts +0 -1
- package/build/session/__tests__/memory.session-store.test.js +0 -77
- package/build/session/__tests__/session-handler.test.d.ts +0 -1
- package/build/session/__tests__/session-handler.test.js +0 -337
- package/build/strategies/__tests__/base-auth.strategy.test.d.ts +0 -14
- package/build/strategies/__tests__/base-auth.strategy.test.js +0 -137
- package/build/strategies/__tests__/credential-auth.strategy.test.d.ts +0 -14
- package/build/strategies/__tests__/credential-auth.strategy.test.js +0 -265
- package/build/strategies/__tests__/token-auth.strategy.test.d.ts +0 -28
- package/build/strategies/__tests__/token-auth.strategy.test.js +0 -298
- package/build/strategies/api-key/__tests__/api-key.strategy.test.d.ts +0 -1
- package/build/strategies/api-key/__tests__/api-key.strategy.test.js +0 -103
- package/build/strategies/basic/__tests__/basic.strategy.test.d.ts +0 -1
- package/build/strategies/basic/__tests__/basic.strategy.test.js +0 -104
- package/build/strategies/jwt/__tests__/jwt.strategy.test.d.ts +0 -1
- package/build/strategies/jwt/__tests__/jwt.strategy.test.js +0 -156
- package/build/strategies/jwt/__tests__/jwt.tools.test.d.ts +0 -1
- package/build/strategies/jwt/__tests__/jwt.tools.test.js +0 -98
- package/build/strategies/local/__tests__/local.strategy.test.d.ts +0 -1
- package/build/strategies/local/__tests__/local.strategy.test.js +0 -115
|
@@ -1,337 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const session_handler_1 = require("../session-handler");
|
|
4
|
-
const session_errors_1 = require("../session.errors");
|
|
5
|
-
describe("SessionHandler", () => {
|
|
6
|
-
let mockStore;
|
|
7
|
-
let mockLogger;
|
|
8
|
-
let sessionHandler;
|
|
9
|
-
let config;
|
|
10
|
-
beforeEach(() => {
|
|
11
|
-
mockStore = {
|
|
12
|
-
getSession: jest.fn(),
|
|
13
|
-
setSession: jest.fn(),
|
|
14
|
-
touchSession: jest.fn(),
|
|
15
|
-
destroySession: jest.fn(),
|
|
16
|
-
getSessionIds: jest.fn().mockResolvedValue(["s1", "s2"]),
|
|
17
|
-
};
|
|
18
|
-
mockLogger = {
|
|
19
|
-
info: jest.fn(),
|
|
20
|
-
error: jest.fn(),
|
|
21
|
-
warn: jest.fn(),
|
|
22
|
-
};
|
|
23
|
-
config = {
|
|
24
|
-
store: mockStore,
|
|
25
|
-
sessionKey: "CUSTOMSESSION",
|
|
26
|
-
sessionHeader: "x-custom-session",
|
|
27
|
-
logger: mockLogger,
|
|
28
|
-
cookie: {
|
|
29
|
-
maxAge: 3600,
|
|
30
|
-
},
|
|
31
|
-
generateSessionId: jest.fn(),
|
|
32
|
-
getSessionId: undefined,
|
|
33
|
-
embedSessionId: undefined,
|
|
34
|
-
createSessionData: undefined,
|
|
35
|
-
};
|
|
36
|
-
sessionHandler = new session_handler_1.SessionHandler(config, mockLogger);
|
|
37
|
-
});
|
|
38
|
-
describe("constructor", () => {
|
|
39
|
-
it("should throw if store is not provided", () => {
|
|
40
|
-
expect(() => {
|
|
41
|
-
new session_handler_1.SessionHandler({});
|
|
42
|
-
}).toThrowError("Session store is required.");
|
|
43
|
-
});
|
|
44
|
-
it("should set default sessionKey and headerKey if not provided", () => {
|
|
45
|
-
const newHandler = new session_handler_1.SessionHandler({ store: mockStore });
|
|
46
|
-
expect(newHandler.sessionKey).toBe("SESSIONID");
|
|
47
|
-
expect(newHandler.headerKey).toBe("x-session-id");
|
|
48
|
-
});
|
|
49
|
-
it("should use provided sessionKey and headerKey if available", () => {
|
|
50
|
-
expect(sessionHandler.sessionKey).toBe("CUSTOMSESSION");
|
|
51
|
-
expect(sessionHandler.headerKey).toBe("x-custom-session");
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
describe("setSessionId", () => {
|
|
55
|
-
it("should call config.embedSessionId if defined", () => {
|
|
56
|
-
config.embedSessionId = jest.fn();
|
|
57
|
-
const handler = new session_handler_1.SessionHandler(config, mockLogger);
|
|
58
|
-
const context = {};
|
|
59
|
-
handler.setSessionId(context, "session123");
|
|
60
|
-
expect(config.embedSessionId).toHaveBeenCalledWith(context, "session123");
|
|
61
|
-
});
|
|
62
|
-
it("should set session ID in cookie if res.cookie is available", () => {
|
|
63
|
-
const context = {
|
|
64
|
-
res: {
|
|
65
|
-
cookie: jest.fn(),
|
|
66
|
-
},
|
|
67
|
-
};
|
|
68
|
-
sessionHandler.setSessionId(context, "sessionABC");
|
|
69
|
-
expect(context.res.cookie).toHaveBeenCalledWith("CUSTOMSESSION", "sessionABC", expect.objectContaining({
|
|
70
|
-
httpOnly: true,
|
|
71
|
-
secure: true,
|
|
72
|
-
sameSite: "strict",
|
|
73
|
-
}));
|
|
74
|
-
expect(mockLogger.info).toHaveBeenCalledWith(`Session ID set in cookie: CUSTOMSESSION`);
|
|
75
|
-
});
|
|
76
|
-
it("should set session ID in header if res.setHeader is available", () => {
|
|
77
|
-
const context = {
|
|
78
|
-
res: {
|
|
79
|
-
setHeader: jest.fn(),
|
|
80
|
-
},
|
|
81
|
-
};
|
|
82
|
-
sessionHandler.setSessionId(context, "headerSessionId");
|
|
83
|
-
expect(context.res.setHeader).toHaveBeenCalledWith("x-custom-session", "headerSessionId");
|
|
84
|
-
expect(mockLogger.info).toHaveBeenCalledWith(`Session ID set in header: x-custom-session`);
|
|
85
|
-
});
|
|
86
|
-
it("should set sessionId directly on context object if no res", () => {
|
|
87
|
-
const context = {};
|
|
88
|
-
sessionHandler.setSessionId(context, "direct123");
|
|
89
|
-
expect(context.sessionId).toBe("direct123");
|
|
90
|
-
expect(mockLogger.info).toHaveBeenCalledWith("Session ID set in context object");
|
|
91
|
-
});
|
|
92
|
-
it("should log error if something goes wrong", () => {
|
|
93
|
-
config.embedSessionId = jest.fn().mockImplementation(() => {
|
|
94
|
-
throw new Error("Test error");
|
|
95
|
-
});
|
|
96
|
-
const handler = new session_handler_1.SessionHandler(config, mockLogger);
|
|
97
|
-
handler.setSessionId({}, "boom");
|
|
98
|
-
expect(mockLogger.error).toHaveBeenCalledWith("Error setting session ID:", expect.any(Error));
|
|
99
|
-
});
|
|
100
|
-
});
|
|
101
|
-
describe("getSessionId", () => {
|
|
102
|
-
it("should use config.getSessionId if defined", () => {
|
|
103
|
-
config.getSessionId = jest.fn().mockReturnValue("customSessionId");
|
|
104
|
-
const handler = new session_handler_1.SessionHandler(config, mockLogger);
|
|
105
|
-
const sid = handler.getSessionId({});
|
|
106
|
-
expect(sid).toBe("customSessionId");
|
|
107
|
-
expect(config.getSessionId).toHaveBeenCalled();
|
|
108
|
-
});
|
|
109
|
-
it("should return cookie session if present", () => {
|
|
110
|
-
const context = { cookies: { CUSTOMSESSION: "cookieValue" } };
|
|
111
|
-
const sid = sessionHandler.getSessionId(context);
|
|
112
|
-
expect(sid).toBe("cookieValue");
|
|
113
|
-
});
|
|
114
|
-
it("should return header session if present", () => {
|
|
115
|
-
const context = { headers: { "x-custom-session": "headerValue" } };
|
|
116
|
-
const sid = sessionHandler.getSessionId(context);
|
|
117
|
-
expect(sid).toBe("headerValue");
|
|
118
|
-
});
|
|
119
|
-
it("should return sessionId if set directly on context", () => {
|
|
120
|
-
const context = { sessionId: "directValue" };
|
|
121
|
-
const sid = sessionHandler.getSessionId(context);
|
|
122
|
-
expect(sid).toBe("directValue");
|
|
123
|
-
});
|
|
124
|
-
it("should return null if not found", () => {
|
|
125
|
-
const context = {};
|
|
126
|
-
const sid = sessionHandler.getSessionId(context);
|
|
127
|
-
expect(sid).toBeNull();
|
|
128
|
-
});
|
|
129
|
-
it("should log error and return null if something goes wrong", () => {
|
|
130
|
-
config.getSessionId = jest.fn().mockImplementation(() => {
|
|
131
|
-
throw new Error("Get error");
|
|
132
|
-
});
|
|
133
|
-
const handler = new session_handler_1.SessionHandler(config, mockLogger);
|
|
134
|
-
const sid = handler.getSessionId({});
|
|
135
|
-
expect(mockLogger.error).toHaveBeenCalledWith("Error retrieving session ID:", expect.any(Error));
|
|
136
|
-
expect(sid).toBeNull();
|
|
137
|
-
});
|
|
138
|
-
});
|
|
139
|
-
describe("generateSessionId", () => {
|
|
140
|
-
it("should use config.generateSessionId if provided", () => {
|
|
141
|
-
config.generateSessionId.mockReturnValue("customGenerated");
|
|
142
|
-
const sid = sessionHandler.generateSessionId();
|
|
143
|
-
expect(sid).toBe("customGenerated");
|
|
144
|
-
expect(config.generateSessionId).toHaveBeenCalled();
|
|
145
|
-
});
|
|
146
|
-
it("should fallback to uuid if no config.generateSessionId is given", () => {
|
|
147
|
-
config.generateSessionId = undefined;
|
|
148
|
-
const sid = sessionHandler.generateSessionId();
|
|
149
|
-
expect(typeof sid).toBe("string");
|
|
150
|
-
expect(sid.length).toBeGreaterThan(0);
|
|
151
|
-
});
|
|
152
|
-
});
|
|
153
|
-
describe("buildSessionData", () => {
|
|
154
|
-
it("should call config.createSessionData if provided", () => {
|
|
155
|
-
config.createSessionData = jest
|
|
156
|
-
.fn()
|
|
157
|
-
.mockReturnValue({ user: "mockUser" });
|
|
158
|
-
const data = sessionHandler.buildSessionData({ id: "test" }, {});
|
|
159
|
-
expect(config.createSessionData).toHaveBeenCalledWith({ id: "test" }, {});
|
|
160
|
-
expect(data).toEqual({ user: "mockUser" });
|
|
161
|
-
});
|
|
162
|
-
it("should default to { user: data } if createSessionData not provided", () => {
|
|
163
|
-
config.createSessionData = undefined;
|
|
164
|
-
const input = { id: "testId" };
|
|
165
|
-
const data = sessionHandler.buildSessionData(input);
|
|
166
|
-
expect(data).toEqual({ user: input });
|
|
167
|
-
});
|
|
168
|
-
});
|
|
169
|
-
describe("getSessionData", () => {
|
|
170
|
-
it("should return data from the store", async () => {
|
|
171
|
-
mockStore.getSession.mockResolvedValue({ user: { id: "1" } });
|
|
172
|
-
const data = await sessionHandler.getSessionData("session123");
|
|
173
|
-
expect(data).toEqual({ user: { id: "1" } });
|
|
174
|
-
});
|
|
175
|
-
it("should return null if store.getSession fails", async () => {
|
|
176
|
-
mockStore.getSession.mockRejectedValue(new Error("Store error"));
|
|
177
|
-
const data = await sessionHandler.getSessionData("sessionX");
|
|
178
|
-
expect(data).toBeNull();
|
|
179
|
-
expect(mockLogger.error).toHaveBeenCalledWith("Error retrieving session data:", expect.any(Error));
|
|
180
|
-
});
|
|
181
|
-
});
|
|
182
|
-
describe("setSessionData", () => {
|
|
183
|
-
it("should warn if sessionId is falsy", async () => {
|
|
184
|
-
await sessionHandler.setSessionData("", { user: {} });
|
|
185
|
-
expect(mockLogger.warn).toHaveBeenCalledWith("No session ID found, unable to set session.");
|
|
186
|
-
expect(mockStore.setSession).not.toHaveBeenCalled();
|
|
187
|
-
});
|
|
188
|
-
it("should call store.setSession with provided data", async () => {
|
|
189
|
-
await sessionHandler.setSessionData("sessionXYZ", {
|
|
190
|
-
user: { id: "abc" },
|
|
191
|
-
});
|
|
192
|
-
expect(mockStore.setSession).toHaveBeenCalledWith("sessionXYZ", {
|
|
193
|
-
user: { id: "abc" },
|
|
194
|
-
});
|
|
195
|
-
expect(mockLogger.info).toHaveBeenCalledWith("Session set for ID: sessionXYZ");
|
|
196
|
-
});
|
|
197
|
-
it("should log error if store.setSession fails", async () => {
|
|
198
|
-
mockStore.setSession.mockRejectedValue(new Error("Store error"));
|
|
199
|
-
await sessionHandler.setSessionData("session123", {
|
|
200
|
-
user: { id: "xyz" },
|
|
201
|
-
});
|
|
202
|
-
expect(mockLogger.error).toHaveBeenCalledWith("Error storing session data:", expect.any(Error));
|
|
203
|
-
});
|
|
204
|
-
});
|
|
205
|
-
describe("touch", () => {
|
|
206
|
-
it("should warn if no sessionId is provided", async () => {
|
|
207
|
-
await sessionHandler.touch("");
|
|
208
|
-
expect(mockLogger.warn).toHaveBeenCalledWith("No session ID found, unable to touch session.");
|
|
209
|
-
});
|
|
210
|
-
it("should warn if session not found", async () => {
|
|
211
|
-
mockStore.getSession.mockResolvedValue(null);
|
|
212
|
-
await sessionHandler.touch("noSuchId", { user: { id: "1" } });
|
|
213
|
-
expect(mockLogger.warn).toHaveBeenCalledWith("Session not found for ID: noSuchId");
|
|
214
|
-
});
|
|
215
|
-
it("should merge data and call store.touchSession if session found", async () => {
|
|
216
|
-
mockStore.getSession.mockResolvedValue({ user: { id: "old" } });
|
|
217
|
-
await sessionHandler.touch("session123", { user: { id: "new" } });
|
|
218
|
-
expect(mockStore.touchSession).toHaveBeenCalledWith("session123", {
|
|
219
|
-
user: { id: "new" },
|
|
220
|
-
});
|
|
221
|
-
expect(mockLogger.info).toHaveBeenCalledWith("Session touched for ID: session123");
|
|
222
|
-
});
|
|
223
|
-
it("should log error on store errors", async () => {
|
|
224
|
-
mockStore.getSession.mockResolvedValue({ user: {} });
|
|
225
|
-
mockStore.touchSession.mockRejectedValue(new Error("Touch error"));
|
|
226
|
-
await sessionHandler.touch("session123");
|
|
227
|
-
expect(mockLogger.error).toHaveBeenCalledWith("Error touching session:", expect.any(Error));
|
|
228
|
-
});
|
|
229
|
-
});
|
|
230
|
-
describe("destroy", () => {
|
|
231
|
-
it("should call store.destroySession with sessionId", async () => {
|
|
232
|
-
await sessionHandler.destroy("sessionABC");
|
|
233
|
-
expect(mockStore.destroySession).toHaveBeenCalledWith("sessionABC");
|
|
234
|
-
expect(mockLogger.info).toHaveBeenCalledWith("Session destroyed for ID: sessionABC");
|
|
235
|
-
});
|
|
236
|
-
it("should do nothing if no sessionId is provided", async () => {
|
|
237
|
-
await sessionHandler.destroy("");
|
|
238
|
-
expect(mockStore.destroySession).not.toHaveBeenCalled();
|
|
239
|
-
});
|
|
240
|
-
it("should log error on store error", async () => {
|
|
241
|
-
mockStore.destroySession.mockRejectedValue(new Error("Destroy error"));
|
|
242
|
-
await sessionHandler.destroy("sessionXYZ");
|
|
243
|
-
expect(mockLogger.error).toHaveBeenCalledWith("Error destroying session:", expect.any(Error));
|
|
244
|
-
});
|
|
245
|
-
});
|
|
246
|
-
describe("isSessionExpired", () => {
|
|
247
|
-
it("should return false if no sessionData or no createdAt", () => {
|
|
248
|
-
expect(sessionHandler.isSessionExpired({})).toBe(false);
|
|
249
|
-
expect(sessionHandler.isSessionExpired(null)).toBe(false);
|
|
250
|
-
});
|
|
251
|
-
it("should return true if now - createdAt > maxAge", () => {
|
|
252
|
-
const oldTime = Date.now() - 7200 * 1000;
|
|
253
|
-
config.cookie.maxAge = 3600 * 1000;
|
|
254
|
-
const data = { createdAt: oldTime };
|
|
255
|
-
expect(sessionHandler.isSessionExpired(data)).toBe(true);
|
|
256
|
-
});
|
|
257
|
-
it("should return false if within maxAge", () => {
|
|
258
|
-
const recentTime = Date.now() - 1000 * 100;
|
|
259
|
-
config.cookie.maxAge = 600000;
|
|
260
|
-
const data = { createdAt: recentTime };
|
|
261
|
-
expect(sessionHandler.isSessionExpired(data)).toBe(false);
|
|
262
|
-
});
|
|
263
|
-
});
|
|
264
|
-
describe("issueSession", () => {
|
|
265
|
-
it("should reuse existing sessionId if present in context", async () => {
|
|
266
|
-
jest
|
|
267
|
-
.spyOn(sessionHandler, "getSessionId")
|
|
268
|
-
.mockReturnValue("ctxSessionId");
|
|
269
|
-
await sessionHandler.issueSession({ id: "u1" }, {});
|
|
270
|
-
expect(mockStore.setSession).toHaveBeenCalledWith("ctxSessionId", {
|
|
271
|
-
user: { id: "u1" },
|
|
272
|
-
});
|
|
273
|
-
});
|
|
274
|
-
it("should generate a new sessionId if none found in context", async () => {
|
|
275
|
-
jest.spyOn(sessionHandler, "getSessionId").mockReturnValue(null);
|
|
276
|
-
jest.spyOn(sessionHandler, "generateSessionId").mockReturnValue("newID");
|
|
277
|
-
const result = await sessionHandler.issueSession({ id: "u1" }, {});
|
|
278
|
-
expect(mockStore.setSession).toHaveBeenCalledWith("newID", {
|
|
279
|
-
user: { id: "u1" },
|
|
280
|
-
});
|
|
281
|
-
expect(result.sessionId).toBe("newID");
|
|
282
|
-
});
|
|
283
|
-
it("should call session.createSessionData if provided in config", async () => {
|
|
284
|
-
config.createSessionData = jest
|
|
285
|
-
.fn()
|
|
286
|
-
.mockReturnValue({ user: { id: "custom" }, extra: "hello" });
|
|
287
|
-
config.embedSessionId = jest.fn();
|
|
288
|
-
const handler = new session_handler_1.SessionHandler(config, mockLogger);
|
|
289
|
-
jest.spyOn(handler, "getSessionId").mockReturnValue("testSid");
|
|
290
|
-
const result = await handler.issueSession({ id: "u2" }, {});
|
|
291
|
-
expect(config.createSessionData).toHaveBeenCalledWith({ id: "u2" }, {});
|
|
292
|
-
expect(mockStore.setSession).toHaveBeenCalledWith("testSid", {
|
|
293
|
-
user: { id: "custom" },
|
|
294
|
-
extra: "hello",
|
|
295
|
-
});
|
|
296
|
-
expect(result.data).toEqual({ user: { id: "custom" }, extra: "hello" });
|
|
297
|
-
});
|
|
298
|
-
it("should embed sessionId if embedSessionId is defined in config.session", async () => {
|
|
299
|
-
config.embedSessionId = jest.fn();
|
|
300
|
-
const handler = new session_handler_1.SessionHandler(config, mockLogger);
|
|
301
|
-
jest.spyOn(handler, "getSessionId").mockReturnValue("abc123");
|
|
302
|
-
await handler.issueSession({ id: "u5" }, {});
|
|
303
|
-
expect(config.embedSessionId).toHaveBeenCalledWith({}, "abc123");
|
|
304
|
-
expect(mockLogger.info).toHaveBeenCalledWith("Stored user session with ID: abc123");
|
|
305
|
-
});
|
|
306
|
-
});
|
|
307
|
-
describe("logoutSession", () => {
|
|
308
|
-
it("should throw MissingSessionIdError if sessionId not found", async () => {
|
|
309
|
-
jest.spyOn(sessionHandler, "getSessionId").mockReturnValue(null);
|
|
310
|
-
await expect(sessionHandler.logoutSession({})).rejects.toThrow(session_errors_1.MissingSessionIdError);
|
|
311
|
-
});
|
|
312
|
-
it("should destroy session with found sessionId", async () => {
|
|
313
|
-
jest
|
|
314
|
-
.spyOn(sessionHandler, "getSessionId")
|
|
315
|
-
.mockReturnValue("logoutSessionId");
|
|
316
|
-
const destroySpy = jest.spyOn(sessionHandler, "destroy");
|
|
317
|
-
await sessionHandler.logoutSession({});
|
|
318
|
-
expect(destroySpy).toHaveBeenCalledWith("logoutSessionId");
|
|
319
|
-
expect(mockLogger.info).toHaveBeenCalledWith("Session destroyed: logoutSessionId");
|
|
320
|
-
});
|
|
321
|
-
});
|
|
322
|
-
describe("clearAllSessions", () => {
|
|
323
|
-
it("should destroy all sessions if store.getSessionIds is available", async () => {
|
|
324
|
-
mockStore.getSessionIds.mockResolvedValue(["s1", "s2", "s3"]);
|
|
325
|
-
await sessionHandler.clearAllSessions();
|
|
326
|
-
expect(mockStore.destroySession).toHaveBeenCalledWith("s1");
|
|
327
|
-
expect(mockStore.destroySession).toHaveBeenCalledWith("s2");
|
|
328
|
-
expect(mockStore.destroySession).toHaveBeenCalledWith("s3");
|
|
329
|
-
expect(mockLogger.info).toHaveBeenCalledWith("All sessions have been cleared.");
|
|
330
|
-
});
|
|
331
|
-
it("should log error if something goes wrong", async () => {
|
|
332
|
-
mockStore.getSessionIds.mockRejectedValue(new Error("Store read error"));
|
|
333
|
-
await sessionHandler.clearAllSessions();
|
|
334
|
-
expect(mockLogger.error).toHaveBeenCalledWith("Error clearing all sessions:", expect.any(Error));
|
|
335
|
-
});
|
|
336
|
-
});
|
|
337
|
-
});
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { AuthResult, BaseAuthStrategyConfig } from "../../../src/types";
|
|
2
|
-
import { SessionHandler } from "../../../src/session/session-handler";
|
|
3
|
-
import * as Soap from "@soapjs/soap";
|
|
4
|
-
import { BaseAuthStrategy } from "../base-auth.strategy";
|
|
5
|
-
export interface MockUser {
|
|
6
|
-
id: string;
|
|
7
|
-
name: string;
|
|
8
|
-
}
|
|
9
|
-
export interface MockContext {
|
|
10
|
-
}
|
|
11
|
-
export declare class TestBaseAuthStrategy extends BaseAuthStrategy<MockContext, MockUser> {
|
|
12
|
-
constructor(config: BaseAuthStrategyConfig<MockContext, MockUser>, session?: SessionHandler, logger?: Soap.Logger);
|
|
13
|
-
authenticate(context?: MockContext): Promise<AuthResult<MockUser>>;
|
|
14
|
-
}
|
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.TestBaseAuthStrategy = void 0;
|
|
4
|
-
const session_errors_1 = require("../../../src/session/session.errors");
|
|
5
|
-
const base_auth_strategy_1 = require("../base-auth.strategy");
|
|
6
|
-
class TestBaseAuthStrategy extends base_auth_strategy_1.BaseAuthStrategy {
|
|
7
|
-
constructor(config, session, logger) {
|
|
8
|
-
super(config, session, logger);
|
|
9
|
-
}
|
|
10
|
-
async authenticate(context) {
|
|
11
|
-
return { user: null };
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
exports.TestBaseAuthStrategy = TestBaseAuthStrategy;
|
|
15
|
-
describe("BaseAuthStrategy", () => {
|
|
16
|
-
let config;
|
|
17
|
-
let mockSessionHandler;
|
|
18
|
-
let mockLogger;
|
|
19
|
-
let mockAccountLock;
|
|
20
|
-
let mockMfa;
|
|
21
|
-
let mockRateLimit;
|
|
22
|
-
let mockRole;
|
|
23
|
-
let mockThrottle;
|
|
24
|
-
let strategy;
|
|
25
|
-
let context;
|
|
26
|
-
beforeEach(() => {
|
|
27
|
-
config = {
|
|
28
|
-
onSuccess: jest.fn(),
|
|
29
|
-
onFailure: jest.fn(),
|
|
30
|
-
};
|
|
31
|
-
mockSessionHandler = {
|
|
32
|
-
getSessionId: jest.fn().mockReturnValue("session-id"),
|
|
33
|
-
getSessionData: jest
|
|
34
|
-
.fn()
|
|
35
|
-
.mockResolvedValue({ user: { id: "123", name: "TestUser" } }),
|
|
36
|
-
};
|
|
37
|
-
mockLogger = {
|
|
38
|
-
error: jest.fn(),
|
|
39
|
-
info: jest.fn(),
|
|
40
|
-
warn: jest.fn(),
|
|
41
|
-
};
|
|
42
|
-
mockAccountLock = {};
|
|
43
|
-
mockMfa = {};
|
|
44
|
-
mockRateLimit = {
|
|
45
|
-
checkRateLimit: jest.fn().mockResolvedValue(undefined),
|
|
46
|
-
};
|
|
47
|
-
mockRole = {
|
|
48
|
-
isAuthorized: jest.fn().mockResolvedValue(true),
|
|
49
|
-
};
|
|
50
|
-
mockThrottle = {};
|
|
51
|
-
strategy = new TestBaseAuthStrategy(config, mockSessionHandler, mockLogger);
|
|
52
|
-
strategy.accountLock = mockAccountLock;
|
|
53
|
-
strategy.mfa = mockMfa;
|
|
54
|
-
strategy.rateLimit = mockRateLimit;
|
|
55
|
-
strategy.role = mockRole;
|
|
56
|
-
strategy.throttle = mockThrottle;
|
|
57
|
-
context = {};
|
|
58
|
-
});
|
|
59
|
-
describe("constructor & init", () => {
|
|
60
|
-
it("should instantiate services and allow optional init override", async () => {
|
|
61
|
-
expect(strategy).toBeDefined();
|
|
62
|
-
await expect(strategy.init()).resolves.toBeUndefined();
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
describe("onSuccess", () => {
|
|
66
|
-
it("should call config.onSuccess if defined and log errors if it fails", async () => {
|
|
67
|
-
const spy = jest.spyOn(config, "onSuccess");
|
|
68
|
-
await strategy.onSuccess("someAction", {
|
|
69
|
-
user: { id: "1", name: "Bob" },
|
|
70
|
-
context,
|
|
71
|
-
});
|
|
72
|
-
expect(spy).toHaveBeenCalledWith("someAction", {
|
|
73
|
-
user: { id: "1", name: "Bob" },
|
|
74
|
-
context,
|
|
75
|
-
});
|
|
76
|
-
});
|
|
77
|
-
it("should log error if config.onSuccess throws", async () => {
|
|
78
|
-
const error = new Error("onSuccess error");
|
|
79
|
-
config.onSuccess = jest.fn().mockRejectedValue(error);
|
|
80
|
-
await strategy.onSuccess("someAction", {
|
|
81
|
-
user: { id: "1", name: "Bob" },
|
|
82
|
-
context,
|
|
83
|
-
});
|
|
84
|
-
expect(mockLogger.error).toHaveBeenCalledWith(error);
|
|
85
|
-
});
|
|
86
|
-
});
|
|
87
|
-
describe("onFailure", () => {
|
|
88
|
-
it("should call config.onFailure if defined and log with logger.error", async () => {
|
|
89
|
-
const spy = jest.spyOn(config, "onFailure");
|
|
90
|
-
await strategy.onFailure("someAction", {
|
|
91
|
-
context,
|
|
92
|
-
error: new Error("Failure reason"),
|
|
93
|
-
});
|
|
94
|
-
expect(mockLogger.error).toHaveBeenCalledWith("someAction failed:", expect.any(Error));
|
|
95
|
-
expect(spy).toHaveBeenCalledWith("someAction", {
|
|
96
|
-
context,
|
|
97
|
-
error: expect.any(Error),
|
|
98
|
-
});
|
|
99
|
-
});
|
|
100
|
-
it("should log error if config.onFailure throws", async () => {
|
|
101
|
-
config.onFailure = jest
|
|
102
|
-
.fn()
|
|
103
|
-
.mockRejectedValue(new Error("onFailure error"));
|
|
104
|
-
await strategy.onFailure("someAction", {
|
|
105
|
-
context,
|
|
106
|
-
error: new Error("boom"),
|
|
107
|
-
});
|
|
108
|
-
expect(mockLogger.error).toHaveBeenCalledWith("someAction failed:", expect.any(Error));
|
|
109
|
-
expect(mockLogger.error).toHaveBeenCalledWith(expect.any(Error));
|
|
110
|
-
});
|
|
111
|
-
});
|
|
112
|
-
describe("authenticateWithSession", () => {
|
|
113
|
-
it("should throw MissingSessionIdError if getSessionId returns undefined", async () => {
|
|
114
|
-
mockSessionHandler.getSessionId.mockReturnValueOnce(undefined);
|
|
115
|
-
await expect(strategy.authenticateWithSession(context)).rejects.toThrow(session_errors_1.MissingSessionIdError);
|
|
116
|
-
});
|
|
117
|
-
it("should throw InvalidSessionError if getSessionData returns null/undefined", async () => {
|
|
118
|
-
mockSessionHandler.getSessionData.mockResolvedValueOnce(null);
|
|
119
|
-
await expect(strategy.authenticateWithSession(context)).rejects.toThrow(session_errors_1.InvalidSessionError);
|
|
120
|
-
});
|
|
121
|
-
it("should call rateLimit.checkRateLimit, role.isAuthorized, and return user from session", async () => {
|
|
122
|
-
const result = await strategy.authenticateWithSession(context);
|
|
123
|
-
expect(mockRateLimit.checkRateLimit).toHaveBeenCalledWith(context);
|
|
124
|
-
expect(mockRole.isAuthorized).toHaveBeenCalledWith({
|
|
125
|
-
id: "123",
|
|
126
|
-
name: "TestUser",
|
|
127
|
-
});
|
|
128
|
-
expect(result).toEqual({ user: { id: "123", name: "TestUser" } });
|
|
129
|
-
});
|
|
130
|
-
});
|
|
131
|
-
describe("authenticate", () => {
|
|
132
|
-
it("should be implemented by the concrete class", async () => {
|
|
133
|
-
const res = await strategy.authenticate(context);
|
|
134
|
-
expect(res).toEqual({ user: null });
|
|
135
|
-
});
|
|
136
|
-
});
|
|
137
|
-
});
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { CredentialAuthStrategyConfig } from "../../../src/types";
|
|
2
|
-
import { SessionHandler } from "../../../src/session/session-handler";
|
|
3
|
-
import { JwtStrategy } from "../../../src/strategies/jwt/jwt.strategy";
|
|
4
|
-
import * as Soap from "@soapjs/soap";
|
|
5
|
-
import { CredentialAuthStrategy } from "../credential-auth.strategy";
|
|
6
|
-
export declare class TestCredentialAuthStrategy extends CredentialAuthStrategy<any, any> {
|
|
7
|
-
constructor(config: CredentialAuthStrategyConfig<any, any>, session?: SessionHandler, jwt?: JwtStrategy<any, any>, logger?: Soap.Logger);
|
|
8
|
-
protected verifyCredentials(identifier: string, password: string): Promise<boolean>;
|
|
9
|
-
protected extractCredentials(context: any): Promise<{
|
|
10
|
-
identifier: string;
|
|
11
|
-
password: string;
|
|
12
|
-
}>;
|
|
13
|
-
protected fetchUser(credentials: any): Promise<any | null>;
|
|
14
|
-
}
|