@platform-mesh/portal-server-lib 0.9.95 → 0.9.97
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/portal-options/index.d.ts +4 -0
- package/dist/portal-options/index.js +4 -0
- package/dist/portal-options/index.js.map +1 -1
- package/dist/portal-options/logout-callback.service.js +16 -8
- package/dist/portal-options/logout-callback.service.js.map +1 -1
- package/dist/portal-options/service-providers/content-configuration-service-providers.service.d.ts +4 -1
- package/dist/portal-options/service-providers/content-configuration-service-providers.service.js +14 -3
- package/dist/portal-options/service-providers/content-configuration-service-providers.service.js.map +1 -1
- package/dist/portal-options/service-providers/kubernetes-service-providers.service.d.ts +4 -2
- package/dist/portal-options/service-providers/kubernetes-service-providers.service.js +10 -4
- package/dist/portal-options/service-providers/kubernetes-service-providers.service.js.map +1 -1
- package/dist/portal-options/services/kcp-k8s.service.d.ts +0 -1
- package/dist/portal-options/services/kcp-k8s.service.js +4 -13
- package/dist/portal-options/services/kcp-k8s.service.js.map +1 -1
- package/dist/portal-options/services/permissions/adapters/authz-webhook.service.d.ts +14 -0
- package/dist/portal-options/services/permissions/adapters/authz-webhook.service.js +183 -0
- package/dist/portal-options/services/permissions/adapters/authz-webhook.service.js.map +1 -0
- package/dist/portal-options/services/permissions/models/permissions.model.d.ts +51 -0
- package/dist/portal-options/services/permissions/models/permissions.model.js +2 -0
- package/dist/portal-options/services/permissions/models/permissions.model.js.map +1 -0
- package/dist/portal-options/services/permissions/permissions-proxy.service.d.ts +9 -0
- package/dist/portal-options/services/permissions/permissions-proxy.service.js +48 -0
- package/dist/portal-options/services/permissions/permissions-proxy.service.js.map +1 -0
- package/dist/portal-options/services/permissions/permissions.controller.d.ts +9 -0
- package/dist/portal-options/services/permissions/permissions.controller.js +49 -0
- package/dist/portal-options/services/permissions/permissions.controller.js.map +1 -0
- package/dist/portal-options/utils/account-hierarchy-resolver.js +7 -3
- package/dist/portal-options/utils/account-hierarchy-resolver.js.map +1 -1
- package/dist/portal-options/utils/build-workspace-path.util.d.ts +1 -0
- package/dist/portal-options/utils/build-workspace-path.util.js +4 -0
- package/dist/portal-options/utils/build-workspace-path.util.js.map +1 -0
- package/dist/portal-options/utils/extract-resource-definitions.util.d.ts +7 -0
- package/dist/portal-options/utils/extract-resource-definitions.util.js +33 -0
- package/dist/portal-options/utils/extract-resource-definitions.util.js.map +1 -0
- package/package.json +1 -1
- package/src/portal-options/index.ts +4 -0
- package/src/portal-options/logout-callback.service.spec.ts +57 -1
- package/src/portal-options/logout-callback.service.ts +34 -8
- package/src/portal-options/service-providers/content-configuration-service-providers.service.spec.ts +8 -1
- package/src/portal-options/service-providers/content-configuration-service-providers.service.ts +17 -6
- package/src/portal-options/service-providers/kubernetes-service-providers.service.spec.ts +13 -4
- package/src/portal-options/service-providers/kubernetes-service-providers.service.ts +21 -8
- package/src/portal-options/services/kcp-k8s.service.ts +4 -15
- package/src/portal-options/services/permissions/adapters/authz-webhook.service.spec.ts +500 -0
- package/src/portal-options/services/permissions/adapters/authz-webhook.service.ts +238 -0
- package/src/portal-options/services/permissions/models/permissions.model.ts +56 -0
- package/src/portal-options/services/permissions/permissions-proxy.service.spec.ts +232 -0
- package/src/portal-options/services/permissions/permissions-proxy.service.ts +58 -0
- package/src/portal-options/services/permissions/permissions.controller.spec.ts +143 -0
- package/src/portal-options/services/permissions/permissions.controller.ts +31 -0
- package/src/portal-options/utils/account-hierarchy-resolver.ts +13 -8
- package/src/portal-options/utils/build-workspace-path.util.spec.ts +59 -0
- package/src/portal-options/utils/build-workspace-path.util.ts +21 -0
- package/src/portal-options/utils/extract-resource-definitions.util.spec.ts +303 -0
- package/src/portal-options/utils/extract-resource-definitions.util.ts +62 -0
- package/tsconfig.json +2 -1
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
import { Injectable } from '@nestjs/common';
|
|
11
|
+
import { extractResourceDefinitions } from '../../utils/extract-resource-definitions.util.js';
|
|
12
|
+
import { AuthzWebhookService } from './adapters/authz-webhook.service.js';
|
|
13
|
+
let PermissionsProxyService = class PermissionsProxyService {
|
|
14
|
+
authzWebhook;
|
|
15
|
+
constructor(authzWebhook) {
|
|
16
|
+
this.authzWebhook = authzWebhook;
|
|
17
|
+
}
|
|
18
|
+
async resolvePermissions(token, organization, accountPath, contentConfigurations) {
|
|
19
|
+
const resourceDefinitions = extractResourceDefinitions(contentConfigurations);
|
|
20
|
+
const checks = resourceDefinitions
|
|
21
|
+
.map((rd) => rd.permissionsDefinition)
|
|
22
|
+
.filter((pd) => !!pd && pd.resourceActions.length > 0)
|
|
23
|
+
.map((pd) => ({
|
|
24
|
+
resource: pd.resource,
|
|
25
|
+
group: pd.group,
|
|
26
|
+
actions: pd.resourceActions,
|
|
27
|
+
}));
|
|
28
|
+
if (!checks.length) {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
const req = {
|
|
32
|
+
token,
|
|
33
|
+
organization,
|
|
34
|
+
accountPath,
|
|
35
|
+
checks,
|
|
36
|
+
};
|
|
37
|
+
return this.authzWebhook.checkActionsForResource(req);
|
|
38
|
+
}
|
|
39
|
+
async checkResourceInstance(req) {
|
|
40
|
+
return this.authzWebhook.checkActionsForInstance(req);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
PermissionsProxyService = __decorate([
|
|
44
|
+
Injectable(),
|
|
45
|
+
__metadata("design:paramtypes", [AuthzWebhookService])
|
|
46
|
+
], PermissionsProxyService);
|
|
47
|
+
export { PermissionsProxyService };
|
|
48
|
+
//# sourceMappingURL=permissions-proxy.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissions-proxy.service.js","sourceRoot":"","sources":["../../../../src/portal-options/services/permissions/permissions-proxy.service.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE5C,OAAO,EAAE,0BAA0B,EAAE,MAAM,kDAAkD,CAAC;AAC9F,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAQnE,IAAM,uBAAuB,GAA7B,MAAM,uBAAuB;IACL;IAA7B,YAA6B,YAAiC;QAAjC,iBAAY,GAAZ,YAAY,CAAqB;IAAG,CAAC;IAGlE,KAAK,CAAC,kBAAkB,CACtB,KAAa,EACb,YAAoB,EACpB,WAAmB,EACnB,qBAA6C;QAE7C,MAAM,mBAAmB,GAAG,0BAA0B,CACpD,qBAAqB,CACtB,CAAC;QAEF,MAAM,MAAM,GAAG,mBAAmB;aAC/B,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,qBAAqB,CAAC;aACrC,MAAM,CACL,CAAC,EAAE,EAA+B,EAAE,CAClC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC,CACxC;aACA,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;YACZ,QAAQ,EAAE,EAAE,CAAC,QAAQ;YACrB,KAAK,EAAE,EAAE,CAAC,KAAK;YACf,OAAO,EAAE,EAAE,CAAC,eAAe;SAC5B,CAAC,CAAC,CAAC;QAEN,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;YACnB,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,MAAM,GAAG,GAAyB;YAChC,KAAK;YACL,YAAY;YACZ,WAAW;YACX,MAAM;SACP,CAAC;QAEF,OAAO,IAAI,CAAC,YAAY,CAAC,uBAAuB,CAAC,GAAG,CAAC,CAAC;IACxD,CAAC;IAGD,KAAK,CAAC,qBAAqB,CACzB,GAAyB;QAEzB,OAAO,IAAI,CAAC,YAAY,CAAC,uBAAuB,CAAC,GAAG,CAAC,CAAC;IACxD,CAAC;CACF,CAAA;AA9CY,uBAAuB;IADnC,UAAU,EAAE;qCAEgC,mBAAmB;GADnD,uBAAuB,CA8CnC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { HeaderParserService } from '@openmfp/portal-server-lib';
|
|
2
|
+
import { AuthorizationRequest, Permission } from './models/permissions.model.js';
|
|
3
|
+
import { PermissionsProxyService } from './permissions-proxy.service.js';
|
|
4
|
+
export declare class PermissionsController {
|
|
5
|
+
private readonly permissionsProxyService;
|
|
6
|
+
private readonly headerParser;
|
|
7
|
+
constructor(permissionsProxyService: PermissionsProxyService, headerParser: HeaderParserService);
|
|
8
|
+
checkResource(request: Request, body: AuthorizationRequest): Promise<Permission[]>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
11
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
12
|
+
};
|
|
13
|
+
import { Body, Controller, Post, Req, UnauthorizedException } from '@nestjs/common';
|
|
14
|
+
import { HeaderParserService } from '@openmfp/portal-server-lib';
|
|
15
|
+
import { PermissionsProxyService } from './permissions-proxy.service.js';
|
|
16
|
+
let PermissionsController = class PermissionsController {
|
|
17
|
+
permissionsProxyService;
|
|
18
|
+
headerParser;
|
|
19
|
+
constructor(permissionsProxyService, headerParser) {
|
|
20
|
+
this.permissionsProxyService = permissionsProxyService;
|
|
21
|
+
this.headerParser = headerParser;
|
|
22
|
+
}
|
|
23
|
+
async checkResource(request, body) {
|
|
24
|
+
const token = this.headerParser.extractBearerToken(request);
|
|
25
|
+
if (!token) {
|
|
26
|
+
throw new UnauthorizedException();
|
|
27
|
+
}
|
|
28
|
+
const result = await this.permissionsProxyService.checkResourceInstance({
|
|
29
|
+
...body,
|
|
30
|
+
token,
|
|
31
|
+
});
|
|
32
|
+
return result ?? [];
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
__decorate([
|
|
36
|
+
Post('resource-check'),
|
|
37
|
+
__param(0, Req()),
|
|
38
|
+
__param(1, Body()),
|
|
39
|
+
__metadata("design:type", Function),
|
|
40
|
+
__metadata("design:paramtypes", [Request, Object]),
|
|
41
|
+
__metadata("design:returntype", Promise)
|
|
42
|
+
], PermissionsController.prototype, "checkResource", null);
|
|
43
|
+
PermissionsController = __decorate([
|
|
44
|
+
Controller('rest/permissions'),
|
|
45
|
+
__metadata("design:paramtypes", [PermissionsProxyService,
|
|
46
|
+
HeaderParserService])
|
|
47
|
+
], PermissionsController);
|
|
48
|
+
export { PermissionsController };
|
|
49
|
+
//# sourceMappingURL=permissions.controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissions.controller.js","sourceRoot":"","sources":["../../../../src/portal-options/services/permissions/permissions.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AACpF,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAEjE,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAGlE,IAAM,qBAAqB,GAA3B,MAAM,qBAAqB;IAEb;IACA;IAFnB,YACmB,uBAAgD,EAChD,YAAiC;QADjC,4BAAuB,GAAvB,uBAAuB,CAAyB;QAChD,iBAAY,GAAZ,YAAY,CAAqB;IACjD,CAAC;IAGE,AAAN,KAAK,CAAC,aAAa,CACV,OAAgB,EACf,IAA0B;QAElC,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;QAE5D,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,qBAAqB,EAAE,CAAC;QACpC,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,uBAAuB,CAAC,qBAAqB,CAAC;YACtE,GAAG,IAAI;YACP,KAAK;SACN,CAAC,CAAC;QAEH,OAAO,MAAM,IAAI,EAAE,CAAC;IACtB,CAAC;CACF,CAAA;AAjBO;IADL,IAAI,CAAC,gBAAgB,CAAC;IAEpB,WAAA,GAAG,EAAE,CAAA;IACL,WAAA,IAAI,EAAE,CAAA;;qCADS,OAAO;;0DAexB;AAvBU,qBAAqB;IADjC,UAAU,CAAC,kBAAkB,CAAC;qCAGe,uBAAuB;QAClC,mBAAmB;GAHzC,qBAAqB,CAwBjC"}
|
|
@@ -2,7 +2,7 @@ import { replaceStringDeep } from './replace-string-deep.js';
|
|
|
2
2
|
const ACCOUNT_ENTITY_TYPE = 'core_platform-mesh_io_account';
|
|
3
3
|
export const updateEntityTypeFromAccountPath = (contentConfiguration, accountPath) => {
|
|
4
4
|
contentConfiguration.luigiConfigFragment.data.nodes.forEach((node) => {
|
|
5
|
-
if (!node.entityType
|
|
5
|
+
if (!node.entityType?.includes(ACCOUNT_ENTITY_TYPE)) {
|
|
6
6
|
return;
|
|
7
7
|
}
|
|
8
8
|
const accountPathParts = accountPath
|
|
@@ -15,12 +15,15 @@ export const updateEntityTypeFromAccountPath = (contentConfiguration, accountPat
|
|
|
15
15
|
return contentConfiguration;
|
|
16
16
|
};
|
|
17
17
|
export const updateAccountNodeChildren = (contentConfiguration, accountPath) => {
|
|
18
|
-
const
|
|
18
|
+
const children = contentConfiguration.luigiConfigFragment.data.nodes[0]?.children;
|
|
19
|
+
const accountChildrenNode = Array.isArray(children) ? children[0] : undefined;
|
|
19
20
|
if (accountChildrenNode) {
|
|
20
21
|
const nextHierarchyLevel = accountPath.split(':').filter(Boolean).length + 1;
|
|
21
22
|
const previousPathSegment = accountChildrenNode.pathSegment;
|
|
22
23
|
const nextPathSegment = `:${nextHierarchyLevel}_${ACCOUNT_ENTITY_TYPE}Id`;
|
|
23
|
-
|
|
24
|
+
if (previousPathSegment) {
|
|
25
|
+
replaceStringDeep(accountChildrenNode, previousPathSegment, nextPathSegment);
|
|
26
|
+
}
|
|
24
27
|
}
|
|
25
28
|
return contentConfiguration;
|
|
26
29
|
};
|
|
@@ -32,5 +35,6 @@ export const processContentConfigurationForAccountHierarchy = (contentConfigurat
|
|
|
32
35
|
}
|
|
33
36
|
return updateEntityTypeFromAccountPath(contentConfiguration, accountPath);
|
|
34
37
|
}
|
|
38
|
+
return contentConfiguration;
|
|
35
39
|
};
|
|
36
40
|
//# sourceMappingURL=account-hierarchy-resolver.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"account-hierarchy-resolver.js","sourceRoot":"","sources":["../../../src/portal-options/utils/account-hierarchy-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAG7D,MAAM,mBAAmB,GAAG,+BAA+B,CAAC;AAE5D,MAAM,CAAC,MAAM,+BAA+B,GAAG,CAC7C,oBAA0C,EAC1C,WAAmB,EACG,EAAE;IACxB,oBAAoB,CAAC,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;QACnE,IAAI,CAAC,IAAI,CAAC,UAAU,
|
|
1
|
+
{"version":3,"file":"account-hierarchy-resolver.js","sourceRoot":"","sources":["../../../src/portal-options/utils/account-hierarchy-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAG7D,MAAM,mBAAmB,GAAG,+BAA+B,CAAC;AAE5D,MAAM,CAAC,MAAM,+BAA+B,GAAG,CAC7C,oBAA0C,EAC1C,WAAmB,EACG,EAAE;IACxB,oBAAoB,CAAC,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;QACnE,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC;YACpD,OAAO;QACT,CAAC;QAED,MAAM,gBAAgB,GAAG,WAAW;aACjC,KAAK,CAAC,GAAG,CAAC;aACV,MAAM,CAAC,OAAO,CAAC;aACf,GAAG,CAAC,GAAG,EAAE,CAAC,mBAAmB,CAAC;aAC9B,IAAI,CAAC,GAAG,CAAC,CAAC;QAEb,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CACvC,mBAAmB,EACnB,gBAAgB,CACjB,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,OAAO,oBAAoB,CAAC;AAC9B,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,yBAAyB,GAAG,CACvC,oBAA0C,EAC1C,WAAmB,EACG,EAAE;IACxB,MAAM,QAAQ,GACZ,oBAAoB,CAAC,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC;IACnE,MAAM,mBAAmB,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAE9E,IAAI,mBAAmB,EAAE,CAAC;QACxB,MAAM,kBAAkB,GACtB,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;QACpD,MAAM,mBAAmB,GAAG,mBAAmB,CAAC,WAAW,CAAC;QAC5D,MAAM,eAAe,GAAG,IAAI,kBAAkB,IAAI,mBAAmB,IAAI,CAAC;QAE1E,IAAI,mBAAmB,EAAE,CAAC;YACxB,iBAAiB,CACf,mBAAmB,EACnB,mBAAmB,EACnB,eAAe,CAChB,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,oBAAoB,CAAC;AAC9B,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,8CAA8C,GAAG,CAC5D,oBAA0C,EAC1C,OAA4B,EACN,EAAE;IACxB,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACxE,IAAI,WAAW,EAAE,CAAC;QAChB,IAAI,oBAAoB,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAC7C,yBAAyB,CAAC,oBAAoB,EAAE,WAAW,CAAC,CAAC;QAC/D,CAAC;QAED,OAAO,+BAA+B,CAAC,oBAAoB,EAAE,WAAW,CAAC,CAAC;IAC5E,CAAC;IAED,OAAO,oBAAoB,CAAC;AAC9B,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function buildWorkspacePath(segments?: (string | undefined | null)[]): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-workspace-path.util.js","sourceRoot":"","sources":["../../../src/portal-options/utils/build-workspace-path.util.ts"],"names":[],"mappings":"AAaA,MAAM,UAAU,kBAAkB,CAChC,WAA0C,EAAE;IAE5C,OAAO,QAAQ,CAAC,MAAM,CACpB,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAC1D,WAAW,CACZ,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ContentConfiguration } from '@openmfp/portal-server-lib';
|
|
2
|
+
import { PermissionsDefinition } from '../services/permissions/models/permissions.model.js';
|
|
3
|
+
export interface ResourceDefinitionLocal {
|
|
4
|
+
entity: string;
|
|
5
|
+
permissionsDefinition?: PermissionsDefinition;
|
|
6
|
+
}
|
|
7
|
+
export declare function extractResourceDefinitions(contentConfigurations: ContentConfiguration[]): ResourceDefinitionLocal[];
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
function mergeResourceActions(existing, incoming) {
|
|
2
|
+
return [...new Set([...(existing ?? []), ...(incoming ?? [])])];
|
|
3
|
+
}
|
|
4
|
+
function collectFromNodes(nodes, acc) {
|
|
5
|
+
for (const node of nodes) {
|
|
6
|
+
const rd = node.context?.['resourceDefinition'];
|
|
7
|
+
if (rd?.entity !== undefined && rd.permissionsDefinition !== undefined) {
|
|
8
|
+
const existing = acc.get(rd.entity);
|
|
9
|
+
acc.set(rd.entity, {
|
|
10
|
+
...rd,
|
|
11
|
+
permissionsDefinition: {
|
|
12
|
+
...rd.permissionsDefinition,
|
|
13
|
+
resourceActions: mergeResourceActions(existing?.permissionsDefinition?.resourceActions, rd.permissionsDefinition.resourceActions),
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
const children = node.children;
|
|
18
|
+
if (Array.isArray(children) && children.length > 0) {
|
|
19
|
+
collectFromNodes(children, acc);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export function extractResourceDefinitions(contentConfigurations) {
|
|
24
|
+
const acc = new Map();
|
|
25
|
+
for (const cc of contentConfigurations) {
|
|
26
|
+
const nodes = cc.luigiConfigFragment?.data?.nodes;
|
|
27
|
+
if (Array.isArray(nodes)) {
|
|
28
|
+
collectFromNodes(nodes, acc);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return Array.from(acc.values());
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=extract-resource-definitions.util.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extract-resource-definitions.util.js","sourceRoot":"","sources":["../../../src/portal-options/utils/extract-resource-definitions.util.ts"],"names":[],"mappings":"AAQA,SAAS,oBAAoB,CAC3B,QAA8B,EAC9B,QAA8B;IAE9B,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AAClE,CAAC;AAED,SAAS,gBAAgB,CACvB,KAAmE,EACnE,GAAyC;IAEzC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,oBAAoB,CAEjC,CAAC;QAEd,IAAI,EAAE,EAAE,MAAM,KAAK,SAAS,IAAI,EAAE,CAAC,qBAAqB,KAAK,SAAS,EAAE,CAAC;YACvE,MAAM,QAAQ,GAAG,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;YAIpC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE;gBACjB,GAAG,EAAE;gBACL,qBAAqB,EAAE;oBACrB,GAAG,EAAE,CAAC,qBAAqB;oBAC3B,eAAe,EAAE,oBAAoB,CACnC,QAAQ,EAAE,qBAAqB,EAAE,eAAe,EAChD,EAAE,CAAC,qBAAqB,CAAC,eAAe,CACzC;iBACF;aACF,CAAC,CAAC;QACL,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC/B,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACnD,gBAAgB,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;QAClC,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,0BAA0B,CACxC,qBAA6C;IAE7C,MAAM,GAAG,GAAG,IAAI,GAAG,EAAmC,CAAC;IAEvD,KAAK,MAAM,EAAE,IAAI,qBAAqB,EAAE,CAAC;QACvC,MAAM,KAAK,GAAG,EAAE,CAAC,mBAAmB,EAAE,IAAI,EAAE,KAAK,CAAC;QAClD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,gBAAgB,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;AAClC,CAAC"}
|
package/package.json
CHANGED
|
@@ -7,3 +7,7 @@ export * from './service-providers/content-configuration-service-providers.servi
|
|
|
7
7
|
export * from './service-providers/kubernetes-service-providers.service.js';
|
|
8
8
|
|
|
9
9
|
export * from './services/kcp-k8s.service.js';
|
|
10
|
+
export * from './services/permissions/adapters/authz-webhook.service.js';
|
|
11
|
+
export * from './services/permissions/models/permissions.model.js';
|
|
12
|
+
export * from './services/permissions/permissions-proxy.service.js';
|
|
13
|
+
export * from './services/permissions/permissions.controller.js';
|
|
@@ -63,10 +63,36 @@ describe('PMLogoutService', () => {
|
|
|
63
63
|
expect(httpService.post).toHaveBeenCalledWith(
|
|
64
64
|
'https://keycloak/logout',
|
|
65
65
|
expect.any(URLSearchParams),
|
|
66
|
-
{
|
|
66
|
+
{
|
|
67
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
68
|
+
auth: { username: 'client-id', password: 'secret' },
|
|
69
|
+
},
|
|
67
70
|
);
|
|
68
71
|
});
|
|
69
72
|
|
|
73
|
+
it('should not send the client secret as a form parameter', async () => {
|
|
74
|
+
const mockRequest = {} as Request;
|
|
75
|
+
const mockResponse = {} as Response;
|
|
76
|
+
|
|
77
|
+
(authConfigService.getAuthConfig as jest.Mock).mockResolvedValue({
|
|
78
|
+
clientId: 'client-id',
|
|
79
|
+
clientSecret: 'secret',
|
|
80
|
+
endSessionUrl: 'https://keycloak/logout',
|
|
81
|
+
});
|
|
82
|
+
(cookiesService.getAuthCookie as jest.Mock).mockReturnValue(
|
|
83
|
+
'refresh-token',
|
|
84
|
+
);
|
|
85
|
+
(httpService.post as jest.Mock).mockReturnValue(of({ data: {} }));
|
|
86
|
+
|
|
87
|
+
await service.handleLogout(mockRequest, mockResponse);
|
|
88
|
+
|
|
89
|
+
const body = (httpService.post as jest.Mock).mock
|
|
90
|
+
.calls[0][1] as URLSearchParams;
|
|
91
|
+
expect(body.get('refresh_token')).toBe('refresh-token');
|
|
92
|
+
expect(body.get('client_secret')).toBeNull();
|
|
93
|
+
expect(body.get('client_id')).toBeNull();
|
|
94
|
+
});
|
|
95
|
+
|
|
70
96
|
it('should return logoutWithIdToken URL when logout fails', async () => {
|
|
71
97
|
const mockRequest = {
|
|
72
98
|
query: {
|
|
@@ -105,9 +131,39 @@ describe('PMLogoutService', () => {
|
|
|
105
131
|
const result = (service as any).logoutWithIdToken(
|
|
106
132
|
request,
|
|
107
133
|
'https://kc/logout',
|
|
134
|
+
'client-id',
|
|
108
135
|
);
|
|
109
136
|
expect(result).toBe(
|
|
110
137
|
'https://kc/logout?id_token_hint=token123&post_logout_redirect_uri=https%3A%2F%2Fexample.com',
|
|
111
138
|
);
|
|
112
139
|
});
|
|
140
|
+
|
|
141
|
+
it('logoutWithIdToken should fall back to client_id when no id token is present', () => {
|
|
142
|
+
const request = {
|
|
143
|
+
query: { post_logout_redirect_uri: 'https://example.com' },
|
|
144
|
+
} as unknown as Request;
|
|
145
|
+
|
|
146
|
+
const result = (service as any).logoutWithIdToken(
|
|
147
|
+
request,
|
|
148
|
+
'https://kc/logout',
|
|
149
|
+
'client-id',
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
expect(result).toBe(
|
|
153
|
+
'https://kc/logout?client_id=client-id&post_logout_redirect_uri=https%3A%2F%2Fexample.com',
|
|
154
|
+
);
|
|
155
|
+
expect(result).not.toContain('id_token_hint');
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('logoutWithIdToken should omit an absent post logout redirect uri', () => {
|
|
159
|
+
const request = { query: {} } as unknown as Request;
|
|
160
|
+
|
|
161
|
+
const result = (service as any).logoutWithIdToken(
|
|
162
|
+
request,
|
|
163
|
+
'https://kc/logout',
|
|
164
|
+
'client-id',
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
expect(result).toBe('https://kc/logout?client_id=client-id');
|
|
168
|
+
});
|
|
113
169
|
});
|
|
@@ -29,14 +29,20 @@ export class PMLogoutService implements LogoutCallback {
|
|
|
29
29
|
const refreshToken = this.cookiesService.getAuthCookie(request);
|
|
30
30
|
|
|
31
31
|
const body = new URLSearchParams({
|
|
32
|
-
client_id: authConfig.clientId,
|
|
33
|
-
client_secret: authConfig.clientSecret,
|
|
34
32
|
refresh_token: refreshToken,
|
|
35
33
|
});
|
|
36
34
|
|
|
35
|
+
// Client credentials go in the Authorization header, not the form body:
|
|
36
|
+
// the client is registered with token_endpoint_auth_method
|
|
37
|
+
// client_secret_basic, and an IdP that enforces it rejects credentials
|
|
38
|
+
// sent as form parameters with unauthorized_client.
|
|
37
39
|
await firstValueFrom(
|
|
38
40
|
this.httpService.post(authConfig.endSessionUrl, body, {
|
|
39
41
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
42
|
+
auth: {
|
|
43
|
+
username: authConfig.clientId,
|
|
44
|
+
password: authConfig.clientSecret,
|
|
45
|
+
},
|
|
40
46
|
}),
|
|
41
47
|
);
|
|
42
48
|
} catch (error: any) {
|
|
@@ -45,16 +51,36 @@ export class PMLogoutService implements LogoutCallback {
|
|
|
45
51
|
error?.response?.data || error.message,
|
|
46
52
|
);
|
|
47
53
|
this.logger.warn('Trying to log out with the id token');
|
|
48
|
-
return this.logoutWithIdToken(
|
|
54
|
+
return this.logoutWithIdToken(
|
|
55
|
+
request,
|
|
56
|
+
authConfig.endSessionUrl,
|
|
57
|
+
authConfig.clientId,
|
|
58
|
+
);
|
|
49
59
|
}
|
|
50
60
|
}
|
|
51
61
|
|
|
52
|
-
private logoutWithIdToken(
|
|
62
|
+
private logoutWithIdToken(
|
|
63
|
+
request: Request,
|
|
64
|
+
endSessionUrl: string,
|
|
65
|
+
clientId: string,
|
|
66
|
+
) {
|
|
53
67
|
const { id_token_hint, post_logout_redirect_uri } = request.query;
|
|
54
|
-
const params = new URLSearchParams(
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
68
|
+
const params = new URLSearchParams();
|
|
69
|
+
|
|
70
|
+
// RP-initiated logout honours post_logout_redirect_uri only together with
|
|
71
|
+
// id_token_hint or client_id. An empty id_token_hint is not a no-op: the
|
|
72
|
+
// IdP rejects the request ("Missing parameters: id_token_hint") and the
|
|
73
|
+
// user is stranded on an error page instead of being signed out.
|
|
74
|
+
if (id_token_hint) {
|
|
75
|
+
params.set('id_token_hint', String(id_token_hint));
|
|
76
|
+
} else {
|
|
77
|
+
params.set('client_id', clientId);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (post_logout_redirect_uri) {
|
|
81
|
+
params.set('post_logout_redirect_uri', String(post_logout_redirect_uri));
|
|
82
|
+
}
|
|
83
|
+
|
|
58
84
|
return `${endSessionUrl}?${params}`;
|
|
59
85
|
}
|
|
60
86
|
}
|
package/src/portal-options/service-providers/content-configuration-service-providers.service.spec.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { RequestContext } from '../pm-request-context-provider.js';
|
|
2
|
+
import { PermissionsProxyService } from '../services/permissions/permissions-proxy.service.js';
|
|
2
3
|
import { ContentConfigurationServiceProvidersService } from './content-configuration-service-providers.service.js';
|
|
3
4
|
import { welcomeNodeConfig } from './models/welcome-node-config.js';
|
|
4
5
|
import { GraphQLClient } from 'graphql-request';
|
|
@@ -18,9 +19,15 @@ describe('ContentConfigurationServiceProvidersService', () => {
|
|
|
18
19
|
let service: ContentConfigurationServiceProvidersService;
|
|
19
20
|
let mockClient: jest.Mocked<GraphQLClient>;
|
|
20
21
|
let context: RequestContext;
|
|
22
|
+
let permissionsProxyService: jest.Mocked<PermissionsProxyService>;
|
|
21
23
|
|
|
22
24
|
beforeEach(() => {
|
|
23
|
-
|
|
25
|
+
permissionsProxyService = {
|
|
26
|
+
resolvePermissions: jest.fn().mockResolvedValue([]),
|
|
27
|
+
} as unknown as jest.Mocked<PermissionsProxyService>;
|
|
28
|
+
service = new ContentConfigurationServiceProvidersService(
|
|
29
|
+
permissionsProxyService,
|
|
30
|
+
);
|
|
24
31
|
mockClient = new GraphQLClient('') as any;
|
|
25
32
|
(GraphQLClient as jest.Mock).mockReturnValue(mockClient);
|
|
26
33
|
context = {
|
package/src/portal-options/service-providers/content-configuration-service-providers.service.ts
CHANGED
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
import { RequestContext } from '../pm-request-context-provider.js';
|
|
2
|
-
import { processContentConfigurationForAccountHierarchy } from '../utils/account-hierarchy-resolver.js';
|
|
3
|
-
import { contentConfigurationsQuery } from './contentconfigurations-query.js';
|
|
4
|
-
import { ContentConfigurationQueryResponse } from './models/contentconfigurations.js';
|
|
5
|
-
import { welcomeNodeConfig } from './models/welcome-node-config.js';
|
|
6
1
|
import { Injectable } from '@nestjs/common';
|
|
7
2
|
import {
|
|
8
3
|
ContentConfiguration,
|
|
@@ -10,9 +5,17 @@ import {
|
|
|
10
5
|
ServiceProviderService,
|
|
11
6
|
} from '@openmfp/portal-server-lib';
|
|
12
7
|
import { GraphQLClient } from 'graphql-request';
|
|
8
|
+
import { RequestContext } from '../pm-request-context-provider.js';
|
|
9
|
+
import { PermissionsProxyService } from '../services/permissions/permissions-proxy.service.js';
|
|
10
|
+
import { processContentConfigurationForAccountHierarchy } from '../utils/account-hierarchy-resolver.js';
|
|
11
|
+
import { contentConfigurationsQuery } from './contentconfigurations-query.js';
|
|
12
|
+
import { ContentConfigurationQueryResponse } from './models/contentconfigurations.js';
|
|
13
|
+
import { welcomeNodeConfig } from './models/welcome-node-config.js';
|
|
13
14
|
|
|
14
15
|
@Injectable()
|
|
15
16
|
export class ContentConfigurationServiceProvidersService implements ServiceProviderService {
|
|
17
|
+
constructor(private permissionsProxyService: PermissionsProxyService) {}
|
|
18
|
+
|
|
16
19
|
async getServiceProviders(
|
|
17
20
|
token: string,
|
|
18
21
|
entities: string[],
|
|
@@ -31,7 +34,7 @@ export class ContentConfigurationServiceProvidersService implements ServiceProvi
|
|
|
31
34
|
throw new Error('Context with organization is required');
|
|
32
35
|
}
|
|
33
36
|
|
|
34
|
-
let url = context.crdGatewayApiUrl
|
|
37
|
+
let url = context.crdGatewayApiUrl!.replace(
|
|
35
38
|
'kubernetes-graphql-gateway/root',
|
|
36
39
|
'kubernetes-graphql-gateway/virtual-workspace/contentconfigurations/root',
|
|
37
40
|
);
|
|
@@ -112,6 +115,13 @@ export class ContentConfigurationServiceProvidersService implements ServiceProvi
|
|
|
112
115
|
}
|
|
113
116
|
});
|
|
114
117
|
|
|
118
|
+
const nodesPermissions = await this.permissionsProxyService.resolvePermissions(
|
|
119
|
+
token,
|
|
120
|
+
context.organization,
|
|
121
|
+
accountPath ?? '',
|
|
122
|
+
contentConfigurations,
|
|
123
|
+
);
|
|
124
|
+
|
|
115
125
|
return {
|
|
116
126
|
rawServiceProviders: [
|
|
117
127
|
{
|
|
@@ -119,6 +129,7 @@ export class ContentConfigurationServiceProvidersService implements ServiceProvi
|
|
|
119
129
|
displayName: '',
|
|
120
130
|
creationTimestamp: '',
|
|
121
131
|
contentConfiguration: contentConfigurations,
|
|
132
|
+
nodeContext: { nodesPermissions },
|
|
122
133
|
},
|
|
123
134
|
],
|
|
124
135
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { K8sRequestContext, K8sResourceDescriptor } from '../models/k8s.js';
|
|
2
2
|
import { KcpKubernetesService } from '../services/kcp-k8s.service.js';
|
|
3
|
+
import { PermissionsProxyService } from '../services/permissions/permissions-proxy.service.js';
|
|
3
4
|
import { KubernetesServiceProvidersService } from './kubernetes-service-providers.service.js';
|
|
4
5
|
import { welcomeNodeConfig } from './models/welcome-node-config.js';
|
|
5
6
|
import { Test, TestingModule } from '@nestjs/testing';
|
|
@@ -34,6 +35,7 @@ jest.mock('@kubernetes/client-node/dist/gen/middleware.js', () => ({
|
|
|
34
35
|
describe('KubernetesServiceProvidersService', () => {
|
|
35
36
|
let service: KubernetesServiceProvidersService;
|
|
36
37
|
let kcpKubernetesServiceMock: jest.Mocked<KcpKubernetesService>;
|
|
38
|
+
let permissionsProxyServiceMock: jest.Mocked<PermissionsProxyService>;
|
|
37
39
|
|
|
38
40
|
const mockToken = 'test-token-123';
|
|
39
41
|
const mockEntities = ['test-entity'];
|
|
@@ -44,6 +46,9 @@ describe('KubernetesServiceProvidersService', () => {
|
|
|
44
46
|
|
|
45
47
|
beforeEach(async () => {
|
|
46
48
|
kcpKubernetesServiceMock = mock<KcpKubernetesService>();
|
|
49
|
+
permissionsProxyServiceMock = {
|
|
50
|
+
resolvePermissions: jest.fn().mockResolvedValue([]),
|
|
51
|
+
} as unknown as jest.Mocked<PermissionsProxyService>;
|
|
47
52
|
|
|
48
53
|
const module: TestingModule = await Test.createTestingModule({
|
|
49
54
|
providers: [
|
|
@@ -52,6 +57,10 @@ describe('KubernetesServiceProvidersService', () => {
|
|
|
52
57
|
provide: KcpKubernetesService,
|
|
53
58
|
useValue: kcpKubernetesServiceMock,
|
|
54
59
|
},
|
|
60
|
+
{
|
|
61
|
+
provide: PermissionsProxyService,
|
|
62
|
+
useValue: permissionsProxyServiceMock,
|
|
63
|
+
},
|
|
55
64
|
],
|
|
56
65
|
}).compile();
|
|
57
66
|
|
|
@@ -443,7 +452,7 @@ describe('KubernetesServiceProvidersService', () => {
|
|
|
443
452
|
},
|
|
444
453
|
);
|
|
445
454
|
|
|
446
|
-
const svc = new KubernetesServiceProvidersService(kcpKubernetesServiceMock);
|
|
455
|
+
const svc = new KubernetesServiceProvidersService(kcpKubernetesServiceMock, permissionsProxyServiceMock);
|
|
447
456
|
const res = await svc.getServiceProviders('token', ['main'], {
|
|
448
457
|
organization: 'org',
|
|
449
458
|
isSubDomain: true,
|
|
@@ -477,7 +486,7 @@ describe('KubernetesServiceProvidersService', () => {
|
|
|
477
486
|
},
|
|
478
487
|
);
|
|
479
488
|
|
|
480
|
-
const svc = new KubernetesServiceProvidersService(kcpKubernetesServiceMock);
|
|
489
|
+
const svc = new KubernetesServiceProvidersService(kcpKubernetesServiceMock, permissionsProxyServiceMock);
|
|
481
490
|
const res = await svc.getServiceProviders('token', ['main'], {
|
|
482
491
|
organization: 'org',
|
|
483
492
|
isSubDomain: true,
|
|
@@ -524,7 +533,7 @@ describe('KubernetesServiceProvidersService', () => {
|
|
|
524
533
|
},
|
|
525
534
|
);
|
|
526
535
|
|
|
527
|
-
const svc = new KubernetesServiceProvidersService(kcpKubernetesServiceMock);
|
|
536
|
+
const svc = new KubernetesServiceProvidersService(kcpKubernetesServiceMock, permissionsProxyServiceMock);
|
|
528
537
|
const res = await svc.getServiceProviders('token', ['main'], {
|
|
529
538
|
organization: 'org',
|
|
530
539
|
isSubDomain: true,
|
|
@@ -560,7 +569,7 @@ describe('KubernetesServiceProvidersService', () => {
|
|
|
560
569
|
},
|
|
561
570
|
);
|
|
562
571
|
|
|
563
|
-
const svc = new KubernetesServiceProvidersService(kcpKubernetesServiceMock);
|
|
572
|
+
const svc = new KubernetesServiceProvidersService(kcpKubernetesServiceMock, permissionsProxyServiceMock);
|
|
564
573
|
const res = await svc.getServiceProviders('token', ['main'], {
|
|
565
574
|
organization: 'org',
|
|
566
575
|
isSubDomain: true,
|
|
@@ -1,17 +1,21 @@
|
|
|
1
|
-
import { K8sRequestContext, K8sResourceDescriptor } from '../models/k8s.js';
|
|
2
|
-
import { KcpKubernetesService } from '../services/kcp-k8s.service.js';
|
|
3
|
-
import { processContentConfigurationForAccountHierarchy } from '../utils/account-hierarchy-resolver.js';
|
|
4
|
-
import { welcomeNodeConfig } from './models/welcome-node-config.js';
|
|
5
1
|
import { Injectable } from '@nestjs/common';
|
|
6
2
|
import {
|
|
7
3
|
ContentConfiguration,
|
|
8
4
|
ServiceProviderResponse,
|
|
9
5
|
ServiceProviderService,
|
|
10
6
|
} from '@openmfp/portal-server-lib';
|
|
7
|
+
import { K8sRequestContext, K8sResourceDescriptor } from '../models/k8s.js';
|
|
8
|
+
import { KcpKubernetesService } from '../services/kcp-k8s.service.js';
|
|
9
|
+
import { PermissionsProxyService } from '../services/permissions/permissions-proxy.service.js';
|
|
10
|
+
import { processContentConfigurationForAccountHierarchy } from '../utils/account-hierarchy-resolver.js';
|
|
11
|
+
import { welcomeNodeConfig } from './models/welcome-node-config.js';
|
|
11
12
|
|
|
12
13
|
@Injectable()
|
|
13
14
|
export class KubernetesServiceProvidersService implements ServiceProviderService {
|
|
14
|
-
constructor(
|
|
15
|
+
constructor(
|
|
16
|
+
private kcpKubernetesService: KcpKubernetesService,
|
|
17
|
+
private permissionsProxyService: PermissionsProxyService,
|
|
18
|
+
) {}
|
|
15
19
|
|
|
16
20
|
async getServiceProviders(
|
|
17
21
|
token: string,
|
|
@@ -30,7 +34,7 @@ export class KubernetesServiceProvidersService implements ServiceProviderService
|
|
|
30
34
|
if (!context?.organization) {
|
|
31
35
|
throw new Error('Context with organization is required');
|
|
32
36
|
}
|
|
33
|
-
|
|
37
|
+
|
|
34
38
|
const response = await this.listContentConfigurationsForEntity(
|
|
35
39
|
token,
|
|
36
40
|
context as K8sRequestContext,
|
|
@@ -62,6 +66,15 @@ export class KubernetesServiceProvidersService implements ServiceProviderService
|
|
|
62
66
|
return contentConfiguration;
|
|
63
67
|
});
|
|
64
68
|
|
|
69
|
+
const accountPath =
|
|
70
|
+
context?.accountPath ?? context?.['core_platform-mesh_io_account'] ?? '';
|
|
71
|
+
const nodesPermissions = await this.permissionsProxyService.resolvePermissions(
|
|
72
|
+
token,
|
|
73
|
+
context.organization,
|
|
74
|
+
accountPath,
|
|
75
|
+
contentConfigurations,
|
|
76
|
+
);
|
|
77
|
+
|
|
65
78
|
return {
|
|
66
79
|
rawServiceProviders: [
|
|
67
80
|
{
|
|
@@ -69,6 +82,7 @@ export class KubernetesServiceProvidersService implements ServiceProviderService
|
|
|
69
82
|
displayName: '',
|
|
70
83
|
creationTimestamp: '',
|
|
71
84
|
contentConfiguration: contentConfigurations,
|
|
85
|
+
nodeContext: { nodesPermissions },
|
|
72
86
|
},
|
|
73
87
|
],
|
|
74
88
|
};
|
|
@@ -90,12 +104,11 @@ export class KubernetesServiceProvidersService implements ServiceProviderService
|
|
|
90
104
|
context,
|
|
91
105
|
token,
|
|
92
106
|
);
|
|
93
|
-
} catch (error) {
|
|
107
|
+
} catch (error: any) {
|
|
94
108
|
console.error(error);
|
|
95
109
|
|
|
96
110
|
if (error.code == 429 || error.statusCode == 429) {
|
|
97
111
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
98
|
-
console.log('Retry after 1 second reading kubernetes resources.');
|
|
99
112
|
return await this.kcpKubernetesService.listClusterCustomObjectInKcpVirtualWorkspace(
|
|
100
113
|
gvr,
|
|
101
114
|
context,
|