@kuadrant/kuadrant-backstage-plugin-backend 0.0.2-dev-39963ad → 0.0.2-dev-8f2e157
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/index.cjs.js +7 -5
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +8 -6
- package/dist/permissions.cjs.js +36 -24
- package/dist/permissions.cjs.js.map +1 -1
- package/dist/providers/APIProductEntityProvider.cjs.js +14 -17
- package/dist/providers/APIProductEntityProvider.cjs.js.map +1 -1
- package/dist/router.cjs.js +258 -69
- package/dist/router.cjs.js.map +1 -1
- package/package.json +1 -1
package/dist/router.cjs.js
CHANGED
|
@@ -21,17 +21,19 @@ var cors__default = /*#__PURE__*/_interopDefaultCompat(cors);
|
|
|
21
21
|
function generateApiKey() {
|
|
22
22
|
return crypto.randomBytes(32).toString("hex");
|
|
23
23
|
}
|
|
24
|
+
function extractNameFromEntityRef(entityRef) {
|
|
25
|
+
const parts = entityRef.split("/");
|
|
26
|
+
return parts[parts.length - 1];
|
|
27
|
+
}
|
|
24
28
|
async function getUserIdentity(req, httpAuth, userInfo) {
|
|
25
29
|
const credentials = await httpAuth.credentials(req);
|
|
26
30
|
if (!credentials || !credentials.principal) {
|
|
27
31
|
throw new errors.NotAllowedError("authentication required");
|
|
28
32
|
}
|
|
29
33
|
const info = await userInfo.getUserInfo(credentials);
|
|
30
|
-
const userId = info.userEntityRef.split("/")[1];
|
|
31
34
|
const groups = info.ownershipEntityRefs || [];
|
|
32
|
-
console.log(`user identity resolved:
|
|
35
|
+
console.log(`user identity resolved: userEntityRef=${info.userEntityRef}, groups=${groups.join(",")}`);
|
|
33
36
|
return {
|
|
34
|
-
userId,
|
|
35
37
|
userEntityRef: info.userEntityRef,
|
|
36
38
|
groups
|
|
37
39
|
};
|
|
@@ -52,15 +54,35 @@ async function createRouter({
|
|
|
52
54
|
router.get("/apiproducts", async (req, res) => {
|
|
53
55
|
try {
|
|
54
56
|
const credentials = await httpAuth.credentials(req);
|
|
55
|
-
const
|
|
57
|
+
const listDecision = await permissions$1.authorize(
|
|
56
58
|
[{ permission: permissions.kuadrantApiProductListPermission }],
|
|
57
59
|
{ credentials }
|
|
58
60
|
);
|
|
59
|
-
if (
|
|
61
|
+
if (listDecision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
|
|
60
62
|
throw new errors.NotAllowedError("unauthorised");
|
|
61
63
|
}
|
|
64
|
+
const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);
|
|
62
65
|
const data = await k8sClient$1.listCustomResources("extensions.kuadrant.io", "v1alpha1", "apiproducts");
|
|
63
|
-
|
|
66
|
+
const readAllDecision = await permissions$1.authorize(
|
|
67
|
+
[{ permission: permissions.kuadrantApiProductReadAllPermission }],
|
|
68
|
+
{ credentials }
|
|
69
|
+
);
|
|
70
|
+
if (readAllDecision[0].result === pluginPermissionCommon.AuthorizeResult.ALLOW) {
|
|
71
|
+
res.json(data);
|
|
72
|
+
} else {
|
|
73
|
+
const readOwnDecision = await permissions$1.authorize(
|
|
74
|
+
[{ permission: permissions.kuadrantApiProductReadOwnPermission }],
|
|
75
|
+
{ credentials }
|
|
76
|
+
);
|
|
77
|
+
if (readOwnDecision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
|
|
78
|
+
throw new errors.NotAllowedError("unauthorised");
|
|
79
|
+
}
|
|
80
|
+
const ownedItems = (data.items || []).filter((item) => {
|
|
81
|
+
const owner = item.metadata?.annotations?.["backstage.io/owner"];
|
|
82
|
+
return owner === userEntityRef;
|
|
83
|
+
});
|
|
84
|
+
res.json({ ...data, items: ownedItems });
|
|
85
|
+
}
|
|
64
86
|
} catch (error) {
|
|
65
87
|
console.error("error fetching apiproducts:", error);
|
|
66
88
|
if (error instanceof errors.NotAllowedError) {
|
|
@@ -73,16 +95,30 @@ async function createRouter({
|
|
|
73
95
|
router.get("/apiproducts/:namespace/:name", async (req, res) => {
|
|
74
96
|
try {
|
|
75
97
|
const credentials = await httpAuth.credentials(req);
|
|
76
|
-
const
|
|
77
|
-
|
|
98
|
+
const { namespace, name } = req.params;
|
|
99
|
+
const readAllDecision = await permissions$1.authorize(
|
|
100
|
+
[{ permission: permissions.kuadrantApiProductReadAllPermission }],
|
|
78
101
|
{ credentials }
|
|
79
102
|
);
|
|
80
|
-
if (
|
|
81
|
-
|
|
103
|
+
if (readAllDecision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
|
|
104
|
+
const readOwnDecision = await permissions$1.authorize(
|
|
105
|
+
[{ permission: permissions.kuadrantApiProductReadOwnPermission }],
|
|
106
|
+
{ credentials }
|
|
107
|
+
);
|
|
108
|
+
if (readOwnDecision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
|
|
109
|
+
throw new errors.NotAllowedError("unauthorised");
|
|
110
|
+
}
|
|
111
|
+
const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);
|
|
112
|
+
const data = await k8sClient$1.getCustomResource("extensions.kuadrant.io", "v1alpha1", namespace, "apiproducts", name);
|
|
113
|
+
const owner = data.metadata?.annotations?.["backstage.io/owner"];
|
|
114
|
+
if (owner !== userEntityRef) {
|
|
115
|
+
throw new errors.NotAllowedError("you can only read your own api products");
|
|
116
|
+
}
|
|
117
|
+
res.json(data);
|
|
118
|
+
} else {
|
|
119
|
+
const data = await k8sClient$1.getCustomResource("extensions.kuadrant.io", "v1alpha1", namespace, "apiproducts", name);
|
|
120
|
+
res.json(data);
|
|
82
121
|
}
|
|
83
|
-
const { namespace, name } = req.params;
|
|
84
|
-
const data = await k8sClient$1.getCustomResource("extensions.kuadrant.io", "v1alpha1", namespace, "apiproducts", name);
|
|
85
|
-
res.json(data);
|
|
86
122
|
} catch (error) {
|
|
87
123
|
console.error("error fetching apiproduct:", error);
|
|
88
124
|
if (error instanceof errors.NotAllowedError) {
|
|
@@ -102,7 +138,7 @@ async function createRouter({
|
|
|
102
138
|
if (decision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
|
|
103
139
|
throw new errors.NotAllowedError("unauthorised");
|
|
104
140
|
}
|
|
105
|
-
const {
|
|
141
|
+
const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);
|
|
106
142
|
const apiProduct = req.body;
|
|
107
143
|
const targetRef = apiProduct.spec?.targetRef;
|
|
108
144
|
if (!targetRef?.name || !targetRef?.kind || !targetRef?.namespace) {
|
|
@@ -110,10 +146,10 @@ async function createRouter({
|
|
|
110
146
|
}
|
|
111
147
|
const namespace = targetRef.namespace;
|
|
112
148
|
apiProduct.metadata.namespace = namespace;
|
|
113
|
-
if (!apiProduct.
|
|
114
|
-
apiProduct.
|
|
149
|
+
if (!apiProduct.metadata.annotations) {
|
|
150
|
+
apiProduct.metadata.annotations = {};
|
|
115
151
|
}
|
|
116
|
-
apiProduct.
|
|
152
|
+
apiProduct.metadata.annotations["backstage.io/owner"] = userEntityRef;
|
|
117
153
|
const httpRouteNamespace = namespace;
|
|
118
154
|
const httpRouteName = targetRef.name;
|
|
119
155
|
try {
|
|
@@ -167,14 +203,26 @@ async function createRouter({
|
|
|
167
203
|
router.delete("/apiproducts/:namespace/:name", async (req, res) => {
|
|
168
204
|
try {
|
|
169
205
|
const credentials = await httpAuth.credentials(req);
|
|
170
|
-
const
|
|
171
|
-
|
|
206
|
+
const { namespace, name } = req.params;
|
|
207
|
+
const deleteAllDecision = await permissions$1.authorize(
|
|
208
|
+
[{ permission: permissions.kuadrantApiProductDeleteAllPermission }],
|
|
172
209
|
{ credentials }
|
|
173
210
|
);
|
|
174
|
-
if (
|
|
175
|
-
|
|
211
|
+
if (deleteAllDecision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
|
|
212
|
+
const deleteOwnDecision = await permissions$1.authorize(
|
|
213
|
+
[{ permission: permissions.kuadrantApiProductDeleteOwnPermission }],
|
|
214
|
+
{ credentials }
|
|
215
|
+
);
|
|
216
|
+
if (deleteOwnDecision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
|
|
217
|
+
throw new errors.NotAllowedError("unauthorised");
|
|
218
|
+
}
|
|
219
|
+
const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);
|
|
220
|
+
const existing = await k8sClient$1.getCustomResource("extensions.kuadrant.io", "v1alpha1", namespace, "apiproducts", name);
|
|
221
|
+
const owner = existing.metadata?.annotations?.["backstage.io/owner"];
|
|
222
|
+
if (owner !== userEntityRef) {
|
|
223
|
+
throw new errors.NotAllowedError("you can only delete your own api products");
|
|
224
|
+
}
|
|
176
225
|
}
|
|
177
|
-
const { namespace, name } = req.params;
|
|
178
226
|
await k8sClient$1.deleteCustomResource(
|
|
179
227
|
"extensions.kuadrant.io",
|
|
180
228
|
"v1alpha1",
|
|
@@ -246,14 +294,29 @@ async function createRouter({
|
|
|
246
294
|
if (!credentials || !credentials.principal) {
|
|
247
295
|
throw new errors.NotAllowedError("authentication required");
|
|
248
296
|
}
|
|
249
|
-
const
|
|
250
|
-
|
|
297
|
+
const { namespace, name } = req.params;
|
|
298
|
+
const updateAllDecision = await permissions$1.authorize(
|
|
299
|
+
[{ permission: permissions.kuadrantApiProductUpdateAllPermission }],
|
|
251
300
|
{ credentials }
|
|
252
301
|
);
|
|
253
|
-
if (
|
|
254
|
-
|
|
302
|
+
if (updateAllDecision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
|
|
303
|
+
const updateOwnDecision = await permissions$1.authorize(
|
|
304
|
+
[{ permission: permissions.kuadrantApiProductUpdateOwnPermission }],
|
|
305
|
+
{ credentials }
|
|
306
|
+
);
|
|
307
|
+
if (updateOwnDecision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
|
|
308
|
+
throw new errors.NotAllowedError("unauthorised");
|
|
309
|
+
}
|
|
310
|
+
const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);
|
|
311
|
+
const existing = await k8sClient$1.getCustomResource("extensions.kuadrant.io", "v1alpha1", namespace, "apiproducts", name);
|
|
312
|
+
const owner = existing.metadata?.annotations?.["backstage.io/owner"];
|
|
313
|
+
if (owner !== userEntityRef) {
|
|
314
|
+
throw new errors.NotAllowedError("you can only update your own api products");
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
if (req.body.metadata?.annotations) {
|
|
318
|
+
delete req.body.metadata.annotations["backstage.io/owner"];
|
|
255
319
|
}
|
|
256
|
-
const { namespace, name } = req.params;
|
|
257
320
|
const updated = await k8sClient$1.patchCustomResource(
|
|
258
321
|
"extensions.kuadrant.io",
|
|
259
322
|
"v1alpha1",
|
|
@@ -353,7 +416,7 @@ async function createRouter({
|
|
|
353
416
|
try {
|
|
354
417
|
const credentials = await httpAuth.credentials(req);
|
|
355
418
|
const { apiName, apiNamespace, planTier, useCase, userEmail } = parsed.data;
|
|
356
|
-
const {
|
|
419
|
+
const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);
|
|
357
420
|
const resourceRef = `apiproduct:${apiNamespace}/${apiName}`;
|
|
358
421
|
const decision = await permissions$1.authorize(
|
|
359
422
|
[{
|
|
@@ -367,8 +430,9 @@ async function createRouter({
|
|
|
367
430
|
}
|
|
368
431
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
369
432
|
const randomSuffix = crypto.randomBytes(4).toString("hex");
|
|
370
|
-
const
|
|
371
|
-
const
|
|
433
|
+
const userName = extractNameFromEntityRef(userEntityRef);
|
|
434
|
+
const requestName = `${userName}-${apiName}-${randomSuffix}`.toLowerCase().replace(/[^a-z0-9-]/g, "-");
|
|
435
|
+
const requestedBy = { userId: userEntityRef };
|
|
372
436
|
if (userEmail) {
|
|
373
437
|
requestedBy.email = userEmail;
|
|
374
438
|
}
|
|
@@ -406,7 +470,8 @@ async function createRouter({
|
|
|
406
470
|
if (apiProduct.spec?.approvalMode === "automatic") {
|
|
407
471
|
const apiKey = generateApiKey();
|
|
408
472
|
const timestamp2 = Date.now();
|
|
409
|
-
const
|
|
473
|
+
const userName2 = extractNameFromEntityRef(userEntityRef);
|
|
474
|
+
const secretName = `${userName2}-${apiName}-${timestamp2}`.toLowerCase().replace(/[^a-z0-9-]/g, "-");
|
|
410
475
|
const secret = {
|
|
411
476
|
apiVersion: "v1",
|
|
412
477
|
kind: "Secret",
|
|
@@ -418,7 +483,7 @@ async function createRouter({
|
|
|
418
483
|
},
|
|
419
484
|
annotations: {
|
|
420
485
|
"secret.kuadrant.io/plan-id": planTier,
|
|
421
|
-
"secret.kuadrant.io/user-id":
|
|
486
|
+
"secret.kuadrant.io/user-id": userEntityRef
|
|
422
487
|
}
|
|
423
488
|
},
|
|
424
489
|
stringData: {
|
|
@@ -483,12 +548,19 @@ async function createRouter({
|
|
|
483
548
|
router.get("/requests", async (req, res) => {
|
|
484
549
|
try {
|
|
485
550
|
const credentials = await httpAuth.credentials(req);
|
|
486
|
-
const
|
|
487
|
-
[{ permission: permissions.
|
|
551
|
+
const readAllDecision = await permissions$1.authorize(
|
|
552
|
+
[{ permission: permissions.kuadrantApiKeyRequestReadAllPermission }],
|
|
488
553
|
{ credentials }
|
|
489
554
|
);
|
|
490
|
-
|
|
491
|
-
|
|
555
|
+
const canReadAll = readAllDecision[0].result === pluginPermissionCommon.AuthorizeResult.ALLOW;
|
|
556
|
+
if (!canReadAll) {
|
|
557
|
+
const readOwnDecision = await permissions$1.authorize(
|
|
558
|
+
[{ permission: permissions.kuadrantApiKeyRequestReadOwnPermission }],
|
|
559
|
+
{ credentials }
|
|
560
|
+
);
|
|
561
|
+
if (readOwnDecision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
|
|
562
|
+
throw new errors.NotAllowedError("unauthorised");
|
|
563
|
+
}
|
|
492
564
|
}
|
|
493
565
|
const status = req.query.status;
|
|
494
566
|
const namespace = req.query.namespace;
|
|
@@ -499,6 +571,17 @@ async function createRouter({
|
|
|
499
571
|
data = await k8sClient$1.listCustomResources("extensions.kuadrant.io", "v1alpha1", "apikeyrequests");
|
|
500
572
|
}
|
|
501
573
|
let filteredItems = data.items || [];
|
|
574
|
+
if (!canReadAll) {
|
|
575
|
+
const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);
|
|
576
|
+
const apiproducts = await k8sClient$1.listCustomResources("extensions.kuadrant.io", "v1alpha1", "apiproducts");
|
|
577
|
+
const ownedApiProducts = (apiproducts.items || []).filter((product) => {
|
|
578
|
+
const owner = product.metadata?.annotations?.["backstage.io/owner"];
|
|
579
|
+
return owner === userEntityRef;
|
|
580
|
+
}).map((product) => product.metadata.name);
|
|
581
|
+
filteredItems = filteredItems.filter(
|
|
582
|
+
(req2) => ownedApiProducts.includes(req2.spec?.apiName)
|
|
583
|
+
);
|
|
584
|
+
}
|
|
502
585
|
if (status) {
|
|
503
586
|
filteredItems = filteredItems.filter((req2) => {
|
|
504
587
|
const phase = req2.status?.phase || "Pending";
|
|
@@ -525,7 +608,7 @@ async function createRouter({
|
|
|
525
608
|
if (decision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
|
|
526
609
|
throw new errors.NotAllowedError("unauthorised");
|
|
527
610
|
}
|
|
528
|
-
const {
|
|
611
|
+
const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);
|
|
529
612
|
const namespace = req.query.namespace;
|
|
530
613
|
let data;
|
|
531
614
|
if (namespace) {
|
|
@@ -534,7 +617,7 @@ async function createRouter({
|
|
|
534
617
|
data = await k8sClient$1.listCustomResources("extensions.kuadrant.io", "v1alpha1", "apikeyrequests");
|
|
535
618
|
}
|
|
536
619
|
const filteredItems = (data.items || []).filter(
|
|
537
|
-
(req2) => req2.spec?.requestedBy?.userId ===
|
|
620
|
+
(req2) => req2.spec?.requestedBy?.userId === userEntityRef
|
|
538
621
|
);
|
|
539
622
|
res.json({ items: filteredItems });
|
|
540
623
|
} catch (error) {
|
|
@@ -556,17 +639,10 @@ async function createRouter({
|
|
|
556
639
|
}
|
|
557
640
|
try {
|
|
558
641
|
const credentials = await httpAuth.credentials(req);
|
|
559
|
-
const {
|
|
560
|
-
const decision = await permissions$1.authorize(
|
|
561
|
-
[{ permission: permissions.kuadrantApiKeyRequestUpdatePermission }],
|
|
562
|
-
{ credentials }
|
|
563
|
-
);
|
|
564
|
-
if (decision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
|
|
565
|
-
throw new errors.NotAllowedError("unauthorised");
|
|
566
|
-
}
|
|
642
|
+
const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);
|
|
567
643
|
const { namespace, name } = req.params;
|
|
568
644
|
const { comment } = parsed.data;
|
|
569
|
-
const reviewedBy =
|
|
645
|
+
const reviewedBy = userEntityRef;
|
|
570
646
|
const request = await k8sClient$1.getCustomResource(
|
|
571
647
|
"extensions.kuadrant.io",
|
|
572
648
|
"v1alpha1",
|
|
@@ -575,9 +651,34 @@ async function createRouter({
|
|
|
575
651
|
name
|
|
576
652
|
);
|
|
577
653
|
const spec = request.spec;
|
|
654
|
+
const apiProduct = await k8sClient$1.getCustomResource(
|
|
655
|
+
"extensions.kuadrant.io",
|
|
656
|
+
"v1alpha1",
|
|
657
|
+
spec.apiNamespace,
|
|
658
|
+
"apiproducts",
|
|
659
|
+
spec.apiName
|
|
660
|
+
);
|
|
661
|
+
const owner = apiProduct.metadata?.annotations?.["backstage.io/owner"];
|
|
662
|
+
const updateAllDecision = await permissions$1.authorize(
|
|
663
|
+
[{ permission: permissions.kuadrantApiKeyRequestUpdateAllPermission }],
|
|
664
|
+
{ credentials }
|
|
665
|
+
);
|
|
666
|
+
if (updateAllDecision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
|
|
667
|
+
const updateOwnDecision = await permissions$1.authorize(
|
|
668
|
+
[{ permission: permissions.kuadrantApiKeyRequestUpdateOwnPermission }],
|
|
669
|
+
{ credentials }
|
|
670
|
+
);
|
|
671
|
+
if (updateOwnDecision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
|
|
672
|
+
throw new errors.NotAllowedError("unauthorised");
|
|
673
|
+
}
|
|
674
|
+
if (owner !== userEntityRef) {
|
|
675
|
+
throw new errors.NotAllowedError("you can only approve requests for your own api products");
|
|
676
|
+
}
|
|
677
|
+
}
|
|
578
678
|
const apiKey = generateApiKey();
|
|
579
679
|
const timestamp = Date.now();
|
|
580
|
-
const
|
|
680
|
+
const userName = extractNameFromEntityRef(spec.requestedBy.userId);
|
|
681
|
+
const secretName = `${userName}-${spec.apiName}-${timestamp}`.toLowerCase().replace(/[^a-z0-9-]/g, "-");
|
|
581
682
|
const secret = {
|
|
582
683
|
apiVersion: "v1",
|
|
583
684
|
kind: "Secret",
|
|
@@ -681,17 +782,42 @@ async function createRouter({
|
|
|
681
782
|
}
|
|
682
783
|
try {
|
|
683
784
|
const credentials = await httpAuth.credentials(req);
|
|
684
|
-
const {
|
|
685
|
-
const
|
|
686
|
-
|
|
785
|
+
const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);
|
|
786
|
+
const { namespace, name } = req.params;
|
|
787
|
+
const { comment } = parsed.data;
|
|
788
|
+
const reviewedBy = userEntityRef;
|
|
789
|
+
const request = await k8sClient$1.getCustomResource(
|
|
790
|
+
"extensions.kuadrant.io",
|
|
791
|
+
"v1alpha1",
|
|
792
|
+
namespace,
|
|
793
|
+
"apikeyrequests",
|
|
794
|
+
name
|
|
795
|
+
);
|
|
796
|
+
const spec = request.spec;
|
|
797
|
+
const apiProduct = await k8sClient$1.getCustomResource(
|
|
798
|
+
"extensions.kuadrant.io",
|
|
799
|
+
"v1alpha1",
|
|
800
|
+
spec.apiNamespace,
|
|
801
|
+
"apiproducts",
|
|
802
|
+
spec.apiName
|
|
803
|
+
);
|
|
804
|
+
const owner = apiProduct.metadata?.annotations?.["backstage.io/owner"];
|
|
805
|
+
const updateAllDecision = await permissions$1.authorize(
|
|
806
|
+
[{ permission: permissions.kuadrantApiKeyRequestUpdateAllPermission }],
|
|
687
807
|
{ credentials }
|
|
688
808
|
);
|
|
689
|
-
if (
|
|
690
|
-
|
|
809
|
+
if (updateAllDecision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
|
|
810
|
+
const updateOwnDecision = await permissions$1.authorize(
|
|
811
|
+
[{ permission: permissions.kuadrantApiKeyRequestUpdateOwnPermission }],
|
|
812
|
+
{ credentials }
|
|
813
|
+
);
|
|
814
|
+
if (updateOwnDecision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
|
|
815
|
+
throw new errors.NotAllowedError("unauthorised");
|
|
816
|
+
}
|
|
817
|
+
if (owner !== userEntityRef) {
|
|
818
|
+
throw new errors.NotAllowedError("you can only reject requests for your own api products");
|
|
819
|
+
}
|
|
691
820
|
}
|
|
692
|
-
const { namespace, name } = req.params;
|
|
693
|
-
const { comment } = parsed.data;
|
|
694
|
-
const reviewedBy = `user:default/${userId}`;
|
|
695
821
|
const status = {
|
|
696
822
|
phase: "Rejected",
|
|
697
823
|
reviewedBy,
|
|
@@ -730,16 +856,16 @@ async function createRouter({
|
|
|
730
856
|
}
|
|
731
857
|
try {
|
|
732
858
|
const credentials = await httpAuth.credentials(req);
|
|
733
|
-
const {
|
|
859
|
+
const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);
|
|
734
860
|
const decision = await permissions$1.authorize(
|
|
735
|
-
[{ permission: permissions.
|
|
861
|
+
[{ permission: permissions.kuadrantApiKeyRequestUpdateAllPermission }],
|
|
736
862
|
{ credentials }
|
|
737
863
|
);
|
|
738
864
|
if (decision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
|
|
739
865
|
throw new errors.NotAllowedError("unauthorised");
|
|
740
866
|
}
|
|
741
867
|
const { requests, comment } = parsed.data;
|
|
742
|
-
const reviewedBy =
|
|
868
|
+
const reviewedBy = userEntityRef;
|
|
743
869
|
const results = [];
|
|
744
870
|
for (const reqRef of requests) {
|
|
745
871
|
try {
|
|
@@ -751,9 +877,34 @@ async function createRouter({
|
|
|
751
877
|
reqRef.name
|
|
752
878
|
);
|
|
753
879
|
const spec = request.spec;
|
|
880
|
+
const apiProduct = await k8sClient$1.getCustomResource(
|
|
881
|
+
"extensions.kuadrant.io",
|
|
882
|
+
"v1alpha1",
|
|
883
|
+
spec.apiNamespace,
|
|
884
|
+
"apiproducts",
|
|
885
|
+
spec.apiName
|
|
886
|
+
);
|
|
887
|
+
const owner = apiProduct.metadata?.annotations?.["backstage.io/owner"];
|
|
888
|
+
const updateAllDecision = await permissions$1.authorize(
|
|
889
|
+
[{ permission: permissions.kuadrantApiProductUpdateAllPermission }],
|
|
890
|
+
{ credentials }
|
|
891
|
+
);
|
|
892
|
+
if (updateAllDecision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
|
|
893
|
+
const updateOwnDecision = await permissions$1.authorize(
|
|
894
|
+
[{ permission: permissions.kuadrantApiProductUpdateOwnPermission }],
|
|
895
|
+
{ credentials }
|
|
896
|
+
);
|
|
897
|
+
if (updateOwnDecision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
|
|
898
|
+
throw new errors.NotAllowedError("unauthorised");
|
|
899
|
+
}
|
|
900
|
+
if (owner !== userEntityRef) {
|
|
901
|
+
throw new errors.NotAllowedError("you can only approve requests for your own api products");
|
|
902
|
+
}
|
|
903
|
+
}
|
|
754
904
|
const apiKey = generateApiKey();
|
|
755
905
|
const timestamp = Date.now();
|
|
756
|
-
const
|
|
906
|
+
const userName = extractNameFromEntityRef(spec.requestedBy.userId);
|
|
907
|
+
const secretName = `${userName}-${spec.apiName}-${timestamp}`.toLowerCase().replace(/[^a-z0-9-]/g, "-");
|
|
757
908
|
const secret = {
|
|
758
909
|
apiVersion: "v1",
|
|
759
910
|
kind: "Secret",
|
|
@@ -868,19 +1019,51 @@ async function createRouter({
|
|
|
868
1019
|
}
|
|
869
1020
|
try {
|
|
870
1021
|
const credentials = await httpAuth.credentials(req);
|
|
871
|
-
const {
|
|
1022
|
+
const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);
|
|
872
1023
|
const decision = await permissions$1.authorize(
|
|
873
|
-
[{ permission: permissions.
|
|
1024
|
+
[{ permission: permissions.kuadrantApiKeyRequestUpdateAllPermission }],
|
|
874
1025
|
{ credentials }
|
|
875
1026
|
);
|
|
876
1027
|
if (decision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
|
|
877
1028
|
throw new errors.NotAllowedError("unauthorised");
|
|
878
1029
|
}
|
|
879
1030
|
const { requests, comment } = parsed.data;
|
|
880
|
-
const reviewedBy =
|
|
1031
|
+
const reviewedBy = userEntityRef;
|
|
881
1032
|
const results = [];
|
|
882
1033
|
for (const reqRef of requests) {
|
|
883
1034
|
try {
|
|
1035
|
+
const request = await k8sClient$1.getCustomResource(
|
|
1036
|
+
"extensions.kuadrant.io",
|
|
1037
|
+
"v1alpha1",
|
|
1038
|
+
reqRef.namespace,
|
|
1039
|
+
"apikeyrequests",
|
|
1040
|
+
reqRef.name
|
|
1041
|
+
);
|
|
1042
|
+
const spec = request.spec;
|
|
1043
|
+
const apiProduct = await k8sClient$1.getCustomResource(
|
|
1044
|
+
"extensions.kuadrant.io",
|
|
1045
|
+
"v1alpha1",
|
|
1046
|
+
spec.apiNamespace,
|
|
1047
|
+
"apiproducts",
|
|
1048
|
+
spec.apiName
|
|
1049
|
+
);
|
|
1050
|
+
const owner = apiProduct.metadata?.annotations?.["backstage.io/owner"];
|
|
1051
|
+
const updateAllDecision = await permissions$1.authorize(
|
|
1052
|
+
[{ permission: permissions.kuadrantApiProductUpdateAllPermission }],
|
|
1053
|
+
{ credentials }
|
|
1054
|
+
);
|
|
1055
|
+
if (updateAllDecision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
|
|
1056
|
+
const updateOwnDecision = await permissions$1.authorize(
|
|
1057
|
+
[{ permission: permissions.kuadrantApiProductUpdateOwnPermission }],
|
|
1058
|
+
{ credentials }
|
|
1059
|
+
);
|
|
1060
|
+
if (updateOwnDecision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
|
|
1061
|
+
throw new errors.NotAllowedError("unauthorised");
|
|
1062
|
+
}
|
|
1063
|
+
if (owner !== userEntityRef) {
|
|
1064
|
+
throw new errors.NotAllowedError("you can only reject requests for your own api products");
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
884
1067
|
const status = {
|
|
885
1068
|
phase: "Rejected",
|
|
886
1069
|
reviewedBy,
|
|
@@ -919,7 +1102,7 @@ async function createRouter({
|
|
|
919
1102
|
router.delete("/requests/:namespace/:name", async (req, res) => {
|
|
920
1103
|
try {
|
|
921
1104
|
const credentials = await httpAuth.credentials(req);
|
|
922
|
-
const {
|
|
1105
|
+
const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);
|
|
923
1106
|
const { namespace, name } = req.params;
|
|
924
1107
|
const request = await k8sClient$1.getCustomResource(
|
|
925
1108
|
"extensions.kuadrant.io",
|
|
@@ -942,7 +1125,7 @@ async function createRouter({
|
|
|
942
1125
|
if (deleteOwnDecision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
|
|
943
1126
|
throw new errors.NotAllowedError("unauthorised");
|
|
944
1127
|
}
|
|
945
|
-
if (requestUserId !==
|
|
1128
|
+
if (requestUserId !== userEntityRef) {
|
|
946
1129
|
throw new errors.NotAllowedError("you can only delete your own api key requests");
|
|
947
1130
|
}
|
|
948
1131
|
}
|
|
@@ -983,7 +1166,8 @@ async function createRouter({
|
|
|
983
1166
|
router.patch("/requests/:namespace/:name", async (req, res) => {
|
|
984
1167
|
const patchSchema = zod.z.object({
|
|
985
1168
|
spec: zod.z.object({
|
|
986
|
-
useCase: zod.z.string().optional()
|
|
1169
|
+
useCase: zod.z.string().optional(),
|
|
1170
|
+
planTier: zod.z.string().optional()
|
|
987
1171
|
}).partial()
|
|
988
1172
|
});
|
|
989
1173
|
const parsed = patchSchema.safeParse(req.body);
|
|
@@ -992,7 +1176,7 @@ async function createRouter({
|
|
|
992
1176
|
}
|
|
993
1177
|
try {
|
|
994
1178
|
const credentials = await httpAuth.credentials(req);
|
|
995
|
-
const {
|
|
1179
|
+
const { userEntityRef } = await getUserIdentity(req, httpAuth, userInfo);
|
|
996
1180
|
const { namespace, name } = req.params;
|
|
997
1181
|
const existing = await k8sClient$1.getCustomResource(
|
|
998
1182
|
"extensions.kuadrant.io",
|
|
@@ -1001,8 +1185,13 @@ async function createRouter({
|
|
|
1001
1185
|
"apikeyrequests",
|
|
1002
1186
|
name
|
|
1003
1187
|
);
|
|
1188
|
+
const requestUserId = existing.spec?.requestedBy?.userId;
|
|
1189
|
+
const currentPhase = existing.status?.phase || "Pending";
|
|
1190
|
+
if (currentPhase !== "Pending") {
|
|
1191
|
+
throw new errors.NotAllowedError("only pending requests can be edited");
|
|
1192
|
+
}
|
|
1004
1193
|
const updateAllDecision = await permissions$1.authorize(
|
|
1005
|
-
[{ permission: permissions.
|
|
1194
|
+
[{ permission: permissions.kuadrantApiKeyRequestUpdateAllPermission }],
|
|
1006
1195
|
{ credentials }
|
|
1007
1196
|
);
|
|
1008
1197
|
if (updateAllDecision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
|
|
@@ -1013,7 +1202,7 @@ async function createRouter({
|
|
|
1013
1202
|
if (updateOwnDecision[0].result !== pluginPermissionCommon.AuthorizeResult.ALLOW) {
|
|
1014
1203
|
throw new errors.NotAllowedError("unauthorised");
|
|
1015
1204
|
}
|
|
1016
|
-
if (
|
|
1205
|
+
if (requestUserId !== userEntityRef) {
|
|
1017
1206
|
throw new errors.NotAllowedError("you can only update your own api key requests");
|
|
1018
1207
|
}
|
|
1019
1208
|
}
|