@optimizely-opal/opal-tool-ocp-sdk 0.0.0-OCP-1487.4 → 0.0.0-OCP-1487.6
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/README.md +103 -14
- package/dist/auth/AuthUtils.d.ts +12 -28
- package/dist/auth/AuthUtils.d.ts.map +1 -1
- package/dist/auth/AuthUtils.js +94 -50
- package/dist/auth/AuthUtils.js.map +1 -1
- package/dist/auth/AuthUtils.test.js +535 -403
- package/dist/auth/AuthUtils.test.js.map +1 -1
- package/dist/decorator/Decorator.d.ts +1 -0
- package/dist/decorator/Decorator.d.ts.map +1 -1
- package/dist/decorator/Decorator.js +1 -1
- package/dist/decorator/Decorator.js.map +1 -1
- package/dist/decorator/Decorator.test.js +33 -11
- package/dist/decorator/Decorator.test.js.map +1 -1
- package/dist/function/GlobalToolFunction.d.ts +0 -1
- package/dist/function/GlobalToolFunction.d.ts.map +1 -1
- package/dist/function/GlobalToolFunction.js +1 -10
- package/dist/function/GlobalToolFunction.js.map +1 -1
- package/dist/function/ToolFunction.d.ts +0 -1
- package/dist/function/ToolFunction.d.ts.map +1 -1
- package/dist/function/ToolFunction.js +1 -13
- package/dist/function/ToolFunction.js.map +1 -1
- package/dist/service/Service.d.ts.map +1 -1
- package/dist/service/Service.js.map +1 -1
- package/package.json +1 -1
- package/src/auth/AuthUtils.test.ts +638 -495
- package/src/auth/AuthUtils.ts +99 -48
- package/src/decorator/Decorator.test.ts +52 -10
- package/src/decorator/Decorator.ts +3 -1
- package/src/function/GlobalToolFunction.ts +2 -14
- package/src/function/ToolFunction.ts +2 -18
- package/src/service/Service.ts +4 -2
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
|
|
3
|
+
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
|
4
4
|
const app_sdk_1 = require("@zaiusinc/app-sdk");
|
|
5
5
|
const TokenVerifier_1 = require("./TokenVerifier");
|
|
6
|
+
const AuthUtils_1 = require("./AuthUtils");
|
|
6
7
|
// Mock the dependencies
|
|
7
8
|
jest.mock('./TokenVerifier', () => ({
|
|
8
9
|
getTokenVerifier: jest.fn(),
|
|
@@ -17,452 +18,583 @@ jest.mock('@zaiusinc/app-sdk', () => ({
|
|
|
17
18
|
},
|
|
18
19
|
}));
|
|
19
20
|
describe('AuthUtils', () => {
|
|
21
|
+
let mockTokenVerifier;
|
|
20
22
|
let mockGetTokenVerifier;
|
|
21
23
|
let mockGetAppContext;
|
|
22
|
-
let mockTokenVerifier;
|
|
23
24
|
beforeEach(() => {
|
|
24
25
|
jest.clearAllMocks();
|
|
25
|
-
//
|
|
26
|
+
// Setup token verifier mock
|
|
26
27
|
mockTokenVerifier = {
|
|
27
28
|
verify: jest.fn(),
|
|
28
29
|
};
|
|
29
|
-
|
|
30
|
-
mockGetTokenVerifier = jest.mocked(TokenVerifier_1.getTokenVerifier);
|
|
31
|
-
mockGetAppContext = jest.mocked(app_sdk_1.getAppContext);
|
|
30
|
+
mockGetTokenVerifier = TokenVerifier_1.getTokenVerifier;
|
|
32
31
|
mockGetTokenVerifier.mockResolvedValue(mockTokenVerifier);
|
|
32
|
+
// Setup app context mock with default organization
|
|
33
|
+
mockGetAppContext = app_sdk_1.getAppContext;
|
|
33
34
|
mockGetAppContext.mockReturnValue({
|
|
34
35
|
account: {
|
|
35
|
-
organizationId: '
|
|
36
|
+
organizationId: 'test-org-123'
|
|
36
37
|
}
|
|
37
38
|
});
|
|
38
39
|
});
|
|
39
|
-
describe('
|
|
40
|
-
|
|
41
|
-
//
|
|
42
|
-
const validToken = 'valid-access-token';
|
|
40
|
+
describe('authorizeRegularRequest', () => {
|
|
41
|
+
beforeEach(() => {
|
|
42
|
+
// Default to successful token verification
|
|
43
43
|
mockTokenVerifier.verify.mockResolvedValue(true);
|
|
44
|
-
// Act
|
|
45
|
-
const result = await AuthUtils_1.AuthUtils.validateAccessToken(validToken);
|
|
46
|
-
// Assert
|
|
47
|
-
expect(result).toBe(true);
|
|
48
|
-
expect(mockGetTokenVerifier).toHaveBeenCalledTimes(1);
|
|
49
|
-
expect(mockTokenVerifier.verify).toHaveBeenCalledWith(validToken);
|
|
50
|
-
expect(app_sdk_1.logger.error).not.toHaveBeenCalled();
|
|
51
|
-
});
|
|
52
|
-
it('should return false for invalid token', async () => {
|
|
53
|
-
// Arrange
|
|
54
|
-
const invalidToken = 'invalid-access-token';
|
|
55
|
-
mockTokenVerifier.verify.mockResolvedValue(false);
|
|
56
|
-
// Act
|
|
57
|
-
const result = await AuthUtils_1.AuthUtils.validateAccessToken(invalidToken);
|
|
58
|
-
// Assert
|
|
59
|
-
expect(result).toBe(false);
|
|
60
|
-
expect(mockGetTokenVerifier).toHaveBeenCalledTimes(1);
|
|
61
|
-
expect(mockTokenVerifier.verify).toHaveBeenCalledWith(invalidToken);
|
|
62
|
-
expect(app_sdk_1.logger.error).not.toHaveBeenCalled();
|
|
63
|
-
});
|
|
64
|
-
it('should return false for undefined token', async () => {
|
|
65
|
-
// Act
|
|
66
|
-
const result = await AuthUtils_1.AuthUtils.validateAccessToken(undefined);
|
|
67
|
-
// Assert
|
|
68
|
-
expect(result).toBe(false);
|
|
69
|
-
expect(mockGetTokenVerifier).not.toHaveBeenCalled();
|
|
70
|
-
expect(mockTokenVerifier.verify).not.toHaveBeenCalled();
|
|
71
|
-
expect(app_sdk_1.logger.error).not.toHaveBeenCalled();
|
|
72
|
-
});
|
|
73
|
-
it('should return false for null token', async () => {
|
|
74
|
-
// Act
|
|
75
|
-
const result = await AuthUtils_1.AuthUtils.validateAccessToken(null);
|
|
76
|
-
// Assert
|
|
77
|
-
expect(result).toBe(false);
|
|
78
|
-
expect(mockGetTokenVerifier).not.toHaveBeenCalled();
|
|
79
|
-
expect(mockTokenVerifier.verify).not.toHaveBeenCalled();
|
|
80
|
-
expect(app_sdk_1.logger.error).not.toHaveBeenCalled();
|
|
81
|
-
});
|
|
82
|
-
it('should return false for empty string token', async () => {
|
|
83
|
-
// Act
|
|
84
|
-
const result = await AuthUtils_1.AuthUtils.validateAccessToken('');
|
|
85
|
-
// Assert
|
|
86
|
-
expect(result).toBe(false);
|
|
87
|
-
expect(mockGetTokenVerifier).not.toHaveBeenCalled();
|
|
88
|
-
expect(mockTokenVerifier.verify).not.toHaveBeenCalled();
|
|
89
|
-
expect(app_sdk_1.logger.error).not.toHaveBeenCalled();
|
|
90
44
|
});
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
expect(result).toBe(false);
|
|
100
|
-
expect(mockGetTokenVerifier).toHaveBeenCalledTimes(1);
|
|
101
|
-
expect(mockTokenVerifier.verify).not.toHaveBeenCalled();
|
|
102
|
-
expect(app_sdk_1.logger.error).toHaveBeenCalledWith('OptiID token validation failed:', error);
|
|
103
|
-
});
|
|
104
|
-
it('should return false and log error when token verification throws', async () => {
|
|
105
|
-
// Arrange
|
|
106
|
-
const validToken = 'valid-access-token';
|
|
107
|
-
const error = new Error('Token verification failed');
|
|
108
|
-
mockTokenVerifier.verify.mockRejectedValue(error);
|
|
109
|
-
// Act
|
|
110
|
-
const result = await AuthUtils_1.AuthUtils.validateAccessToken(validToken);
|
|
111
|
-
// Assert
|
|
112
|
-
expect(result).toBe(false);
|
|
113
|
-
expect(mockGetTokenVerifier).toHaveBeenCalledTimes(1);
|
|
114
|
-
expect(mockTokenVerifier.verify).toHaveBeenCalledWith(validToken);
|
|
115
|
-
expect(app_sdk_1.logger.error).toHaveBeenCalledWith('OptiID token validation failed:', error);
|
|
45
|
+
describe('when request is for discovery endpoint', () => {
|
|
46
|
+
it('should return true without authentication', async () => {
|
|
47
|
+
const request = { path: '/discovery' };
|
|
48
|
+
const result = await (0, AuthUtils_1.authorizeRegularRequest)(request);
|
|
49
|
+
expect(result).toBe(true);
|
|
50
|
+
expect(mockGetTokenVerifier).not.toHaveBeenCalled();
|
|
51
|
+
expect(mockTokenVerifier.verify).not.toHaveBeenCalled();
|
|
52
|
+
});
|
|
116
53
|
});
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
expect(mockTokenVerifier.verify).toHaveBeenCalledWith(' ');
|
|
54
|
+
describe('when request is for ready endpoint', () => {
|
|
55
|
+
it('should return true without authentication', async () => {
|
|
56
|
+
const request = { path: '/ready' };
|
|
57
|
+
const result = await (0, AuthUtils_1.authorizeRegularRequest)(request);
|
|
58
|
+
expect(result).toBe(true);
|
|
59
|
+
expect(mockGetTokenVerifier).not.toHaveBeenCalled();
|
|
60
|
+
expect(mockTokenVerifier.verify).not.toHaveBeenCalled();
|
|
61
|
+
});
|
|
126
62
|
});
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
63
|
+
describe('when request has valid authentication', () => {
|
|
64
|
+
it('should return true for valid OptiID token with matching organization', async () => {
|
|
65
|
+
const request = {
|
|
66
|
+
path: '/some-tool',
|
|
67
|
+
bodyJSON: {
|
|
68
|
+
auth: {
|
|
69
|
+
provider: 'OptiID',
|
|
70
|
+
credentials: {
|
|
71
|
+
customer_id: 'test-org-123',
|
|
72
|
+
access_token: 'valid-token-123'
|
|
73
|
+
}
|
|
74
|
+
}
|
|
138
75
|
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
request.bodyJSON.auth.provider = 'optiid'; // lowercase
|
|
157
|
-
// Act
|
|
158
|
-
const result = AuthUtils_1.AuthUtils.extractAuthData(request);
|
|
159
|
-
// Assert
|
|
160
|
-
expect(result).not.toBeNull();
|
|
161
|
-
expect(result?.authData).toBe(request.bodyJSON.auth);
|
|
162
|
-
expect(result?.accessToken).toBe('valid-access-token');
|
|
163
|
-
expect(app_sdk_1.logger.error).not.toHaveBeenCalled();
|
|
164
|
-
});
|
|
165
|
-
it('should handle mixed case provider name', () => {
|
|
166
|
-
// Arrange
|
|
167
|
-
const request = createValidRequest();
|
|
168
|
-
request.bodyJSON.auth.provider = 'OpTiId'; // mixed case
|
|
169
|
-
// Act
|
|
170
|
-
const result = AuthUtils_1.AuthUtils.extractAuthData(request);
|
|
171
|
-
// Assert
|
|
172
|
-
expect(result).not.toBeNull();
|
|
173
|
-
expect(result?.authData).toBe(request.bodyJSON.auth);
|
|
174
|
-
expect(result?.accessToken).toBe('valid-access-token');
|
|
175
|
-
expect(app_sdk_1.logger.error).not.toHaveBeenCalled();
|
|
176
|
-
});
|
|
177
|
-
it('should return null when access token is missing', () => {
|
|
178
|
-
// Arrange
|
|
179
|
-
const request = createValidRequest();
|
|
180
|
-
delete request.bodyJSON.auth.credentials.access_token;
|
|
181
|
-
// Act
|
|
182
|
-
const result = AuthUtils_1.AuthUtils.extractAuthData(request);
|
|
183
|
-
// Assert
|
|
184
|
-
expect(result).toBeNull();
|
|
185
|
-
expect(app_sdk_1.logger.error).toHaveBeenCalledWith('OptiID token is required but not provided');
|
|
186
|
-
});
|
|
187
|
-
it('should return null when access token is undefined', () => {
|
|
188
|
-
// Arrange
|
|
189
|
-
const request = createValidRequest();
|
|
190
|
-
request.bodyJSON.auth.credentials.access_token = undefined;
|
|
191
|
-
// Act
|
|
192
|
-
const result = AuthUtils_1.AuthUtils.extractAuthData(request);
|
|
193
|
-
// Assert
|
|
194
|
-
expect(result).toBeNull();
|
|
195
|
-
expect(app_sdk_1.logger.error).toHaveBeenCalledWith('OptiID token is required but not provided');
|
|
196
|
-
});
|
|
197
|
-
it('should return null when access token is empty string', () => {
|
|
198
|
-
// Arrange
|
|
199
|
-
const request = createValidRequest();
|
|
200
|
-
request.bodyJSON.auth.credentials.access_token = '';
|
|
201
|
-
// Act
|
|
202
|
-
const result = AuthUtils_1.AuthUtils.extractAuthData(request);
|
|
203
|
-
// Assert
|
|
204
|
-
expect(result).toBeNull();
|
|
205
|
-
expect(app_sdk_1.logger.error).toHaveBeenCalledWith('OptiID token is required but not provided');
|
|
206
|
-
});
|
|
207
|
-
it('should return null when provider is not OptiID', () => {
|
|
208
|
-
// Arrange
|
|
209
|
-
const request = createValidRequest();
|
|
210
|
-
request.bodyJSON.auth.provider = 'SomeOtherProvider';
|
|
211
|
-
// Act
|
|
212
|
-
const result = AuthUtils_1.AuthUtils.extractAuthData(request);
|
|
213
|
-
// Assert
|
|
214
|
-
expect(result).toBeNull();
|
|
215
|
-
expect(app_sdk_1.logger.error).toHaveBeenCalledWith('OptiID token is required but not provided');
|
|
216
|
-
});
|
|
217
|
-
it('should return null when provider is missing', () => {
|
|
218
|
-
// Arrange
|
|
219
|
-
const request = createValidRequest();
|
|
220
|
-
delete request.bodyJSON.auth.provider;
|
|
221
|
-
// Act
|
|
222
|
-
const result = AuthUtils_1.AuthUtils.extractAuthData(request);
|
|
223
|
-
// Assert
|
|
224
|
-
expect(result).toBeNull();
|
|
225
|
-
expect(app_sdk_1.logger.error).toHaveBeenCalledWith('OptiID token is required but not provided');
|
|
226
|
-
});
|
|
227
|
-
it('should return null when auth structure is missing', () => {
|
|
228
|
-
// Arrange
|
|
229
|
-
const request = {
|
|
230
|
-
bodyJSON: {
|
|
231
|
-
parameters: { some: 'data' }
|
|
232
|
-
}
|
|
233
|
-
};
|
|
234
|
-
// Act
|
|
235
|
-
const result = AuthUtils_1.AuthUtils.extractAuthData(request);
|
|
236
|
-
// Assert
|
|
237
|
-
expect(result).toBeNull();
|
|
238
|
-
expect(app_sdk_1.logger.error).toHaveBeenCalledWith('OptiID token is required but not provided');
|
|
239
|
-
});
|
|
240
|
-
it('should return null when credentials structure is missing', () => {
|
|
241
|
-
// Arrange
|
|
242
|
-
const request = {
|
|
243
|
-
bodyJSON: {
|
|
244
|
-
auth: {
|
|
245
|
-
provider: 'OptiID'
|
|
76
|
+
};
|
|
77
|
+
const result = await (0, AuthUtils_1.authorizeRegularRequest)(request);
|
|
78
|
+
expect(result).toBe(true);
|
|
79
|
+
expect(mockGetTokenVerifier).toHaveBeenCalled();
|
|
80
|
+
expect(mockTokenVerifier.verify).toHaveBeenCalledWith('valid-token-123');
|
|
81
|
+
});
|
|
82
|
+
it('should handle case-insensitive provider names', async () => {
|
|
83
|
+
const request = {
|
|
84
|
+
path: '/some-tool',
|
|
85
|
+
bodyJSON: {
|
|
86
|
+
auth: {
|
|
87
|
+
provider: 'optiid', // lowercase
|
|
88
|
+
credentials: {
|
|
89
|
+
customer_id: 'test-org-123',
|
|
90
|
+
access_token: 'valid-token-123'
|
|
91
|
+
}
|
|
92
|
+
}
|
|
246
93
|
}
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
94
|
+
};
|
|
95
|
+
const result = await (0, AuthUtils_1.authorizeRegularRequest)(request);
|
|
96
|
+
expect(result).toBe(true);
|
|
97
|
+
expect(mockTokenVerifier.verify).toHaveBeenCalledWith('valid-token-123');
|
|
98
|
+
});
|
|
99
|
+
it('should handle mixed case provider names', async () => {
|
|
100
|
+
const request = {
|
|
101
|
+
path: '/some-tool',
|
|
102
|
+
bodyJSON: {
|
|
103
|
+
auth: {
|
|
104
|
+
provider: 'OpTiId', // mixed case
|
|
105
|
+
credentials: {
|
|
106
|
+
customer_id: 'test-org-123',
|
|
107
|
+
access_token: 'valid-token-123'
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
const result = await (0, AuthUtils_1.authorizeRegularRequest)(request);
|
|
113
|
+
expect(result).toBe(true);
|
|
114
|
+
expect(mockTokenVerifier.verify).toHaveBeenCalledWith('valid-token-123');
|
|
115
|
+
});
|
|
254
116
|
});
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
117
|
+
describe('when authentication fails', () => {
|
|
118
|
+
it('should return false when auth data is missing', async () => {
|
|
119
|
+
const request = {
|
|
120
|
+
path: '/some-tool',
|
|
121
|
+
bodyJSON: {}
|
|
122
|
+
};
|
|
123
|
+
const result = await (0, AuthUtils_1.authorizeRegularRequest)(request);
|
|
124
|
+
expect(result).toBe(false);
|
|
125
|
+
expect(app_sdk_1.logger.error).toHaveBeenCalledWith('OptiID token is required but not provided');
|
|
126
|
+
expect(mockTokenVerifier.verify).not.toHaveBeenCalled();
|
|
127
|
+
});
|
|
128
|
+
it('should return false when bodyJSON is missing', async () => {
|
|
129
|
+
const request = {
|
|
130
|
+
path: '/some-tool'
|
|
131
|
+
};
|
|
132
|
+
const result = await (0, AuthUtils_1.authorizeRegularRequest)(request);
|
|
133
|
+
expect(result).toBe(false);
|
|
134
|
+
expect(app_sdk_1.logger.error).toHaveBeenCalledWith('OptiID token is required but not provided');
|
|
135
|
+
});
|
|
136
|
+
it('should return false when provider is not OptiID', async () => {
|
|
137
|
+
const request = {
|
|
138
|
+
path: '/some-tool',
|
|
139
|
+
bodyJSON: {
|
|
140
|
+
auth: {
|
|
141
|
+
provider: 'SomeOtherProvider',
|
|
142
|
+
credentials: {
|
|
143
|
+
customer_id: 'test-org-123',
|
|
144
|
+
access_token: 'some-token'
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
const result = await (0, AuthUtils_1.authorizeRegularRequest)(request);
|
|
150
|
+
expect(result).toBe(false);
|
|
151
|
+
expect(app_sdk_1.logger.error).toHaveBeenCalledWith('OptiID token is required but not provided');
|
|
152
|
+
});
|
|
153
|
+
it('should return false when access token is missing', async () => {
|
|
154
|
+
const request = {
|
|
155
|
+
path: '/some-tool',
|
|
156
|
+
bodyJSON: {
|
|
157
|
+
auth: {
|
|
158
|
+
provider: 'OptiID',
|
|
159
|
+
credentials: {
|
|
160
|
+
customer_id: 'test-org-123'
|
|
161
|
+
// access_token missing
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
const result = await (0, AuthUtils_1.authorizeRegularRequest)(request);
|
|
167
|
+
expect(result).toBe(false);
|
|
168
|
+
expect(app_sdk_1.logger.error).toHaveBeenCalledWith('OptiID token is required but not provided');
|
|
169
|
+
});
|
|
170
|
+
it('should return false when access token is empty string', async () => {
|
|
171
|
+
const request = {
|
|
172
|
+
path: '/some-tool',
|
|
173
|
+
bodyJSON: {
|
|
174
|
+
auth: {
|
|
175
|
+
provider: 'OptiID',
|
|
176
|
+
credentials: {
|
|
177
|
+
customer_id: 'test-org-123',
|
|
178
|
+
access_token: ''
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
const result = await (0, AuthUtils_1.authorizeRegularRequest)(request);
|
|
184
|
+
expect(result).toBe(false);
|
|
185
|
+
expect(app_sdk_1.logger.error).toHaveBeenCalledWith('OptiID token is required but not provided');
|
|
186
|
+
});
|
|
187
|
+
it('should return false when access token is undefined', async () => {
|
|
188
|
+
const request = {
|
|
189
|
+
path: '/some-tool',
|
|
190
|
+
bodyJSON: {
|
|
191
|
+
auth: {
|
|
192
|
+
provider: 'OptiID',
|
|
193
|
+
credentials: {
|
|
194
|
+
customer_id: 'test-org-123',
|
|
195
|
+
access_token: undefined
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
const result = await (0, AuthUtils_1.authorizeRegularRequest)(request);
|
|
201
|
+
expect(result).toBe(false);
|
|
202
|
+
expect(app_sdk_1.logger.error).toHaveBeenCalledWith('OptiID token is required but not provided');
|
|
203
|
+
});
|
|
263
204
|
});
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
205
|
+
describe('when organization validation fails', () => {
|
|
206
|
+
it('should return false when customer_id does not match app organization', async () => {
|
|
207
|
+
const request = {
|
|
208
|
+
path: '/some-tool',
|
|
209
|
+
bodyJSON: {
|
|
210
|
+
auth: {
|
|
211
|
+
provider: 'OptiID',
|
|
212
|
+
credentials: {
|
|
213
|
+
customer_id: 'different-org-456',
|
|
214
|
+
access_token: 'valid-token-123'
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
const result = await (0, AuthUtils_1.authorizeRegularRequest)(request);
|
|
220
|
+
expect(result).toBe(false);
|
|
221
|
+
expect(app_sdk_1.logger.error).toHaveBeenCalledWith('Invalid organisation ID: expected test-org-123, received different-org-456');
|
|
222
|
+
expect(mockTokenVerifier.verify).not.toHaveBeenCalled();
|
|
223
|
+
});
|
|
224
|
+
it('should return false when customer_id is missing', async () => {
|
|
225
|
+
const request = {
|
|
226
|
+
path: '/some-tool',
|
|
227
|
+
bodyJSON: {
|
|
228
|
+
auth: {
|
|
229
|
+
provider: 'OptiID',
|
|
230
|
+
credentials: {
|
|
231
|
+
access_token: 'valid-token-123'
|
|
232
|
+
// customer_id missing
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
const result = await (0, AuthUtils_1.authorizeRegularRequest)(request);
|
|
238
|
+
expect(result).toBe(false);
|
|
239
|
+
expect(app_sdk_1.logger.error).toHaveBeenCalledWith('Organisation ID is required but not provided');
|
|
240
|
+
});
|
|
241
|
+
it('should return false when customer_id is empty string', async () => {
|
|
242
|
+
const request = {
|
|
243
|
+
path: '/some-tool',
|
|
244
|
+
bodyJSON: {
|
|
245
|
+
auth: {
|
|
246
|
+
provider: 'OptiID',
|
|
247
|
+
credentials: {
|
|
248
|
+
customer_id: '',
|
|
249
|
+
access_token: 'valid-token-123'
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
const result = await (0, AuthUtils_1.authorizeRegularRequest)(request);
|
|
255
|
+
expect(result).toBe(false);
|
|
256
|
+
expect(app_sdk_1.logger.error).toHaveBeenCalledWith('Organisation ID is required but not provided');
|
|
257
|
+
});
|
|
258
|
+
it('should handle case when app context has no account', async () => {
|
|
259
|
+
mockGetAppContext.mockReturnValue({});
|
|
260
|
+
const request = {
|
|
261
|
+
path: '/some-tool',
|
|
262
|
+
bodyJSON: {
|
|
263
|
+
auth: {
|
|
264
|
+
provider: 'OptiID',
|
|
265
|
+
credentials: {
|
|
266
|
+
customer_id: 'some-org-123',
|
|
267
|
+
access_token: 'valid-token-123'
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
const result = await (0, AuthUtils_1.authorizeRegularRequest)(request);
|
|
273
|
+
expect(result).toBe(false);
|
|
274
|
+
expect(app_sdk_1.logger.error).toHaveBeenCalledWith('Invalid organisation ID: expected undefined, received some-org-123');
|
|
275
|
+
});
|
|
276
|
+
it('should handle case when app context is null', async () => {
|
|
277
|
+
mockGetAppContext.mockReturnValue(null);
|
|
278
|
+
const request = {
|
|
279
|
+
path: '/some-tool',
|
|
280
|
+
bodyJSON: {
|
|
281
|
+
auth: {
|
|
282
|
+
provider: 'OptiID',
|
|
283
|
+
credentials: {
|
|
284
|
+
customer_id: 'some-org-123',
|
|
285
|
+
access_token: 'valid-token-123'
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
const result = await (0, AuthUtils_1.authorizeRegularRequest)(request);
|
|
291
|
+
expect(result).toBe(false);
|
|
292
|
+
expect(app_sdk_1.logger.error).toHaveBeenCalledWith('Invalid organisation ID: expected undefined, received some-org-123');
|
|
293
|
+
});
|
|
270
294
|
});
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
295
|
+
describe('when token validation fails', () => {
|
|
296
|
+
it('should return false when token verifier returns false', async () => {
|
|
297
|
+
mockTokenVerifier.verify.mockResolvedValue(false);
|
|
298
|
+
const request = {
|
|
299
|
+
path: '/some-tool',
|
|
300
|
+
bodyJSON: {
|
|
301
|
+
auth: {
|
|
302
|
+
provider: 'OptiID',
|
|
303
|
+
credentials: {
|
|
304
|
+
customer_id: 'test-org-123',
|
|
305
|
+
access_token: 'invalid-token'
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
const result = await (0, AuthUtils_1.authorizeRegularRequest)(request);
|
|
311
|
+
expect(result).toBe(false);
|
|
312
|
+
expect(mockTokenVerifier.verify).toHaveBeenCalledWith('invalid-token');
|
|
313
|
+
});
|
|
314
|
+
it('should return false when token verification throws an error', async () => {
|
|
315
|
+
const verificationError = new Error('Token verification failed');
|
|
316
|
+
mockTokenVerifier.verify.mockRejectedValue(verificationError);
|
|
317
|
+
const request = {
|
|
318
|
+
path: '/some-tool',
|
|
319
|
+
bodyJSON: {
|
|
320
|
+
auth: {
|
|
321
|
+
provider: 'OptiID',
|
|
322
|
+
credentials: {
|
|
323
|
+
customer_id: 'test-org-123',
|
|
324
|
+
access_token: 'error-token'
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
const result = await (0, AuthUtils_1.authorizeRegularRequest)(request);
|
|
330
|
+
expect(result).toBe(false);
|
|
331
|
+
expect(app_sdk_1.logger.error).toHaveBeenCalledWith('OptiID token validation failed:', verificationError);
|
|
332
|
+
});
|
|
333
|
+
it('should return false when getTokenVerifier throws an error', async () => {
|
|
334
|
+
const verifierError = new Error('Failed to get token verifier');
|
|
335
|
+
mockGetTokenVerifier.mockRejectedValue(verifierError);
|
|
336
|
+
const request = {
|
|
337
|
+
path: '/some-tool',
|
|
338
|
+
bodyJSON: {
|
|
339
|
+
auth: {
|
|
340
|
+
provider: 'OptiID',
|
|
341
|
+
credentials: {
|
|
342
|
+
customer_id: 'test-org-123',
|
|
343
|
+
access_token: 'some-token'
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
const result = await (0, AuthUtils_1.authorizeRegularRequest)(request);
|
|
349
|
+
expect(result).toBe(false);
|
|
350
|
+
expect(app_sdk_1.logger.error).toHaveBeenCalledWith('OptiID token validation failed:', verifierError);
|
|
351
|
+
});
|
|
277
352
|
});
|
|
278
353
|
});
|
|
279
|
-
describe('
|
|
354
|
+
describe('authorizeGlobalRequest', () => {
|
|
280
355
|
beforeEach(() => {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
organizationId: 'app-org-123'
|
|
284
|
-
}
|
|
285
|
-
});
|
|
286
|
-
});
|
|
287
|
-
it('should return true when customer ID matches app organization ID', () => {
|
|
288
|
-
// Act
|
|
289
|
-
const result = AuthUtils_1.AuthUtils.validateOrganizationId('app-org-123');
|
|
290
|
-
// Assert
|
|
291
|
-
expect(result).toBe(true);
|
|
292
|
-
expect(mockGetAppContext).toHaveBeenCalledTimes(1);
|
|
293
|
-
expect(app_sdk_1.logger.error).not.toHaveBeenCalled();
|
|
294
|
-
});
|
|
295
|
-
it('should return false when customer ID does not match app organization ID', () => {
|
|
296
|
-
// Act
|
|
297
|
-
const result = AuthUtils_1.AuthUtils.validateOrganizationId('different-org-456');
|
|
298
|
-
// Assert
|
|
299
|
-
expect(result).toBe(false);
|
|
300
|
-
expect(mockGetAppContext).toHaveBeenCalledTimes(1);
|
|
301
|
-
expect(app_sdk_1.logger.error).toHaveBeenCalledWith('Invalid organisation ID: expected app-org-123, received different-org-456');
|
|
302
|
-
});
|
|
303
|
-
it('should return false when customer ID is undefined', () => {
|
|
304
|
-
// Act
|
|
305
|
-
const result = AuthUtils_1.AuthUtils.validateOrganizationId(undefined);
|
|
306
|
-
// Assert
|
|
307
|
-
expect(result).toBe(false);
|
|
308
|
-
expect(mockGetAppContext).not.toHaveBeenCalled();
|
|
309
|
-
expect(app_sdk_1.logger.error).toHaveBeenCalledWith('Organisation ID is required but not provided');
|
|
310
|
-
});
|
|
311
|
-
it('should return false when customer ID is null', () => {
|
|
312
|
-
// Act
|
|
313
|
-
const result = AuthUtils_1.AuthUtils.validateOrganizationId(null);
|
|
314
|
-
// Assert
|
|
315
|
-
expect(result).toBe(false);
|
|
316
|
-
expect(mockGetAppContext).not.toHaveBeenCalled();
|
|
317
|
-
expect(app_sdk_1.logger.error).toHaveBeenCalledWith('Organisation ID is required but not provided');
|
|
318
|
-
});
|
|
319
|
-
it('should return false when customer ID is empty string', () => {
|
|
320
|
-
// Act
|
|
321
|
-
const result = AuthUtils_1.AuthUtils.validateOrganizationId('');
|
|
322
|
-
// Assert
|
|
323
|
-
expect(result).toBe(false);
|
|
324
|
-
expect(mockGetAppContext).not.toHaveBeenCalled();
|
|
325
|
-
expect(app_sdk_1.logger.error).toHaveBeenCalledWith('Organisation ID is required but not provided');
|
|
326
|
-
});
|
|
327
|
-
it('should handle case when app context has no account', () => {
|
|
328
|
-
// Arrange
|
|
329
|
-
mockGetAppContext.mockReturnValue({});
|
|
330
|
-
// Act
|
|
331
|
-
const result = AuthUtils_1.AuthUtils.validateOrganizationId('some-org-123');
|
|
332
|
-
// Assert
|
|
333
|
-
expect(result).toBe(false);
|
|
334
|
-
expect(mockGetAppContext).toHaveBeenCalledTimes(1);
|
|
335
|
-
expect(app_sdk_1.logger.error).toHaveBeenCalledWith('Invalid organisation ID: expected undefined, received some-org-123');
|
|
356
|
+
// Default to successful token verification
|
|
357
|
+
mockTokenVerifier.verify.mockResolvedValue(true);
|
|
336
358
|
});
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
expect(result).toBe(false);
|
|
346
|
-
expect(mockGetAppContext).toHaveBeenCalledTimes(1);
|
|
347
|
-
expect(app_sdk_1.logger.error).toHaveBeenCalledWith('Invalid organisation ID: expected undefined, received some-org-123');
|
|
359
|
+
describe('when request is for discovery endpoint', () => {
|
|
360
|
+
it('should return true without authentication', async () => {
|
|
361
|
+
const request = { path: '/discovery' };
|
|
362
|
+
const result = await (0, AuthUtils_1.authorizeGlobalRequest)(request);
|
|
363
|
+
expect(result).toBe(true);
|
|
364
|
+
expect(mockGetTokenVerifier).not.toHaveBeenCalled();
|
|
365
|
+
expect(mockTokenVerifier.verify).not.toHaveBeenCalled();
|
|
366
|
+
});
|
|
348
367
|
});
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
expect(app_sdk_1.logger.error).toHaveBeenCalledWith('Invalid organisation ID: expected undefined, received some-org-123');
|
|
368
|
+
describe('when request is for ready endpoint', () => {
|
|
369
|
+
it('should return true without authentication', async () => {
|
|
370
|
+
const request = { path: '/ready' };
|
|
371
|
+
const result = await (0, AuthUtils_1.authorizeGlobalRequest)(request);
|
|
372
|
+
expect(result).toBe(true);
|
|
373
|
+
expect(mockGetTokenVerifier).not.toHaveBeenCalled();
|
|
374
|
+
expect(mockTokenVerifier.verify).not.toHaveBeenCalled();
|
|
375
|
+
});
|
|
358
376
|
});
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
377
|
+
describe('when request has valid authentication', () => {
|
|
378
|
+
it('should return true for valid OptiID token regardless of organization', async () => {
|
|
379
|
+
const request = {
|
|
380
|
+
path: '/global-tool',
|
|
381
|
+
bodyJSON: {
|
|
382
|
+
auth: {
|
|
383
|
+
provider: 'OptiID',
|
|
384
|
+
credentials: {
|
|
385
|
+
customer_id: 'different-org-456', // Different from app org
|
|
386
|
+
access_token: 'valid-token-123'
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
};
|
|
391
|
+
const result = await (0, AuthUtils_1.authorizeGlobalRequest)(request);
|
|
392
|
+
expect(result).toBe(true);
|
|
393
|
+
expect(mockTokenVerifier.verify).toHaveBeenCalledWith('valid-token-123');
|
|
394
|
+
// Should not log organization validation errors for global requests
|
|
395
|
+
expect(app_sdk_1.logger.error).not.toHaveBeenCalledWith(expect.stringContaining('Invalid organisation ID'));
|
|
396
|
+
});
|
|
397
|
+
it('should return true even without customer_id', async () => {
|
|
398
|
+
const request = {
|
|
399
|
+
path: '/global-tool',
|
|
400
|
+
bodyJSON: {
|
|
401
|
+
auth: {
|
|
402
|
+
provider: 'OptiID',
|
|
403
|
+
credentials: {
|
|
404
|
+
access_token: 'valid-token-123'
|
|
405
|
+
// No customer_id - should be fine for global functions
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
const result = await (0, AuthUtils_1.authorizeGlobalRequest)(request);
|
|
411
|
+
expect(result).toBe(true);
|
|
412
|
+
expect(mockTokenVerifier.verify).toHaveBeenCalledWith('valid-token-123');
|
|
413
|
+
});
|
|
414
|
+
it('should handle case-insensitive provider names', async () => {
|
|
415
|
+
const request = {
|
|
416
|
+
path: '/global-tool',
|
|
417
|
+
bodyJSON: {
|
|
418
|
+
auth: {
|
|
419
|
+
provider: 'optiid',
|
|
420
|
+
credentials: {
|
|
421
|
+
customer_id: 'any-org',
|
|
422
|
+
access_token: 'valid-token-123'
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
};
|
|
427
|
+
const result = await (0, AuthUtils_1.authorizeGlobalRequest)(request);
|
|
428
|
+
expect(result).toBe(true);
|
|
429
|
+
expect(mockTokenVerifier.verify).toHaveBeenCalledWith('valid-token-123');
|
|
365
430
|
});
|
|
366
|
-
// Act
|
|
367
|
-
const result = AuthUtils_1.AuthUtils.validateOrganizationId('app-org-123');
|
|
368
|
-
// Assert
|
|
369
|
-
expect(result).toBe(false);
|
|
370
|
-
expect(mockGetAppContext).toHaveBeenCalledTimes(1);
|
|
371
|
-
expect(app_sdk_1.logger.error).toHaveBeenCalledWith('Invalid organisation ID: expected App-Org-123, received app-org-123');
|
|
372
431
|
});
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
432
|
+
describe('when authentication fails', () => {
|
|
433
|
+
it('should return false when auth data is missing', async () => {
|
|
434
|
+
const request = {
|
|
435
|
+
path: '/global-tool',
|
|
436
|
+
bodyJSON: {}
|
|
437
|
+
};
|
|
438
|
+
const result = await (0, AuthUtils_1.authorizeGlobalRequest)(request);
|
|
439
|
+
expect(result).toBe(false);
|
|
440
|
+
expect(app_sdk_1.logger.error).toHaveBeenCalledWith('OptiID token is required but not provided');
|
|
441
|
+
});
|
|
442
|
+
it('should return false when provider is not OptiID', async () => {
|
|
443
|
+
const request = {
|
|
444
|
+
path: '/global-tool',
|
|
445
|
+
bodyJSON: {
|
|
446
|
+
auth: {
|
|
447
|
+
provider: 'SomeOtherProvider',
|
|
448
|
+
credentials: {
|
|
449
|
+
customer_id: 'any-org',
|
|
450
|
+
access_token: 'some-token'
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
};
|
|
455
|
+
const result = await (0, AuthUtils_1.authorizeGlobalRequest)(request);
|
|
456
|
+
expect(result).toBe(false);
|
|
457
|
+
expect(app_sdk_1.logger.error).toHaveBeenCalledWith('OptiID token is required but not provided');
|
|
458
|
+
});
|
|
459
|
+
it('should return false when access token is missing', async () => {
|
|
460
|
+
const request = {
|
|
461
|
+
path: '/global-tool',
|
|
462
|
+
bodyJSON: {
|
|
463
|
+
auth: {
|
|
464
|
+
provider: 'OptiID',
|
|
465
|
+
credentials: {
|
|
466
|
+
customer_id: 'any-org'
|
|
467
|
+
// access_token missing
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
};
|
|
472
|
+
const result = await (0, AuthUtils_1.authorizeGlobalRequest)(request);
|
|
473
|
+
expect(result).toBe(false);
|
|
474
|
+
expect(app_sdk_1.logger.error).toHaveBeenCalledWith('OptiID token is required but not provided');
|
|
475
|
+
});
|
|
476
|
+
it('should return false when access token is empty', async () => {
|
|
477
|
+
const request = {
|
|
478
|
+
path: '/global-tool',
|
|
479
|
+
bodyJSON: {
|
|
480
|
+
auth: {
|
|
481
|
+
provider: 'OptiID',
|
|
482
|
+
credentials: {
|
|
483
|
+
customer_id: 'any-org',
|
|
484
|
+
access_token: ''
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
};
|
|
489
|
+
const result = await (0, AuthUtils_1.authorizeGlobalRequest)(request);
|
|
490
|
+
expect(result).toBe(false);
|
|
491
|
+
expect(app_sdk_1.logger.error).toHaveBeenCalledWith('OptiID token is required but not provided');
|
|
492
|
+
});
|
|
380
493
|
});
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
product_sku: 'OPAL'
|
|
494
|
+
describe('when token validation fails', () => {
|
|
495
|
+
it('should return false when token verifier returns false', async () => {
|
|
496
|
+
mockTokenVerifier.verify.mockResolvedValue(false);
|
|
497
|
+
const request = {
|
|
498
|
+
path: '/global-tool',
|
|
499
|
+
bodyJSON: {
|
|
500
|
+
auth: {
|
|
501
|
+
provider: 'OptiID',
|
|
502
|
+
credentials: {
|
|
503
|
+
customer_id: 'any-org',
|
|
504
|
+
access_token: 'invalid-token'
|
|
505
|
+
}
|
|
394
506
|
}
|
|
395
507
|
}
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
508
|
+
};
|
|
509
|
+
const result = await (0, AuthUtils_1.authorizeGlobalRequest)(request);
|
|
510
|
+
expect(result).toBe(false);
|
|
511
|
+
expect(mockTokenVerifier.verify).toHaveBeenCalledWith('invalid-token');
|
|
512
|
+
});
|
|
513
|
+
it('should return false when token verification throws an error', async () => {
|
|
514
|
+
const verificationError = new Error('Global token verification failed');
|
|
515
|
+
mockTokenVerifier.verify.mockRejectedValue(verificationError);
|
|
516
|
+
const request = {
|
|
517
|
+
path: '/global-tool',
|
|
518
|
+
bodyJSON: {
|
|
519
|
+
auth: {
|
|
520
|
+
provider: 'OptiID',
|
|
521
|
+
credentials: {
|
|
522
|
+
customer_id: 'any-org',
|
|
523
|
+
access_token: 'error-token'
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
};
|
|
528
|
+
const result = await (0, AuthUtils_1.authorizeGlobalRequest)(request);
|
|
529
|
+
expect(result).toBe(false);
|
|
530
|
+
expect(app_sdk_1.logger.error).toHaveBeenCalledWith('OptiID token validation failed:', verificationError);
|
|
402
531
|
});
|
|
403
|
-
mockTokenVerifier.verify.mockResolvedValue(true);
|
|
404
|
-
// Act
|
|
405
|
-
const authInfo = AuthUtils_1.AuthUtils.extractAuthData(request);
|
|
406
|
-
const isValidOrg = authInfo
|
|
407
|
-
? AuthUtils_1.AuthUtils.validateOrganizationId(authInfo.authData.credentials?.customer_id)
|
|
408
|
-
: false;
|
|
409
|
-
const isValidToken = authInfo ? await AuthUtils_1.AuthUtils.validateAccessToken(authInfo.accessToken) : false;
|
|
410
|
-
// Assert
|
|
411
|
-
expect(authInfo).not.toBeNull();
|
|
412
|
-
expect(isValidOrg).toBe(true);
|
|
413
|
-
expect(isValidToken).toBe(true);
|
|
414
|
-
expect(app_sdk_1.logger.error).not.toHaveBeenCalled();
|
|
415
532
|
});
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
533
|
+
describe('organization validation differences from authorizeRegularRequest', () => {
|
|
534
|
+
it('should NOT validate organization ID and allow any customer_id', async () => {
|
|
535
|
+
const request = {
|
|
536
|
+
path: '/global-tool',
|
|
537
|
+
bodyJSON: {
|
|
538
|
+
auth: {
|
|
539
|
+
provider: 'OptiID',
|
|
540
|
+
credentials: {
|
|
541
|
+
customer_id: 'completely-different-org',
|
|
542
|
+
access_token: 'valid-token-123'
|
|
543
|
+
}
|
|
427
544
|
}
|
|
428
545
|
}
|
|
429
|
-
}
|
|
546
|
+
};
|
|
547
|
+
const result = await (0, AuthUtils_1.authorizeGlobalRequest)(request);
|
|
548
|
+
expect(result).toBe(true);
|
|
549
|
+
expect(mockTokenVerifier.verify).toHaveBeenCalledWith('valid-token-123');
|
|
550
|
+
// Should NOT log organization validation errors
|
|
551
|
+
expect(app_sdk_1.logger.error).not.toHaveBeenCalledWith(expect.stringContaining('Invalid organisation ID'));
|
|
552
|
+
expect(app_sdk_1.logger.error).not.toHaveBeenCalledWith(expect.stringContaining('Organisation ID is required'));
|
|
553
|
+
});
|
|
554
|
+
it('should work even when app context has no organization', async () => {
|
|
555
|
+
mockGetAppContext.mockReturnValue({});
|
|
556
|
+
const request = {
|
|
557
|
+
path: '/global-tool',
|
|
558
|
+
bodyJSON: {
|
|
559
|
+
auth: {
|
|
560
|
+
provider: 'OptiID',
|
|
561
|
+
credentials: {
|
|
562
|
+
customer_id: 'any-org',
|
|
563
|
+
access_token: 'valid-token-123'
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
};
|
|
568
|
+
const result = await (0, AuthUtils_1.authorizeGlobalRequest)(request);
|
|
569
|
+
expect(result).toBe(true);
|
|
570
|
+
expect(mockTokenVerifier.verify).toHaveBeenCalledWith('valid-token-123');
|
|
571
|
+
});
|
|
572
|
+
});
|
|
573
|
+
});
|
|
574
|
+
describe('edge cases and error handling', () => {
|
|
575
|
+
it('should handle requests with null bodyJSON', async () => {
|
|
576
|
+
const request = {
|
|
577
|
+
path: '/some-tool',
|
|
578
|
+
bodyJSON: null
|
|
430
579
|
};
|
|
431
|
-
|
|
432
|
-
const
|
|
433
|
-
|
|
434
|
-
expect(
|
|
580
|
+
const result1 = await (0, AuthUtils_1.authorizeRegularRequest)(request);
|
|
581
|
+
const result2 = await (0, AuthUtils_1.authorizeGlobalRequest)(request);
|
|
582
|
+
expect(result1).toBe(false);
|
|
583
|
+
expect(result2).toBe(false);
|
|
435
584
|
expect(app_sdk_1.logger.error).toHaveBeenCalledWith('OptiID token is required but not provided');
|
|
436
585
|
});
|
|
437
|
-
it('should handle
|
|
438
|
-
// Arrange
|
|
586
|
+
it('should handle malformed auth objects', async () => {
|
|
439
587
|
const request = {
|
|
588
|
+
path: '/some-tool',
|
|
440
589
|
bodyJSON: {
|
|
441
|
-
auth:
|
|
442
|
-
provider: 'OptiID',
|
|
443
|
-
credentials: {
|
|
444
|
-
access_token: 'valid-access-token',
|
|
445
|
-
customer_id: 'different-org-456',
|
|
446
|
-
instance_id: 'instance-456',
|
|
447
|
-
product_sku: 'OPAL'
|
|
448
|
-
}
|
|
449
|
-
}
|
|
590
|
+
auth: 'invalid-auth-format'
|
|
450
591
|
}
|
|
451
592
|
};
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
// Act
|
|
458
|
-
const authInfo = AuthUtils_1.AuthUtils.extractAuthData(request);
|
|
459
|
-
const isValidOrg = authInfo
|
|
460
|
-
? AuthUtils_1.AuthUtils.validateOrganizationId(authInfo.authData.credentials?.customer_id)
|
|
461
|
-
: false;
|
|
462
|
-
// Assert
|
|
463
|
-
expect(authInfo).not.toBeNull();
|
|
464
|
-
expect(isValidOrg).toBe(false);
|
|
465
|
-
expect(app_sdk_1.logger.error).toHaveBeenCalledWith('Invalid organisation ID: expected app-org-123, received different-org-456');
|
|
593
|
+
const result1 = await (0, AuthUtils_1.authorizeRegularRequest)(request);
|
|
594
|
+
const result2 = await (0, AuthUtils_1.authorizeGlobalRequest)(request);
|
|
595
|
+
expect(result1).toBe(false);
|
|
596
|
+
expect(result2).toBe(false);
|
|
597
|
+
expect(app_sdk_1.logger.error).toHaveBeenCalledWith('OptiID token is required but not provided');
|
|
466
598
|
});
|
|
467
599
|
});
|
|
468
600
|
});
|