mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-18 02:21:13 +00:00
refactor(core): Enforce authorization by default on all routes (no-changelog) (#8762)
This commit is contained in:
committed by
GitHub
parent
2811f77798
commit
db4a419c8d
@@ -17,14 +17,12 @@ describe('Auth Middleware', () => {
|
||||
['PATCH', '/me'],
|
||||
['PATCH', '/me/password'],
|
||||
['POST', '/me/survey'],
|
||||
['POST', '/owner/setup'],
|
||||
];
|
||||
|
||||
/** Routes requiring a valid `n8n-auth` cookie for an owner. */
|
||||
const ROUTES_REQUIRING_AUTHORIZATION: Readonly<Array<[string, string]>> = [
|
||||
['POST', '/invitations'],
|
||||
['DELETE', '/users/123'],
|
||||
['POST', '/owner/setup'],
|
||||
];
|
||||
|
||||
describe('Routes requiring Authentication', () => {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import validator from 'validator';
|
||||
import type { SuperAgentTest } from 'supertest';
|
||||
|
||||
import config from '@/config';
|
||||
import type { User } from '@db/entities/User';
|
||||
@@ -18,11 +17,9 @@ import Container from 'typedi';
|
||||
const testServer = utils.setupTestServer({ endpointGroups: ['owner'] });
|
||||
|
||||
let ownerShell: User;
|
||||
let authOwnerShellAgent: SuperAgentTest;
|
||||
|
||||
beforeEach(async () => {
|
||||
ownerShell = await createUserShell('global:owner');
|
||||
authOwnerShellAgent = testServer.authAgentFor(ownerShell);
|
||||
config.set('userManagement.isInstanceOwnerSetUp', false);
|
||||
});
|
||||
|
||||
@@ -39,7 +36,7 @@ describe('POST /owner/setup', () => {
|
||||
password: randomValidPassword(),
|
||||
};
|
||||
|
||||
const response = await authOwnerShellAgent.post('/owner/setup').send(newOwnerData);
|
||||
const response = await testServer.authlessAgent.post('/owner/setup').send(newOwnerData);
|
||||
|
||||
expect(response.statusCode).toBe(200);
|
||||
|
||||
@@ -88,7 +85,7 @@ describe('POST /owner/setup', () => {
|
||||
password: randomValidPassword(),
|
||||
};
|
||||
|
||||
const response = await authOwnerShellAgent.post('/owner/setup').send(newOwnerData);
|
||||
const response = await testServer.authlessAgent.post('/owner/setup').send(newOwnerData);
|
||||
|
||||
expect(response.statusCode).toBe(200);
|
||||
|
||||
@@ -150,7 +147,7 @@ describe('POST /owner/setup', () => {
|
||||
|
||||
test('should fail with invalid inputs', async () => {
|
||||
for (const invalidPayload of INVALID_POST_OWNER_PAYLOADS) {
|
||||
const response = await authOwnerShellAgent.post('/owner/setup').send(invalidPayload);
|
||||
const response = await testServer.authlessAgent.post('/owner/setup').send(invalidPayload);
|
||||
expect(response.statusCode).toBe(400);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -39,7 +39,7 @@ describe('AuthService', () => {
|
||||
config.set('userManagement.jwtRefreshTimeoutHours', 0);
|
||||
});
|
||||
|
||||
describe('createAuthMiddleware', () => {
|
||||
describe('authMiddleware', () => {
|
||||
const req = mock<AuthenticatedRequest>({ cookies: {}, user: undefined });
|
||||
const res = mock<Response>();
|
||||
const next = jest.fn() as NextFunction;
|
||||
@@ -48,64 +48,34 @@ describe('AuthService', () => {
|
||||
res.status.mockReturnThis();
|
||||
});
|
||||
|
||||
describe('authRole = none', () => {
|
||||
const authMiddleware = authService.createAuthMiddleware('none');
|
||||
|
||||
it('should just skips auth checks', async () => {
|
||||
await authMiddleware(req, res, next);
|
||||
expect(next).toHaveBeenCalled();
|
||||
expect(res.status).not.toHaveBeenCalled();
|
||||
});
|
||||
it('should 401 if no cookie is set', async () => {
|
||||
req.cookies[AUTH_COOKIE_NAME] = undefined;
|
||||
await authService.authMiddleware(req, res, next);
|
||||
expect(next).not.toHaveBeenCalled();
|
||||
expect(res.status).toHaveBeenCalledWith(401);
|
||||
});
|
||||
|
||||
describe('authRole = any', () => {
|
||||
const authMiddleware = authService.createAuthMiddleware('any');
|
||||
it('should 401 and clear the cookie if the JWT is expired', async () => {
|
||||
req.cookies[AUTH_COOKIE_NAME] = validToken;
|
||||
jest.advanceTimersByTime(365 * Time.days.toMilliseconds);
|
||||
|
||||
it('should 401 if no cookie is set', async () => {
|
||||
req.cookies[AUTH_COOKIE_NAME] = undefined;
|
||||
await authMiddleware(req, res, next);
|
||||
expect(next).not.toHaveBeenCalled();
|
||||
expect(res.status).toHaveBeenCalledWith(401);
|
||||
});
|
||||
|
||||
it('should 401 and clear the cookie if the JWT is expired', async () => {
|
||||
req.cookies[AUTH_COOKIE_NAME] = validToken;
|
||||
jest.advanceTimersByTime(365 * Time.days.toMilliseconds);
|
||||
|
||||
await authMiddleware(req, res, next);
|
||||
expect(next).not.toHaveBeenCalled();
|
||||
expect(res.status).toHaveBeenCalledWith(401);
|
||||
expect(res.clearCookie).toHaveBeenCalledWith(AUTH_COOKIE_NAME);
|
||||
});
|
||||
|
||||
it('should refresh the cookie before it expires', async () => {
|
||||
req.cookies[AUTH_COOKIE_NAME] = validToken;
|
||||
jest.advanceTimersByTime(6 * Time.days.toMilliseconds);
|
||||
userRepository.findOne.mockResolvedValue(user);
|
||||
|
||||
await authMiddleware(req, res, next);
|
||||
expect(next).toHaveBeenCalled();
|
||||
expect(res.cookie).toHaveBeenCalledWith('n8n-auth', expect.any(String), {
|
||||
httpOnly: true,
|
||||
maxAge: 604800000,
|
||||
sameSite: 'lax',
|
||||
});
|
||||
});
|
||||
await authService.authMiddleware(req, res, next);
|
||||
expect(next).not.toHaveBeenCalled();
|
||||
expect(res.status).toHaveBeenCalledWith(401);
|
||||
expect(res.clearCookie).toHaveBeenCalledWith(AUTH_COOKIE_NAME);
|
||||
});
|
||||
|
||||
describe('authRole = global:owner', () => {
|
||||
const authMiddleware = authService.createAuthMiddleware('global:owner');
|
||||
it('should refresh the cookie before it expires', async () => {
|
||||
req.cookies[AUTH_COOKIE_NAME] = validToken;
|
||||
jest.advanceTimersByTime(6 * Time.days.toMilliseconds);
|
||||
userRepository.findOne.mockResolvedValue(user);
|
||||
|
||||
it('should 403 if the user does not have the correct role', async () => {
|
||||
req.cookies[AUTH_COOKIE_NAME] = validToken;
|
||||
jest.advanceTimersByTime(6 * Time.days.toMilliseconds);
|
||||
userRepository.findOne.mockResolvedValue(
|
||||
mock<User>({ ...userData, role: 'global:member' }),
|
||||
);
|
||||
|
||||
await authMiddleware(req, res, next);
|
||||
expect(next).not.toHaveBeenCalled();
|
||||
expect(res.status).toHaveBeenCalledWith(403);
|
||||
await authService.authMiddleware(req, res, next);
|
||||
expect(next).toHaveBeenCalled();
|
||||
expect(res.cookie).toHaveBeenCalledWith('n8n-auth', expect.any(String), {
|
||||
httpOnly: true,
|
||||
maxAge: 604800000,
|
||||
sameSite: 'lax',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -93,11 +93,15 @@ describe('OwnerController', () => {
|
||||
});
|
||||
const res = mock<Response>();
|
||||
configGetSpy.mockReturnValue(false);
|
||||
userRepository.findOneOrFail.calledWith(anyObject()).mockResolvedValue(user);
|
||||
userRepository.save.calledWith(anyObject()).mockResolvedValue(user);
|
||||
jest.spyOn(jwt, 'sign').mockImplementation(() => 'signed-token');
|
||||
|
||||
await controller.setupOwner(req, res);
|
||||
|
||||
expect(userRepository.findOneOrFail).toHaveBeenCalledWith({
|
||||
where: { role: 'global:owner' },
|
||||
});
|
||||
expect(userRepository.save).toHaveBeenCalledWith(user, { transaction: false });
|
||||
expect(authService.issueCookie).toHaveBeenCalledWith(res, user);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user