@axinom/mosaic-id-guard 0.18.0-rc.9 → 0.18.0
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/dist/common/helpers/guard-authorization.d.ts +22 -0
- package/dist/common/helpers/guard-authorization.d.ts.map +1 -0
- package/dist/common/helpers/guard-authorization.js +49 -0
- package/dist/common/helpers/guard-authorization.js.map +1 -0
- package/dist/common/id-guard-error.d.ts +1 -0
- package/dist/common/id-guard-error.d.ts.map +1 -1
- package/dist/common/id-guard-error.js +7 -1
- package/dist/common/id-guard-error.js.map +1 -1
- package/dist/common/id-guard-errors.d.ts +8 -0
- package/dist/common/id-guard-errors.d.ts.map +1 -1
- package/dist/common/id-guard-errors.js +8 -0
- package/dist/common/id-guard-errors.js.map +1 -1
- package/dist/graphql/ax-guard-plugin.d.ts +23 -0
- package/dist/graphql/ax-guard-plugin.d.ts.map +1 -0
- package/dist/graphql/ax-guard-plugin.js +29 -0
- package/dist/graphql/ax-guard-plugin.js.map +1 -0
- package/dist/graphql/enforce-strict-permissions.plugin.d.ts +1 -1
- package/dist/graphql/enforce-strict-permissions.plugin.d.ts.map +1 -1
- package/dist/graphql/index.d.ts +3 -2
- package/dist/graphql/index.d.ts.map +1 -1
- package/dist/graphql/index.js +3 -2
- package/dist/graphql/index.js.map +1 -1
- package/dist/graphql/{guard-plugin.d.ts → query-mutation-guard-plugin.d.ts} +2 -2
- package/dist/graphql/query-mutation-guard-plugin.d.ts.map +1 -0
- package/dist/graphql/{guard-plugin.js → query-mutation-guard-plugin.js} +5 -26
- package/dist/graphql/query-mutation-guard-plugin.js.map +1 -0
- package/dist/graphql/subscription-guard-plugin.d.ts +20 -0
- package/dist/graphql/subscription-guard-plugin.d.ts.map +1 -0
- package/dist/graphql/subscription-guard-plugin.js +81 -0
- package/dist/graphql/subscription-guard-plugin.js.map +1 -0
- package/package.json +9 -10
- package/src/common/helpers/guard-authorization.ts +76 -0
- package/src/common/id-guard-error.ts +13 -0
- package/src/common/id-guard-errors.ts +10 -0
- package/src/graphql/ax-guard-plugin.ts +29 -0
- package/src/graphql/enforce-strict-permissions.plugin.ts +1 -1
- package/src/graphql/index.ts +3 -2
- package/src/graphql/{guard-plugin.spec.ts → query-mutation-guard-plugin.spec.ts} +3 -3
- package/src/graphql/{guard-plugin.ts → query-mutation-guard-plugin.ts} +12 -36
- package/src/graphql/subscription-guard-plugin.spec.ts +257 -0
- package/src/graphql/subscription-guard-plugin.ts +112 -0
- package/dist/graphql/guard-plugin.d.ts.map +0 -1
- package/dist/graphql/guard-plugin.js.map +0 -1
- package/dist/graphql/subscription-authorization-hook-factory.d.ts +0 -13
- package/dist/graphql/subscription-authorization-hook-factory.d.ts.map +0 -1
- package/dist/graphql/subscription-authorization-hook-factory.js +0 -182
- package/dist/graphql/subscription-authorization-hook-factory.js.map +0 -1
- package/src/graphql/subscription-authorization-hook-factory.spec.ts +0 -749
- package/src/graphql/subscription-authorization-hook-factory.ts +0 -286
|
@@ -1,749 +0,0 @@
|
|
|
1
|
-
import { Request, Response } from 'express';
|
|
2
|
-
import { ExecutionArgs, GraphQLSchema } from 'graphql';
|
|
3
|
-
import gql from 'graphql-tag';
|
|
4
|
-
import { CloseCode } from 'graphql-ws';
|
|
5
|
-
import { makePluginHook, PostGraphileOptions } from 'postgraphile';
|
|
6
|
-
import { ExecutionParams } from 'subscriptions-transport-ws';
|
|
7
|
-
import { IdGuardErrors, SubjectType } from '../common';
|
|
8
|
-
import { subscriptionAuthorizationHookFactory } from './subscription-authorization-hook-factory';
|
|
9
|
-
|
|
10
|
-
describe('subscriptionAuthorizationHookFactory', () => {
|
|
11
|
-
describe('When calling the subscription through postgraphile:ws:onOperation', () => {
|
|
12
|
-
it('Management User without required permissions -> UserNotAuthorized error', async () => {
|
|
13
|
-
// Arrange
|
|
14
|
-
const hookGenerator = subscriptionAuthorizationHookFactory;
|
|
15
|
-
const buildOptions: PostGraphileOptions<Request, Response> = {
|
|
16
|
-
graphileBuildOptions: {
|
|
17
|
-
// permission definition without permissions for the required subscription 'echoSubscription'
|
|
18
|
-
permissionDefinition: {
|
|
19
|
-
gqlOptions: {
|
|
20
|
-
anonymousGqlOperations: [],
|
|
21
|
-
ignoredGqlOperations: [],
|
|
22
|
-
},
|
|
23
|
-
permissions: [
|
|
24
|
-
{
|
|
25
|
-
key: 'Editor',
|
|
26
|
-
title: 'Editor',
|
|
27
|
-
gqlOperations: ['otherEndpoint'],
|
|
28
|
-
},
|
|
29
|
-
],
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
|
-
};
|
|
33
|
-
const hookPlugin = hookGenerator(buildOptions);
|
|
34
|
-
const context = {
|
|
35
|
-
subject: {
|
|
36
|
-
sub: 'test-user',
|
|
37
|
-
permissions: { 'test-service': ['Editor'] },
|
|
38
|
-
exp: new Date().getTime() / 1000 + 20, // set expiry time of the token to currentTime + 20 seconds
|
|
39
|
-
subjectType: SubjectType.UserAccount,
|
|
40
|
-
},
|
|
41
|
-
config: { serviceId: 'test-service' },
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
const params: ExecutionParams = {
|
|
45
|
-
query: `subscription EchoSubscription {
|
|
46
|
-
echoSubscription
|
|
47
|
-
}`,
|
|
48
|
-
operationName: 'EchoSubscription',
|
|
49
|
-
context: context,
|
|
50
|
-
variables: [],
|
|
51
|
-
};
|
|
52
|
-
const hookFunction = makePluginHook([hookPlugin]);
|
|
53
|
-
|
|
54
|
-
// Act & Assert
|
|
55
|
-
expect(() =>
|
|
56
|
-
hookFunction('postgraphile:ws:onOperation', params, context),
|
|
57
|
-
).toThrow('User is not authorized to access the operation.');
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
it('EndUserApplication token without required permissions -> UserNotAuthorized error', async () => {
|
|
61
|
-
// Arrange
|
|
62
|
-
const hookGenerator = subscriptionAuthorizationHookFactory;
|
|
63
|
-
const buildOptions: PostGraphileOptions<Request, Response> = {
|
|
64
|
-
graphileBuildOptions: {
|
|
65
|
-
endUserAuthorizationConfig: {
|
|
66
|
-
anonymousGqlOperations: [],
|
|
67
|
-
applicationTokenAllowedGqlOperations: [
|
|
68
|
-
'subscriptionPlans',
|
|
69
|
-
'subscriptionLifecycleStatusMutated',
|
|
70
|
-
],
|
|
71
|
-
},
|
|
72
|
-
},
|
|
73
|
-
};
|
|
74
|
-
const hookPlugin = hookGenerator(buildOptions);
|
|
75
|
-
const context = {
|
|
76
|
-
subject: {
|
|
77
|
-
sub: 'test-user',
|
|
78
|
-
exp: new Date().getTime() / 1000 + 20, // set expiry time of the token to currentTime + 20 seconds
|
|
79
|
-
subjectType: SubjectType.EndUserApplication,
|
|
80
|
-
},
|
|
81
|
-
config: { serviceId: 'test-service' },
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
const params: ExecutionParams = {
|
|
85
|
-
query: `subscription EchoSubscription {
|
|
86
|
-
echoSubscription
|
|
87
|
-
}`,
|
|
88
|
-
operationName: 'EchoSubscription',
|
|
89
|
-
context: context,
|
|
90
|
-
variables: [],
|
|
91
|
-
};
|
|
92
|
-
const hookFunction = makePluginHook([hookPlugin]);
|
|
93
|
-
|
|
94
|
-
// Act & Assert
|
|
95
|
-
expect(() =>
|
|
96
|
-
hookFunction('postgraphile:ws:onOperation', params, context),
|
|
97
|
-
).toThrow('Application Token is not authorized to access the operation.');
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
it.each([
|
|
101
|
-
SubjectType.UserAccount,
|
|
102
|
-
SubjectType.ManagedServiceAccount,
|
|
103
|
-
SubjectType.ServiceAccount,
|
|
104
|
-
SubjectType.ImpersonatedUserAccount,
|
|
105
|
-
SubjectType.EndUserApplication,
|
|
106
|
-
SubjectType.EndUserAccount,
|
|
107
|
-
])(
|
|
108
|
-
'Authorized %s with expired token for subscription -> UserNotAuthorized error',
|
|
109
|
-
async (subjectType) => {
|
|
110
|
-
// Arrange
|
|
111
|
-
const hookGenerator = subscriptionAuthorizationHookFactory;
|
|
112
|
-
let buildOptions: PostGraphileOptions<Request, Response>;
|
|
113
|
-
if (
|
|
114
|
-
subjectType !== SubjectType.EndUserAccount &&
|
|
115
|
-
subjectType !== SubjectType.EndUserApplication
|
|
116
|
-
) {
|
|
117
|
-
buildOptions = {
|
|
118
|
-
graphileBuildOptions: {
|
|
119
|
-
permissionDefinition: {
|
|
120
|
-
gqlOptions: {
|
|
121
|
-
anonymousGqlOperations: [],
|
|
122
|
-
ignoredGqlOperations: [],
|
|
123
|
-
},
|
|
124
|
-
permissions: [
|
|
125
|
-
{
|
|
126
|
-
key: 'Editor',
|
|
127
|
-
title: 'Editor',
|
|
128
|
-
gqlOperations: ['otherEndpoint', 'echoSubscription'],
|
|
129
|
-
},
|
|
130
|
-
],
|
|
131
|
-
},
|
|
132
|
-
},
|
|
133
|
-
};
|
|
134
|
-
} else {
|
|
135
|
-
buildOptions = {
|
|
136
|
-
graphileBuildOptions: {
|
|
137
|
-
endUserAuthorizationConfig: {
|
|
138
|
-
anonymousGqlOperations: [],
|
|
139
|
-
applicationTokenAllowedGqlOperations: ['echoSubscription'],
|
|
140
|
-
},
|
|
141
|
-
},
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
const hookPlugin = hookGenerator(buildOptions);
|
|
146
|
-
const context = {
|
|
147
|
-
subject: {
|
|
148
|
-
sub: 'test-user',
|
|
149
|
-
permissions: { 'test-service': ['Editor'] },
|
|
150
|
-
exp: new Date().getTime() / 1000 - 20, // set expiry time of the token to currentTime - 20 seconds
|
|
151
|
-
subjectType: subjectType,
|
|
152
|
-
},
|
|
153
|
-
config: { serviceId: 'test-service' },
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
const params: ExecutionParams = {
|
|
157
|
-
query: `subscription EchoSubscription {
|
|
158
|
-
echoSubscription
|
|
159
|
-
}`,
|
|
160
|
-
operationName: 'EchoSubscription',
|
|
161
|
-
context: context,
|
|
162
|
-
variables: [],
|
|
163
|
-
};
|
|
164
|
-
const hookFunction = makePluginHook([hookPlugin]);
|
|
165
|
-
|
|
166
|
-
// Act & Assert
|
|
167
|
-
expect(() =>
|
|
168
|
-
hookFunction('postgraphile:ws:onOperation', params, context),
|
|
169
|
-
).toThrow('Access Token has expired.');
|
|
170
|
-
},
|
|
171
|
-
);
|
|
172
|
-
|
|
173
|
-
it.each([
|
|
174
|
-
SubjectType.UserAccount,
|
|
175
|
-
SubjectType.ManagedServiceAccount,
|
|
176
|
-
SubjectType.ServiceAccount,
|
|
177
|
-
SubjectType.ImpersonatedUserAccount,
|
|
178
|
-
SubjectType.EndUserApplication,
|
|
179
|
-
SubjectType.EndUserAccount,
|
|
180
|
-
])(
|
|
181
|
-
'Authorized %s with non-expired token for subscription -> no error',
|
|
182
|
-
async (subjectType) => {
|
|
183
|
-
// Arrange
|
|
184
|
-
const hookGenerator = subscriptionAuthorizationHookFactory;
|
|
185
|
-
let buildOptions: PostGraphileOptions<Request, Response>;
|
|
186
|
-
if (
|
|
187
|
-
subjectType !== SubjectType.EndUserAccount &&
|
|
188
|
-
subjectType !== SubjectType.EndUserApplication
|
|
189
|
-
) {
|
|
190
|
-
buildOptions = {
|
|
191
|
-
graphileBuildOptions: {
|
|
192
|
-
permissionDefinition: {
|
|
193
|
-
gqlOptions: {
|
|
194
|
-
anonymousGqlOperations: [],
|
|
195
|
-
ignoredGqlOperations: [],
|
|
196
|
-
},
|
|
197
|
-
permissions: [
|
|
198
|
-
{
|
|
199
|
-
key: 'Editor',
|
|
200
|
-
title: 'Editor',
|
|
201
|
-
gqlOperations: ['otherEndpoint', 'echoSubscription'],
|
|
202
|
-
},
|
|
203
|
-
],
|
|
204
|
-
},
|
|
205
|
-
},
|
|
206
|
-
};
|
|
207
|
-
} else {
|
|
208
|
-
buildOptions = {
|
|
209
|
-
graphileBuildOptions: {
|
|
210
|
-
endUserAuthorizationConfig: {
|
|
211
|
-
anonymousGqlOperations: [],
|
|
212
|
-
applicationTokenAllowedGqlOperations: ['echoSubscription'],
|
|
213
|
-
},
|
|
214
|
-
},
|
|
215
|
-
};
|
|
216
|
-
}
|
|
217
|
-
const hookPlugin = hookGenerator(buildOptions);
|
|
218
|
-
|
|
219
|
-
const context = {
|
|
220
|
-
subject: {
|
|
221
|
-
sub: 'test-user',
|
|
222
|
-
permissions: { 'test-service': ['Editor'] },
|
|
223
|
-
exp: new Date().getTime() / 1000 + 20, // set expiry time of the token to currentTime + 20 seconds
|
|
224
|
-
subjectType: subjectType,
|
|
225
|
-
},
|
|
226
|
-
config: { serviceId: 'test-service' },
|
|
227
|
-
};
|
|
228
|
-
|
|
229
|
-
const params: ExecutionParams = {
|
|
230
|
-
query: `subscription EchoSubscription {
|
|
231
|
-
echoSubscription
|
|
232
|
-
}`,
|
|
233
|
-
operationName: 'EchoSubscription',
|
|
234
|
-
context: context,
|
|
235
|
-
variables: [],
|
|
236
|
-
};
|
|
237
|
-
const hookFunction = makePluginHook([hookPlugin]);
|
|
238
|
-
|
|
239
|
-
// Act & Assert
|
|
240
|
-
expect(() =>
|
|
241
|
-
hookFunction('postgraphile:ws:onOperation', params, context),
|
|
242
|
-
).not.toThrow();
|
|
243
|
-
},
|
|
244
|
-
);
|
|
245
|
-
|
|
246
|
-
it.each([
|
|
247
|
-
SubjectType.UserAccount,
|
|
248
|
-
SubjectType.ManagedServiceAccount,
|
|
249
|
-
SubjectType.ServiceAccount,
|
|
250
|
-
SubjectType.ImpersonatedUserAccount,
|
|
251
|
-
SubjectType.EndUserApplication,
|
|
252
|
-
SubjectType.EndUserAccount,
|
|
253
|
-
])(
|
|
254
|
-
'When ensureOnlyAuthentication is set to true and %s with non-expired token without any specific permission for subscription -> no error',
|
|
255
|
-
async (subjectType) => {
|
|
256
|
-
// Arrange
|
|
257
|
-
const hookGenerator = subscriptionAuthorizationHookFactory;
|
|
258
|
-
let buildOptions: PostGraphileOptions<Request, Response>;
|
|
259
|
-
if (
|
|
260
|
-
subjectType !== SubjectType.EndUserAccount &&
|
|
261
|
-
subjectType !== SubjectType.EndUserApplication
|
|
262
|
-
) {
|
|
263
|
-
buildOptions = {
|
|
264
|
-
graphileBuildOptions: {
|
|
265
|
-
ensureOnlyAuthentication: true,
|
|
266
|
-
permissionDefinition: {
|
|
267
|
-
gqlOptions: {
|
|
268
|
-
anonymousGqlOperations: [],
|
|
269
|
-
ignoredGqlOperations: [],
|
|
270
|
-
},
|
|
271
|
-
permissions: [
|
|
272
|
-
{
|
|
273
|
-
key: 'Editor',
|
|
274
|
-
title: 'Editor',
|
|
275
|
-
gqlOperations: ['otherEndpoint'],
|
|
276
|
-
},
|
|
277
|
-
],
|
|
278
|
-
},
|
|
279
|
-
},
|
|
280
|
-
};
|
|
281
|
-
} else {
|
|
282
|
-
buildOptions = {
|
|
283
|
-
graphileBuildOptions: {
|
|
284
|
-
ensureOnlyAuthentication: true,
|
|
285
|
-
endUserAuthorizationConfig: {
|
|
286
|
-
anonymousGqlOperations: [],
|
|
287
|
-
applicationTokenAllowedGqlOperations: ['otherEndpoint'],
|
|
288
|
-
},
|
|
289
|
-
},
|
|
290
|
-
};
|
|
291
|
-
}
|
|
292
|
-
const hookPlugin = hookGenerator(buildOptions);
|
|
293
|
-
|
|
294
|
-
const context = {
|
|
295
|
-
subject: {
|
|
296
|
-
sub: 'test-user',
|
|
297
|
-
permissions: { 'test-service': ['Editor'] },
|
|
298
|
-
exp: new Date().getTime() / 1000 + 20, // set expiry time of the token to currentTime + 20 seconds
|
|
299
|
-
subjectType: subjectType,
|
|
300
|
-
},
|
|
301
|
-
config: { serviceId: 'test-service' },
|
|
302
|
-
};
|
|
303
|
-
|
|
304
|
-
const params: ExecutionParams = {
|
|
305
|
-
query: `subscription EchoSubscription {
|
|
306
|
-
echoSubscription
|
|
307
|
-
}`,
|
|
308
|
-
operationName: 'EchoSubscription',
|
|
309
|
-
context: context,
|
|
310
|
-
variables: [],
|
|
311
|
-
};
|
|
312
|
-
const hookFunction = makePluginHook([hookPlugin]);
|
|
313
|
-
|
|
314
|
-
// Act & Assert
|
|
315
|
-
expect(() =>
|
|
316
|
-
hookFunction('postgraphile:ws:onOperation', params, context),
|
|
317
|
-
).not.toThrow();
|
|
318
|
-
},
|
|
319
|
-
);
|
|
320
|
-
});
|
|
321
|
-
|
|
322
|
-
describe('When calling the subscription through postgraphile:ws:onSubscribe', () => {
|
|
323
|
-
const schema: GraphQLSchema = {
|
|
324
|
-
astNode: {
|
|
325
|
-
kind: 'SchemaDefinition',
|
|
326
|
-
operationTypes: [
|
|
327
|
-
{
|
|
328
|
-
kind: 'OperationTypeDefinition',
|
|
329
|
-
operation: 'subscription',
|
|
330
|
-
type: {
|
|
331
|
-
kind: 'NamedType',
|
|
332
|
-
name: {
|
|
333
|
-
kind: 'Name',
|
|
334
|
-
value: 'EchoSubscription',
|
|
335
|
-
},
|
|
336
|
-
},
|
|
337
|
-
},
|
|
338
|
-
],
|
|
339
|
-
},
|
|
340
|
-
description: 'EchoSubscription',
|
|
341
|
-
extensionASTNodes: [],
|
|
342
|
-
extensions: [],
|
|
343
|
-
getDirective: jest.fn(),
|
|
344
|
-
getDirectives: jest.fn(),
|
|
345
|
-
getImplementations: jest.fn(),
|
|
346
|
-
getMutationType: jest.fn(),
|
|
347
|
-
getPossibleTypes: jest.fn(),
|
|
348
|
-
getQueryType: jest.fn(),
|
|
349
|
-
getSubscriptionType: jest.fn(),
|
|
350
|
-
getType: jest.fn(),
|
|
351
|
-
getTypeMap: jest.fn(),
|
|
352
|
-
isPossibleType: jest.fn(),
|
|
353
|
-
isSubType: jest.fn(),
|
|
354
|
-
toConfig: jest.fn(),
|
|
355
|
-
};
|
|
356
|
-
it('Management User without required permissions -> UserNotAuthorized error', async () => {
|
|
357
|
-
// Arrange
|
|
358
|
-
const hookGenerator = subscriptionAuthorizationHookFactory;
|
|
359
|
-
const buildOptions: PostGraphileOptions<Request, Response> = {
|
|
360
|
-
graphileBuildOptions: {
|
|
361
|
-
// permission definition without permissions for the required subscription 'echoSubscription'
|
|
362
|
-
permissionDefinition: {
|
|
363
|
-
gqlOptions: {
|
|
364
|
-
anonymousGqlOperations: [],
|
|
365
|
-
ignoredGqlOperations: [],
|
|
366
|
-
},
|
|
367
|
-
permissions: [
|
|
368
|
-
{
|
|
369
|
-
key: 'Editor',
|
|
370
|
-
title: 'Editor',
|
|
371
|
-
gqlOperations: ['otherEndpoint'],
|
|
372
|
-
},
|
|
373
|
-
],
|
|
374
|
-
},
|
|
375
|
-
},
|
|
376
|
-
};
|
|
377
|
-
const hookPlugin = hookGenerator(buildOptions);
|
|
378
|
-
const socket = {
|
|
379
|
-
close: jest.fn(),
|
|
380
|
-
};
|
|
381
|
-
const socketSpy = jest.spyOn(socket, 'close');
|
|
382
|
-
const context = {
|
|
383
|
-
extra: {
|
|
384
|
-
request: {
|
|
385
|
-
authContext: {
|
|
386
|
-
subject: {
|
|
387
|
-
sub: 'test-user',
|
|
388
|
-
permissions: { 'test-service': ['Editor'] },
|
|
389
|
-
exp: new Date().getTime() / 1000 + 20, // set expiry time of the token to currentTime - 20 seconds
|
|
390
|
-
subjectType: SubjectType.UserAccount,
|
|
391
|
-
},
|
|
392
|
-
},
|
|
393
|
-
},
|
|
394
|
-
socket,
|
|
395
|
-
},
|
|
396
|
-
config: { serviceId: 'test-service' },
|
|
397
|
-
};
|
|
398
|
-
|
|
399
|
-
const args: ExecutionArgs = {
|
|
400
|
-
schema,
|
|
401
|
-
document: gql(`subscription EchoSubscription {
|
|
402
|
-
echoSubscription
|
|
403
|
-
}`),
|
|
404
|
-
operationName: 'EchoSubscription',
|
|
405
|
-
contextValue: {
|
|
406
|
-
subject: context.extra.request.authContext.subject,
|
|
407
|
-
config: { serviceId: 'test-service' },
|
|
408
|
-
},
|
|
409
|
-
};
|
|
410
|
-
const hookFunction = makePluginHook([hookPlugin]);
|
|
411
|
-
|
|
412
|
-
// Act & Assert
|
|
413
|
-
expect(() =>
|
|
414
|
-
hookFunction('postgraphile:ws:onSubscribe', args, {
|
|
415
|
-
context: context,
|
|
416
|
-
}),
|
|
417
|
-
).toThrow('User is not authorized to access the operation.');
|
|
418
|
-
});
|
|
419
|
-
|
|
420
|
-
it('ApplicationToken user without required permissions -> UserNotAuthorized error', async () => {
|
|
421
|
-
// Arrange
|
|
422
|
-
const hookGenerator = subscriptionAuthorizationHookFactory;
|
|
423
|
-
const buildOptions: PostGraphileOptions<Request, Response> = {
|
|
424
|
-
graphileBuildOptions: {
|
|
425
|
-
// endUserAuthorizationConfig without permissions for the required subscription 'echoSubscription'
|
|
426
|
-
endUserAuthorizationConfig: {
|
|
427
|
-
anonymousGqlOperations: [],
|
|
428
|
-
applicationTokenAllowedGqlOperations: [
|
|
429
|
-
'subscriptionPlans',
|
|
430
|
-
'subscriptionLifecycleStatusMutated',
|
|
431
|
-
],
|
|
432
|
-
},
|
|
433
|
-
},
|
|
434
|
-
};
|
|
435
|
-
const hookPlugin = hookGenerator(buildOptions);
|
|
436
|
-
const socket = {
|
|
437
|
-
close: jest.fn(),
|
|
438
|
-
};
|
|
439
|
-
const socketSpy = jest.spyOn(socket, 'close');
|
|
440
|
-
const context = {
|
|
441
|
-
extra: {
|
|
442
|
-
request: {
|
|
443
|
-
authContext: {
|
|
444
|
-
subject: {
|
|
445
|
-
sub: 'test-user',
|
|
446
|
-
exp: new Date().getTime() / 1000 + 20, // set expiry time of the token to currentTime - 20 seconds
|
|
447
|
-
subjectType: SubjectType.EndUserApplication,
|
|
448
|
-
},
|
|
449
|
-
},
|
|
450
|
-
},
|
|
451
|
-
socket,
|
|
452
|
-
},
|
|
453
|
-
config: { serviceId: 'test-service' },
|
|
454
|
-
};
|
|
455
|
-
|
|
456
|
-
const args: ExecutionArgs = {
|
|
457
|
-
schema,
|
|
458
|
-
document: gql(`subscription EchoSubscription {
|
|
459
|
-
echoSubscription
|
|
460
|
-
}`),
|
|
461
|
-
operationName: 'EchoSubscription',
|
|
462
|
-
contextValue: {
|
|
463
|
-
subject: context.extra.request.authContext.subject,
|
|
464
|
-
config: { serviceId: 'test-service' },
|
|
465
|
-
},
|
|
466
|
-
};
|
|
467
|
-
const hookFunction = makePluginHook([hookPlugin]);
|
|
468
|
-
|
|
469
|
-
// Act & Assert
|
|
470
|
-
expect(() =>
|
|
471
|
-
hookFunction('postgraphile:ws:onSubscribe', args, {
|
|
472
|
-
context: context,
|
|
473
|
-
}),
|
|
474
|
-
).toThrow('Application Token is not authorized to access the operation.');
|
|
475
|
-
});
|
|
476
|
-
|
|
477
|
-
it.each([
|
|
478
|
-
SubjectType.UserAccount,
|
|
479
|
-
SubjectType.ManagedServiceAccount,
|
|
480
|
-
SubjectType.ServiceAccount,
|
|
481
|
-
SubjectType.ImpersonatedUserAccount,
|
|
482
|
-
SubjectType.EndUserApplication,
|
|
483
|
-
SubjectType.EndUserAccount,
|
|
484
|
-
])(
|
|
485
|
-
'Authorized %s with expired token for subscription -> Closes the websocket with CloseCode.Forbidden',
|
|
486
|
-
async (subjectType) => {
|
|
487
|
-
// Arrange
|
|
488
|
-
const hookGenerator = subscriptionAuthorizationHookFactory;
|
|
489
|
-
|
|
490
|
-
let buildOptions: PostGraphileOptions<Request, Response>;
|
|
491
|
-
if (
|
|
492
|
-
subjectType !== SubjectType.EndUserAccount &&
|
|
493
|
-
subjectType !== SubjectType.EndUserApplication
|
|
494
|
-
) {
|
|
495
|
-
buildOptions = {
|
|
496
|
-
graphileBuildOptions: {
|
|
497
|
-
permissionDefinition: {
|
|
498
|
-
gqlOptions: {
|
|
499
|
-
anonymousGqlOperations: [],
|
|
500
|
-
ignoredGqlOperations: [],
|
|
501
|
-
},
|
|
502
|
-
permissions: [
|
|
503
|
-
{
|
|
504
|
-
key: 'Editor',
|
|
505
|
-
title: 'Editor',
|
|
506
|
-
gqlOperations: ['otherEndpoint', 'echoSubscription'],
|
|
507
|
-
},
|
|
508
|
-
],
|
|
509
|
-
},
|
|
510
|
-
},
|
|
511
|
-
};
|
|
512
|
-
} else {
|
|
513
|
-
buildOptions = {
|
|
514
|
-
graphileBuildOptions: {
|
|
515
|
-
endUserAuthorizationConfig: {
|
|
516
|
-
anonymousGqlOperations: [],
|
|
517
|
-
applicationTokenAllowedGqlOperations: [],
|
|
518
|
-
},
|
|
519
|
-
},
|
|
520
|
-
};
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
const hookPlugin = hookGenerator(buildOptions);
|
|
524
|
-
const socket = {
|
|
525
|
-
close: jest.fn(),
|
|
526
|
-
};
|
|
527
|
-
const socketSpy = jest.spyOn(socket, 'close');
|
|
528
|
-
|
|
529
|
-
const context = {
|
|
530
|
-
extra: {
|
|
531
|
-
request: {
|
|
532
|
-
authContext: {
|
|
533
|
-
subject: {
|
|
534
|
-
sub: 'test-user',
|
|
535
|
-
permissions: { 'test-service': ['Editor'] },
|
|
536
|
-
exp: new Date().getTime() / 1000 - 20, // set expiry time of the token to currentTime - 20 seconds
|
|
537
|
-
subjectType,
|
|
538
|
-
},
|
|
539
|
-
},
|
|
540
|
-
},
|
|
541
|
-
socket,
|
|
542
|
-
},
|
|
543
|
-
config: { serviceId: 'test-service' },
|
|
544
|
-
};
|
|
545
|
-
|
|
546
|
-
const args: ExecutionArgs = {
|
|
547
|
-
schema,
|
|
548
|
-
document: gql(`subscription EchoSubscription {
|
|
549
|
-
echoSubscription
|
|
550
|
-
}`),
|
|
551
|
-
operationName: 'EchoSubscription',
|
|
552
|
-
contextValue: {
|
|
553
|
-
subject: context.extra.request.authContext.subject,
|
|
554
|
-
config: { serviceId: 'test-service' },
|
|
555
|
-
},
|
|
556
|
-
};
|
|
557
|
-
const hookFunction = makePluginHook([hookPlugin]);
|
|
558
|
-
|
|
559
|
-
// Act
|
|
560
|
-
hookFunction('postgraphile:ws:onSubscribe', args, { context: context });
|
|
561
|
-
// Assert
|
|
562
|
-
expect(socketSpy).toHaveBeenCalledWith(
|
|
563
|
-
CloseCode.Forbidden,
|
|
564
|
-
IdGuardErrors.AccessTokenExpired.code,
|
|
565
|
-
);
|
|
566
|
-
},
|
|
567
|
-
);
|
|
568
|
-
|
|
569
|
-
it.each([
|
|
570
|
-
SubjectType.UserAccount,
|
|
571
|
-
SubjectType.ManagedServiceAccount,
|
|
572
|
-
SubjectType.ServiceAccount,
|
|
573
|
-
SubjectType.ImpersonatedUserAccount,
|
|
574
|
-
SubjectType.EndUserApplication,
|
|
575
|
-
SubjectType.EndUserAccount,
|
|
576
|
-
])(
|
|
577
|
-
'Authorized %s with non-expired token for subscription -> no error',
|
|
578
|
-
async (subjectType) => {
|
|
579
|
-
// Arrange
|
|
580
|
-
const hookGenerator = subscriptionAuthorizationHookFactory;
|
|
581
|
-
let buildOptions: PostGraphileOptions<Request, Response>;
|
|
582
|
-
if (
|
|
583
|
-
subjectType !== SubjectType.EndUserAccount &&
|
|
584
|
-
subjectType !== SubjectType.EndUserApplication
|
|
585
|
-
) {
|
|
586
|
-
buildOptions = {
|
|
587
|
-
graphileBuildOptions: {
|
|
588
|
-
permissionDefinition: {
|
|
589
|
-
gqlOptions: {
|
|
590
|
-
anonymousGqlOperations: [],
|
|
591
|
-
ignoredGqlOperations: [],
|
|
592
|
-
},
|
|
593
|
-
permissions: [
|
|
594
|
-
{
|
|
595
|
-
key: 'Editor',
|
|
596
|
-
title: 'Editor',
|
|
597
|
-
gqlOperations: ['otherEndpoint', 'echoSubscription'],
|
|
598
|
-
},
|
|
599
|
-
],
|
|
600
|
-
},
|
|
601
|
-
},
|
|
602
|
-
};
|
|
603
|
-
} else {
|
|
604
|
-
buildOptions = {
|
|
605
|
-
graphileBuildOptions: {
|
|
606
|
-
endUserAuthorizationConfig: {
|
|
607
|
-
anonymousGqlOperations: [],
|
|
608
|
-
applicationTokenAllowedGqlOperations: ['echoSubscription'],
|
|
609
|
-
},
|
|
610
|
-
},
|
|
611
|
-
};
|
|
612
|
-
}
|
|
613
|
-
const hookPlugin = hookGenerator(buildOptions);
|
|
614
|
-
const socket = {
|
|
615
|
-
close: jest.fn(),
|
|
616
|
-
};
|
|
617
|
-
const socketSpy = jest.spyOn(socket, 'close');
|
|
618
|
-
const context = {
|
|
619
|
-
extra: {
|
|
620
|
-
request: {
|
|
621
|
-
authContext: {
|
|
622
|
-
subject: {
|
|
623
|
-
sub: 'test-user',
|
|
624
|
-
permissions: { 'test-service': ['Editor'] },
|
|
625
|
-
exp: new Date().getTime() / 1000 + 20, // set expiry time of the token to currentTime - 20 seconds
|
|
626
|
-
subjectType,
|
|
627
|
-
},
|
|
628
|
-
},
|
|
629
|
-
},
|
|
630
|
-
socket,
|
|
631
|
-
},
|
|
632
|
-
config: { serviceId: 'test-service' },
|
|
633
|
-
};
|
|
634
|
-
|
|
635
|
-
const args: ExecutionArgs = {
|
|
636
|
-
schema,
|
|
637
|
-
document: gql(`subscription EchoSubscription {
|
|
638
|
-
echoSubscription
|
|
639
|
-
}`),
|
|
640
|
-
operationName: 'EchoSubscription',
|
|
641
|
-
contextValue: {
|
|
642
|
-
subject: context.extra.request.authContext.subject,
|
|
643
|
-
config: { serviceId: 'test-service' },
|
|
644
|
-
},
|
|
645
|
-
};
|
|
646
|
-
const hookFunction = makePluginHook([hookPlugin]);
|
|
647
|
-
|
|
648
|
-
// Act & Assert
|
|
649
|
-
expect(() =>
|
|
650
|
-
hookFunction('postgraphile:ws:onSubscribe', args, {
|
|
651
|
-
context: context,
|
|
652
|
-
}),
|
|
653
|
-
).not.toThrow();
|
|
654
|
-
expect(socketSpy).not.toHaveBeenCalled();
|
|
655
|
-
},
|
|
656
|
-
);
|
|
657
|
-
|
|
658
|
-
it.each([
|
|
659
|
-
SubjectType.UserAccount,
|
|
660
|
-
SubjectType.ManagedServiceAccount,
|
|
661
|
-
SubjectType.ServiceAccount,
|
|
662
|
-
SubjectType.ImpersonatedUserAccount,
|
|
663
|
-
SubjectType.EndUserApplication,
|
|
664
|
-
SubjectType.EndUserAccount,
|
|
665
|
-
])(
|
|
666
|
-
'When ensureOnlyAuthentication is set to true, %s with non-expired token and no specific permission for subscription -> no error',
|
|
667
|
-
async (subjectType) => {
|
|
668
|
-
// Arrange
|
|
669
|
-
const hookGenerator = subscriptionAuthorizationHookFactory;
|
|
670
|
-
let buildOptions: PostGraphileOptions<Request, Response>;
|
|
671
|
-
if (
|
|
672
|
-
subjectType !== SubjectType.EndUserAccount &&
|
|
673
|
-
subjectType !== SubjectType.EndUserApplication
|
|
674
|
-
) {
|
|
675
|
-
buildOptions = {
|
|
676
|
-
graphileBuildOptions: {
|
|
677
|
-
ensureOnlyAuthentication: true,
|
|
678
|
-
permissionDefinition: {
|
|
679
|
-
gqlOptions: {
|
|
680
|
-
anonymousGqlOperations: [],
|
|
681
|
-
ignoredGqlOperations: [],
|
|
682
|
-
},
|
|
683
|
-
permissions: [
|
|
684
|
-
{
|
|
685
|
-
key: 'Editor',
|
|
686
|
-
title: 'Editor',
|
|
687
|
-
gqlOperations: ['otherEndpoint'],
|
|
688
|
-
},
|
|
689
|
-
],
|
|
690
|
-
},
|
|
691
|
-
},
|
|
692
|
-
};
|
|
693
|
-
} else {
|
|
694
|
-
buildOptions = {
|
|
695
|
-
graphileBuildOptions: {
|
|
696
|
-
ensureOnlyAuthentication: true,
|
|
697
|
-
endUserAuthorizationConfig: {
|
|
698
|
-
anonymousGqlOperations: [],
|
|
699
|
-
applicationTokenAllowedGqlOperations: ['otherEndpoint'],
|
|
700
|
-
},
|
|
701
|
-
},
|
|
702
|
-
};
|
|
703
|
-
}
|
|
704
|
-
const hookPlugin = hookGenerator(buildOptions);
|
|
705
|
-
const socket = {
|
|
706
|
-
close: jest.fn(),
|
|
707
|
-
};
|
|
708
|
-
const socketSpy = jest.spyOn(socket, 'close');
|
|
709
|
-
const context = {
|
|
710
|
-
extra: {
|
|
711
|
-
request: {
|
|
712
|
-
authContext: {
|
|
713
|
-
subject: {
|
|
714
|
-
sub: 'test-user',
|
|
715
|
-
permissions: { 'test-service': ['Editor'] },
|
|
716
|
-
exp: new Date().getTime() / 1000 + 20, // set expiry time of the token to currentTime - 20 seconds
|
|
717
|
-
subjectType,
|
|
718
|
-
},
|
|
719
|
-
},
|
|
720
|
-
},
|
|
721
|
-
socket,
|
|
722
|
-
},
|
|
723
|
-
config: { serviceId: 'test-service' },
|
|
724
|
-
};
|
|
725
|
-
|
|
726
|
-
const args: ExecutionArgs = {
|
|
727
|
-
schema,
|
|
728
|
-
document: gql(`subscription EchoSubscription {
|
|
729
|
-
echoSubscription
|
|
730
|
-
}`),
|
|
731
|
-
operationName: 'EchoSubscription',
|
|
732
|
-
contextValue: {
|
|
733
|
-
subject: context.extra.request.authContext.subject,
|
|
734
|
-
config: { serviceId: 'test-service' },
|
|
735
|
-
},
|
|
736
|
-
};
|
|
737
|
-
const hookFunction = makePluginHook([hookPlugin]);
|
|
738
|
-
|
|
739
|
-
// Act & Assert
|
|
740
|
-
expect(() =>
|
|
741
|
-
hookFunction('postgraphile:ws:onSubscribe', args, {
|
|
742
|
-
context: context,
|
|
743
|
-
}),
|
|
744
|
-
).not.toThrow();
|
|
745
|
-
expect(socketSpy).not.toHaveBeenCalled();
|
|
746
|
-
},
|
|
747
|
-
);
|
|
748
|
-
});
|
|
749
|
-
});
|