refactor(core): Enforce authorization by default on all routes (no-changelog) (#8762)

This commit is contained in:
कारतोफ्फेलस्क्रिप्ट™
2024-02-28 17:02:18 +01:00
committed by GitHub
parent 2811f77798
commit db4a419c8d
46 changed files with 126 additions and 299 deletions

View File

@@ -1,15 +0,0 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { CONTROLLER_AUTH_ROLES } from './constants';
import type { AuthRoleMetadata } from './types';
export function Authorized(authRole: AuthRoleMetadata[string] = 'any'): Function {
return function (target: Function | object, handlerName?: string) {
const controllerClass = handlerName ? target.constructor : target;
const authRoles = (Reflect.getMetadata(CONTROLLER_AUTH_ROLES, controllerClass) ??
{}) as AuthRoleMetadata;
authRoles[handlerName ?? '*'] = authRole;
Reflect.defineMetadata(CONTROLLER_AUTH_ROLES, authRoles, controllerClass);
};
}
export const NoAuthRequired = () => Authorized('none');

View File

@@ -5,6 +5,8 @@ import type { Method, RouteMetadata } from './types';
interface RouteOptions {
middlewares?: RequestHandler[];
usesTemplates?: boolean;
/** When this flag is set to true, auth cookie isn't validated, and req.user will not be set */
skipAuth?: boolean;
}
const RouteFactory =
@@ -20,6 +22,7 @@ const RouteFactory =
middlewares: options.middlewares ?? [],
handlerName: String(handlerName),
usesTemplates: options.usesTemplates ?? false,
skipAuth: options.skipAuth ?? false,
});
Reflect.defineMetadata(CONTROLLER_ROUTES, routes, controllerClass);
};

View File

@@ -1,6 +1,5 @@
export const CONTROLLER_ROUTES = 'CONTROLLER_ROUTES';
export const CONTROLLER_BASE_PATH = 'CONTROLLER_BASE_PATH';
export const CONTROLLER_MIDDLEWARES = 'CONTROLLER_MIDDLEWARES';
export const CONTROLLER_AUTH_ROLES = 'CONTROLLER_AUTH_ROLES';
export const CONTROLLER_LICENSE_FEATURES = 'CONTROLLER_LICENSE_FEATURES';
export const CONTROLLER_REQUIRED_SCOPES = 'CONTROLLER_REQUIRED_SCOPES';

View File

@@ -1,4 +1,3 @@
export { Authorized, NoAuthRequired } from './Authorized';
export { RestController } from './RestController';
export { Get, Post, Put, Patch, Delete } from './Route';
export { Middleware } from './Middleware';

View File

@@ -12,7 +12,6 @@ import { License } from '@/License';
import type { AuthenticatedRequest } from '@/requests';
import { send } from '@/ResponseHelper'; // TODO: move `ResponseHelper.send` to this file
import {
CONTROLLER_AUTH_ROLES,
CONTROLLER_BASE_PATH,
CONTROLLER_LICENSE_FEATURES,
CONTROLLER_MIDDLEWARES,
@@ -20,7 +19,6 @@ import {
CONTROLLER_ROUTES,
} from './constants';
import type {
AuthRoleMetadata,
Controller,
LicenseMetadata,
MiddlewareMetadata,
@@ -74,9 +72,6 @@ export const registerController = (app: Application, controllerClass: Class<obje
extra: { controllerName: controllerClass.name },
});
const authRoles = Reflect.getMetadata(CONTROLLER_AUTH_ROLES, controllerClass) as
| AuthRoleMetadata
| undefined;
const routes = Reflect.getMetadata(CONTROLLER_ROUTES, controllerClass) as RouteMetadata[];
const licenseFeatures = Reflect.getMetadata(CONTROLLER_LICENSE_FEATURES, controllerClass) as
| LicenseMetadata
@@ -99,15 +94,15 @@ export const registerController = (app: Application, controllerClass: Class<obje
const authService = Container.get(AuthService);
routes.forEach(
({ method, path, middlewares: routeMiddlewares, handlerName, usesTemplates }) => {
const authRole = authRoles?.[handlerName] ?? authRoles?.['*'];
({ method, path, middlewares: routeMiddlewares, handlerName, usesTemplates, skipAuth }) => {
const features = licenseFeatures?.[handlerName] ?? licenseFeatures?.['*'];
const scopes = requiredScopes?.[handlerName] ?? requiredScopes?.['*'];
const handler = async (req: Request, res: Response) =>
await controller[handlerName](req, res);
router[method](
path,
...(authRole ? [authService.createAuthMiddleware(authRole)] : []),
// eslint-disable-next-line @typescript-eslint/unbound-method
...(skipAuth ? [] : [authService.authMiddleware]),
...(features ? [createLicenseMiddleware(features)] : []),
...(scopes ? [createGlobalScopeMiddleware(scopes)] : []),
...controllerMiddlewares,

View File

@@ -1,13 +1,9 @@
import type { Request, Response, RequestHandler } from 'express';
import type { GlobalRole } from '@db/entities/User';
import type { BooleanLicenseFeature } from '@/Interfaces';
import type { Scope } from '@n8n/permissions';
export type Method = 'get' | 'post' | 'put' | 'patch' | 'delete';
export type AuthRole = GlobalRole | 'any' | 'none';
export type AuthRoleMetadata = Record<string, AuthRole>;
export type LicenseMetadata = Record<string, BooleanLicenseFeature[]>;
export type ScopeMetadata = Record<string, Scope[]>;
@@ -22,6 +18,7 @@ export interface RouteMetadata {
handlerName: string;
middlewares: RequestHandler[];
usesTemplates: boolean;
skipAuth: boolean;
}
export type Controller = Record<