refactor(core): Enforce authorization by default on all routes (no-changelog) (#8762)
This commit is contained in:
committed by
GitHub
parent
2811f77798
commit
db4a419c8d
@@ -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');
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<
|
||||
|
||||
Reference in New Issue
Block a user