@xen-orchestra/rest-api 0.29.0 → 0.30.1

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.
Files changed (53) hide show
  1. package/README.md +101 -1
  2. package/dist/abstract-classes/base-controller.mjs +20 -3
  3. package/dist/abstract-classes/listener.mjs +116 -12
  4. package/dist/acl-privileges/acl-privilege.controller.mjs +172 -0
  5. package/dist/acl-roles/acl-role.controller.mjs +384 -0
  6. package/dist/alarms/alarm.controller.mjs +22 -9
  7. package/dist/alarms/alarm.service.mjs +8 -0
  8. package/dist/backup-archives/backup-archive.controller.mjs +30 -21
  9. package/dist/backup-archives/backup-archive.service.mjs +21 -0
  10. package/dist/backup-jobs/backup-job.controller.mjs +59 -15
  11. package/dist/backup-jobs/backup-job.service.mjs +7 -0
  12. package/dist/backup-logs/backup-log.controller.mjs +25 -11
  13. package/dist/backup-logs/backup-log.service.mjs +19 -0
  14. package/dist/backup-repositories/backup-repositories.controller.mjs +21 -3
  15. package/dist/events/event.class.mjs +24 -9
  16. package/dist/events/event.controller.mjs +3 -0
  17. package/dist/events/event.service.mjs +2 -1
  18. package/dist/groups/group.controller.mjs +90 -6
  19. package/dist/hosts/host.controller.mjs +78 -7
  20. package/dist/ioc/ioc.mjs +13 -4
  21. package/dist/messages/message.controller.mjs +29 -8
  22. package/dist/middlewares/acl.middleware.mjs +206 -0
  23. package/dist/middlewares/authentication.middleware.mjs +15 -6
  24. package/dist/middlewares/tsoa-to-xo-error.middleware.mjs +19 -1
  25. package/dist/networks/network.controller.mjs +60 -9
  26. package/dist/open-api/oa-examples/acl-privilege.oa-example.mjs +25 -0
  27. package/dist/open-api/oa-examples/acl-role.oa-example.mjs +22 -0
  28. package/dist/open-api/oa-examples/backup-archive.oa-example.mjs +6 -6
  29. package/dist/open-api/oa-examples/common.oa-example.mjs +3 -0
  30. package/dist/open-api/routes/routes.js +676 -132
  31. package/dist/pbds/pbd.controller.mjs +17 -3
  32. package/dist/pcis/pci.controller.mjs +16 -3
  33. package/dist/pgpus/pgpu.controller.mjs +16 -3
  34. package/dist/pifs/pif.controller.mjs +44 -8
  35. package/dist/pools/pool.controller.mjs +154 -9
  36. package/dist/proxies/proxy.controller.mjs +22 -4
  37. package/dist/restore-logs/restore-log.controller.mjs +36 -19
  38. package/dist/schedules/schedule.controller.mjs +33 -3
  39. package/dist/servers/server.controller.mjs +65 -5
  40. package/dist/sms/sm.controller.mjs +14 -2
  41. package/dist/srs/sr.controller.mjs +62 -10
  42. package/dist/tasks/task.controller.mjs +75 -11
  43. package/dist/users/user.controller.mjs +115 -16
  44. package/dist/vbds/vbd.controller.mjs +65 -31
  45. package/dist/vdi-snapshots/vdi-snapshot.controller.mjs +36 -6
  46. package/dist/vdis/vdi.controller.mjs +69 -8
  47. package/dist/vifs/vif.controller.mjs +43 -7
  48. package/dist/vm-controller/vm-controller.controller.mjs +62 -9
  49. package/dist/vm-snapshots/vm-snapshot.controller.mjs +70 -8
  50. package/dist/vm-templates/vm-template.controller.mjs +71 -8
  51. package/dist/vms/vm.controller.mjs +164 -12
  52. package/open-api/spec/swagger.json +10907 -3265
  53. package/package.json +4 -3
package/README.md CHANGED
@@ -60,7 +60,107 @@ class Foo extends Controller {
60
60
 
61
61
  ### Examples
62
62
 
63
- In order not to pollute important decorators, all example structures should be in a separate file. `src/open-api/examples/<resource>.example.mts`
63
+ In order not to pollute important decorators, all example structures should be in a separate file. `src/open-api/oa-examples/<resource>.oa-example.mts`
64
+
65
+ ### ACLs
66
+
67
+ To define an ACL for an endpoint, simply add the `acl` middleware and pass the required ACL(s).
68
+
69
+ If an endpoint does not have a middleware ACL, it will be accessible **ONLY** to administrators.
70
+
71
+ It is sometimes necessary to check ACLs based on the body of the request sent by the user (for example, for a PATCH endpoint). For this, you can use `actions` (which allows you to pass multiple actions) and `actionsFromBody` (a function exported from `acl.middleware.mts`).
72
+
73
+ `actionsFromBody(['update:name_label', 'update:name_description'])` checks if `name_label` is present in the request body, and then applies the ACL check. The same applies to `name_description`.
74
+
75
+ `actionIfNotSelfUser('read')` returns the given action only if the current user is **not** the target user. If the current user is the target (self), no action is returned and the ACL check is skipped entirely.
76
+
77
+ #### Guidelines
78
+
79
+ - **JSDoc Documentation**: Always document the required privileges in the JSDoc annotation so users know which permissions are needed. Use the format: `Required privilege: - ...`
80
+ - **Error Handling**: If you define an ACL for an endpoint, you **must** add a `@Response(403)` decorator.
81
+ - **Non XAPI objects**: When dealing with non XAPI XO Record, you must define the `getObject` function.
82
+
83
+ ##### Example: ACL on an existing resource
84
+
85
+ ```ts
86
+ /**
87
+ * Start a VM
88
+ *
89
+ * Required privilege:
90
+ * - resource: vm, action: start
91
+ */
92
+ @Post('{id}/actions/start')
93
+ @Middlewares(acl({resource: 'vm', action: 'start', objectId: 'params.id'}))
94
+ @Response(403)
95
+ getVm(@Path() id: string) {
96
+ const action = async () => {
97
+ const vm = await this.getObject(id)
98
+ // ...
99
+ }
100
+ }
101
+ ```
102
+
103
+ ##### Example: Resource creation
104
+
105
+ ```ts
106
+ /**
107
+ * Create a new VDI
108
+ *
109
+ * Required privilege:
110
+ * - resource: vdi, action: create
111
+ */
112
+ @Post('/')
113
+ @Middlewares(acl({resource: 'vdi', action: 'create', object: ({req}) => req.body }))
114
+ @Response(403)
115
+ createVdi(@Body() body: VdiConfig) {
116
+ const {srId, ...rest}
117
+ const bodyParam = {$SR: srId, ...rest}
118
+ await VDI_create(bodyParam)
119
+ // ...
120
+ }
121
+ ```
122
+
123
+ ##### Example: Resource update
124
+
125
+ ```ts
126
+ /**
127
+ * Update a VM
128
+ *
129
+ * Required privileges:
130
+ * - resource: vm, action: update (grants all fields)
131
+ * - resource: vm, action: update:name_label (if name_label is passed)
132
+ * - resource: vm, action: update:name_description (if name_description is passed)
133
+ */
134
+ @Patch('{id}')
135
+ @Middlewares(acl({resource: 'vm', actions: actionsFromBody(['update:name_label', 'update:name_description']), objectId: 'params.id'}))
136
+ @Response(403)
137
+ createVdi(@Path() id: string, @Body() body: patchBody) {
138
+ updateVm(id, body)
139
+ // ...
140
+ }
141
+ ```
142
+
143
+ ##### Example: Self-bypass ACL
144
+
145
+ ```ts
146
+ /**
147
+ * Get a user
148
+ *
149
+ * Required privilege:
150
+ * - resource: user, action: read (if not self)
151
+ */
152
+ @Get('{id}')
153
+ @Middlewares(acl({
154
+ resource: 'user',
155
+ actions: actionsIfNotSelfUser(['read']),
156
+ objectId: 'params.id',
157
+ getObject: ({ restApi }) => restApi.xoApp.getUser,
158
+ }))
159
+ @Response(403)
160
+ getUser(@Path() id: string) { ... }
161
+ ```
162
+
163
+ If you need to use a privilege that doesn't exist yet (e.g., `resource: 'vm', action: 'foo'`), you must register it in ACL Definition: here `@xen-orchestra/acl/src/actions/vm.mts`, add: `foo: true`.
64
164
 
65
165
  ## Contributions
66
166
 
@@ -2,6 +2,7 @@ import { Controller } from 'tsoa';
2
2
  import { createGzip } from 'node:zlib';
3
3
  import { pipeline } from 'node:stream/promises';
4
4
  import { Readable } from 'node:stream';
5
+ import { hasPrivilegeOn, } from '@xen-orchestra/acl';
5
6
  import { BASE_URL } from '../index.mjs';
6
7
  import { makeMarkdownTable } from '../helpers/markdown.helper.mjs';
7
8
  import { makeNdJsonStream } from '../helpers/stream.helper.mjs';
@@ -17,9 +18,25 @@ export class BaseController extends Controller {
17
18
  this.type = type;
18
19
  this.restApi = restApi;
19
20
  }
20
- sendObjects(objects, req, path) {
21
- const mapper = makeObjectMapper(req, path);
22
- const mappedObjects = objects.map(mapper);
21
+ async sendObjects(objects, req, opts) {
22
+ const mapper = makeObjectMapper(req, opts?.path);
23
+ const mappedObjects = [];
24
+ const user = this.restApi.getCurrentUser();
25
+ const userPrivileges = (opts?.privilege !== undefined && user.permission !== 'admin'
26
+ ? await this.restApi.xoApp.getAclV2UserPrivileges(user.id)
27
+ : []);
28
+ let limit = opts?.limit ?? Infinity;
29
+ for (const object of objects) {
30
+ if (limit === 0) {
31
+ break;
32
+ }
33
+ if (opts?.privilege !== undefined &&
34
+ !hasPrivilegeOn({ user, userPrivileges, objects: object, ...opts.privilege })) {
35
+ continue;
36
+ }
37
+ mappedObjects.push(mapper(object));
38
+ limit--;
39
+ }
23
40
  if (req.query.ndjson === 'true' && req.query.markdown === 'true') {
24
41
  throw invalidParameters('Cannot use both ndjson and markdown output formats simultaneously');
25
42
  }
@@ -1,11 +1,20 @@
1
+ import { createLogger } from '@xen-orchestra/log';
2
+ import { hasPrivilegeOn } from '@xen-orchestra/acl';
3
+ import { iocContainer } from '../ioc/ioc.mjs';
4
+ import { RestApi } from '../rest-api/rest-api.mjs';
5
+ import { XAPI_TYPE_BY_ACL_RESOURCE } from '../middlewares/acl.middleware.mjs';
6
+ const log = createLogger('xo:rest-api:listener');
1
7
  export class Listener {
2
8
  #subscribers = new Map();
3
9
  #eventEmitter;
4
10
  #eventCallbacks = new Map();
5
11
  #watchedEvent;
6
- constructor(eventEmitter, watchedEvent) {
12
+ #type;
13
+ constructor(eventEmitter, watchedEvent, type) {
7
14
  this.#eventEmitter = eventEmitter;
8
15
  this.#watchedEvent = watchedEvent;
16
+ // cast needed because Type !== Type | undefined (even if Type extends undefined...)
17
+ this.#type = type;
9
18
  }
10
19
  get subscribers() {
11
20
  return this.#subscribers;
@@ -13,6 +22,9 @@ export class Listener {
13
22
  get eventEmitter() {
14
23
  return this.#eventEmitter;
15
24
  }
25
+ get type() {
26
+ return this.#type;
27
+ }
16
28
  addSubscriber(subscriber, fields = '*') {
17
29
  const unregisterOnClear = subscriber.onClear(() => this.removeSubscriber(subscriber.id));
18
30
  this.#subscribers.set(subscriber.id, { fields, subscriber, unregisterOnClear });
@@ -45,20 +57,112 @@ export class Listener {
45
57
  if (this.#eventCallbacks.has(event)) {
46
58
  return;
47
59
  }
48
- const broadcastAllSubscriber = (...args) => {
49
- this.#subscribers.forEach(conf => {
50
- if (!conf.subscriber.isAlive) {
51
- this.removeSubscriber(conf.subscriber.id);
60
+ const broadcastAllSubscriber = async (...args) => {
61
+ try {
62
+ await Promise.all([...this.#subscribers.values()].map(async (conf) => {
63
+ if (!conf.subscriber.isAlive) {
64
+ this.removeSubscriber(conf.subscriber.id);
65
+ return;
66
+ }
67
+ let data;
68
+ try {
69
+ data = await this.handleData({ ...conf, event }, ...args);
70
+ }
71
+ catch (error) {
72
+ log.error(`cannot handle data for ${this.type} listener on subscriber: ${conf.subscriber.id} (user: ${conf.subscriber.userId}). Removing it from the subscriber list.`, { error });
73
+ this.removeSubscriber(conf.subscriber.id);
74
+ conf.subscriber.clear();
75
+ return;
76
+ }
77
+ if (data === undefined) {
78
+ return;
79
+ }
80
+ const { event: overridenEvent, ...dataToBroadcast } = data;
81
+ conf.subscriber.broadcast(overridenEvent ?? event, dataToBroadcast);
82
+ }));
83
+ }
84
+ catch (error) {
85
+ log.warn('unexpected error broadcasting to subscribers', { error });
86
+ }
87
+ };
88
+ this.#eventCallbacks.set(event, broadcastAllSubscriber);
89
+ this.#eventEmitter.on(event, broadcastAllSubscriber);
90
+ }
91
+ async getAclEvent({ event, object, previousObject, userId, }) {
92
+ if (this.type === undefined || (object === undefined && previousObject === undefined)) {
93
+ return;
94
+ }
95
+ const restApi = iocContainer.get(RestApi);
96
+ const user = await restApi.xoApp.getUser(userId);
97
+ if (user.permission === 'admin') {
98
+ return event;
99
+ }
100
+ const userPrivileges = (await restApi.xoApp.getAclV2UserPrivileges(user.id));
101
+ let resource;
102
+ // alarm and task are not real `XAPI` type
103
+ if (this.type === 'alarm' || this.type === 'task') {
104
+ resource = this.type;
105
+ }
106
+ else {
107
+ const resourceXapiType = Object.entries(XAPI_TYPE_BY_ACL_RESOURCE).find(([, xapiType]) => xapiType === this.type);
108
+ if (resourceXapiType === undefined) {
109
+ throw new Error(`No resource found for ${this.type} listener type`);
110
+ }
111
+ // cast is necessary because `Object.entries` loses inference on the key (it transforms it into a simple string).
112
+ ;
113
+ [resource] = resourceXapiType;
114
+ }
115
+ switch (event) {
116
+ case 'add':
117
+ if (object === undefined) {
52
118
  return;
53
119
  }
54
- const data = this.handleData({ ...conf, event }, ...args);
55
- if (data === undefined) {
120
+ if (!hasPrivilegeOn({ user, userPrivileges, action: 'read', objects: object, resource })) {
56
121
  return;
57
122
  }
58
- conf.subscriber.broadcast(event, data);
59
- });
60
- };
61
- this.#eventCallbacks.set(event, broadcastAllSubscriber);
62
- this.#eventEmitter.on(event, broadcastAllSubscriber);
123
+ return 'add';
124
+ case 'update': {
125
+ const canSeeObject = object !== undefined &&
126
+ hasPrivilegeOn({
127
+ user,
128
+ userPrivileges,
129
+ action: 'read',
130
+ objects: object,
131
+ resource,
132
+ });
133
+ const canSeePreviousObject = previousObject !== undefined &&
134
+ hasPrivilegeOn({
135
+ user,
136
+ userPrivileges,
137
+ action: 'read',
138
+ objects: previousObject,
139
+ resource,
140
+ });
141
+ if (canSeeObject && canSeePreviousObject) {
142
+ return 'update';
143
+ }
144
+ if (canSeeObject) {
145
+ return 'add';
146
+ }
147
+ if (canSeePreviousObject) {
148
+ return 'remove';
149
+ }
150
+ return;
151
+ }
152
+ case 'remove':
153
+ if (!hasPrivilegeOn({
154
+ user,
155
+ userPrivileges,
156
+ action: 'read',
157
+ objects: object ?? previousObject,
158
+ resource,
159
+ })) {
160
+ return;
161
+ }
162
+ return 'remove';
163
+ default:
164
+ // Not supposed to be here
165
+ throw new Error(`${event} event unhandled on ${this.type} listener`);
166
+ }
63
167
  }
64
168
  }
@@ -0,0 +1,172 @@
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 __param = (this && this.__param) || function (paramIndex, decorator) {
8
+ return function (target, key) { decorator(target, key, paramIndex); }
9
+ };
10
+ import { Body, Delete, Example, Get, Middlewares, Patch, Path, Post, Query, Request, Response, Route, Security, SuccessResponse, Tags, } from 'tsoa';
11
+ import { provide } from 'inversify-binding-decorators';
12
+ import { json } from 'express';
13
+ import { acl, actionsFromBody } from '../middlewares/acl.middleware.mjs';
14
+ import { aclPrivilege, aclPrivilegeIds, partialAclPrivileges, } from '../open-api/oa-examples/acl-privilege.oa-example.mjs';
15
+ import { badRequestResp, createdResp, forbiddenOperationResp, invalidParameters, noContentResp, notFoundResp, unauthorizedResp, } from '../open-api/common/response.common.mjs';
16
+ import { XoController } from '../abstract-classes/xo-controller.mjs';
17
+ import { entityId } from '../open-api/oa-examples/common.oa-example.mjs';
18
+ import { inject } from 'inversify';
19
+ import { RestApi } from '../rest-api/rest-api.mjs';
20
+ let AclPrivilegeController = class AclPrivilegeController extends XoController {
21
+ constructor(restApi) {
22
+ super('acl-privilege', restApi);
23
+ }
24
+ getAllCollectionObjects() {
25
+ return this.restApi.xoApp.getAclV2Privileges();
26
+ }
27
+ getCollectionObject(id) {
28
+ return this.restApi.xoApp.getAclV2Privilege(id);
29
+ }
30
+ /**
31
+ * Returns all ACL privileges that match the following privilege:
32
+ * - resource: acl-privilege, action: read
33
+ *
34
+ * @example fields "id,action,resource"
35
+ * @example filter "action:create"
36
+ * @example limit 42
37
+ */
38
+ async getAclV2Privileges(req, fields, ndjson, filter, limit) {
39
+ return this.sendObjects(Object.values(await this.getObjects({ filter })), req, {
40
+ limit,
41
+ privilege: { action: 'read', resource: 'acl-privilege' },
42
+ });
43
+ }
44
+ /**
45
+ * Required privilege:
46
+ * - resource: acl-privilege, action: create
47
+ *
48
+ * @example privilege {
49
+ * "action": "read",
50
+ * "resource": "alarm",
51
+ * "roleId": "784bd959-08de-4b26-b575-92ded5aef872",
52
+ * "effect": "allow",
53
+ * "selector": "id:784bd959-08de-4b26-b575-92ded5aef872"
54
+ * }
55
+ */
56
+ async createAclV2Privilege(privilege) {
57
+ const newPrivilege = await this.restApi.xoApp.createAclV2Privilege(privilege);
58
+ return { id: newPrivilege.id };
59
+ }
60
+ /**
61
+ * Required privilege:
62
+ * - resource: acl-privilege, action: read
63
+ *
64
+ * @example id "c5d89d1a-df1e-4b72-98a0-c40adfdf49c1"
65
+ */
66
+ getAclV2Privilege(id) {
67
+ return this.getObject(id);
68
+ }
69
+ /**
70
+ * Required privilege:
71
+ * - resource: acl-privilege, action: delete
72
+ *
73
+ * @example id "784bd959-08de-4b26-b575-92ded5aef872"
74
+ */
75
+ async deleteAclV2Privilege(id) {
76
+ await this.restApi.xoApp.deleteAclV2Privilege(id);
77
+ }
78
+ /**
79
+ * Required privileges:
80
+ * - resource: acl-privilege, action: update (grants all fields)
81
+ * - resource: acl-privilege, action: update:action (if action is passed)
82
+ * - resource: acl-privilege, action: update:resource (if resource is passed)
83
+ * - resource: acl-privilege, action: update:effect (if effect is passed)
84
+ * - resource: acl-privilege, action: update:selector (if selector is passed)
85
+ *
86
+ * @example id "784bd959-08de-4b26-b575-92ded5aef872"
87
+ * @example privilege {
88
+ * "action": "read",
89
+ * "resource": "alarm",
90
+ * "effect": "allow",
91
+ * "selector": "id:784bd959-08de-4b26-b575-92ded5aef872"
92
+ * }
93
+ */
94
+ async updateAclV2Privilege(id, privilege) {
95
+ await this.restApi.xoApp.updateAclV2Privilege(id, privilege);
96
+ }
97
+ };
98
+ __decorate([
99
+ Example(aclPrivilegeIds),
100
+ Example(partialAclPrivileges),
101
+ Get(''),
102
+ Security('*', ['acl']),
103
+ __param(0, Request()),
104
+ __param(1, Query()),
105
+ __param(2, Query()),
106
+ __param(3, Query()),
107
+ __param(4, Query())
108
+ ], AclPrivilegeController.prototype, "getAclV2Privileges", null);
109
+ __decorate([
110
+ Example(entityId),
111
+ Post(''),
112
+ Middlewares([json(), acl({ resource: 'acl-privilege', action: 'create', object: ({ req }) => req.body })]),
113
+ SuccessResponse(createdResp.status, createdResp.description),
114
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
115
+ Response(notFoundResp.status, notFoundResp.description),
116
+ Response(invalidParameters.status, invalidParameters.description),
117
+ __param(0, Body())
118
+ ], AclPrivilegeController.prototype, "createAclV2Privilege", null);
119
+ __decorate([
120
+ Example(aclPrivilege),
121
+ Get('{id}'),
122
+ Middlewares(acl({
123
+ resource: 'acl-privilege',
124
+ action: 'read',
125
+ objectId: 'params.id',
126
+ getObject: ({ restApi }) => restApi.xoApp.getAclV2Privilege,
127
+ })),
128
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
129
+ Response(notFoundResp.status, notFoundResp.description),
130
+ __param(0, Path())
131
+ ], AclPrivilegeController.prototype, "getAclV2Privilege", null);
132
+ __decorate([
133
+ Delete('{id}'),
134
+ Middlewares(acl({
135
+ resource: 'acl-privilege',
136
+ action: 'delete',
137
+ objectId: 'params.id',
138
+ getObject: ({ restApi }) => restApi.xoApp.getAclV2Privilege,
139
+ })),
140
+ SuccessResponse(noContentResp.status, noContentResp.description),
141
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
142
+ Response(notFoundResp.status, notFoundResp.description),
143
+ __param(0, Path())
144
+ ], AclPrivilegeController.prototype, "deleteAclV2Privilege", null);
145
+ __decorate([
146
+ Patch('{id}'),
147
+ Middlewares([
148
+ json(),
149
+ acl({
150
+ resource: 'acl-privilege',
151
+ actions: actionsFromBody(['update:action', 'update:resource', 'update:effect', 'update:selector']),
152
+ objectId: 'params.id',
153
+ getObject: ({ restApi }) => restApi.xoApp.getAclV2Privilege,
154
+ }),
155
+ ]),
156
+ SuccessResponse(noContentResp.status, noContentResp.description),
157
+ Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
158
+ Response(notFoundResp.status, notFoundResp.description),
159
+ Response(invalidParameters.status, invalidParameters.description),
160
+ __param(0, Path()),
161
+ __param(1, Body())
162
+ ], AclPrivilegeController.prototype, "updateAclV2Privilege", null);
163
+ AclPrivilegeController = __decorate([
164
+ Route('acl-privileges'),
165
+ Security('*'),
166
+ Response(badRequestResp.status, badRequestResp.description),
167
+ Response(unauthorizedResp.status, unauthorizedResp.description),
168
+ Tags('acls'),
169
+ provide(AclPrivilegeController),
170
+ __param(0, inject(RestApi))
171
+ ], AclPrivilegeController);
172
+ export { AclPrivilegeController };