mirror of
https://github.com/Unleash/unleash.git
synced 2025-07-07 01:16:28 +02:00
## 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.
89 lines
2.6 KiB
TypeScript
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;
|