@mondaydotcomorg/monday-authorization 1.1.8 → 1.1.9-authzbashanyeadd-async-resource-attributes-support.3112
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/CHANGELOG.md +15 -0
- package/README.md +32 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +28 -1
- package/dist/lib/attributions-service.d.ts +3 -0
- package/dist/lib/attributions-service.js +54 -0
- package/dist/lib/authorization-attributes-service.d.ts +33 -0
- package/dist/lib/authorization-attributes-service.js +105 -0
- package/dist/lib/authorization-internal-service.d.ts +8 -0
- package/dist/lib/authorization-internal-service.js +62 -1
- package/dist/lib/authorization-middleware.d.ts +2 -1
- package/dist/lib/authorization-middleware.js +4 -1
- package/dist/lib/authorization-service.d.ts +2 -1
- package/dist/lib/authorization-service.js +20 -68
- package/dist/lib/testKit/index.d.ts +11 -0
- package/dist/lib/testKit/index.js +58 -0
- package/dist/lib/types/authorization-attributes-contracts.d.ts +15 -0
- package/dist/lib/types/authorization-attributes-contracts.js +2 -0
- package/package.json +7 -5
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
|
6
6
|
and this project adheres to [Semantic Versioning](http://semver.org/).
|
|
7
7
|
|
|
8
|
+
## [1.2.9] - 2024-10-06
|
|
9
|
+
### Added
|
|
10
|
+
- [`authz/bashanye/add-async-resource-attributes-support`](https://github.com/DaPulse/monday-npm-packages/pull/6859)
|
|
11
|
+
- `AuthorizationAttributesService` - now supports async upsert and delete (sending through SNS-SQS).
|
|
12
|
+
|
|
13
|
+
## [1.2.3] - 2024-06-10
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- [`feature/yarden/resource-attributes-api-support-authz-sdk (#5826)`](https://github.com/DaPulse/monday-npm-packages/pull/5826)
|
|
17
|
+
- `AuthorizationAttributesService` - now supports upsert (`upsertResourceAttributesSync`) and delete (`deleteResourceAttributesSync`) resource attributes in the authorization MS
|
|
18
|
+
|
|
19
|
+
## [1.2.0] - 2024-01-05
|
|
20
|
+
### Added
|
|
21
|
+
- `isAuthorized` now return the unauthorized objects - regardless to the unauthorized ids (which may be missing resource ids if resource has no id, like `feature` e.g.)
|
|
22
|
+
|
|
8
23
|
## [1.1.0] - 2023-08-09
|
|
9
24
|
|
|
10
25
|
### ⚠ BREAKING CHANGES
|
package/README.md
CHANGED
|
@@ -136,3 +136,35 @@ const canActionInScopeMultipleResponse: ScopedActionResponseObject[] =
|
|
|
136
136
|
* ]
|
|
137
137
|
* /
|
|
138
138
|
```
|
|
139
|
+
|
|
140
|
+
### Authorization Attributes API
|
|
141
|
+
|
|
142
|
+
Use `AuthorizationAttributesService.upsertResourceAttributesSync` to upsert multiple resource attributes in the authorization MS synchronously.
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
import { AuthorizationAttributesService, ResourceAttributeAssignment, ResourceAttributeResponse } from '@mondaydotcomorg/monday-authorization';
|
|
146
|
+
|
|
147
|
+
const accountId = 739630;
|
|
148
|
+
const userId = 4;
|
|
149
|
+
const resourceAttributesAssignments: ResourceAttributeAssignment[] = [
|
|
150
|
+
{ resourceId: 18, resourceType: 'workspace', key: 'is_default_workspace', value: 'true' },
|
|
151
|
+
{ resourceId: 23, resourceType: 'board', key: 'board_kind', value: 'private' }
|
|
152
|
+
];
|
|
153
|
+
|
|
154
|
+
const response: ResourceAttributeResponse = await AuthorizationAttributesService.upsertResourceAttributesSync(accountId, userId, resourceAttributesAssignments);
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Use `AuthorizationAttributesService.deleteResourceAttributesSync` to delete single resource's attributes in the authorization MS synchronously.
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
```ts
|
|
161
|
+
import { AuthorizationAttributesService, ResourceAttributeResponse, Resource } from '@mondaydotcomorg/monday-authorization';
|
|
162
|
+
|
|
163
|
+
const accountId = 739630;
|
|
164
|
+
const userId = 4;
|
|
165
|
+
const resource: Resource = { type: 'workspace', id: 18 };
|
|
166
|
+
const attributeKeys: string[] = ['is_default_workspace', 'workspace_kind'];
|
|
167
|
+
|
|
168
|
+
const response: ResourceAttributeResponse = await AuthorizationAttributesService.deleteResourceAttributesSync(accountId, userId, resource, attributeKeys);
|
|
169
|
+
```
|
|
170
|
+
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { MondayFetchOptions } from '@mondaydotcomorg/monday-fetch';
|
|
2
|
+
import * as TestKit from './lib/testKit';
|
|
2
3
|
export interface InitOptions {
|
|
3
4
|
prometheus?: any;
|
|
4
5
|
mondayFetchOptions?: MondayFetchOptions;
|
|
@@ -8,3 +9,5 @@ export interface InitOptions {
|
|
|
8
9
|
export declare function init(options?: InitOptions): void;
|
|
9
10
|
export { authorizationCheckMiddleware, getAuthorizationMiddleware, skipAuthorizationMiddleware, } from './lib/authorization-middleware';
|
|
10
11
|
export { AuthorizationService } from './lib/authorization-service';
|
|
12
|
+
export { AuthorizationAttributesService } from './lib/authorization-attributes-service';
|
|
13
|
+
export { TestKit };
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,33 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
2
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.AuthorizationService = exports.skipAuthorizationMiddleware = exports.getAuthorizationMiddleware = exports.authorizationCheckMiddleware = exports.init = void 0;
|
|
26
|
+
exports.TestKit = exports.AuthorizationAttributesService = exports.AuthorizationService = exports.skipAuthorizationMiddleware = exports.getAuthorizationMiddleware = exports.authorizationCheckMiddleware = exports.init = void 0;
|
|
4
27
|
const prometheus_service_1 = require("./lib/prometheus-service");
|
|
5
28
|
const authorization_service_1 = require("./lib/authorization-service");
|
|
29
|
+
const TestKit = __importStar(require("./lib/testKit"));
|
|
30
|
+
exports.TestKit = TestKit;
|
|
6
31
|
function init(options = {}) {
|
|
7
32
|
if (options.prometheus) {
|
|
8
33
|
(0, prometheus_service_1.setPrometheus)(options.prometheus);
|
|
@@ -21,3 +46,5 @@ Object.defineProperty(exports, "getAuthorizationMiddleware", { enumerable: true,
|
|
|
21
46
|
Object.defineProperty(exports, "skipAuthorizationMiddleware", { enumerable: true, get: function () { return authorization_middleware_1.skipAuthorizationMiddleware; } });
|
|
22
47
|
var authorization_service_2 = require("./lib/authorization-service");
|
|
23
48
|
Object.defineProperty(exports, "AuthorizationService", { enumerable: true, get: function () { return authorization_service_2.AuthorizationService; } });
|
|
49
|
+
var authorization_attributes_service_1 = require("./lib/authorization-attributes-service");
|
|
50
|
+
Object.defineProperty(exports, "AuthorizationAttributesService", { enumerable: true, get: function () { return authorization_attributes_service_1.AuthorizationAttributesService; } });
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getAttributionsFromApi = void 0;
|
|
4
|
+
const trident_backend_api_1 = require("@mondaydotcomorg/trident-backend-api");
|
|
5
|
+
const authorization_internal_service_1 = require("./authorization-internal-service");
|
|
6
|
+
const APP_NAME_VARIABLE_KEY = 'APP_NAME';
|
|
7
|
+
const APP_NAME_HEADER_NAME = 'x-caller-app-name-from-sdk';
|
|
8
|
+
const FROM_SDK_HEADER_SUFFIX = `-from-sdk`;
|
|
9
|
+
let didSendFailureLogOnce = false;
|
|
10
|
+
function getAttributionsFromApi() {
|
|
11
|
+
let callerAppNameFromSdk = {
|
|
12
|
+
[APP_NAME_HEADER_NAME]: tryJsonParse(getEnvVariable(APP_NAME_VARIABLE_KEY)),
|
|
13
|
+
};
|
|
14
|
+
try {
|
|
15
|
+
const tridentContext = trident_backend_api_1.Api.getPart('context');
|
|
16
|
+
if (!tridentContext) {
|
|
17
|
+
return callerAppNameFromSdk;
|
|
18
|
+
}
|
|
19
|
+
const { runtimeAttributions } = tridentContext;
|
|
20
|
+
let runtimeAttributionsOutgoingHeaders = runtimeAttributions === null || runtimeAttributions === void 0 ? void 0 : runtimeAttributions.buildOutgoingHeaders('HTTP_INTERNAL');
|
|
21
|
+
if (!runtimeAttributionsOutgoingHeaders) {
|
|
22
|
+
return callerAppNameFromSdk;
|
|
23
|
+
}
|
|
24
|
+
const attributionsHeaders = Object.fromEntries(runtimeAttributionsOutgoingHeaders);
|
|
25
|
+
const attributionHeadersFromSdk = {};
|
|
26
|
+
Object.keys(attributionsHeaders).forEach(function (key) {
|
|
27
|
+
attributionHeadersFromSdk[`${key}${FROM_SDK_HEADER_SUFFIX}`] = attributionsHeaders[key];
|
|
28
|
+
});
|
|
29
|
+
return attributionHeadersFromSdk;
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
if (!didSendFailureLogOnce) {
|
|
33
|
+
authorization_internal_service_1.logger.warn({ tag: 'authorization-service', error }, 'Failed to generate attributions headers from the API. Unexpected error while extracting headers. It may be caused by out of date Trident version.');
|
|
34
|
+
didSendFailureLogOnce = true;
|
|
35
|
+
}
|
|
36
|
+
return callerAppNameFromSdk;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
exports.getAttributionsFromApi = getAttributionsFromApi;
|
|
40
|
+
function getEnvVariable(key) {
|
|
41
|
+
const envVar = process.env[key] || process.env[key.toUpperCase()] || process.env[key.toLowerCase()];
|
|
42
|
+
return envVar;
|
|
43
|
+
}
|
|
44
|
+
function tryJsonParse(value) {
|
|
45
|
+
if (!value) {
|
|
46
|
+
return value;
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
return JSON.parse(value);
|
|
50
|
+
}
|
|
51
|
+
catch (_err) {
|
|
52
|
+
return value;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { ResourceAttributeAssignment, ResourceAttributeDelete, ResourceAttributeResponse } from './types/authorization-attributes-contracts';
|
|
2
|
+
import { Resource } from './types/general';
|
|
3
|
+
export declare class AuthorizationAttributesService {
|
|
4
|
+
/**
|
|
5
|
+
* Upsert resource attributes synchronously, performing http call to the authorization MS to assign the given attributes to the given resource.
|
|
6
|
+
* @param accountId
|
|
7
|
+
* @param userId
|
|
8
|
+
* @param resourceAttributeAssignments - Array of resource (resourceType, resourceId) and attribute (key, value) pairs to upsert in the authorization MS.
|
|
9
|
+
* e.g. [{ resourceType: 'board', resourceId: 123, key: 'board_kind', value: 'private' }]
|
|
10
|
+
* @returns ResourceAttributeResponse - The affected (created and updated_ resource attributes assignments in the `attributes` field.
|
|
11
|
+
*/
|
|
12
|
+
static upsertResourceAttributes(accountId: number, userId: number, resourceAttributeAssignments: ResourceAttributeAssignment[]): Promise<ResourceAttributeResponse>;
|
|
13
|
+
/**
|
|
14
|
+
* Delete resource attributes assignments synchronously, performing http call to the authorization MS to delete the given attributes from the given singular resource.
|
|
15
|
+
* @param accountId
|
|
16
|
+
* @param userId
|
|
17
|
+
* @param resource - The resource (resourceType, resourceId) to delete the attributes for.
|
|
18
|
+
* @param attributeKeys - Array of attribute keys to delete for the resource.
|
|
19
|
+
* @returns ResourceAttributeResponse - The affected (deleted) resource attributes assignments in the `attributes` field.
|
|
20
|
+
*/
|
|
21
|
+
static deleteResourceAttributes(accountId: number, userId: number, resource: Resource, attributeKeys: string[]): Promise<ResourceAttributeResponse>;
|
|
22
|
+
/**
|
|
23
|
+
* Async function, this function only send the updates request to SNS and return before the change actually took place
|
|
24
|
+
* @param accountId
|
|
25
|
+
* @param resourceAttributeUpserts - Array of resource and attributes keys to add or update their value.
|
|
26
|
+
* @param resourceAttributeDeletes - Array of resources and attribute keys to delete.
|
|
27
|
+
* */
|
|
28
|
+
static resourceAttributesAsyncUpdates(accountId: number, resourceAttributeUpserts: ResourceAttributeAssignment[], resourceAttributeDeletes: ResourceAttributeDelete[]): Promise<void>;
|
|
29
|
+
private static getUpsertOperations;
|
|
30
|
+
private static getDeleteOperations;
|
|
31
|
+
private static getSnsTopicArn;
|
|
32
|
+
private static getResourceAttributesUrl;
|
|
33
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.AuthorizationAttributesService = void 0;
|
|
13
|
+
const monday_fetch_1 = require("@mondaydotcomorg/monday-fetch");
|
|
14
|
+
const authorization_internal_service_1 = require("./authorization-internal-service");
|
|
15
|
+
const attributions_service_1 = require("./attributions-service");
|
|
16
|
+
const trident_backend_api_1 = require("@mondaydotcomorg/trident-backend-api");
|
|
17
|
+
const monday_sns_1 = require("@mondaydotcomorg/monday-sns");
|
|
18
|
+
class AuthorizationAttributesService {
|
|
19
|
+
/**
|
|
20
|
+
* Upsert resource attributes synchronously, performing http call to the authorization MS to assign the given attributes to the given resource.
|
|
21
|
+
* @param accountId
|
|
22
|
+
* @param userId
|
|
23
|
+
* @param resourceAttributeAssignments - Array of resource (resourceType, resourceId) and attribute (key, value) pairs to upsert in the authorization MS.
|
|
24
|
+
* e.g. [{ resourceType: 'board', resourceId: 123, key: 'board_kind', value: 'private' }]
|
|
25
|
+
* @returns ResourceAttributeResponse - The affected (created and updated_ resource attributes assignments in the `attributes` field.
|
|
26
|
+
*/
|
|
27
|
+
static upsertResourceAttributes(accountId, userId, resourceAttributeAssignments) {
|
|
28
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
29
|
+
const internalAuthToken = authorization_internal_service_1.AuthorizationInternalService.generateInternalAuthToken(accountId, userId);
|
|
30
|
+
const attributionHeaders = (0, attributions_service_1.getAttributionsFromApi)();
|
|
31
|
+
const response = yield (0, monday_fetch_1.fetch)(this.getResourceAttributesUrl(accountId), {
|
|
32
|
+
method: 'POST',
|
|
33
|
+
headers: Object.assign({ Authorization: internalAuthToken, 'Content-Type': 'application/json' }, attributionHeaders),
|
|
34
|
+
timeout: authorization_internal_service_1.AuthorizationInternalService.getRequestTimeout(),
|
|
35
|
+
body: JSON.stringify({ resourceAttributeAssignments }),
|
|
36
|
+
}, authorization_internal_service_1.AuthorizationInternalService.getRequestFetchOptions());
|
|
37
|
+
const responseBody = yield response.json();
|
|
38
|
+
authorization_internal_service_1.AuthorizationInternalService.throwOnHttpErrorIfNeeded(response, 'upsertResourceAttributesSync');
|
|
39
|
+
return { attributes: responseBody['attributes'] };
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Delete resource attributes assignments synchronously, performing http call to the authorization MS to delete the given attributes from the given singular resource.
|
|
44
|
+
* @param accountId
|
|
45
|
+
* @param userId
|
|
46
|
+
* @param resource - The resource (resourceType, resourceId) to delete the attributes for.
|
|
47
|
+
* @param attributeKeys - Array of attribute keys to delete for the resource.
|
|
48
|
+
* @returns ResourceAttributeResponse - The affected (deleted) resource attributes assignments in the `attributes` field.
|
|
49
|
+
*/
|
|
50
|
+
static deleteResourceAttributes(accountId, userId, resource, attributeKeys) {
|
|
51
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
52
|
+
const internalAuthToken = authorization_internal_service_1.AuthorizationInternalService.generateInternalAuthToken(accountId, userId);
|
|
53
|
+
const url = `${this.getResourceAttributesUrl(accountId)}/${resource.type}/${resource.id}`;
|
|
54
|
+
const attributionHeaders = (0, attributions_service_1.getAttributionsFromApi)();
|
|
55
|
+
const response = yield (0, monday_fetch_1.fetch)(url, {
|
|
56
|
+
method: 'DELETE',
|
|
57
|
+
headers: Object.assign({ Authorization: internalAuthToken, 'Content-Type': 'application/json' }, attributionHeaders),
|
|
58
|
+
timeout: authorization_internal_service_1.AuthorizationInternalService.getRequestTimeout(),
|
|
59
|
+
body: JSON.stringify({ keys: attributeKeys }),
|
|
60
|
+
}, authorization_internal_service_1.AuthorizationInternalService.getRequestFetchOptions());
|
|
61
|
+
const responseBody = yield response.json();
|
|
62
|
+
authorization_internal_service_1.AuthorizationInternalService.throwOnHttpErrorIfNeeded(response, 'deleteResourceAttributesSync');
|
|
63
|
+
return { attributes: responseBody['attributes'] };
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Async function, this function only send the updates request to SNS and return before the change actually took place
|
|
68
|
+
* @param accountId
|
|
69
|
+
* @param resourceAttributeUpserts - Array of resource and attributes keys to add or update their value.
|
|
70
|
+
* @param resourceAttributeDeletes - Array of resources and attribute keys to delete.
|
|
71
|
+
* */
|
|
72
|
+
static resourceAttributesAsyncUpdates(accountId, resourceAttributeUpserts, resourceAttributeDeletes) {
|
|
73
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
74
|
+
const topicArn = this.getSnsTopicArn();
|
|
75
|
+
const appName = process.env.APP_NAME;
|
|
76
|
+
const upsertOperations = this.getUpsertOperations(resourceAttributeUpserts);
|
|
77
|
+
const deleteOperations = this.getDeleteOperations(resourceAttributeDeletes);
|
|
78
|
+
const payload = {
|
|
79
|
+
accountId: accountId,
|
|
80
|
+
callerAppName: appName,
|
|
81
|
+
callerActionIdentifier: "test-action",
|
|
82
|
+
operations: [
|
|
83
|
+
...upsertOperations,
|
|
84
|
+
...deleteOperations,
|
|
85
|
+
],
|
|
86
|
+
};
|
|
87
|
+
yield (0, monday_sns_1.sendToSns)(payload, topicArn);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
static getUpsertOperations(resourceAttributeUpserts) {
|
|
91
|
+
return resourceAttributeUpserts.map((resourceAttributeUpsert) => (Object.assign({ operationType: "upsert" }, resourceAttributeUpsert)));
|
|
92
|
+
}
|
|
93
|
+
static getDeleteOperations(resourceAttributeDeletes) {
|
|
94
|
+
return resourceAttributeDeletes.map((resourceAttributeDelete) => (Object.assign({ operationType: "delete" }, resourceAttributeDelete)));
|
|
95
|
+
}
|
|
96
|
+
static getSnsTopicArn() {
|
|
97
|
+
var _a;
|
|
98
|
+
return ((_a = trident_backend_api_1.Api.getPart('configurationVariables')) === null || _a === void 0 ? void 0 : _a.get('authorization_resource_attributes_sns')) ||
|
|
99
|
+
process.env.AUTHORIZATION_RESOURCE_ATTRIBUTES_SNS;
|
|
100
|
+
}
|
|
101
|
+
static getResourceAttributesUrl(accountId) {
|
|
102
|
+
return `${process.env.AUTHORIZATION_URL}/attributes/${accountId}/resource`;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
exports.AuthorizationAttributesService = AuthorizationAttributesService;
|
|
@@ -1,6 +1,14 @@
|
|
|
1
|
+
/// <reference types="bunyan" />
|
|
1
2
|
import { Request } from 'express';
|
|
3
|
+
import { fetch, MondayFetchOptions } from '@mondaydotcomorg/monday-fetch';
|
|
4
|
+
export declare const logger: import("bunyan");
|
|
2
5
|
export declare class AuthorizationInternalService {
|
|
3
6
|
static skipAuthorization(requset: Request): void;
|
|
4
7
|
static markAuthorized(request: Request): void;
|
|
5
8
|
static failIfNotCoveredByAuthorization(request: Request): void;
|
|
9
|
+
static throwOnHttpErrorIfNeeded(response: Awaited<ReturnType<typeof fetch>>, placement: string): void;
|
|
10
|
+
static generateInternalAuthToken(accountId: number, userId: number): string;
|
|
11
|
+
static setRequestFetchOptions(customMondayFetchOptions: MondayFetchOptions): void;
|
|
12
|
+
static getRequestFetchOptions(): MondayFetchOptions;
|
|
13
|
+
static getRequestTimeout(): 60000 | 2000;
|
|
6
14
|
}
|
|
@@ -1,6 +1,46 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
2
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.AuthorizationInternalService = void 0;
|
|
26
|
+
exports.AuthorizationInternalService = exports.logger = void 0;
|
|
27
|
+
const monday_jwt_1 = require("@mondaydotcomorg/monday-jwt");
|
|
28
|
+
const MondayLogger = __importStar(require("@mondaydotcomorg/monday-logger"));
|
|
29
|
+
const INTERNAL_APP_NAME = 'internal_ms';
|
|
30
|
+
const defaultMondayFetchOptions = {
|
|
31
|
+
retries: 3,
|
|
32
|
+
callback: logOnFetchFail,
|
|
33
|
+
};
|
|
34
|
+
function logOnFetchFail(retriesLeft, error) {
|
|
35
|
+
if (retriesLeft == 0) {
|
|
36
|
+
exports.logger.error({ retriesLeft, error }, 'Authorization attempt failed due to network issues');
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
exports.logger.info({ retriesLeft, error }, 'Authorization attempt failed due to network issues, trying again');
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
let mondayFetchOptions = defaultMondayFetchOptions;
|
|
43
|
+
exports.logger = MondayLogger.getLogger();
|
|
4
44
|
class AuthorizationInternalService {
|
|
5
45
|
static skipAuthorization(requset) {
|
|
6
46
|
requset.authorizationSkipPerformed = true;
|
|
@@ -13,5 +53,26 @@ class AuthorizationInternalService {
|
|
|
13
53
|
throw 'Endpoint is not covered by authorization check';
|
|
14
54
|
}
|
|
15
55
|
}
|
|
56
|
+
static throwOnHttpErrorIfNeeded(response, placement) {
|
|
57
|
+
if (response.ok) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const status = response.status;
|
|
61
|
+
exports.logger.error({ tag: 'authorization-service', placement, status }, 'AuthorizationService: authorization request failed');
|
|
62
|
+
throw new Error(`AuthorizationService: [${placement}] authorization request failed with status ${status}`);
|
|
63
|
+
}
|
|
64
|
+
static generateInternalAuthToken(accountId, userId) {
|
|
65
|
+
return (0, monday_jwt_1.signAuthorizationHeader)({ appName: INTERNAL_APP_NAME, accountId, userId });
|
|
66
|
+
}
|
|
67
|
+
static setRequestFetchOptions(customMondayFetchOptions) {
|
|
68
|
+
mondayFetchOptions = Object.assign(Object.assign({}, defaultMondayFetchOptions), customMondayFetchOptions);
|
|
69
|
+
}
|
|
70
|
+
static getRequestFetchOptions() {
|
|
71
|
+
return mondayFetchOptions;
|
|
72
|
+
}
|
|
73
|
+
static getRequestTimeout() {
|
|
74
|
+
const isDevEnv = process.env.NODE_ENV === 'development';
|
|
75
|
+
return isDevEnv ? 60000 : 2000;
|
|
76
|
+
}
|
|
16
77
|
}
|
|
17
78
|
exports.AuthorizationInternalService = AuthorizationInternalService;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { NextFunction } from 'express';
|
|
2
|
-
import { Action, BaseRequest, BaseResponse, ContextGetter, ResourceGetter } from './types/general';
|
|
2
|
+
import { Action, BaseRequest, BaseResponse, Context, ContextGetter, ResourceGetter } from './types/general';
|
|
3
3
|
export declare function getAuthorizationMiddleware(action: Action, resourceGetter: ResourceGetter, contextGetter?: ContextGetter): (request: BaseRequest, response: BaseResponse, next: NextFunction) => Promise<void>;
|
|
4
4
|
export declare function skipAuthorizationMiddleware(request: BaseRequest, response: BaseResponse, next: NextFunction): void;
|
|
5
5
|
export declare function authorizationCheckMiddleware(request: BaseRequest, response: BaseResponse, next: NextFunction): void;
|
|
6
|
+
export declare function defaultContextGetter(request: BaseRequest): Context;
|
|
@@ -12,10 +12,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
12
12
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
13
|
};
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.authorizationCheckMiddleware = exports.skipAuthorizationMiddleware = exports.getAuthorizationMiddleware = void 0;
|
|
15
|
+
exports.defaultContextGetter = exports.authorizationCheckMiddleware = exports.skipAuthorizationMiddleware = exports.getAuthorizationMiddleware = void 0;
|
|
16
16
|
const on_headers_1 = __importDefault(require("on-headers"));
|
|
17
17
|
const authorization_internal_service_1 = require("./authorization-internal-service");
|
|
18
18
|
const authorization_service_1 = require("./authorization-service");
|
|
19
|
+
// getAuthorizationMiddleware is duplicated in testKit/index.ts
|
|
20
|
+
// If you are making changes to this function, please make sure to update the other file as well
|
|
19
21
|
function getAuthorizationMiddleware(action, resourceGetter, contextGetter) {
|
|
20
22
|
return function authorizationMiddleware(request, response, next) {
|
|
21
23
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -52,3 +54,4 @@ exports.authorizationCheckMiddleware = authorizationCheckMiddleware;
|
|
|
52
54
|
function defaultContextGetter(request) {
|
|
53
55
|
return request.payload;
|
|
54
56
|
}
|
|
57
|
+
exports.defaultContextGetter = defaultContextGetter;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { MondayFetchOptions } from '@mondaydotcomorg/monday-fetch';
|
|
2
2
|
import { Action, AuthorizationObject, Resource } from './types/general';
|
|
3
|
-
import { ScopedAction, ScopedActionPermit, ScopedActionResponseObject, ScopeOptions } from '
|
|
3
|
+
import { ScopedAction, ScopedActionPermit, ScopedActionResponseObject, ScopeOptions } from './types/scoped-actions-contracts';
|
|
4
4
|
export interface AuthorizeResponse {
|
|
5
5
|
isAuthorized: boolean;
|
|
6
6
|
unauthorizedIds?: number[];
|
|
7
|
+
unauthorizedObjects?: AuthorizationObject[];
|
|
7
8
|
}
|
|
8
9
|
export declare function setRequestFetchOptions(customMondayFetchOptions: MondayFetchOptions): void;
|
|
9
10
|
export declare function setRedisClient(client: any, grantedFeatureRedisExpirationInSeconds?: number): void;
|
|
@@ -1,27 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
-
if (mod && mod.__esModule) return mod;
|
|
20
|
-
var result = {};
|
|
21
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
-
__setModuleDefault(result, mod);
|
|
23
|
-
return result;
|
|
24
|
-
};
|
|
25
2
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
3
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
4
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -35,20 +12,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
35
12
|
exports.AuthorizationService = exports.setRedisClient = exports.setRequestFetchOptions = void 0;
|
|
36
13
|
const lodash_1 = require("lodash");
|
|
37
14
|
const perf_hooks_1 = require("perf_hooks");
|
|
38
|
-
const monday_jwt_1 = require("@mondaydotcomorg/monday-jwt");
|
|
39
|
-
const MondayLogger = __importStar(require("@mondaydotcomorg/monday-logger"));
|
|
40
15
|
const monday_fetch_1 = require("@mondaydotcomorg/monday-fetch");
|
|
41
16
|
const prometheus_service_1 = require("./prometheus-service");
|
|
42
|
-
const
|
|
43
|
-
const
|
|
17
|
+
const authorization_internal_service_1 = require("./authorization-internal-service");
|
|
18
|
+
const attributions_service_1 = require("./attributions-service");
|
|
44
19
|
const GRANTED_FEATURE_CACHE_EXPIRATION_SECONDS = 5 * 60;
|
|
45
|
-
const defaultMondayFetchOptions = {
|
|
46
|
-
retries: 3,
|
|
47
|
-
callback: logOnFetchFail,
|
|
48
|
-
};
|
|
49
|
-
let mondayFetchOptions = defaultMondayFetchOptions;
|
|
50
20
|
function setRequestFetchOptions(customMondayFetchOptions) {
|
|
51
|
-
|
|
21
|
+
authorization_internal_service_1.AuthorizationInternalService.setRequestFetchOptions(customMondayFetchOptions);
|
|
52
22
|
}
|
|
53
23
|
exports.setRequestFetchOptions = setRequestFetchOptions;
|
|
54
24
|
function setRedisClient(client, grantedFeatureRedisExpirationInSeconds = GRANTED_FEATURE_CACHE_EXPIRATION_SECONDS) {
|
|
@@ -57,7 +27,7 @@ function setRedisClient(client, grantedFeatureRedisExpirationInSeconds = GRANTED
|
|
|
57
27
|
AuthorizationService.grantedFeatureRedisExpirationInSeconds = grantedFeatureRedisExpirationInSeconds;
|
|
58
28
|
}
|
|
59
29
|
else {
|
|
60
|
-
logger.warn({ grantedFeatureRedisExpirationInSeconds }, 'Invalid input for grantedFeatureRedisExpirationInSeconds, must be positive number. using default ttl.');
|
|
30
|
+
authorization_internal_service_1.logger.warn({ grantedFeatureRedisExpirationInSeconds }, 'Invalid input for grantedFeatureRedisExpirationInSeconds, must be positive number. using default ttl.');
|
|
61
31
|
AuthorizationService.grantedFeatureRedisExpirationInSeconds = GRANTED_FEATURE_CACHE_EXPIRATION_SECONDS;
|
|
62
32
|
}
|
|
63
33
|
}
|
|
@@ -117,26 +87,27 @@ class AuthorizationService {
|
|
|
117
87
|
}
|
|
118
88
|
static canActionInScopeMultiple(accountId, userId, scopedActions) {
|
|
119
89
|
return __awaiter(this, void 0, void 0, function* () {
|
|
120
|
-
const internalAuthToken =
|
|
90
|
+
const internalAuthToken = authorization_internal_service_1.AuthorizationInternalService.generateInternalAuthToken(accountId, userId);
|
|
121
91
|
const scopedActionsPayload = scopedActions.map(scopedAction => {
|
|
122
92
|
return Object.assign(Object.assign({}, scopedAction), { scope: (0, lodash_1.mapKeys)(scopedAction.scope, (_, key) => (0, lodash_1.snakeCase)(key)) }); // for example: { workspaceId: 1 } => { workspace_id: 1 }
|
|
123
93
|
});
|
|
94
|
+
const attributionHeaders = (0, attributions_service_1.getAttributionsFromApi)();
|
|
124
95
|
const response = yield (0, monday_fetch_1.fetch)(getCanActionsInScopesUrl(), {
|
|
125
96
|
method: 'POST',
|
|
126
|
-
headers: { Authorization: internalAuthToken, 'Content-Type': 'application/json' },
|
|
127
|
-
timeout: getRequestTimeout(),
|
|
97
|
+
headers: Object.assign({ Authorization: internalAuthToken, 'Content-Type': 'application/json' }, attributionHeaders),
|
|
98
|
+
timeout: authorization_internal_service_1.AuthorizationInternalService.getRequestTimeout(),
|
|
128
99
|
body: JSON.stringify({
|
|
129
100
|
user_id: userId,
|
|
130
101
|
scoped_actions: scopedActionsPayload,
|
|
131
102
|
}),
|
|
132
|
-
},
|
|
133
|
-
throwOnHttpErrorIfNeeded(response, 'canActionInScopeMultiple');
|
|
103
|
+
}, authorization_internal_service_1.AuthorizationInternalService.getRequestFetchOptions());
|
|
104
|
+
authorization_internal_service_1.AuthorizationInternalService.throwOnHttpErrorIfNeeded(response, 'canActionInScopeMultiple');
|
|
134
105
|
const responseBody = yield response.json();
|
|
135
|
-
const camelCaseKeys =
|
|
106
|
+
const camelCaseKeys = obj => Object.fromEntries(Object.entries(obj).map(([key, value]) => [(0, lodash_1.camelCase)(key), value]));
|
|
136
107
|
const scopedActionsResponseObjects = responseBody.result.map(responseObject => {
|
|
137
108
|
const { scopedAction, permit } = responseObject;
|
|
138
109
|
const { scope } = scopedAction;
|
|
139
|
-
const transformKeys =
|
|
110
|
+
const transformKeys = obj => camelCaseKeys(obj);
|
|
140
111
|
return Object.assign(Object.assign({}, responseObject), { scopedAction: Object.assign(Object.assign({}, scopedAction), { scope: transformKeys(scope) }), permit: transformKeys(permit) });
|
|
141
112
|
});
|
|
142
113
|
return scopedActionsResponseObjects;
|
|
@@ -150,22 +121,23 @@ class AuthorizationService {
|
|
|
150
121
|
}
|
|
151
122
|
static isAuthorizedMultiple(accountId, userId, authorizationRequestObjects) {
|
|
152
123
|
return __awaiter(this, void 0, void 0, function* () {
|
|
153
|
-
const internalAuthToken =
|
|
124
|
+
const internalAuthToken = authorization_internal_service_1.AuthorizationInternalService.generateInternalAuthToken(accountId, userId);
|
|
154
125
|
const startTime = perf_hooks_1.performance.now();
|
|
126
|
+
const attributionHeaders = (0, attributions_service_1.getAttributionsFromApi)();
|
|
155
127
|
const response = yield (0, monday_fetch_1.fetch)(getAuthorizeUrl(), {
|
|
156
128
|
method: 'POST',
|
|
157
|
-
headers: { Authorization: internalAuthToken, 'Content-Type': 'application/json' },
|
|
158
|
-
timeout: getRequestTimeout(),
|
|
129
|
+
headers: Object.assign({ Authorization: internalAuthToken, 'Content-Type': 'application/json' }, attributionHeaders),
|
|
130
|
+
timeout: authorization_internal_service_1.AuthorizationInternalService.getRequestTimeout(),
|
|
159
131
|
body: JSON.stringify({
|
|
160
132
|
user_id: userId,
|
|
161
133
|
authorize_request_objects: authorizationRequestObjects,
|
|
162
134
|
}),
|
|
163
|
-
},
|
|
135
|
+
}, authorization_internal_service_1.AuthorizationInternalService.getRequestFetchOptions());
|
|
164
136
|
const endTime = perf_hooks_1.performance.now();
|
|
165
137
|
const time = endTime - startTime;
|
|
166
138
|
const responseStatus = response.status;
|
|
167
139
|
(0, prometheus_service_1.sendAuthorizationChecksPerRequestMetric)(responseStatus, authorizationRequestObjects.length);
|
|
168
|
-
throwOnHttpErrorIfNeeded(response, 'isAuthorizedMultiple');
|
|
140
|
+
authorization_internal_service_1.AuthorizationInternalService.throwOnHttpErrorIfNeeded(response, 'isAuthorizedMultiple');
|
|
169
141
|
const responseBody = yield response.json();
|
|
170
142
|
const unauthorizedObjects = [];
|
|
171
143
|
responseBody.result.forEach(function (isAuthorized, index) {
|
|
@@ -176,13 +148,13 @@ class AuthorizationService {
|
|
|
176
148
|
(0, prometheus_service_1.sendAuthorizationCheckResponseTimeMetric)(authorizationObject.resource_type, authorizationObject.action, isAuthorized, responseStatus, time);
|
|
177
149
|
});
|
|
178
150
|
if (unauthorizedObjects.length > 0) {
|
|
179
|
-
logger.info({
|
|
151
|
+
authorization_internal_service_1.logger.info({
|
|
180
152
|
resources: JSON.stringify(unauthorizedObjects),
|
|
181
153
|
}, 'AuthorizationService: resource is unauthorized');
|
|
182
154
|
const unauthorizedIds = unauthorizedObjects
|
|
183
155
|
.filter(obj => !!obj.resource_id)
|
|
184
156
|
.map(obj => obj.resource_id);
|
|
185
|
-
return { isAuthorized: false, unauthorizedIds };
|
|
157
|
+
return { isAuthorized: false, unauthorizedIds, unauthorizedObjects };
|
|
186
158
|
}
|
|
187
159
|
return { isAuthorized: true };
|
|
188
160
|
});
|
|
@@ -205,29 +177,9 @@ function createAuthorizationParams(resources, action) {
|
|
|
205
177
|
};
|
|
206
178
|
return params;
|
|
207
179
|
}
|
|
208
|
-
function logOnFetchFail(retriesLeft, error) {
|
|
209
|
-
if (retriesLeft == 0) {
|
|
210
|
-
logger.error({ retriesLeft, error }, 'Authorization attempt failed due to network issues');
|
|
211
|
-
}
|
|
212
|
-
else {
|
|
213
|
-
logger.info({ retriesLeft, error }, 'Authorization attempt failed due to network issues, trying again');
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
180
|
function getAuthorizeUrl() {
|
|
217
181
|
return `${process.env.MONDAY_INTERNAL_URL}/internal_ms/authorization/authorize`;
|
|
218
182
|
}
|
|
219
183
|
function getCanActionsInScopesUrl() {
|
|
220
184
|
return `${process.env.MONDAY_INTERNAL_URL}/internal_ms/authorization/can_actions_in_scopes`;
|
|
221
185
|
}
|
|
222
|
-
function getRequestTimeout() {
|
|
223
|
-
const isDevEnv = process.env.NODE_ENV === 'development';
|
|
224
|
-
return isDevEnv ? 60000 : 2000;
|
|
225
|
-
}
|
|
226
|
-
function throwOnHttpErrorIfNeeded(response, placement) {
|
|
227
|
-
if (response.ok) {
|
|
228
|
-
return;
|
|
229
|
-
}
|
|
230
|
-
const status = response.status;
|
|
231
|
-
logger.error({ tag: 'authorization-service', placement, status }, 'AuthorizationService: authorization request failed');
|
|
232
|
-
throw new Error(`AuthorizationService: [${placement}] authorization request failed with status ${status}`);
|
|
233
|
-
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { NextFunction } from "express";
|
|
2
|
+
import { Action, BaseRequest, BaseResponse, ContextGetter, Resource, ResourceGetter } from "../types/general";
|
|
3
|
+
export type TestPermittedAction = {
|
|
4
|
+
accountId: number;
|
|
5
|
+
userId: number;
|
|
6
|
+
resources: Resource[];
|
|
7
|
+
action: Action;
|
|
8
|
+
};
|
|
9
|
+
export declare const addTestPermittedAction: (accountId: number, userId: number, resources: Resource[], action: Action) => void;
|
|
10
|
+
export declare const clearTestPermittedActions: () => void;
|
|
11
|
+
export declare const getTestAuthorizationMiddleware: (action: Action, resourceGetter: ResourceGetter, contextGetter?: ContextGetter) => (request: BaseRequest, response: BaseResponse, next: NextFunction) => Promise<void>;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.getTestAuthorizationMiddleware = exports.clearTestPermittedActions = exports.addTestPermittedAction = void 0;
|
|
13
|
+
const authorization_middleware_1 = require("../authorization-middleware");
|
|
14
|
+
const authorization_internal_service_1 = require("../authorization-internal-service");
|
|
15
|
+
let testPermittedActions = [];
|
|
16
|
+
const addTestPermittedAction = (accountId, userId, resources, action) => {
|
|
17
|
+
testPermittedActions.push({ accountId, userId, resources, action });
|
|
18
|
+
};
|
|
19
|
+
exports.addTestPermittedAction = addTestPermittedAction;
|
|
20
|
+
const clearTestPermittedActions = () => {
|
|
21
|
+
testPermittedActions = [];
|
|
22
|
+
};
|
|
23
|
+
exports.clearTestPermittedActions = clearTestPermittedActions;
|
|
24
|
+
const isActionAuthorized = (accountId, userId, resources, action) => {
|
|
25
|
+
return {
|
|
26
|
+
isAuthorized: resources.every(resource => {
|
|
27
|
+
return testPermittedActions.some(combination => {
|
|
28
|
+
return combination.accountId === accountId &&
|
|
29
|
+
combination.userId === userId &&
|
|
30
|
+
combination.action === action &&
|
|
31
|
+
combination.resources.some(combinationResource => {
|
|
32
|
+
return resources.some(resource => {
|
|
33
|
+
return combinationResource.id === resource.id &&
|
|
34
|
+
combinationResource.type === resource.type &&
|
|
35
|
+
JSON.stringify(combinationResource.wrapperData) === JSON.stringify(resource.wrapperData);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
})
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
const getTestAuthorizationMiddleware = (action, resourceGetter, contextGetter) => {
|
|
43
|
+
return function authorizationMiddleware(request, response, next) {
|
|
44
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
45
|
+
contextGetter || (contextGetter = authorization_middleware_1.defaultContextGetter);
|
|
46
|
+
const { userId, accountId } = contextGetter(request);
|
|
47
|
+
const resources = resourceGetter(request);
|
|
48
|
+
const { isAuthorized } = isActionAuthorized(accountId, userId, resources, action);
|
|
49
|
+
authorization_internal_service_1.AuthorizationInternalService.markAuthorized(request);
|
|
50
|
+
if (!isAuthorized) {
|
|
51
|
+
response.status(403).json({ message: 'Access denied' });
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
next();
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
exports.getTestAuthorizationMiddleware = getTestAuthorizationMiddleware;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Resource } from './general';
|
|
2
|
+
export interface ResourceAttributeAssignment {
|
|
3
|
+
resourceType: Resource['type'];
|
|
4
|
+
resourceId: Resource['id'];
|
|
5
|
+
key: string;
|
|
6
|
+
value: string;
|
|
7
|
+
}
|
|
8
|
+
export interface ResourceAttributeResponse {
|
|
9
|
+
attributes: ResourceAttributeAssignment[];
|
|
10
|
+
}
|
|
11
|
+
export interface ResourceAttributeDelete {
|
|
12
|
+
resourceType: Resource['type'];
|
|
13
|
+
resourceId: Resource['id'];
|
|
14
|
+
key: string;
|
|
15
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mondaydotcomorg/monday-authorization",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.9-authzbashanyeadd-async-resource-attributes-support.3112+963c7b49f",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"license": "BSD-3-Clause",
|
|
@@ -10,9 +10,12 @@
|
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@mondaydotcomorg/monday-fetch": "^0.0.7",
|
|
13
|
-
"@mondaydotcomorg/monday-jwt": "^3.0.
|
|
14
|
-
"@mondaydotcomorg/monday-logger": "^
|
|
13
|
+
"@mondaydotcomorg/monday-jwt": "^3.0.14",
|
|
14
|
+
"@mondaydotcomorg/monday-logger": "^4.0.11",
|
|
15
|
+
"@mondaydotcomorg/monday-sns": "^1.0.6",
|
|
16
|
+
"@mondaydotcomorg/trident-backend-api": "^0.23.10",
|
|
15
17
|
"node-fetch": "^2.6.7",
|
|
18
|
+
"on-headers": "^1.0.2",
|
|
16
19
|
"ts-node": "^10.0.0"
|
|
17
20
|
},
|
|
18
21
|
"devDependencies": {
|
|
@@ -24,7 +27,6 @@
|
|
|
24
27
|
"ioredis": "^5.2.4",
|
|
25
28
|
"ioredis-mock": "^8.2.2",
|
|
26
29
|
"mocha": "^9.0.1",
|
|
27
|
-
"on-headers": "^1.0.2",
|
|
28
30
|
"supertest": "^6.1.3",
|
|
29
31
|
"tsconfig-paths": "^3.9.0",
|
|
30
32
|
"typescript": "^5.1.6"
|
|
@@ -32,5 +34,5 @@
|
|
|
32
34
|
"files": [
|
|
33
35
|
"dist/"
|
|
34
36
|
],
|
|
35
|
-
"gitHead": "
|
|
37
|
+
"gitHead": "963c7b49f6bf56bb15150dc2b76f0d875c77ec97"
|
|
36
38
|
}
|