@mondaydotcomorg/monday-authorization 3.1.2-feature-bashanye-enhance-profile-selection-release-process.51e4fbf → 3.1.2
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/attributions-service.d.ts +2 -1
- package/dist/attributions-service.d.ts.map +1 -1
- package/dist/attributions-service.js +6 -6
- package/dist/authorization-service.d.ts +15 -1
- package/dist/authorization-service.d.ts.map +1 -1
- package/dist/authorization-service.js +110 -23
- package/dist/esm/attributions-service.d.ts +2 -1
- package/dist/esm/attributions-service.d.ts.map +1 -1
- package/dist/esm/attributions-service.mjs +1 -1
- package/dist/esm/authorization-service.d.ts +15 -1
- package/dist/esm/authorization-service.d.ts.map +1 -1
- package/dist/esm/authorization-service.mjs +111 -24
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Context, ExecutionContext } from '@mondaydotcomorg/trident-backend-api';
|
|
2
|
-
|
|
2
|
+
declare enum PlatformProfile {
|
|
3
3
|
API_INTERNAL = "api-internal",
|
|
4
4
|
SLOW = "slow",
|
|
5
5
|
INTERNAL = "internal"
|
|
@@ -9,4 +9,5 @@ export declare function getExecutionContext(context: Context): ExecutionContext;
|
|
|
9
9
|
export declare function getAttributionsFromApi(): {
|
|
10
10
|
[key: string]: string;
|
|
11
11
|
};
|
|
12
|
+
export {};
|
|
12
13
|
//# sourceMappingURL=attributions-service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attributions-service.d.ts","sourceRoot":"","sources":["../src/attributions-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,OAAO,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AAStF,
|
|
1
|
+
{"version":3,"file":"attributions-service.d.ts","sourceRoot":"","sources":["../src/attributions-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,OAAO,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AAStF,aAAK,eAAe;IAClB,YAAY,iBAAiB;IAC7B,IAAI,SAAS;IACb,QAAQ,aAAa;CACtB;AAED,wBAAgB,UAAU,oBAiBzB;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,gBAAgB,CAEtE;AAED,wBAAgB,sBAAsB,IAAI;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,CAqClE"}
|
|
@@ -7,27 +7,27 @@ const APP_NAME_VARIABLE_KEY = 'APP_NAME';
|
|
|
7
7
|
const APP_NAME_HEADER_NAME = 'x-caller-app-name-from-sdk';
|
|
8
8
|
const FROM_SDK_HEADER_SUFFIX = `-from-sdk`;
|
|
9
9
|
let didSendFailureLogOnce = false;
|
|
10
|
-
|
|
10
|
+
var PlatformProfile;
|
|
11
11
|
(function (PlatformProfile) {
|
|
12
12
|
PlatformProfile["API_INTERNAL"] = "api-internal";
|
|
13
13
|
PlatformProfile["SLOW"] = "slow";
|
|
14
14
|
PlatformProfile["INTERNAL"] = "internal";
|
|
15
|
-
})(
|
|
15
|
+
})(PlatformProfile || (PlatformProfile = {}));
|
|
16
16
|
function getProfile() {
|
|
17
17
|
const tridentContext = tridentBackendApi.Api.getPart('context');
|
|
18
18
|
if (!tridentContext) {
|
|
19
|
-
return
|
|
19
|
+
return PlatformProfile.INTERNAL;
|
|
20
20
|
}
|
|
21
21
|
const { mondayRequestSource } = getExecutionContext(tridentContext);
|
|
22
22
|
switch (mondayRequestSource) {
|
|
23
23
|
case 'api': {
|
|
24
|
-
return
|
|
24
|
+
return PlatformProfile.API_INTERNAL;
|
|
25
25
|
}
|
|
26
26
|
case 'slow': {
|
|
27
|
-
return
|
|
27
|
+
return PlatformProfile.SLOW;
|
|
28
28
|
}
|
|
29
29
|
default:
|
|
30
|
-
return
|
|
30
|
+
return PlatformProfile.INTERNAL;
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
function getExecutionContext(context) {
|
|
@@ -28,9 +28,23 @@ export declare class AuthorizationService {
|
|
|
28
28
|
private static fetchIsUserGrantedWithFeature;
|
|
29
29
|
private static getCachedKeyName;
|
|
30
30
|
static canActionInScope(accountId: number, userId: number, action: string, scope: ScopeOptions): Promise<ScopedActionPermit>;
|
|
31
|
-
|
|
31
|
+
/**
|
|
32
|
+
* @deprecated - gradually phasing this out
|
|
33
|
+
* @param accountId
|
|
34
|
+
* @param userId
|
|
35
|
+
* @param scopedActions
|
|
36
|
+
*/
|
|
37
|
+
private static canActionInScopeMultiple_withoutPlatformProfile;
|
|
32
38
|
static canActionInScopeMultiple(accountId: number, userId: number, scopedActions: ScopedAction[]): Promise<ScopedActionResponseObject[]>;
|
|
33
39
|
private static isAuthorizedSingular;
|
|
40
|
+
/**
|
|
41
|
+
* @deprecated - gradually phasing this out
|
|
42
|
+
* @param accountId
|
|
43
|
+
* @param userId
|
|
44
|
+
* @param authorizationRequestObjects
|
|
45
|
+
* @private
|
|
46
|
+
*/
|
|
47
|
+
private static isAuthorizedMultiple_withoutPlatformProfile;
|
|
34
48
|
private static isAuthorizedMultiple;
|
|
35
49
|
}
|
|
36
50
|
export declare function setRedisClient(client: any, grantedFeatureRedisExpirationInSeconds?: number): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authorization-service.d.ts","sourceRoot":"","sources":["../src/authorization-service.ts"],"names":[],"mappings":"AAIA,OAAO,
|
|
1
|
+
{"version":3,"file":"authorization-service.d.ts","sourceRoot":"","sources":["../src/authorization-service.ts"],"names":[],"mappings":"AAIA,OAAO,EAAS,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAG1E,OAAO,EAAmB,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE7F,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,0BAA0B,EAC1B,YAAY,EACb,MAAM,kCAAkC,CAAC;AAQ1C,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,OAAO,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,mBAAmB,CAAC,EAAE,mBAAmB,EAAE,CAAC;CAC7C;AAED,wBAAgB,sBAAsB,CAAC,wBAAwB,EAAE,kBAAkB,QAElF;AAeD,qBAAa,oBAAoB;IAC/B,MAAM,CAAC,WAAW,CAAC,MAAC;IACpB,MAAM,CAAC,sCAAsC,CAAC,EAAE,MAAM,CAAC;IACvD,MAAM,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC;IAEnC;;;OAGG;WACU,YAAY,CACvB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,QAAQ,EAAE,EACrB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,iBAAiB,CAAC;WAEhB,YAAY,CACvB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,2BAA2B,EAAE,mBAAmB,EAAE,GACjD,OAAO,CAAC,iBAAiB,CAAC;IAY7B;;;OAGG;WACU,wBAAwB,CACnC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAO,GAC1C,OAAO,CAAC,OAAO,CAAC;mBAkBE,6BAA6B;IAclD,OAAO,CAAC,MAAM,CAAC,gBAAgB;WAIlB,gBAAgB,CAC3B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,kBAAkB,CAAC;IAM9B;;;;;OAKG;mBACkB,+CAA+C;WAgDvD,wBAAwB,CACnC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,YAAY,EAAE,GAC5B,OAAO,CAAC,0BAA0B,EAAE,CAAC;mBA4EnB,oBAAoB;IAUzC;;;;;;OAMG;mBACkB,2CAA2C;mBAiE3C,oBAAoB;CAiG1C;AAED,wBAAgB,cAAc,CAC5B,MAAM,KAAA,EACN,sCAAsC,GAAE,MAAiD,QAY1F;AAED,wBAAsB,eAAe,kBAIpC;AAED,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,mBAAmB,CAepG"}
|
|
@@ -4,6 +4,7 @@ const perf_hooks = require('perf_hooks');
|
|
|
4
4
|
const snakeCase = require('lodash/snakeCase.js');
|
|
5
5
|
const camelCase = require('lodash/camelCase.js');
|
|
6
6
|
const mapKeys = require('lodash/mapKeys.js');
|
|
7
|
+
const mondayFetch = require('@mondaydotcomorg/monday-fetch');
|
|
7
8
|
const tridentBackendApi = require('@mondaydotcomorg/trident-backend-api');
|
|
8
9
|
const mondayFetchApi = require('@mondaydotcomorg/monday-fetch-api');
|
|
9
10
|
const igniteSdk = require('@mondaydotcomorg/ignite-sdk');
|
|
@@ -20,9 +21,6 @@ const mapKeys__default = /*#__PURE__*/_interopDefault(mapKeys);
|
|
|
20
21
|
const GRANTED_FEATURE_CACHE_EXPIRATION_SECONDS = 5 * 60;
|
|
21
22
|
const PLATFORM_AUTHORIZE_PATH = '/internal_ms/authorization/authorize';
|
|
22
23
|
const PLATFORM_CAN_ACTIONS_IN_SCOPES_PATH = '/internal_ms/authorization/can_actions_in_scopes';
|
|
23
|
-
const ALLOWED_SDK_PLATFORM_PROFILES_KEY = 'allowed-sdk-platform-profiles';
|
|
24
|
-
const IN_RELEASE_SDK_PLATFORM_PROFILES_KEY = 'in-release-sdk-platform-profile';
|
|
25
|
-
const PLATFORM_PROFILE_RELEASE_FF = 'sdk-platform-profiles';
|
|
26
24
|
function setRequestFetchOptions(customMondayFetchOptions) {
|
|
27
25
|
authorizationInternalService.AuthorizationInternalService.setRequestFetchOptions(customMondayFetchOptions);
|
|
28
26
|
}
|
|
@@ -77,33 +75,61 @@ class AuthorizationService {
|
|
|
77
75
|
const scopedActionResponseObjects = await this.canActionInScopeMultiple(accountId, userId, scopedActions);
|
|
78
76
|
return scopedActionResponseObjects[0].permit;
|
|
79
77
|
}
|
|
80
|
-
|
|
81
|
-
|
|
78
|
+
/**
|
|
79
|
+
* @deprecated - gradually phasing this out
|
|
80
|
+
* @param accountId
|
|
81
|
+
* @param userId
|
|
82
|
+
* @param scopedActions
|
|
83
|
+
*/
|
|
84
|
+
static async canActionInScopeMultiple_withoutPlatformProfile(accountId, userId, scopedActions) {
|
|
85
|
+
const internalAuthToken = authorizationInternalService.AuthorizationInternalService.generateInternalAuthToken(accountId, userId);
|
|
86
|
+
const scopedActionsPayload = scopedActions.map(scopedAction => {
|
|
87
|
+
return { ...scopedAction, scope: mapKeys__default.default(scopedAction.scope, (_, key) => snakeCase__default.default(key)) }; // for example: { workspaceId: 1 } => { workspace_id: 1 }
|
|
88
|
+
});
|
|
89
|
+
const attributionHeaders = attributionsService.getAttributionsFromApi();
|
|
90
|
+
const response = await mondayFetch.fetch(getCanActionsInScopesUrl(), {
|
|
91
|
+
method: 'POST',
|
|
92
|
+
headers: {
|
|
93
|
+
Authorization: internalAuthToken,
|
|
94
|
+
'Content-Type': 'application/json',
|
|
95
|
+
...attributionHeaders,
|
|
96
|
+
},
|
|
97
|
+
timeout: authorizationInternalService.AuthorizationInternalService.getRequestTimeout(),
|
|
98
|
+
body: JSON.stringify({
|
|
99
|
+
user_id: userId,
|
|
100
|
+
scoped_actions: scopedActionsPayload,
|
|
101
|
+
}),
|
|
102
|
+
}, authorizationInternalService.AuthorizationInternalService.getRequestFetchOptions());
|
|
103
|
+
authorizationInternalService.AuthorizationInternalService.throwOnHttpErrorIfNeeded(response, 'canActionInScopeMultiple');
|
|
104
|
+
const responseBody = await response.json();
|
|
105
|
+
const camelCaseKeys = obj => Object.fromEntries(Object.entries(obj).map(([key, value]) => [camelCase__default.default(key), value]));
|
|
106
|
+
const scopedActionsResponseObjects = responseBody.result.map(responseObject => {
|
|
107
|
+
const { scopedAction, permit } = responseObject;
|
|
108
|
+
const { scope } = scopedAction;
|
|
109
|
+
const transformKeys = obj => camelCaseKeys(obj);
|
|
110
|
+
return {
|
|
111
|
+
...responseObject,
|
|
112
|
+
scopedAction: { ...scopedAction, scope: transformKeys(scope) },
|
|
113
|
+
permit: transformKeys(permit),
|
|
114
|
+
};
|
|
115
|
+
});
|
|
116
|
+
return scopedActionsResponseObjects;
|
|
117
|
+
}
|
|
118
|
+
static async canActionInScopeMultiple(accountId, userId, scopedActions) {
|
|
119
|
+
// gradually release the new platform profile features
|
|
82
120
|
if (!this.igniteClient) {
|
|
83
|
-
authorizationInternalService.logger.
|
|
84
|
-
throw new Error('AuthorizationService: igniteClient is not set, failing request');
|
|
85
|
-
}
|
|
86
|
-
if (this.igniteClient.configuration
|
|
87
|
-
.getObjectValue(ALLOWED_SDK_PLATFORM_PROFILES_KEY, [])
|
|
88
|
-
.includes(appName)) {
|
|
89
|
-
return attributionsService.getProfile();
|
|
121
|
+
authorizationInternalService.logger.warn({ tag: 'authorization-service' }, 'AuthorizationService: igniteClient is not set, using new platform profile feature');
|
|
90
122
|
}
|
|
91
|
-
if (this.igniteClient.
|
|
92
|
-
.
|
|
93
|
-
.includes(appName) &&
|
|
94
|
-
this.igniteClient.isReleased(PLATFORM_PROFILE_RELEASE_FF, { accountId, userId })) {
|
|
95
|
-
return attributionsService.getProfile();
|
|
123
|
+
else if (!this.igniteClient.isReleased('sdk-platform-profiles', { accountId, userId })) {
|
|
124
|
+
return AuthorizationService.canActionInScopeMultiple_withoutPlatformProfile(accountId, userId, scopedActions);
|
|
96
125
|
}
|
|
97
|
-
return attributionsService.PlatformProfile.INTERNAL;
|
|
98
|
-
}
|
|
99
|
-
static async canActionInScopeMultiple(accountId, userId, scopedActions) {
|
|
100
|
-
const profile = this.getProfile(accountId, userId);
|
|
101
126
|
const internalAuthToken = authorizationInternalService.AuthorizationInternalService.generateInternalAuthToken(accountId, userId);
|
|
102
127
|
const scopedActionsPayload = scopedActions.map(scopedAction => {
|
|
103
128
|
return { ...scopedAction, scope: mapKeys__default.default(scopedAction.scope, (_, key) => snakeCase__default.default(key)) }; // for example: { workspaceId: 1 } => { workspace_id: 1 }
|
|
104
129
|
});
|
|
105
130
|
const attributionHeaders = attributionsService.getAttributionsFromApi();
|
|
106
131
|
const httpClient = tridentBackendApi.Api.getPart('httpClient');
|
|
132
|
+
const profile = attributionsService.getProfile();
|
|
107
133
|
let response;
|
|
108
134
|
try {
|
|
109
135
|
response = await httpClient.fetch({
|
|
@@ -157,12 +183,67 @@ class AuthorizationService {
|
|
|
157
183
|
const { authorizationObjects } = createAuthorizationParams(resources, action);
|
|
158
184
|
return this.isAuthorizedMultiple(accountId, userId, authorizationObjects);
|
|
159
185
|
}
|
|
186
|
+
/**
|
|
187
|
+
* @deprecated - gradually phasing this out
|
|
188
|
+
* @param accountId
|
|
189
|
+
* @param userId
|
|
190
|
+
* @param authorizationRequestObjects
|
|
191
|
+
* @private
|
|
192
|
+
*/
|
|
193
|
+
static async isAuthorizedMultiple_withoutPlatformProfile(accountId, userId, authorizationRequestObjects) {
|
|
194
|
+
const internalAuthToken = authorizationInternalService.AuthorizationInternalService.generateInternalAuthToken(accountId, userId);
|
|
195
|
+
const startTime = perf_hooks.performance.now();
|
|
196
|
+
const attributionHeaders = attributionsService.getAttributionsFromApi();
|
|
197
|
+
const response = await mondayFetch.fetch(getAuthorizeUrl(), {
|
|
198
|
+
method: 'POST',
|
|
199
|
+
headers: {
|
|
200
|
+
Authorization: internalAuthToken,
|
|
201
|
+
'Content-Type': 'application/json',
|
|
202
|
+
...attributionHeaders,
|
|
203
|
+
},
|
|
204
|
+
timeout: authorizationInternalService.AuthorizationInternalService.getRequestTimeout(),
|
|
205
|
+
body: JSON.stringify({
|
|
206
|
+
user_id: userId,
|
|
207
|
+
authorize_request_objects: authorizationRequestObjects,
|
|
208
|
+
}),
|
|
209
|
+
}, authorizationInternalService.AuthorizationInternalService.getRequestFetchOptions());
|
|
210
|
+
const endTime = perf_hooks.performance.now();
|
|
211
|
+
const time = endTime - startTime;
|
|
212
|
+
const responseStatus = response.status;
|
|
213
|
+
authorizationInternalService.AuthorizationInternalService.throwOnHttpErrorIfNeeded(response, 'isAuthorizedMultiple');
|
|
214
|
+
const responseBody = await response.json();
|
|
215
|
+
const unauthorizedObjects = [];
|
|
216
|
+
responseBody.result.forEach(function (isAuthorized, index) {
|
|
217
|
+
const authorizationObject = authorizationRequestObjects[index];
|
|
218
|
+
if (!isAuthorized) {
|
|
219
|
+
unauthorizedObjects.push(authorizationObject);
|
|
220
|
+
}
|
|
221
|
+
prometheusService.sendAuthorizationCheckResponseTimeMetric(authorizationObject.resource_type, authorizationObject.action, isAuthorized, responseStatus, time);
|
|
222
|
+
});
|
|
223
|
+
if (unauthorizedObjects.length > 0) {
|
|
224
|
+
authorizationInternalService.logger.info({
|
|
225
|
+
resources: JSON.stringify(unauthorizedObjects),
|
|
226
|
+
}, 'AuthorizationService: resource is unauthorized');
|
|
227
|
+
const unauthorizedIds = unauthorizedObjects
|
|
228
|
+
.filter(obj => !!obj.resource_id)
|
|
229
|
+
.map(obj => obj.resource_id);
|
|
230
|
+
return { isAuthorized: false, unauthorizedIds, unauthorizedObjects };
|
|
231
|
+
}
|
|
232
|
+
return { isAuthorized: true };
|
|
233
|
+
}
|
|
160
234
|
static async isAuthorizedMultiple(accountId, userId, authorizationRequestObjects) {
|
|
161
|
-
|
|
235
|
+
// gradually release the new platform profile features
|
|
236
|
+
if (!this.igniteClient) {
|
|
237
|
+
authorizationInternalService.logger.warn({ tag: 'authorization-service' }, 'AuthorizationService: igniteClient is not set, using new platform profile feature');
|
|
238
|
+
}
|
|
239
|
+
else if (!this.igniteClient.isReleased('sdk-platform-profiles', { accountId, userId })) {
|
|
240
|
+
return AuthorizationService.isAuthorizedMultiple_withoutPlatformProfile(accountId, userId, authorizationRequestObjects);
|
|
241
|
+
}
|
|
162
242
|
const internalAuthToken = authorizationInternalService.AuthorizationInternalService.generateInternalAuthToken(accountId, userId);
|
|
163
243
|
const startTime = perf_hooks.performance.now();
|
|
164
244
|
const attributionHeaders = attributionsService.getAttributionsFromApi();
|
|
165
245
|
const httpClient = tridentBackendApi.Api.getPart('httpClient');
|
|
246
|
+
const profile = attributionsService.getProfile();
|
|
166
247
|
let response;
|
|
167
248
|
try {
|
|
168
249
|
response = await httpClient.fetch({
|
|
@@ -232,7 +313,7 @@ function setRedisClient(client, grantedFeatureRedisExpirationInSeconds = GRANTED
|
|
|
232
313
|
}
|
|
233
314
|
async function setIgniteClient() {
|
|
234
315
|
AuthorizationService.igniteClient = await igniteSdk.getIgniteClient({
|
|
235
|
-
namespace: ['authorization
|
|
316
|
+
namespace: ['authorization'],
|
|
236
317
|
});
|
|
237
318
|
}
|
|
238
319
|
function createAuthorizationParams(resources, action) {
|
|
@@ -251,6 +332,12 @@ function createAuthorizationParams(resources, action) {
|
|
|
251
332
|
};
|
|
252
333
|
return params;
|
|
253
334
|
}
|
|
335
|
+
function getAuthorizeUrl() {
|
|
336
|
+
return `${process.env.MONDAY_INTERNAL_URL}/internal_ms/authorization/authorize`;
|
|
337
|
+
}
|
|
338
|
+
function getCanActionsInScopesUrl() {
|
|
339
|
+
return `${process.env.MONDAY_INTERNAL_URL}/internal_ms/authorization/can_actions_in_scopes`;
|
|
340
|
+
}
|
|
254
341
|
|
|
255
342
|
exports.AuthorizationService = AuthorizationService;
|
|
256
343
|
exports.createAuthorizationParams = createAuthorizationParams;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Context, ExecutionContext } from '@mondaydotcomorg/trident-backend-api';
|
|
2
|
-
|
|
2
|
+
declare enum PlatformProfile {
|
|
3
3
|
API_INTERNAL = "api-internal",
|
|
4
4
|
SLOW = "slow",
|
|
5
5
|
INTERNAL = "internal"
|
|
@@ -9,4 +9,5 @@ export declare function getExecutionContext(context: Context): ExecutionContext;
|
|
|
9
9
|
export declare function getAttributionsFromApi(): {
|
|
10
10
|
[key: string]: string;
|
|
11
11
|
};
|
|
12
|
+
export {};
|
|
12
13
|
//# sourceMappingURL=attributions-service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attributions-service.d.ts","sourceRoot":"","sources":["../../src/attributions-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,OAAO,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AAStF,
|
|
1
|
+
{"version":3,"file":"attributions-service.d.ts","sourceRoot":"","sources":["../../src/attributions-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,OAAO,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AAStF,aAAK,eAAe;IAClB,YAAY,iBAAiB;IAC7B,IAAI,SAAS;IACb,QAAQ,aAAa;CACtB;AAED,wBAAgB,UAAU,oBAiBzB;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,gBAAgB,CAEtE;AAED,wBAAgB,sBAAsB,IAAI;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,CAqClE"}
|
|
@@ -28,9 +28,23 @@ export declare class AuthorizationService {
|
|
|
28
28
|
private static fetchIsUserGrantedWithFeature;
|
|
29
29
|
private static getCachedKeyName;
|
|
30
30
|
static canActionInScope(accountId: number, userId: number, action: string, scope: ScopeOptions): Promise<ScopedActionPermit>;
|
|
31
|
-
|
|
31
|
+
/**
|
|
32
|
+
* @deprecated - gradually phasing this out
|
|
33
|
+
* @param accountId
|
|
34
|
+
* @param userId
|
|
35
|
+
* @param scopedActions
|
|
36
|
+
*/
|
|
37
|
+
private static canActionInScopeMultiple_withoutPlatformProfile;
|
|
32
38
|
static canActionInScopeMultiple(accountId: number, userId: number, scopedActions: ScopedAction[]): Promise<ScopedActionResponseObject[]>;
|
|
33
39
|
private static isAuthorizedSingular;
|
|
40
|
+
/**
|
|
41
|
+
* @deprecated - gradually phasing this out
|
|
42
|
+
* @param accountId
|
|
43
|
+
* @param userId
|
|
44
|
+
* @param authorizationRequestObjects
|
|
45
|
+
* @private
|
|
46
|
+
*/
|
|
47
|
+
private static isAuthorizedMultiple_withoutPlatformProfile;
|
|
34
48
|
private static isAuthorizedMultiple;
|
|
35
49
|
}
|
|
36
50
|
export declare function setRedisClient(client: any, grantedFeatureRedisExpirationInSeconds?: number): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authorization-service.d.ts","sourceRoot":"","sources":["../../src/authorization-service.ts"],"names":[],"mappings":"AAIA,OAAO,
|
|
1
|
+
{"version":3,"file":"authorization-service.d.ts","sourceRoot":"","sources":["../../src/authorization-service.ts"],"names":[],"mappings":"AAIA,OAAO,EAAS,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAG1E,OAAO,EAAmB,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE7F,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,0BAA0B,EAC1B,YAAY,EACb,MAAM,kCAAkC,CAAC;AAQ1C,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,OAAO,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,mBAAmB,CAAC,EAAE,mBAAmB,EAAE,CAAC;CAC7C;AAED,wBAAgB,sBAAsB,CAAC,wBAAwB,EAAE,kBAAkB,QAElF;AAeD,qBAAa,oBAAoB;IAC/B,MAAM,CAAC,WAAW,CAAC,MAAC;IACpB,MAAM,CAAC,sCAAsC,CAAC,EAAE,MAAM,CAAC;IACvD,MAAM,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC;IAEnC;;;OAGG;WACU,YAAY,CACvB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,QAAQ,EAAE,EACrB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,iBAAiB,CAAC;WAEhB,YAAY,CACvB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,2BAA2B,EAAE,mBAAmB,EAAE,GACjD,OAAO,CAAC,iBAAiB,CAAC;IAY7B;;;OAGG;WACU,wBAAwB,CACnC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAO,GAC1C,OAAO,CAAC,OAAO,CAAC;mBAkBE,6BAA6B;IAclD,OAAO,CAAC,MAAM,CAAC,gBAAgB;WAIlB,gBAAgB,CAC3B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,kBAAkB,CAAC;IAM9B;;;;;OAKG;mBACkB,+CAA+C;WAgDvD,wBAAwB,CACnC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,YAAY,EAAE,GAC5B,OAAO,CAAC,0BAA0B,EAAE,CAAC;mBA4EnB,oBAAoB;IAUzC;;;;;;OAMG;mBACkB,2CAA2C;mBAiE3C,oBAAoB;CAiG1C;AAED,wBAAgB,cAAc,CAC5B,MAAM,KAAA,EACN,sCAAsC,GAAE,MAAiD,QAY1F;AAED,wBAAsB,eAAe,kBAIpC;AAED,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,mBAAmB,CAepG"}
|
|
@@ -2,19 +2,17 @@ import { performance } from 'perf_hooks';
|
|
|
2
2
|
import snakeCase from 'lodash/snakeCase.js';
|
|
3
3
|
import camelCase from 'lodash/camelCase.js';
|
|
4
4
|
import mapKeys from 'lodash/mapKeys.js';
|
|
5
|
+
import { fetch } from '@mondaydotcomorg/monday-fetch';
|
|
5
6
|
import { Api } from '@mondaydotcomorg/trident-backend-api';
|
|
6
7
|
import { HttpFetcherError } from '@mondaydotcomorg/monday-fetch-api';
|
|
7
8
|
import { getIgniteClient } from '@mondaydotcomorg/ignite-sdk';
|
|
8
9
|
import { sendAuthorizationCheckResponseTimeMetric } from './prometheus-service.mjs';
|
|
9
10
|
import { AuthorizationInternalService, logger } from './authorization-internal-service.mjs';
|
|
10
|
-
import {
|
|
11
|
+
import { getAttributionsFromApi, getProfile } from './attributions-service.mjs';
|
|
11
12
|
|
|
12
13
|
const GRANTED_FEATURE_CACHE_EXPIRATION_SECONDS = 5 * 60;
|
|
13
14
|
const PLATFORM_AUTHORIZE_PATH = '/internal_ms/authorization/authorize';
|
|
14
15
|
const PLATFORM_CAN_ACTIONS_IN_SCOPES_PATH = '/internal_ms/authorization/can_actions_in_scopes';
|
|
15
|
-
const ALLOWED_SDK_PLATFORM_PROFILES_KEY = 'allowed-sdk-platform-profiles';
|
|
16
|
-
const IN_RELEASE_SDK_PLATFORM_PROFILES_KEY = 'in-release-sdk-platform-profile';
|
|
17
|
-
const PLATFORM_PROFILE_RELEASE_FF = 'sdk-platform-profiles';
|
|
18
16
|
function setRequestFetchOptions(customMondayFetchOptions) {
|
|
19
17
|
AuthorizationInternalService.setRequestFetchOptions(customMondayFetchOptions);
|
|
20
18
|
}
|
|
@@ -69,33 +67,61 @@ class AuthorizationService {
|
|
|
69
67
|
const scopedActionResponseObjects = await this.canActionInScopeMultiple(accountId, userId, scopedActions);
|
|
70
68
|
return scopedActionResponseObjects[0].permit;
|
|
71
69
|
}
|
|
72
|
-
|
|
73
|
-
|
|
70
|
+
/**
|
|
71
|
+
* @deprecated - gradually phasing this out
|
|
72
|
+
* @param accountId
|
|
73
|
+
* @param userId
|
|
74
|
+
* @param scopedActions
|
|
75
|
+
*/
|
|
76
|
+
static async canActionInScopeMultiple_withoutPlatformProfile(accountId, userId, scopedActions) {
|
|
77
|
+
const internalAuthToken = AuthorizationInternalService.generateInternalAuthToken(accountId, userId);
|
|
78
|
+
const scopedActionsPayload = scopedActions.map(scopedAction => {
|
|
79
|
+
return { ...scopedAction, scope: mapKeys(scopedAction.scope, (_, key) => snakeCase(key)) }; // for example: { workspaceId: 1 } => { workspace_id: 1 }
|
|
80
|
+
});
|
|
81
|
+
const attributionHeaders = getAttributionsFromApi();
|
|
82
|
+
const response = await fetch(getCanActionsInScopesUrl(), {
|
|
83
|
+
method: 'POST',
|
|
84
|
+
headers: {
|
|
85
|
+
Authorization: internalAuthToken,
|
|
86
|
+
'Content-Type': 'application/json',
|
|
87
|
+
...attributionHeaders,
|
|
88
|
+
},
|
|
89
|
+
timeout: AuthorizationInternalService.getRequestTimeout(),
|
|
90
|
+
body: JSON.stringify({
|
|
91
|
+
user_id: userId,
|
|
92
|
+
scoped_actions: scopedActionsPayload,
|
|
93
|
+
}),
|
|
94
|
+
}, AuthorizationInternalService.getRequestFetchOptions());
|
|
95
|
+
AuthorizationInternalService.throwOnHttpErrorIfNeeded(response, 'canActionInScopeMultiple');
|
|
96
|
+
const responseBody = await response.json();
|
|
97
|
+
const camelCaseKeys = obj => Object.fromEntries(Object.entries(obj).map(([key, value]) => [camelCase(key), value]));
|
|
98
|
+
const scopedActionsResponseObjects = responseBody.result.map(responseObject => {
|
|
99
|
+
const { scopedAction, permit } = responseObject;
|
|
100
|
+
const { scope } = scopedAction;
|
|
101
|
+
const transformKeys = obj => camelCaseKeys(obj);
|
|
102
|
+
return {
|
|
103
|
+
...responseObject,
|
|
104
|
+
scopedAction: { ...scopedAction, scope: transformKeys(scope) },
|
|
105
|
+
permit: transformKeys(permit),
|
|
106
|
+
};
|
|
107
|
+
});
|
|
108
|
+
return scopedActionsResponseObjects;
|
|
109
|
+
}
|
|
110
|
+
static async canActionInScopeMultiple(accountId, userId, scopedActions) {
|
|
111
|
+
// gradually release the new platform profile features
|
|
74
112
|
if (!this.igniteClient) {
|
|
75
|
-
logger.
|
|
76
|
-
throw new Error('AuthorizationService: igniteClient is not set, failing request');
|
|
77
|
-
}
|
|
78
|
-
if (this.igniteClient.configuration
|
|
79
|
-
.getObjectValue(ALLOWED_SDK_PLATFORM_PROFILES_KEY, [])
|
|
80
|
-
.includes(appName)) {
|
|
81
|
-
return getProfile();
|
|
113
|
+
logger.warn({ tag: 'authorization-service' }, 'AuthorizationService: igniteClient is not set, using new platform profile feature');
|
|
82
114
|
}
|
|
83
|
-
if (this.igniteClient.
|
|
84
|
-
.
|
|
85
|
-
.includes(appName) &&
|
|
86
|
-
this.igniteClient.isReleased(PLATFORM_PROFILE_RELEASE_FF, { accountId, userId })) {
|
|
87
|
-
return getProfile();
|
|
115
|
+
else if (!this.igniteClient.isReleased('sdk-platform-profiles', { accountId, userId })) {
|
|
116
|
+
return AuthorizationService.canActionInScopeMultiple_withoutPlatformProfile(accountId, userId, scopedActions);
|
|
88
117
|
}
|
|
89
|
-
return PlatformProfile.INTERNAL;
|
|
90
|
-
}
|
|
91
|
-
static async canActionInScopeMultiple(accountId, userId, scopedActions) {
|
|
92
|
-
const profile = this.getProfile(accountId, userId);
|
|
93
118
|
const internalAuthToken = AuthorizationInternalService.generateInternalAuthToken(accountId, userId);
|
|
94
119
|
const scopedActionsPayload = scopedActions.map(scopedAction => {
|
|
95
120
|
return { ...scopedAction, scope: mapKeys(scopedAction.scope, (_, key) => snakeCase(key)) }; // for example: { workspaceId: 1 } => { workspace_id: 1 }
|
|
96
121
|
});
|
|
97
122
|
const attributionHeaders = getAttributionsFromApi();
|
|
98
123
|
const httpClient = Api.getPart('httpClient');
|
|
124
|
+
const profile = getProfile();
|
|
99
125
|
let response;
|
|
100
126
|
try {
|
|
101
127
|
response = await httpClient.fetch({
|
|
@@ -149,12 +175,67 @@ class AuthorizationService {
|
|
|
149
175
|
const { authorizationObjects } = createAuthorizationParams(resources, action);
|
|
150
176
|
return this.isAuthorizedMultiple(accountId, userId, authorizationObjects);
|
|
151
177
|
}
|
|
178
|
+
/**
|
|
179
|
+
* @deprecated - gradually phasing this out
|
|
180
|
+
* @param accountId
|
|
181
|
+
* @param userId
|
|
182
|
+
* @param authorizationRequestObjects
|
|
183
|
+
* @private
|
|
184
|
+
*/
|
|
185
|
+
static async isAuthorizedMultiple_withoutPlatformProfile(accountId, userId, authorizationRequestObjects) {
|
|
186
|
+
const internalAuthToken = AuthorizationInternalService.generateInternalAuthToken(accountId, userId);
|
|
187
|
+
const startTime = performance.now();
|
|
188
|
+
const attributionHeaders = getAttributionsFromApi();
|
|
189
|
+
const response = await fetch(getAuthorizeUrl(), {
|
|
190
|
+
method: 'POST',
|
|
191
|
+
headers: {
|
|
192
|
+
Authorization: internalAuthToken,
|
|
193
|
+
'Content-Type': 'application/json',
|
|
194
|
+
...attributionHeaders,
|
|
195
|
+
},
|
|
196
|
+
timeout: AuthorizationInternalService.getRequestTimeout(),
|
|
197
|
+
body: JSON.stringify({
|
|
198
|
+
user_id: userId,
|
|
199
|
+
authorize_request_objects: authorizationRequestObjects,
|
|
200
|
+
}),
|
|
201
|
+
}, AuthorizationInternalService.getRequestFetchOptions());
|
|
202
|
+
const endTime = performance.now();
|
|
203
|
+
const time = endTime - startTime;
|
|
204
|
+
const responseStatus = response.status;
|
|
205
|
+
AuthorizationInternalService.throwOnHttpErrorIfNeeded(response, 'isAuthorizedMultiple');
|
|
206
|
+
const responseBody = await response.json();
|
|
207
|
+
const unauthorizedObjects = [];
|
|
208
|
+
responseBody.result.forEach(function (isAuthorized, index) {
|
|
209
|
+
const authorizationObject = authorizationRequestObjects[index];
|
|
210
|
+
if (!isAuthorized) {
|
|
211
|
+
unauthorizedObjects.push(authorizationObject);
|
|
212
|
+
}
|
|
213
|
+
sendAuthorizationCheckResponseTimeMetric(authorizationObject.resource_type, authorizationObject.action, isAuthorized, responseStatus, time);
|
|
214
|
+
});
|
|
215
|
+
if (unauthorizedObjects.length > 0) {
|
|
216
|
+
logger.info({
|
|
217
|
+
resources: JSON.stringify(unauthorizedObjects),
|
|
218
|
+
}, 'AuthorizationService: resource is unauthorized');
|
|
219
|
+
const unauthorizedIds = unauthorizedObjects
|
|
220
|
+
.filter(obj => !!obj.resource_id)
|
|
221
|
+
.map(obj => obj.resource_id);
|
|
222
|
+
return { isAuthorized: false, unauthorizedIds, unauthorizedObjects };
|
|
223
|
+
}
|
|
224
|
+
return { isAuthorized: true };
|
|
225
|
+
}
|
|
152
226
|
static async isAuthorizedMultiple(accountId, userId, authorizationRequestObjects) {
|
|
153
|
-
|
|
227
|
+
// gradually release the new platform profile features
|
|
228
|
+
if (!this.igniteClient) {
|
|
229
|
+
logger.warn({ tag: 'authorization-service' }, 'AuthorizationService: igniteClient is not set, using new platform profile feature');
|
|
230
|
+
}
|
|
231
|
+
else if (!this.igniteClient.isReleased('sdk-platform-profiles', { accountId, userId })) {
|
|
232
|
+
return AuthorizationService.isAuthorizedMultiple_withoutPlatformProfile(accountId, userId, authorizationRequestObjects);
|
|
233
|
+
}
|
|
154
234
|
const internalAuthToken = AuthorizationInternalService.generateInternalAuthToken(accountId, userId);
|
|
155
235
|
const startTime = performance.now();
|
|
156
236
|
const attributionHeaders = getAttributionsFromApi();
|
|
157
237
|
const httpClient = Api.getPart('httpClient');
|
|
238
|
+
const profile = getProfile();
|
|
158
239
|
let response;
|
|
159
240
|
try {
|
|
160
241
|
response = await httpClient.fetch({
|
|
@@ -224,7 +305,7 @@ function setRedisClient(client, grantedFeatureRedisExpirationInSeconds = GRANTED
|
|
|
224
305
|
}
|
|
225
306
|
async function setIgniteClient() {
|
|
226
307
|
AuthorizationService.igniteClient = await getIgniteClient({
|
|
227
|
-
namespace: ['authorization
|
|
308
|
+
namespace: ['authorization'],
|
|
228
309
|
});
|
|
229
310
|
}
|
|
230
311
|
function createAuthorizationParams(resources, action) {
|
|
@@ -243,5 +324,11 @@ function createAuthorizationParams(resources, action) {
|
|
|
243
324
|
};
|
|
244
325
|
return params;
|
|
245
326
|
}
|
|
327
|
+
function getAuthorizeUrl() {
|
|
328
|
+
return `${process.env.MONDAY_INTERNAL_URL}/internal_ms/authorization/authorize`;
|
|
329
|
+
}
|
|
330
|
+
function getCanActionsInScopesUrl() {
|
|
331
|
+
return `${process.env.MONDAY_INTERNAL_URL}/internal_ms/authorization/can_actions_in_scopes`;
|
|
332
|
+
}
|
|
246
333
|
|
|
247
334
|
export { AuthorizationService, createAuthorizationParams, setIgniteClient, setRedisClient, setRequestFetchOptions };
|
package/package.json
CHANGED