unleash-server
Version:
Unleash is an enterprise ready feature flag service. It provides different strategies for handling feature flags.
265 lines • 12.1 kB
JavaScript
import { setupAppWithAuth, } from '../../helpers/test-helper.js';
import dbInit from '../../helpers/database-init.js';
import getLogger from '../../../fixtures/no-logger.js';
import { ApiTokenType } from '../../../../lib/types/model.js';
import { RoleName } from '../../../../lib/types/model.js';
import { CREATE_CLIENT_API_TOKEN, CREATE_PROJECT_API_TOKEN, DELETE_CLIENT_API_TOKEN, READ_CLIENT_API_TOKEN, READ_FRONTEND_API_TOKEN, SYSTEM_USER_AUDIT, SYSTEM_USER_ID, UPDATE_CLIENT_API_TOKEN, } from '../../../../lib/types/index.js';
import { addDays } from 'date-fns';
let stores;
let db;
let app;
let adminToken;
let frontendToken;
let clientToken;
let _backendToken;
const setupUser = async (email, roleName, permissions) => {
const { accessService, userService } = app.services;
const role = (await accessService.getPredefinedRole(roleName));
const user = await userService.createUser({
email,
rootRole: role.id,
}, SYSTEM_USER_AUDIT);
if (permissions) {
const createClientApiTokenRole = await accessService.createRole({
name: `project_client_${email}`,
description: `${email} role`,
permissions,
type: 'root-custom',
createdByUserId: SYSTEM_USER_ID,
}, SYSTEM_USER_AUDIT);
await accessService.addUserToRole(user.id, createClientApiTokenRole.id, 'default');
}
};
beforeAll(async () => {
db = await dbInit('token_api_auth_serial', getLogger);
stores = db.stores;
app = await setupAppWithAuth(stores, {}, db.rawDatabase);
// insert initial tokens
clientToken = await stores.apiTokenStore.insert({
environment: '',
projects: [],
tokenName: 'client',
secret: '*:environment.client_secret',
type: ApiTokenType.CLIENT,
});
_backendToken = await stores.apiTokenStore.insert({
environment: '',
projects: [],
tokenName: 'backend',
secret: '*:environment.backend_secret',
type: ApiTokenType.BACKEND,
});
adminToken = await stores.apiTokenStore.insert({
environment: '',
projects: [],
tokenName: 'admin',
secret: '*:*.sdfsdf2admin_secret',
type: ApiTokenType.ADMIN,
});
frontendToken = await stores.apiTokenStore.insert({
environment: '',
projects: [],
tokenName: 'frontender',
secret: '*:environment:sdfsdf2dfrontend_Secret',
type: ApiTokenType.FRONTEND,
});
});
afterAll(async () => {
if (db) {
await db.destroy();
}
});
test('editor users should only get client, backend or frontend tokens', async () => {
await setupUser('editor@example.com', RoleName.EDITOR, [
{ name: READ_CLIENT_API_TOKEN },
{ name: READ_FRONTEND_API_TOKEN },
]);
await app.login({ email: 'editor@example.com' });
await app.request
.get('/api/admin/api-tokens')
.expect('Content-Type', /json/)
.expect(200)
.expect((res) => {
expect(res.body.tokens.length).toBe(3);
expect(res.body.tokens[0].type).toBe(ApiTokenType.CLIENT);
expect(res.body.tokens[1].type).toBe(ApiTokenType.FRONTEND);
expect(res.body.tokens[2].type).toBe(ApiTokenType.CLIENT);
});
});
test('viewer users should not be allowed to fetch tokens', async () => {
await setupUser('viewer@example.com', RoleName.VIEWER);
await app.login({ email: 'viewer@example.com' });
await app.request
.get('/api/admin/api-tokens')
.expect('Content-Type', /json/)
.expect(403);
});
test.each([
'client',
'backend',
])('A role with only CREATE_PROJECT_API_TOKEN can create project %s token', async (type) => {
await setupUser(`powerpuffgirls_viewer_${type}@example.com`, RoleName.VIEWER, [{ name: CREATE_PROJECT_API_TOKEN }]);
await app.login({ email: `powerpuffgirls_viewer_${type}@example.com` });
const { body, status } = await app.request
.post('/api/admin/projects/default/api-tokens')
.send({
tokenName: `${type}-token-maker`,
type,
projects: ['default'],
})
.set('Content-Type', 'application/json');
expect(status).toBe(201);
// clean up
await stores.apiTokenStore.delete(body.secret);
});
describe('Fine grained API token permissions', () => {
describe('A role with access to CREATE_CLIENT_API_TOKEN', () => {
test('should be allowed to create client tokens', async () => {
await setupUser('mylittlepony_viewer@example.com', RoleName.VIEWER, [{ name: CREATE_CLIENT_API_TOKEN }]);
await app.login({ email: 'mylittlepony_viewer@example.com' });
const { body } = await app.request
.post('/api/admin/api-tokens')
.send({
tokenName: 'default-client',
type: 'client',
})
.set('Content-Type', 'application/json')
.expect(201);
// clean up
await stores.apiTokenStore.delete(body.secret);
});
test('should NOT be allowed to create frontend tokens', async () => {
await setupUser('mylittlepony_viewer_frontend@example.com', RoleName.VIEWER, [{ name: CREATE_CLIENT_API_TOKEN }]);
await app.login({
email: 'mylittlepony_viewer_frontend@example.com',
});
await app.request
.post('/api/admin/api-tokens')
.send({
tokenName: 'default-frontend',
type: 'frontend',
})
.set('Content-Type', 'application/json')
.expect(403);
});
});
describe('Read operations', () => {
test('READ_FRONTEND_API_TOKEN should be able to see FRONTEND tokens', async () => {
await setupUser('read_frontend_token@example.com', RoleName.VIEWER, [{ name: READ_FRONTEND_API_TOKEN }]);
await app.login({ email: 'read_frontend_token@example.com' });
const { body, status } = await app.request
.get('/api/admin/api-tokens')
.set('Content-Type', 'application/json');
expect(status).toBe(200);
expect(body.tokens.every((t) => t.type === ApiTokenType.FRONTEND)).toBe(true);
});
test('READ_CLIENT_API_TOKEN should be able to see CLIENT and BACKEND tokens', async () => {
await setupUser('read_client_token@example.com', RoleName.VIEWER, [
{ name: READ_CLIENT_API_TOKEN },
]);
await app.login({ email: 'read_client_token@example.com' });
await app.request
.get('/api/admin/api-tokens')
.set('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body.tokens).toHaveLength(2);
expect(res.body.tokens[0].type).toBe(ApiTokenType.CLIENT);
expect(res.body.tokens[1].type).toBe(ApiTokenType.CLIENT);
});
});
test('Admin users should be able to see all tokens', async () => {
await setupUser('read_admin_token@example.com', RoleName.ADMIN);
await app.login({ email: 'read_admin_token@example.com' });
const { body, status } = await app.request
.get('/api/admin/api-tokens')
.set('Content-Type', 'application/json');
expect(status).toBe(200);
expect(body.tokens).toHaveLength(4);
[
{ tokenType: ApiTokenType.ADMIN, expectedCount: 1 },
{ tokenType: ApiTokenType.CLIENT, expectedCount: 2 },
{ tokenType: ApiTokenType.FRONTEND, expectedCount: 1 },
].forEach(({ tokenType, expectedCount }) => {
expect(body.tokens.filter((t) => t.type === tokenType)).toHaveLength(expectedCount);
});
});
test('Editor users should be able to see all tokens except ADMIN tokens', async () => {
await setupUser('standard-editor-reads-tokens@example.com', RoleName.EDITOR);
await app.login({
email: 'standard-editor-reads-tokens@example.com',
});
await app.request
.get('/api/admin/api-tokens')
.set('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body.tokens).toHaveLength(3);
expect(res.body.tokens.filter(({ type }) => type === ApiTokenType.ADMIN)).toHaveLength(0);
});
});
});
describe('Update operations', () => {
describe('UPDATE_CLIENT_API_TOKEN can', () => {
test('UPDATE client_api token expiry', async () => {
await setupUser('update_client_token@example.com', RoleName.VIEWER, [{ name: UPDATE_CLIENT_API_TOKEN }]);
await app.login({ email: 'update_client_token@example.com' });
await app.request
.put(`/api/admin/api-tokens/${clientToken.secret}`)
.send({ expiresAt: addDays(new Date(), 14) })
.expect(200);
});
test('NOT UPDATE frontend_api token expiry', async () => {
await setupUser('update_frontend_token@example.com', RoleName.VIEWER, [{ name: UPDATE_CLIENT_API_TOKEN }]);
await app.login({ email: 'update_frontend_token@example.com' });
await app.request
.put(`/api/admin/api-tokens/${frontendToken.secret}`)
.send({ expiresAt: addDays(new Date(), 14) })
.expect(403);
});
test('NOT UPDATE admin_api token expiry', async () => {
await setupUser('update_admin_token@example.com', RoleName.VIEWER, [{ name: UPDATE_CLIENT_API_TOKEN }]);
await app.request
.put(`/api/admin/api-tokens/${adminToken.secret}`)
.send({ expiresAt: addDays(new Date(), 14) })
.expect(403);
});
});
});
describe('Delete operations', () => {
describe('DELETE_CLIENT_API_TOKEN can', () => {
test('DELETE client_api token', async () => {
await setupUser('delete_client_token@example.com', RoleName.VIEWER, [{ name: DELETE_CLIENT_API_TOKEN }]);
await app.login({ email: 'delete_client_token@example.com' });
const tokenToDelete = await stores.apiTokenStore.insert({
environment: '',
projects: [],
tokenName: 'cilent',
secret: '*:environment.delete_client_token',
type: ApiTokenType.CLIENT,
});
await app.request
.delete(`/api/admin/api-tokens/${tokenToDelete.secret}`)
.send({ expiresAt: addDays(new Date(), 14) })
.expect(200);
});
test('NOT DELETE frontend_api token', async () => {
await setupUser('delete_frontend_token@example.com', RoleName.VIEWER, [{ name: DELETE_CLIENT_API_TOKEN }]);
await app.login({ email: 'delete_frontend_token@example.com' });
await app.request
.delete(`/api/admin/api-tokens/${frontendToken.secret}`)
.send({ expiresAt: addDays(new Date(), 14) })
.expect(403);
});
test('NOT DELETE admin_api token', async () => {
await setupUser('delete_admin_token@example.com', RoleName.VIEWER, [{ name: DELETE_CLIENT_API_TOKEN }]);
await app.login({ email: 'delete_admin_token@example.com' });
await app.request
.delete(`/api/admin/api-tokens/${adminToken.secret}`)
.send({ expiresAt: addDays(new Date(), 14) })
.expect(403);
});
});
});
});
//# sourceMappingURL=api-token.auth.e2e.test.js.map