Skip to content

Commit e50464b

Browse files
feat(rbac): add audit log for RBAC backend (#1726)
* feat(rbac): add audit log for RBAC backend Signed-off-by: Oleksandr Andriienko <[email protected]> * feat(rbac): simplify code Signed-off-by: Oleksandr Andriienko <[email protected]> * feat(rbac): handle code review feeback Signed-off-by: Oleksandr Andriienko <[email protected]> * fix(rbac): remove extra audit log for condition-storage Signed-off-by: Oleksandr Andriienko <[email protected]> * feat(rbac): make audit log for all endpoints Signed-off-by: Oleksandr Andriienko <[email protected]> * feat(rbac): simplify code Signed-off-by: Oleksandr Andriienko <[email protected]> * feat(rbac): clean up code Signed-off-by: Oleksandr Andriienko <[email protected]> * feat(rbac): fix unit tests, clean up code Signed-off-by: Oleksandr Andriienko <[email protected]> * feat(rbac): fix code Signed-off-by: Oleksandr Andriienko <[email protected]> * feat(rbac): improve code Signed-off-by: Oleksandr Andriienko <[email protected]> * feat(rbac): fix tests Signed-off-by: Oleksandr Andriienko <[email protected]> * feat(rbac): fix sonar cloud issue Signed-off-by: Oleksandr Andriienko <[email protected]> * feat(rbac): improve audit log messages Signed-off-by: Oleksandr Andriienko <[email protected]> * feat(rbac): handle more unit tests to check audit log Signed-off-by: Oleksandr Andriienko <[email protected]> * feat(rbac): fix unit tests after rebase Signed-off-by: Oleksandr Andriienko <[email protected]> * feat(rbac): use released version audit-log lib Signed-off-by: Oleksandr Andriienko <[email protected]> * feat(rbac): add small audit log doc Signed-off-by: Oleksandr Andriienko <[email protected]> * Update packages/backend/src/logger/customLogger.ts Co-authored-by: Paul Schultz <[email protected]> * Update packages/backend/src/logger/customLogger.ts Co-authored-by: Paul Schultz <[email protected]> * Update packages/backend/src/logger/customLogger.ts Co-authored-by: Paul Schultz <[email protected]> * Update packages/backend/src/logger/customLogger.ts Co-authored-by: Paul Schultz <[email protected]> * Update packages/backend/src/logger/customLogger.ts Co-authored-by: Paul Schultz <[email protected]> * Update plugins/rbac-backend/src/file-permissions/csv-file-watcher.ts Co-authored-by: Paul Schultz <[email protected]> * Update plugins/rbac-backend/src/service/permission-policy.ts Co-authored-by: Paul Schultz <[email protected]> * Update plugins/rbac-backend/src/service/permission-policy.ts Co-authored-by: Paul Schultz <[email protected]> * Update plugins/rbac-backend/src/service/permission-policy.ts Co-authored-by: Paul Schultz <[email protected]> * Update plugins/rbac-backend/src/service/permission-policy.ts Co-authored-by: Paul Schultz <[email protected]> * Update plugins/rbac-backend/src/service/permission-policy.ts Co-authored-by: Paul Schultz <[email protected]> * Update plugins/rbac-backend/src/file-permissions/csv-file-watcher.ts Co-authored-by: Paul Schultz <[email protected]> * Update plugins/rbac-backend/src/file-permissions/csv-file-watcher.ts Co-authored-by: Paul Schultz <[email protected]> * Update plugins/rbac-backend/src/file-permissions/csv-file-watcher.ts Co-authored-by: Paul Schultz <[email protected]> * Update plugins/rbac-backend/src/file-permissions/csv-file-watcher.ts Co-authored-by: Paul Schultz <[email protected]> * Update plugins/rbac-backend/src/helper.ts Co-authored-by: Paul Schultz <[email protected]> * Update plugins/rbac-backend/src/helper.ts Co-authored-by: Paul Schultz <[email protected]> * Update plugins/rbac-backend/src/service/permission-policy.ts Co-authored-by: Paul Schultz <[email protected]> * Update plugins/rbac-backend/src/service/permission-policy.ts Co-authored-by: Paul Schultz <[email protected]> * Update plugins/rbac-backend/src/service/permission-policy.ts Co-authored-by: Paul Schultz <[email protected]> * Update plugins/rbac-backend/src/service/permission-policy.ts Co-authored-by: Paul Schultz <[email protected]> * Update plugins/rbac-backend/src/service/permission-policy.ts Co-authored-by: Paul Schultz <[email protected]> * Update plugins/rbac-backend/src/service/permission-policy.ts Co-authored-by: Paul Schultz <[email protected]> * Update plugins/rbac-backend/src/service/permission-policy.ts Co-authored-by: Paul Schultz <[email protected]> * Update plugins/rbac-backend/src/service/permission-policy.ts Co-authored-by: Paul Schultz <[email protected]> * Update plugins/rbac-backend/src/service/permission-policy.ts Co-authored-by: Paul Schultz <[email protected]> * Update plugins/rbac-backend/src/service/permission-policy.ts Co-authored-by: Paul Schultz <[email protected]> * Update plugins/rbac-backend/src/service/permission-policy.ts Co-authored-by: Paul Schultz <[email protected]> * Update plugins/rbac-backend/src/service/permission-policy.ts Co-authored-by: Paul Schultz <[email protected]> * Update plugins/rbac-backend/src/service/permission-policy.ts Co-authored-by: Paul Schultz <[email protected]> * Update plugins/rbac-backend/src/service/permission-policy.ts Co-authored-by: Paul Schultz <[email protected]> * Update plugins/rbac-backend/src/service/permission-policy.ts Co-authored-by: Paul Schultz <[email protected]> * Update plugins/rbac-backend/src/service/permission-policy.ts Co-authored-by: Paul Schultz <[email protected]> * Update plugins/rbac-backend/src/service/permission-policy.ts Co-authored-by: Paul Schultz <[email protected]> * Update plugins/rbac-backend/src/service/permission-policy.ts Co-authored-by: Paul Schultz <[email protected]> * Update plugins/rbac-backend/src/service/permission-policy.ts Co-authored-by: Paul Schultz <[email protected]> * Update plugins/rbac-backend/src/service/permission-policy.ts Co-authored-by: Paul Schultz <[email protected]> * feat(rbac): fix grammar for doc Signed-off-by: Oleksandr Andriienko <[email protected]> * fix(rbac): handle code review feeback Signed-off-by: Oleksandr Andriienko <[email protected]> --------- Signed-off-by: Oleksandr Andriienko <[email protected]> Co-authored-by: Paul Schultz <[email protected]>
1 parent 4d72641 commit e50464b

23 files changed

+1846
-315
lines changed

packages/backend/package.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
},
1818
"dependencies": {
1919
"@backstage/backend-defaults": "^0.2.17",
20+
"@backstage/backend-plugin-api": "^0.6.17",
2021
"@backstage/plugin-app-backend": "^0.3.65",
2122
"@backstage/plugin-auth-backend": "^0.22.4",
2223
"@backstage/plugin-auth-backend-module-guest-provider": "^0.1.3",
@@ -28,6 +29,12 @@
2829
"@backstage/plugin-search-backend-module-catalog": "^0.1.23",
2930
"@backstage/plugin-search-backend-module-techdocs": "^0.1.22",
3031
"@backstage/plugin-techdocs-backend": "^1.10.4",
32+
"@manypkg/get-packages": "^1.1.3",
33+
"@backstage/config-loader": "^1.8.0",
34+
"winston": "^3.11.0",
35+
"@backstage/backend-app-api": "^0.7.2",
36+
"@backstage/backend-dynamic-feature-service": "^0.2.9",
37+
"@backstage/cli-node": "^0.2.5",
3138
"@janus-idp/backstage-plugin-rbac-backend": "*",
3239
"app": "*"
3340
},

packages/backend/src/index.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,28 @@
11
import { createBackend } from '@backstage/backend-defaults';
2+
import { dynamicPluginsSchemasServiceFactory } from '@backstage/backend-dynamic-feature-service';
3+
import { PackageRoles } from '@backstage/cli-node';
4+
5+
import * as path from 'path';
6+
7+
import { customLogger } from './logger/customLogger';
28

39
const backend = createBackend();
410

11+
backend.add(
12+
dynamicPluginsSchemasServiceFactory({
13+
schemaLocator(pluginPackage) {
14+
const platform = PackageRoles.getRoleInfo(
15+
pluginPackage.manifest.backstage.role,
16+
).platform;
17+
return path.join(
18+
platform === 'node' ? 'dist' : 'dist-scalprum',
19+
'configSchema.json',
20+
);
21+
},
22+
}),
23+
);
24+
backend.add(customLogger());
25+
526
backend.add(import('@backstage/plugin-app-backend/alpha'));
627
backend.add(import('@backstage/plugin-proxy-backend/alpha'));
728
backend.add(import('@backstage/plugin-scaffolder-backend/alpha'));
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import {
2+
createConfigSecretEnumerator,
3+
WinstonLogger,
4+
} from '@backstage/backend-app-api';
5+
import { DynamicPluginsSchemasService } from '@backstage/backend-dynamic-feature-service';
6+
import {
7+
coreServices,
8+
createServiceFactory,
9+
createServiceRef,
10+
} from '@backstage/backend-plugin-api';
11+
import { loadConfigSchema } from '@backstage/config-loader';
12+
13+
import { getPackages } from '@manypkg/get-packages';
14+
import * as winston from 'winston';
15+
16+
const defaultFormat = winston.format.combine(
17+
winston.format.timestamp({
18+
format: 'YYYY-MM-DD HH:mm:ss',
19+
}),
20+
winston.format.errors({ stack: true }),
21+
winston.format.splat(),
22+
);
23+
24+
const auditLogFormat = winston.format((info, opts) => {
25+
const { isAuditLog, ...newInfo } = info;
26+
27+
if (isAuditLog) {
28+
// keep `isAuditLog` field
29+
return opts.isAuditLog ? info : false;
30+
}
31+
32+
// remove `isAuditLog` field from non audit log events
33+
return !opts.isAuditLog ? newInfo : false;
34+
});
35+
36+
const transports = {
37+
log: [
38+
new winston.transports.Console({
39+
format: winston.format.combine(
40+
auditLogFormat({ isAuditLog: false }),
41+
defaultFormat,
42+
winston.format.json(),
43+
),
44+
}),
45+
],
46+
auditLog: [
47+
new winston.transports.Console({
48+
format: winston.format.combine(
49+
auditLogFormat({ isAuditLog: true }),
50+
defaultFormat,
51+
winston.format.json(),
52+
),
53+
}),
54+
],
55+
};
56+
57+
const dynamicPluginsSchemasServiceRef =
58+
createServiceRef<DynamicPluginsSchemasService>({
59+
id: 'core.dynamicplugins.schemas',
60+
scope: 'root',
61+
});
62+
63+
export const customLogger = createServiceFactory({
64+
service: coreServices.rootLogger,
65+
deps: {
66+
config: coreServices.rootConfig,
67+
schemas: dynamicPluginsSchemasServiceRef,
68+
},
69+
async factory({ config, schemas }) {
70+
const logger = WinstonLogger.create({
71+
meta: {
72+
service: 'backstage',
73+
},
74+
level: process.env.LOG_LEVEL ?? 'info',
75+
format: winston.format.combine(defaultFormat, winston.format.json()),
76+
transports: [...transports.log, ...transports.auditLog],
77+
});
78+
79+
const configSchema = await loadConfigSchema({
80+
dependencies: (await getPackages(process.cwd())).packages.map(
81+
p => p.packageJson.name,
82+
),
83+
});
84+
85+
const secretEnumerator = await createConfigSecretEnumerator({
86+
logger,
87+
schema: (await schemas.addDynamicPluginsSchemas(configSchema)).schema,
88+
});
89+
logger.addRedactions(secretEnumerator(config));
90+
config.subscribe?.(() => logger.addRedactions(secretEnumerator(config)));
91+
92+
return logger;
93+
},
94+
});

packages/backend/src/logger/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './customLogger';
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Audit logging
2+
3+
The RBAC backend plugin supports audit logging with the help of the @janus-idp/backstage-plugin-audit-log-node library. Audit logging helps to track the latest changes and events from the RBAC plugin:
4+
5+
- RBAC role changes;
6+
- RBAC permissions changes;
7+
- RBAC conditions changes;
8+
- Changes causing modification of application configuration;
9+
- Changes causing modification of the permission policy file;
10+
- GET requests for RBAC permission information;
11+
- User authorization results to RBAC resources.
12+
13+
The RBAC backend plugin logging doesn't provide information about the actual state of the permissions. The actual state of RBAC permissions can be found in the RBAC UI. Audit logging provides information about the event name, event message, RBAC permission changes, the actor who made these changes, time, log level, stage, status, some part of the request, response, and so on. You can use this information like a history of the RBAC permission hierarchy.
14+
15+
Notice: RBAC permissions and conditions are bound to RBAC roles. However, the RBAC backend plugin logs information about permissions and conditions with the help of separated log messages. That's because for now, the RBAC plugin has a separated API for RBAC roles, RBAC permissions, and RBAC conditions.
16+
17+
## Audit log actor
18+
19+
The audit log actor can be a real REST API user or the RBAC plugin itself. When the actor is a REST API user, then the RBAC plugin logs the user's IP, browser agent, and hostname. The RBAC plugin can also be the actor of the events. In this case, the actor has a name: "rbac-backend". In this case, the plugin typically applies changes from the configuration or permission policy file. Application configuration and permission policy files usually mount to the application deployment with the help of config maps. Unfortunately, the RBAC plugin cannot track who originally made modifications to these resources. But you can enable Kubernetes API audit log: https://kubernetes.io/docs/tasks/debug/debug-cluster/audit. Then you can match RBAC plugin audit log events to the events from Kubernetes logs by time.
20+
21+
## Audit log format
22+
23+
The RBAC plugin prints information to the backend log in JSON format. The format of these messages is defined in the @janus-idp/backstage-plugin-audit-log-node library. Each audit log line contains the key "isAuditLog".
24+
25+
You can change the log level with the help of the environment variable: LOG_LEVEL.
26+
27+
Example logged RBAC events:
28+
29+
a) RBAC role created with corresponding basic permissions and conditional permission:
30+
31+
```json
32+
backend:start: {"actor":{"actorId":"user:default/andrienkoaleksandr","hostname":"localhost","ip":"::1","userAgent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36"},"eventName":"CreateRole","isAuditLog":true,"level":"info","message":"Created role:default/test","meta":{"author":"user:default/andrienkoaleksandr","createdAt":"Tue, 04 Jun 2024 13:51:45 GMT","description":"some test role","lastModified":"Tue, 04 Jun 2024 13:51:45 GMT","members":["user:default/logarifm","group:default/team-a"],"modifiedBy":"user:default/andrienkoaleksandr","roleEntityRef":"role:default/test","source":"rest"},"plugin":"permission","request":{"body":{"memberReferences":["user:default/logarifm","group:default/team-a"],"metadata":{"description":"some test role"},"name":"role:default/test"},"method":"POST","params":{},"query":{},"url":"/api/permission/roles"},"response":{"status":201},"service":"backstage","stage":"sendResponse","status":"succeeded","timestamp":"2024-06-04 16:51:45"}
33+
34+
backend:start: {"actor":{"actorId":"user:default/andrienkoaleksandr","hostname":"localhost","ip":"::1","userAgent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36"},"eventName":"CreatePolicy","isAuditLog":true,"level":"info","message":"Created permission policies","meta":{"policies":[["role:default/test","scaffolder-template","read","allow"]],"source":"rest"},"plugin":"permission","request":{"body":[{"effect":"allow","entityReference":"role:default/test","permission":"scaffolder-template","policy":"read"}],"method":"POST","params":{},"query":{},"url":"/api/permission/policies"},"response":{"status":201},"service":"backstage","stage":"sendResponse","status":"succeeded","timestamp":"2024-06-04 16:51:45"}
35+
36+
backend:start: {"actor":{"actorId":"user:default/andrienkoaleksandr","hostname":"localhost","ip":"::1","userAgent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36"},"eventName":"CreateCondition","isAuditLog":true,"level":"info","message":"Created conditional permission policy","meta":{"condition":{"conditions":{"params":{"claims":["group:default/team-a"]},"resourceType":"catalog-entity","rule":"IS_ENTITY_OWNER"},"permissionMapping":[{"action":"read","name":"catalog.entity.read"},{"action":"delete","name":"catalog.entity.delete"},{"action":"update","name":"catalog.entity.refresh"}],"pluginId":"catalog","resourceType":"catalog-entity","result":"CONDITIONAL","roleEntityRef":"role:default/test"}},"plugin":"permission","request":{"body":{"conditions":{"params":{"claims":["group:default/team-a"]},"resourceType":"catalog-entity","rule":"IS_ENTITY_OWNER"},"permissionMapping":["read","delete","update"],"pluginId":"catalog","resourceType":"catalog-entity","result":"CONDITIONAL","roleEntityRef":"role:default/test"},"method":"POST","params":{},"query":{},"url":"/api/permission/roles/conditions"},"response":{"body":{"id":9},"status":201},"service":"backstage","stage":"sendResponse","status":"succeeded","timestamp":"2024-06-04 16:51:45"}
37+
```
38+
39+
b) Check access user to application resource:
40+
41+
```json
42+
backend:start: {"actor":{"actorId":"user:default/andrienkoaleksandr"},"eventName":"PermissionEvaluationStarted","isAuditLog":true,"level":"info","message":"Policy check for user:default/andrienkoaleksandr","meta":{"action":"create","permissionName":"policy.entity.create","resourceType":"policy-entity","userEntityRef":"user:default/andrienkoaleksandr"},"plugin":"permission","service":"backstage","stage":"evaluatePermissionAccess","status":"succeeded","timestamp":"2024-06-04 16:51:45"}
43+
44+
backend:start: {"actor":{"actorId":"user:default/andrienkoaleksandr"},"eventName":"PermissionEvaluationCompleted","isAuditLog":true,"level":"info","message":"user:default/andrienkoaleksandr is ALLOW for permission 'policy.entity.create', resource type 'policy-entity' and action 'create'","meta":{"action":"create","decision":{"result":"ALLOW"},"permissionName":"policy.entity.create","resourceType":"policy-entity","userEntityRef":"user:default/andrienkoaleksandr"},"plugin":"permission","service":"backstage","stage":"evaluatePermissionAccess","status":"succeeded","timestamp":"2024-06-04 16:51:45"}
45+
```
46+
47+
Most audit log lines contain a metadata object. The RBAC plugin includes information about RBAC roles, permissions, conditions, and authorization results in this metadata. Metadata types can be found in the RBAC plugin file audit-log/audit-logger.ts.
48+
49+
Notice: You need to properly configure the logger to see nested JSON objects in the audit log lines.

plugins/rbac-backend/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
"@dagrejs/graphlib": "^2.1.13",
3939
"@janus-idp/backstage-plugin-rbac-common": "1.4.2",
4040
"@janus-idp/backstage-plugin-rbac-node": "1.1.1",
41+
"@janus-idp/backstage-plugin-audit-log-node": "1.0.2",
4142
"casbin": "^5.27.1",
4243
"chokidar": "^3.6.0",
4344
"csv-parse": "^5.5.5",
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
import {
2+
AuthorizeResult,
3+
PolicyDecision,
4+
ResourcePermission,
5+
} from '@backstage/plugin-permission-common';
6+
import { PolicyQuery } from '@backstage/plugin-permission-node';
7+
8+
import { AuditLogOptions } from '@janus-idp/backstage-plugin-audit-log-node';
9+
import {
10+
PermissionAction,
11+
PermissionInfo,
12+
RoleConditionalPolicyDecision,
13+
Source,
14+
toPermissionAction,
15+
} from '@janus-idp/backstage-plugin-rbac-common';
16+
17+
export const RoleEvents = {
18+
CREATE_ROLE: 'CreateRole',
19+
UPDATE_ROLE: 'UpdateRole',
20+
DELETE_ROLE: 'DeleteRole',
21+
CREATE_OR_UPDATE_ROLE: 'CreateOrUpdateRole',
22+
GET_ROLE: 'GetRole',
23+
24+
CREATE_ROLE_ERROR: 'CreateRoleError',
25+
UPDATE_ROLE_ERROR: 'UpdateRoleError',
26+
DELETE_ROLE_ERROR: 'DeleteRoleError',
27+
GET_ROLE_ERROR: 'GetRoleError',
28+
} as const;
29+
30+
export const PermissionEvents = {
31+
CREATE_POLICY: 'CreatePolicy',
32+
CREATE_OR_UPDATE_POLICY: 'CreateOrUpdatePolicy',
33+
UPDATE_POLICY: 'UpdatePolicy',
34+
DELETE_POLICY: 'DeletePolicy',
35+
GET_POLICY: 'GetPolicy',
36+
37+
CREATE_POLICY_ERROR: 'CreatePolicyError',
38+
UPDATE_POLICY_ERROR: 'UpdatePolicyError',
39+
DELETE_POLICY_ERROR: 'DeletePolicyError',
40+
GET_POLICY_ERROR: 'GetPolicyError',
41+
} as const;
42+
43+
export type RoleAuditInfo = {
44+
roleEntityRef: string;
45+
description?: string;
46+
source: Source;
47+
48+
members: string[];
49+
};
50+
51+
export type PermissionAuditInfo = {
52+
policies: string[][];
53+
source: Source;
54+
};
55+
56+
export const EvaluationEvents = {
57+
PERMISSION_EVALUATION_STARTED: 'PermissionEvaluationStarted',
58+
PERMISSION_EVALUATION_COMPLETED: 'PermissionEvaluationCompleted',
59+
CONDITION_EVALUATION_COMPLETED: 'ConditionEvaluationCompleted',
60+
PERMISSION_EVALUATION_FAILED: 'PermissionEvaluationFailed',
61+
} as const;
62+
63+
export const ListPluginPoliciesEvents = {
64+
GET_PLUGINS_POLICIES: 'GetPluginsPolicies',
65+
GET_PLUGINS_POLICIES_ERROR: 'GetPluginsPoliciesError',
66+
};
67+
68+
export const ListConditionEvents = {
69+
GET_CONDITION_RULES: 'GetConditionRules',
70+
GET_CONDITION_RULES_ERROR: 'GetConditionRulesError',
71+
};
72+
73+
export type EvaluationAuditInfo = {
74+
userEntityRef: string;
75+
permissionName: string;
76+
action: PermissionAction;
77+
resourceType?: string;
78+
decision?: PolicyDecision;
79+
};
80+
81+
export const ConditionEvents = {
82+
CREATE_CONDITION: 'CreateCondition',
83+
UPDATE_CONDITION: 'UpdateCondition',
84+
DELETE_CONDITION: 'DeleteCondition',
85+
GET_CONDITION: 'GetCondition',
86+
87+
CREATE_CONDITION_ERROR: 'CreateConditionError',
88+
UPDATE_CONDITION_ERROR: 'UpdateConditionError',
89+
DELETE_CONDITION_ERROR: 'DeleteConditionError',
90+
GET_CONDITION_ERROR: 'GetConditionError',
91+
};
92+
93+
export type ConditionAuditInfo = {
94+
condition: RoleConditionalPolicyDecision<PermissionInfo>;
95+
};
96+
97+
export const RBAC_BACKEND = 'rbac-backend';
98+
99+
// Audit log stage for processing Role-Based Access Control (RBAC) data
100+
export const HANDLE_RBAC_DATA_STAGE = 'handleRBACData';
101+
102+
// Audit log stage for determining access rights based on user permissions and resource information
103+
export const EVALUATE_PERMISSION_ACCESS_STAGE = 'evaluatePermissionAccess';
104+
105+
// Audit log stage for sending the response to the client about handled permission policies, roles, and condition policies
106+
export const SEND_RESPONSE_STAGE = 'sendResponse';
107+
export const RESPONSE_ERROR = 'responseError';
108+
109+
export function createPermissionEvaluationOptions(
110+
message: string,
111+
userEntityRef: string,
112+
request: PolicyQuery,
113+
policyDecision?: PolicyDecision,
114+
): AuditLogOptions {
115+
const auditInfo: EvaluationAuditInfo = {
116+
userEntityRef,
117+
permissionName: request.permission.name,
118+
action: toPermissionAction(request.permission.attributes),
119+
};
120+
121+
const resourceType = (request.permission as ResourcePermission).resourceType;
122+
if (resourceType) {
123+
auditInfo.resourceType = resourceType;
124+
}
125+
126+
let eventName;
127+
if (!policyDecision) {
128+
eventName = EvaluationEvents.PERMISSION_EVALUATION_STARTED;
129+
} else {
130+
auditInfo.decision = policyDecision;
131+
132+
switch (policyDecision.result) {
133+
case AuthorizeResult.DENY:
134+
case AuthorizeResult.ALLOW:
135+
eventName = EvaluationEvents.PERMISSION_EVALUATION_COMPLETED;
136+
break;
137+
case AuthorizeResult.CONDITIONAL:
138+
eventName = EvaluationEvents.CONDITION_EVALUATION_COMPLETED;
139+
break;
140+
default:
141+
throw new Error('Unknown policy decision result');
142+
}
143+
}
144+
145+
return {
146+
actorId: userEntityRef,
147+
message,
148+
eventName,
149+
metadata: auditInfo,
150+
stage: EVALUATE_PERMISSION_ACCESS_STAGE,
151+
status: 'succeeded',
152+
};
153+
}

0 commit comments

Comments
 (0)