Merge pull request #1540 from automatisch/authentication-tests

feat: Add tests for authentication helper
This commit is contained in:
Ömer Faruk Aydın
2024-01-15 16:10:36 +01:00
committed by GitHub
10 changed files with 945 additions and 1027 deletions

View File

@@ -6,31 +6,6 @@ import { createRole } from '../../../test/factories/role';
import { createUser } from '../../../test/factories/user';
describe('graphQL getCurrentUser query', () => {
describe('with unauthenticated user', () => {
it('should throw not authorized error', async () => {
const invalidUserToken = 'invalid-token';
const query = `
query {
getCurrentUser {
id
email
}
}
`;
const response = await request(app)
.post('/graphql')
.set('Authorization', invalidUserToken)
.send({ query })
.expect(200);
expect(response.body.errors).toBeDefined();
expect(response.body.errors[0].message).toEqual('Not Authorised!');
});
});
describe('with authenticated user', () => {
let role, currentUser, token, requestObject;
beforeEach(async () => {
@@ -101,5 +76,4 @@ describe('graphQL getCurrentUser query', () => {
'Cannot query field "password" on type "User".'
);
});
});
});

View File

@@ -40,23 +40,7 @@ describe('graphQL getExecutions query', () => {
}
`;
const invalidToken = 'invalid-token';
describe('with unauthenticated user', () => {
it('should throw not authorized error', async () => {
const response = await request(app)
.post('/graphql')
.set('Authorization', invalidToken)
.send({ query })
.expect(200);
expect(response.body.errors).toBeDefined();
expect(response.body.errors[0].message).toEqual('Not Authorised!');
});
});
describe('with authenticated user', () => {
describe('and without permissions', () => {
describe('and without correct permissions', () => {
it('should throw not authorized error', async () => {
const userWithoutPermissions = await createUser();
const token = createAuthTokenByUserId(userWithoutPermissions.id);
@@ -485,5 +469,4 @@ describe('graphQL getExecutions query', () => {
});
});
});
});
});

View File

@@ -40,23 +40,6 @@ describe('graphQL getFlow query', () => {
`;
};
describe('with unauthenticated user', () => {
it('should throw not authorized error', async () => {
const invalidToken = 'invalid-token';
const flow = await createFlow();
const response = await request(app)
.post('/graphql')
.set('Authorization', invalidToken)
.send({ query: query(flow.id) })
.expect(200);
expect(response.body.errors).toBeDefined();
expect(response.body.errors[0].message).toEqual('Not Authorised!');
});
});
describe('with authenticated user', () => {
describe('and without permissions', () => {
it('should throw not authorized error', async () => {
const userWithoutPermissions = await createUser();
@@ -145,9 +128,7 @@ describe('graphQL getFlow query', () => {
{
appKey: actionStep.appKey,
connection: {
createdAt: actionConnection.createdAt
.getTime()
.toString(),
createdAt: actionConnection.createdAt.getTime().toString(),
id: actionConnection.id,
verified: actionConnection.verified,
},
@@ -234,9 +215,7 @@ describe('graphQL getFlow query', () => {
{
appKey: actionStep.appKey,
connection: {
createdAt: actionConnection.createdAt
.getTime()
.toString(),
createdAt: actionConnection.createdAt.getTime().toString(),
id: actionConnection.id,
verified: actionConnection.verified,
},
@@ -258,5 +237,4 @@ describe('graphQL getFlow query', () => {
});
});
});
});
});

View File

@@ -17,7 +17,6 @@ describe('graphQL getRole query', () => {
userWithoutPermissions,
tokenWithPermissions,
tokenWithoutPermissions,
invalidToken,
permissionOne,
permissionTwo;
@@ -74,24 +73,8 @@ describe('graphQL getRole query', () => {
tokenWithoutPermissions = createAuthTokenByUserId(
userWithoutPermissions.id
);
invalidToken = 'invalid-token';
});
describe('with unauthenticated user', () => {
it('should throw not authorized error', async () => {
const response = await request(app)
.post('/graphql')
.set('Authorization', invalidToken)
.send({ query: queryWithValidRole })
.expect(200);
expect(response.body.errors).toBeDefined();
expect(response.body.errors[0].message).toEqual('Not Authorised!');
});
});
describe('with authenticated user', () => {
describe('and with valid license', () => {
beforeEach(async () => {
vi.spyOn(license, 'hasValidLicense').mockResolvedValue(true);
@@ -178,5 +161,4 @@ describe('graphQL getRole query', () => {
});
});
});
});
});

View File

@@ -15,8 +15,7 @@ describe('graphQL getRoles query', () => {
userWithPermissions,
userWithoutPermissions,
tokenWithPermissions,
tokenWithoutPermissions,
invalidToken;
tokenWithoutPermissions;
beforeEach(async () => {
currentUserRole = await createRole({ name: 'Current user role' });
@@ -53,24 +52,8 @@ describe('graphQL getRoles query', () => {
tokenWithoutPermissions = createAuthTokenByUserId(
userWithoutPermissions.id
);
invalidToken = 'invalid-token';
});
describe('with unauthenticated user', () => {
it('should throw not authorized error', async () => {
const response = await request(app)
.post('/graphql')
.set('Authorization', invalidToken)
.send({ query })
.expect(200);
expect(response.body.errors).toBeDefined();
expect(response.body.errors[0].message).toEqual('Not Authorised!');
});
});
describe('with authenticated user', () => {
describe('and with valid license', () => {
beforeEach(async () => {
vi.spyOn(license, 'hasValidLicense').mockResolvedValue(true);
@@ -148,5 +131,4 @@ describe('graphQL getRoles query', () => {
});
});
});
});
});

View File

@@ -16,22 +16,6 @@ describe('graphQL getTrialStatus query', () => {
}
`;
const invalidToken = 'invalid-token';
describe('with unauthenticated user', () => {
it('should throw not authorized error', async () => {
const response = await request(app)
.post('/graphql')
.set('Authorization', invalidToken)
.send({ query })
.expect(200);
expect(response.body.errors).toBeDefined();
expect(response.body.errors[0].message).toEqual('Not Authorised!');
});
});
describe('with authenticated user', () => {
let user, userToken;
beforeEach(async () => {
@@ -113,5 +97,4 @@ describe('graphQL getTrialStatus query', () => {
});
});
});
});
});

View File

@@ -8,31 +8,6 @@ import { createPermission } from '../../../test/factories/permission';
import { createUser } from '../../../test/factories/user';
describe('graphQL getUser query', () => {
describe('with unauthenticated user', () => {
it('should throw not authorized error', async () => {
const invalidUserId = '123123123';
const query = `
query {
getUser(id: "${invalidUserId}") {
id
email
}
}
`;
const response = await request(app)
.post('/graphql')
.set('Authorization', 'invalid-token')
.send({ query })
.expect(200);
expect(response.body.errors).toBeDefined();
expect(response.body.errors[0].message).toEqual('Not Authorised!');
});
});
describe('with authenticated user', () => {
describe('and without permissions', () => {
it('should throw not authorized error', async () => {
const userWithoutPermissions = await createUser();
@@ -84,9 +59,7 @@ describe('graphQL getUser query', () => {
});
token = createAuthTokenByUserId(currentUser.id);
requestObject = request(app)
.post('/graphql')
.set('Authorization', token);
requestObject = request(app).post('/graphql').set('Authorization', token);
});
it('should return user data for a valid user id', async () => {
@@ -170,5 +143,4 @@ describe('graphQL getUser query', () => {
expect(response.body.errors[0].message).toEqual('NotFoundError');
});
});
});
});

View File

@@ -30,20 +30,6 @@ describe('graphQL getUsers query', () => {
}
`;
describe('with unauthenticated user', () => {
it('should throw not authorized error', async () => {
const response = await request(app)
.post('/graphql')
.set('Authorization', 'invalid-token')
.send({ query })
.expect(200);
expect(response.body.errors).toBeDefined();
expect(response.body.errors[0].message).toEqual('Not Authorised!');
});
});
describe('with authenticated user', () => {
describe('and without permissions', () => {
it('should throw not authorized error', async () => {
const userWithoutPermissions = await createUser();
@@ -86,9 +72,7 @@ describe('graphQL getUsers query', () => {
});
token = createAuthTokenByUserId(currentUser.id);
requestObject = request(app)
.post('/graphql')
.set('Authorization', token);
requestObject = request(app).post('/graphql').set('Authorization', token);
});
it('should return users data', async () => {
@@ -161,5 +145,4 @@ describe('graphQL getUsers query', () => {
);
});
});
});
});

View File

@@ -3,7 +3,7 @@ import jwt from 'jsonwebtoken';
import appConfig from '../config/app.js';
import User from '../models/user.js';
const isAuthenticated = rule()(async (_parent, _args, req) => {
export const isAuthenticated = async (_parent, _args, req) => {
const token = req.headers['authorization'];
if (token == null) return false;
@@ -26,12 +26,13 @@ const isAuthenticated = rule()(async (_parent, _args, req) => {
} catch (error) {
return false;
}
});
};
const authentication = shield(
{
const isAuthenticatedRule = rule()(isAuthenticated);
export const authenticationRules = {
Query: {
'*': isAuthenticated,
'*': isAuthenticatedRule,
getAutomatischInfo: allow,
getConfig: allow,
getNotifications: allow,
@@ -39,16 +40,18 @@ const authentication = shield(
listSamlAuthProviders: allow,
},
Mutation: {
'*': isAuthenticated,
'*': isAuthenticatedRule,
forgotPassword: allow,
login: allow,
registerUser: allow,
resetPassword: allow,
},
},
{
};
const authenticationOptions = {
allowExternalErrors: true,
}
);
};
const authentication = shield(authenticationRules, authenticationOptions);
export default authentication;

View File

@@ -0,0 +1,78 @@
import { describe, it, expect, vi } from 'vitest';
import { allow } from 'graphql-shield';
import jwt from 'jsonwebtoken';
import User from '../models/user.js';
import { isAuthenticated, authenticationRules } from './authentication.js';
vi.mock('jsonwebtoken');
vi.mock('../models/user.js');
describe('isAuthenticated', () => {
it('should return false if no token is provided', async () => {
const req = { headers: {} };
expect(await isAuthenticated(null, null, req)).toBe(false);
});
it('should return false if token is invalid', async () => {
jwt.verify.mockImplementation(() => {
throw new Error('invalid token');
});
const req = { headers: { authorization: 'invalidToken' } };
expect(await isAuthenticated(null, null, req)).toBe(false);
});
it('should return true if token is valid', async () => {
jwt.verify.mockReturnValue({ userId: '123' });
User.query.mockReturnValue({
findById: vi.fn().mockReturnValue({
leftJoinRelated: vi.fn().mockReturnThis(),
withGraphFetched: vi
.fn()
.mockResolvedValue({ id: '123', role: {}, permissions: {} }),
}),
});
const req = { headers: { authorization: 'validToken' } };
expect(await isAuthenticated(null, null, req)).toBe(true);
});
});
describe('authentication rules', () => {
const getQueryAndMutationNames = (rules) => {
const queries = Object.keys(rules.Query || {});
const mutations = Object.keys(rules.Mutation || {});
return { queries, mutations };
};
const { queries, mutations } = getQueryAndMutationNames(authenticationRules);
describe('for queries', () => {
queries.forEach((query) => {
it(`should apply correct rule for query: ${query}`, () => {
const ruleApplied = authenticationRules.Query[query];
if (query === '*') {
expect(ruleApplied.func).toBe(isAuthenticated);
} else {
expect(ruleApplied).toEqual(allow);
}
});
});
});
describe('for mutations', () => {
mutations.forEach((mutation) => {
it(`should apply correct rule for mutation: ${mutation}`, () => {
const ruleApplied = authenticationRules.Mutation[mutation];
if (mutation === '*') {
expect(ruleApplied.func).toBe(isAuthenticated);
} else {
expect(ruleApplied).toBe(allow);
}
});
});
});
});