1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-07-07 01:16:28 +02:00
unleash.unleash/src/lib/middleware/rbac-middleware.ts
Gastón Fournier fa47fee55e
feat: RBAC read params from body (#2846)
## About the changes
This is a follow-up on #1953

This implementation generalizes how we fetch some standard parameters
from the query parameters or request body.

## Discussion points
Unfortunately, we have not used standard names for our APIs and one
example is our `projectId` (in some cases we just used `project`).
Ideally, we're only using one way of sending these parameters either
`projectId` or `project` (same applies to `environment` vs
`environmentId`).

If both parameters are present, due to historical reasons, we'll give
precedence to:
- `projectId` over `project`
- `environment` over `environmentId` 

In the presence of both query parameters and body, we'll give precedence
to query parameters also for historical reasons.
2023-01-11 10:48:27 +01:00

89 lines
2.6 KiB
TypeScript

import {
CREATE_FEATURE,
DELETE_FEATURE,
ADMIN,
UPDATE_FEATURE,
} from '../types/permissions';
import { IUnleashConfig } from '../types/option';
import { IUnleashStores } from '../types/stores';
import User from '../types/user';
interface PermissionChecker {
hasPermission(
user: User,
permission: string,
projectId?: string,
environment?: string,
): Promise<boolean>;
}
function findParam(
name: string,
{ params, body }: any,
defaultValue?: string,
): string | undefined {
let found = params ? params[name] : undefined;
if (found === undefined) {
found = body ? body[name] : undefined;
}
return found || defaultValue;
}
const rbacMiddleware = (
config: Pick<IUnleashConfig, 'getLogger'>,
{ featureToggleStore }: Pick<IUnleashStores, 'featureToggleStore'>,
accessService: PermissionChecker,
): any => {
const logger = config.getLogger('/middleware/rbac-middleware.ts');
logger.debug('Enabling RBAC middleware');
return (req, res, next) => {
req.checkRbac = async (permission: string) => {
const { user, params } = req;
if (!user) {
logger.error('RBAC requires a user to exist on the request.');
return false;
}
if (user.isAPI) {
return user.permissions.includes(ADMIN);
}
if (!user.id) {
logger.error('RBAC requires the user to have a unique id.');
return false;
}
let projectId =
findParam('projectId', req) || findParam('project', req);
let environment =
findParam('environment', req) ||
findParam('environmentId', req);
// Temporary workaround to figure out projectId for feature toggle updates.
// will be removed in Unleash v5.0
if ([DELETE_FEATURE, UPDATE_FEATURE].includes(permission)) {
const { featureName } = params;
projectId = await featureToggleStore.getProjectId(featureName);
} else if (
projectId === undefined &&
(permission == CREATE_FEATURE ||
permission.endsWith('FEATURE_STRATEGY'))
) {
projectId = 'default';
}
return accessService.hasPermission(
user,
permission,
projectId,
environment,
);
};
return next();
};
};
export default rbacMiddleware;