refactor(core): Setup decorator based RBAC (no-changelog) (#5787)
This commit is contained in:
committed by
GitHub
parent
feb2ba09b9
commit
1eeadc6114
@@ -10,13 +10,7 @@ import type { AuthenticatedRequest } from '@/requests';
|
||||
import config from '@/config';
|
||||
import { AUTH_COOKIE_NAME, EDITOR_UI_DIST_DIR } from '@/constants';
|
||||
import { issueCookie, resolveJwtContent } from '@/auth/jwt';
|
||||
import {
|
||||
isAuthenticatedRequest,
|
||||
isAuthExcluded,
|
||||
isPostUsersId,
|
||||
isUserManagementEnabled,
|
||||
} from '@/UserManagement/UserManagementHelper';
|
||||
import { SamlUrls } from '@/sso/saml/constants';
|
||||
import { isUserManagementEnabled } from '@/UserManagement/UserManagementHelper';
|
||||
import type { UserRepository } from '@db/repositories';
|
||||
|
||||
const jwtFromRequest = (req: Request) => {
|
||||
@@ -66,6 +60,17 @@ const staticAssets = globSync(['**/*.html', '**/*.svg', '**/*.png', '**/*.ico'],
|
||||
cwd: EDITOR_UI_DIST_DIR,
|
||||
});
|
||||
|
||||
// TODO: delete this
|
||||
const isPostUsersId = (req: Request, restEndpoint: string): boolean =>
|
||||
req.method === 'POST' &&
|
||||
new RegExp(`/${restEndpoint}/users/[\\w\\d-]*`).test(req.url) &&
|
||||
!req.url.includes('reinvite');
|
||||
|
||||
const isAuthExcluded = (url: string, ignoredEndpoints: Readonly<string[]>): boolean =>
|
||||
!!ignoredEndpoints
|
||||
.filter(Boolean) // skip empty paths
|
||||
.find((ignoredEndpoint) => url.startsWith(`/${ignoredEndpoint}`));
|
||||
|
||||
/**
|
||||
* This sets up the auth middlewares in the correct order
|
||||
*/
|
||||
@@ -85,20 +90,16 @@ export const setupAuthMiddlewares = (
|
||||
// skip authentication for preflight requests
|
||||
req.method === 'OPTIONS' ||
|
||||
staticAssets.includes(req.url.slice(1)) ||
|
||||
isAuthExcluded(req.url, ignoredEndpoints) ||
|
||||
req.url.startsWith(`/${restEndpoint}/settings`) ||
|
||||
req.url.startsWith(`/${restEndpoint}/login`) ||
|
||||
req.url.startsWith(`/${restEndpoint}/logout`) ||
|
||||
req.url.startsWith(`/${restEndpoint}/resolve-signup-token`) ||
|
||||
isPostUsersId(req, restEndpoint) ||
|
||||
req.url.startsWith(`/${restEndpoint}/forgot-password`) ||
|
||||
req.url.startsWith(`/${restEndpoint}/resolve-password-token`) ||
|
||||
req.url.startsWith(`/${restEndpoint}/change-password`) ||
|
||||
req.url.startsWith(`/${restEndpoint}/oauth2-credential/callback`) ||
|
||||
req.url.startsWith(`/${restEndpoint}/oauth1-credential/callback`) ||
|
||||
req.url.startsWith(`/${restEndpoint}/sso/saml${SamlUrls.metadata}`) ||
|
||||
req.url.startsWith(`/${restEndpoint}/sso/saml${SamlUrls.initSSO}`) ||
|
||||
req.url.startsWith(`/${restEndpoint}/sso/saml${SamlUrls.acs}`) ||
|
||||
isAuthExcluded(req.url, ignoredEndpoints)
|
||||
req.url.startsWith(`/${restEndpoint}/oauth1-credential/callback`)
|
||||
) {
|
||||
return next();
|
||||
}
|
||||
@@ -115,43 +116,5 @@ export const setupAuthMiddlewares = (
|
||||
return passportMiddleware(req, res, next);
|
||||
});
|
||||
|
||||
app.use((req: Request | AuthenticatedRequest, res: Response, next: NextFunction) => {
|
||||
// req.user is empty for public routes, so just proceed
|
||||
// owner can do anything, so proceed as well
|
||||
if (!req.user || (isAuthenticatedRequest(req) && req.user.globalRole.name === 'owner')) {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
// Not owner and user exists. We now protect restricted urls.
|
||||
const postRestrictedUrls = [
|
||||
`/${restEndpoint}/users`,
|
||||
`/${restEndpoint}/owner`,
|
||||
`/${restEndpoint}/ldap/sync`,
|
||||
`/${restEndpoint}/ldap/test-connection`,
|
||||
];
|
||||
const getRestrictedUrls = [`/${restEndpoint}/ldap/sync`, `/${restEndpoint}/ldap/config`];
|
||||
const putRestrictedUrls = [`/${restEndpoint}/ldap/config`];
|
||||
const trimmedUrl = req.url.endsWith('/') ? req.url.slice(0, -1) : req.url;
|
||||
if (
|
||||
(req.method === 'POST' && postRestrictedUrls.includes(trimmedUrl)) ||
|
||||
(req.method === 'GET' && getRestrictedUrls.includes(trimmedUrl)) ||
|
||||
(req.method === 'PUT' && putRestrictedUrls.includes(trimmedUrl)) ||
|
||||
(req.method === 'DELETE' &&
|
||||
new RegExp(`/${restEndpoint}/users/[^/]+`, 'gm').test(trimmedUrl)) ||
|
||||
(req.method === 'POST' &&
|
||||
new RegExp(`/${restEndpoint}/users/[^/]+/reinvite`, 'gm').test(trimmedUrl)) ||
|
||||
new RegExp(`/${restEndpoint}/owner/[^/]+`, 'gm').test(trimmedUrl)
|
||||
) {
|
||||
Logger.verbose('User attempted to access endpoint without authorization', {
|
||||
endpoint: `${req.method} ${trimmedUrl}`,
|
||||
userId: isAuthenticatedRequest(req) ? req.user.id : 'unknown',
|
||||
});
|
||||
res.status(403).json({ status: 'error', message: 'Unauthorized' });
|
||||
return;
|
||||
}
|
||||
|
||||
next();
|
||||
});
|
||||
|
||||
app.use(refreshExpiringCookie);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user