diff --git a/src/lib/ops/authorizeOps.js b/src/lib/ops/authorizeOps.js index 35c3b92d..0a2c21b8 100644 --- a/src/lib/ops/authorizeOps.js +++ b/src/lib/ops/authorizeOps.js @@ -1,10 +1,12 @@ 'use strict' /* eslint-disable handle-callback-err */ const Boom = require('boom') +const Joi = require('joi') const iam = require('iam-js') const policyOps = require('./policyOps') +const validationRules = require('./validation').authorize -module.exports = { +const authorize = { /** * Return if a user can perform an action on a certain resource * @@ -12,18 +14,22 @@ module.exports = { * @param {Function} cb */ isUserAuthorized: function isUserAuthorized ({ resource, action, userId, organizationId }, cb) { - policyOps.listAllUserPolicies({ userId, organizationId }, (err, policies) => { - if (err) { - return cb(err) - } - - iam(policies, ({ process }) => { - process(resource, action, (err, access) => { - if (err) { - return cb(err) - } - - cb(null, { access }) + Joi.validate({ resource, action, userId, organizationId }, validationRules.isUserAuthorized, function (err) { + if (err) return cb(Boom.badRequest(err)) + + policyOps.listAllUserPolicies({ userId, organizationId }, (err, policies) => { + if (err) { + return cb(err) + } + + iam(policies, ({ process }) => { + process(resource, action, (err, access) => { + if (err) { + return cb(err) + } + + cb(null, { access }) + }) }) }) }) @@ -36,16 +42,25 @@ module.exports = { * @param {Function} cb */ listAuthorizations: function listAuthorizations ({ userId, resource, organizationId }, cb) { - policyOps.listAllUserPolicies({ userId, organizationId }, (err, policies) => { - if (err) return cb(Boom.wrap(err)) + Joi.validate({ resource, userId, organizationId }, validationRules.listAuthorizations, function (err) { + if (err) return cb(Boom.badRequest(err)) - iam(policies, ({ actions }) => { - actions(resource, (err, result) => { - if (err) return cb(err) + policyOps.listAllUserPolicies({ userId, organizationId }, (err, policies) => { + if (err) return cb(Boom.wrap(err)) - cb(null, { actions: result }) + iam(policies, ({ actions }) => { + actions(resource, (err, result) => { + if (err) return cb(err) + + cb(null, { actions: result }) + }) }) }) }) } } + +authorize.isUserAuthorized.validate = validationRules.isUserAuthorized +authorize.listAuthorizations.validate = validationRules.listAuthorizations + +module.exports = authorize diff --git a/src/lib/ops/organizationOps.js b/src/lib/ops/organizationOps.js index 6082849a..3e410e6b 100644 --- a/src/lib/ops/organizationOps.js +++ b/src/lib/ops/organizationOps.js @@ -1,5 +1,6 @@ 'use strict' +const Joi = require('joi') const Boom = require('boom') const db = require('./../db') const policyOps = require('./policyOps') @@ -7,6 +8,7 @@ const userOps = require('./userOps') const SQL = require('./../db/SQL') const mapping = require('./../mapping') const utils = require('./utils') +const validationRules = require('./validation').organizations function fetchOrganizationUsers (job, next) { const { id } = job @@ -122,43 +124,69 @@ function insertOrgAdminUser (job, next) { } var organizationOps = { - /** * Fetch all organizations * * @param {Object} params must contain both `limit` and `page` for pagination. Page is 1-indexed. * @param {Function} cb */ - list: function list ({limit, page}, cb) { + list: function list ({ limit, page }, cb) { + Joi.validate({ limit, page }, validationRules.list, function (err) { + if (err) return cb(err) - const sqlQuery = SQL` - WITH total AS ( - SELECT COUNT(*) AS cnt FROM organizations - ) - SELECT o.*, t.cnt::INTEGER AS total - FROM organizations AS o - INNER JOIN total AS t ON 1=1 - ORDER BY UPPER(o.name) - ` - - if (limit) { - sqlQuery.append(SQL` LIMIT ${limit}`) - } - if (limit && page) { - let offset = (page - 1) * limit - sqlQuery.append(SQL` OFFSET ${offset}`) - } - db.query(sqlQuery, function (err, result) { - if (err) return cb(Boom.badImplementation(err)) - let total = result.rows.length > 0 ? result.rows[0].total : 0 - return cb(null, result.rows.map(mapping.organization), total) + const sqlQuery = SQL` + WITH total AS ( + SELECT COUNT(*) AS cnt FROM organizations + ) + SELECT o.*, t.cnt::INTEGER AS total + FROM organizations AS o + INNER JOIN total AS t ON 1=1 + ORDER BY UPPER(o.name) + ` + + if (limit) { + sqlQuery.append(SQL` LIMIT ${limit}`) + } + if (limit && page) { + let offset = (page - 1) * limit + sqlQuery.append(SQL` OFFSET ${offset}`) + } + db.query(sqlQuery, function (err, result) { + if (err) return cb(Boom.badImplementation(err)) + let total = result.rows.length > 0 ? result.rows[0].total : 0 + return cb(null, result.rows.map(mapping.organization), total) + }) + }) + }, + + /** + * Fetch data for an organization + * + * @param {String} id + * @param {Function} cb + */ + readById: function readById (id, cb) { + Joi.validate(id, validationRules.readById, function (err) { + if (err) return cb(err) + + const sqlQuery = SQL` + SELECT * + FROM organizations + WHERE id = ${id} + ` + db.query(sqlQuery, function (err, result) { + if (err) return cb(Boom.badImplementation(err)) + if (result.rowCount === 0) return cb(Boom.notFound(`Organization ${id} not found`)) + + return cb(null, mapping.organization(result.rows[0])) + }) }) }, /** * Creates a new organization * - * @param {Object} params {id, name, description} + * @param {Object} params {id, name, description, user} * @param {Object} opts { createOnly } * @param {Function} cb */ @@ -171,6 +199,15 @@ var organizationOps = { const { createOnly } = opts const tasks = [ + (job, next) => { + const { id, name, description, user } = params + + Joi.validate({ id, name, description, user }, validationRules.create, (err) => { + if (err) return next(Boom.badRequest(err)) + + next() + }) + }, (job, next) => { job.params = params job.user = params.user @@ -197,26 +234,6 @@ var organizationOps = { }) }, - /** - * Fetch data for an organization - * - * @param {String} id - * @param {Function} cb - */ - readById: function readById (id, cb) { - const sqlQuery = SQL` - SELECT * - FROM organizations - WHERE id = ${id} - ` - db.query(sqlQuery, function (err, result) { - if (err) return cb(Boom.badImplementation(err)) - if (result.rowCount === 0) return cb(Boom.notFound(`Organization ${id} not found`)) - - return cb(null, mapping.organization(result.rows[0])) - }) - }, - /** * Delete organization * @@ -225,6 +242,13 @@ var organizationOps = { */ deleteById: function deleteById (id, cb) { const tasks = [ + (job, next) => { + Joi.validate(id, validationRules.deleteById, (err) => { + if (err) return next(Boom.badRequest(err)) + + next() + }) + }, (job, next) => { job.id = id next() @@ -252,20 +276,30 @@ var organizationOps = { update: function update (params, cb) { const { id, name, description } = params - const sqlQuery = SQL` - UPDATE organizations - SET - name = ${name}, - description = ${description} - WHERE id = ${id} - ` - db.query(sqlQuery, function (err, result) { - if (err) return cb(Boom.badImplementation(err)) - if (result.rowCount === 0) return cb(Boom.notFound()) - - organizationOps.readById(id, cb) + Joi.validate({ id, name, description }, validationRules.update, function (err) { + if (err) return cb(err) + + const sqlQuery = SQL` + UPDATE organizations + SET + name = ${name}, + description = ${description} + WHERE id = ${id} + ` + db.query(sqlQuery, function (err, result) { + if (err) return cb(Boom.badImplementation(err)) + if (result.rowCount === 0) return cb(Boom.notFound()) + + organizationOps.readById(id, cb) + }) }) } } +organizationOps.list.validate = validationRules.list +organizationOps.readById.validate = validationRules.readById +organizationOps.create.validate = validationRules.create +organizationOps.deleteById.validate = validationRules.deleteById +organizationOps.update.validate = validationRules.update + module.exports = organizationOps diff --git a/src/lib/ops/policyOps.js b/src/lib/ops/policyOps.js index 41d895f2..f6806e1e 100644 --- a/src/lib/ops/policyOps.js +++ b/src/lib/ops/policyOps.js @@ -1,6 +1,7 @@ 'use strict' const Boom = require('boom') +const Joi = require('joi') const async = require('async') const db = require('./../db') const config = require('./../config') @@ -8,6 +9,7 @@ const SQL = require('./../db/SQL') const mapping = require('./../mapping') const utils = require('./utils') const uuidV4 = require('uuid/v4') +const validationRules = require('./validation').policies function toArrayWithId (policies) { if (Array.isArray(policies)) { @@ -95,85 +97,48 @@ function removePolicy (job, next) { }) } -const policyOps = { - - /** - * List all user policies - * - * @param {Object} params { userId, organizationId } - * @param {Function} cb - */ - listAllUserPolicies: function listAllUserPolicies ({ userId, organizationId }, cb) { - const sql = SQL` - SELECT DISTINCT - ON (id) id, - version, - name, - statements - FROM - policies p - LEFT JOIN - user_policies up ON p.id = up.policy_id - LEFT JOIN - team_policies tp ON p.id = tp.policy_id - LEFT JOIN - organization_policies op ON p.id = op.policy_id - WHERE - up.user_id = ${userId} OR - tp.team_id IN ( - SELECT team_id FROM teams WHERE path @> ( - SELECT array_agg(path) FROM teams - INNER JOIN team_members tm - ON tm.team_id = teams.id - WHERE tm.user_id = ${userId} - ) - ) OR - op.org_id = ${organizationId} - ` - - db.query(sql, function (err, result) { - if (err) return cb(Boom.badImplementation(err)) - - cb(null, result.rows.map(mapping.policy.iam)) - }) - }, +const policyOps = { /** * List all the policies related to a specific organization * - * @param {Object} params { organizationId } + * @param {Object} params { organizationId, limit, page } * @param {Function} cb */ listByOrganization: function listByOrganization (params, cb) { const { organizationId, limit, page } = params - const sqlQuery = SQL` - WITH total AS ( - SELECT COUNT(*) AS cnt FROM policies - WHERE org_id = ${organizationId} - ) - SELECT - p.id, - p.version, - p.name, - p.statements, - t.cnt::INTEGER AS total - FROM policies AS p - INNER JOIN total AS t ON 1=1 - WHERE p.org_id = ${organizationId} - ORDER BY UPPER(p.name) - ` - if (limit) { - sqlQuery.append(SQL` LIMIT ${limit}`) - } - if (limit && page) { - const offset = (page - 1) * limit - sqlQuery.append(SQL` OFFSET ${offset}`) - } - db.query(sqlQuery, function (err, result) { - if (err) return cb(Boom.badImplementation(err)) - let total = result.rows.length > 0 ? result.rows[0].total : 0 - return cb(null, result.rows.map(mapping.policy), total) + Joi.validate({ organizationId, page, limit }, validationRules.listByOrganization, function (err) { + if (err) return cb(Boom.badRequest(err)) + + const sqlQuery = SQL` + WITH total AS ( + SELECT COUNT(*) AS cnt FROM policies + WHERE org_id = ${organizationId} + ) + SELECT + p.id, + p.version, + p.name, + p.statements, + t.cnt::INTEGER AS total + FROM policies AS p + INNER JOIN total AS t ON 1=1 + WHERE p.org_id = ${organizationId} + ORDER BY UPPER(p.name) + ` + if (limit) { + sqlQuery.append(SQL` LIMIT ${limit}`) + } + if (limit && page) { + const offset = (page - 1) * limit + sqlQuery.append(SQL` OFFSET ${offset}`) + } + db.query(sqlQuery, function (err, result) { + if (err) return cb(Boom.badImplementation(err)) + let total = result.rows.length > 0 ? result.rows[0].total : 0 + return cb(null, result.rows.map(mapping.policy), total) + }) }) }, @@ -184,17 +149,21 @@ const policyOps = { * @param {Function} cb */ readPolicy: function readPolicy ({ id, organizationId }, cb) { - const sqlQuery = SQL` - SELECT * - FROM policies - WHERE id = ${id} - AND org_id = ${organizationId} - ` - db.query(sqlQuery, function (err, result) { - if (err) return cb(Boom.badImplementation(err)) - if (result.rowCount === 0) return cb(Boom.notFound()) + Joi.validate({ id, organizationId }, validationRules.readPolicy, function (err) { + if (err) return cb(Boom.badRequest(err)) + + const sqlQuery = SQL` + SELECT * + FROM policies + WHERE id = ${id} + AND org_id = ${organizationId} + ` + db.query(sqlQuery, function (err, result) { + if (err) return cb(Boom.badImplementation(err)) + if (result.rowCount === 0) return cb(Boom.notFound()) - return cb(null, mapping.policy(result.rows[0])) + return cb(null, mapping.policy(result.rows[0])) + }) }) }, @@ -207,46 +176,54 @@ const policyOps = { createPolicy: function createPolicy (params, cb) { const { id, version, name, organizationId, statements } = params - insertPolicies(db, [{ - id: id, - version: version, - name: name, - org_id: organizationId, - statements: statements - }], (err, result) => { - if (utils.isUniqueViolationError(err)) { - return cb(Boom.badRequest(`Policy with id ${id} already present`)) - } - if (err) return cb(Boom.badImplementation(err)) + Joi.validate({ id, version, name, organizationId, statements }, validationRules.createPolicy, function (err) { + if (err) return cb(Boom.badRequest(err)) + + insertPolicies(db, [{ + id: id, + version: version, + name: name, + org_id: organizationId, + statements: statements + }], (err, result) => { + if (utils.isUniqueViolationError(err)) { + return cb(Boom.badRequest(`Policy with id ${id} already present`)) + } + if (err) return cb(Boom.badImplementation(err)) - policyOps.readPolicy({ id: result.rows[0].id, organizationId }, cb) + policyOps.readPolicy({ id: result.rows[0].id, organizationId }, cb) + }) }) }, /** * Update policy values * - * @param {Object} params { id, organizationId, version, name, organizationId, statements } + * @param {Object} params { id, organizationId, version, name, statements } * @param {Function} cb */ updatePolicy: function updatePolicy (params, cb) { const { id, organizationId, version, name, statements } = params - const sqlQuery = SQL` - UPDATE policies - SET - version = ${version}, - name = ${name}, - statements = ${statements} - WHERE - id = ${id} - AND org_id = ${organizationId} - ` - db.query(sqlQuery, function (err, result) { - if (err) return cb(Boom.badImplementation(err)) - if (result.rowCount === 0) return cb(Boom.notFound()) + Joi.validate({ id, organizationId, version, name, statements }, validationRules.updatePolicy, function (err) { + if (err) return cb(Boom.badRequest(err)) - policyOps.readPolicy({ id, organizationId }, cb) + const sqlQuery = SQL` + UPDATE policies + SET + version = ${version}, + name = ${name}, + statements = ${statements} + WHERE + id = ${id} + AND org_id = ${organizationId} + ` + db.query(sqlQuery, function (err, result) { + if (err) return cb(Boom.badImplementation(err)) + if (result.rowCount === 0) return cb(Boom.notFound()) + + policyOps.readPolicy({ id, organizationId }, cb) + }) }) }, @@ -260,6 +237,13 @@ const policyOps = { const { id, organizationId } = params const tasks = [ + (job, next) => { + Joi.validate({ id, organizationId }, validationRules.deletePolicy, (err) => { + if (err) return next(Boom.badRequest(err)) + + next() + }) + }, (job, next) => { job.id = id job.organizationId = organizationId @@ -276,6 +260,47 @@ const policyOps = { }) }, + /** + * List all user policies + * + * @param {Object} params { userId, organizationId } + * @param {Function} cb + */ + listAllUserPolicies: function listAllUserPolicies ({ userId, organizationId }, cb) { + const sql = SQL` + SELECT DISTINCT + ON (id) id, + version, + name, + statements + FROM + policies p + LEFT JOIN + user_policies up ON p.id = up.policy_id + LEFT JOIN + team_policies tp ON p.id = tp.policy_id + LEFT JOIN + organization_policies op ON p.id = op.policy_id + WHERE + up.user_id = ${userId} OR + tp.team_id IN ( + SELECT team_id FROM teams WHERE path @> ( + SELECT array_agg(path) FROM teams + INNER JOIN team_members tm + ON tm.team_id = teams.id + WHERE tm.user_id = ${userId} + ) + ) OR + op.org_id = ${organizationId} + ` + + db.query(sql, function (err, result) { + if (err) return cb(Boom.badImplementation(err)) + + cb(null, result.rows.map(mapping.policy.iam)) + }) + }, + deleteAllPolicyByIds: function deleteAllPolicyByIds (client, ids, orgId, next) { async.applyEachSeries([ deleteTeamsAssociations, @@ -317,4 +342,10 @@ const policyOps = { } } +policyOps.listByOrganization.validate = validationRules.listByOrganization +policyOps.readPolicy.validate = validationRules.readPolicy +policyOps.createPolicy.validate = validationRules.createPolicy +policyOps.updatePolicy.validate = validationRules.updatePolicy +policyOps.deletePolicy.validate = validationRules.deletePolicy + module.exports = policyOps diff --git a/src/lib/ops/teamOps.js b/src/lib/ops/teamOps.js index bbdd17f8..b48f35a1 100644 --- a/src/lib/ops/teamOps.js +++ b/src/lib/ops/teamOps.js @@ -1,5 +1,6 @@ 'use strict' +const Joi = require('joi') const Boom = require('boom') const uuid = require('uuid/v4') const db = require('./../db') @@ -10,6 +11,7 @@ const utils = require('./utils') const SQL = require('./../db/SQL') const mapping = require('./../mapping') const conf = require('./../config') +const validationRules = require('./validation').teams function generateId () { return uuid().replace(/-/g, '_') @@ -271,12 +273,13 @@ function loadTeams (job, next) { } function loadTeamUsers (job, next) { - const { id, offset, limit } = job + const { id, offset, limit, organizationId } = job const sql = SQL` SELECT users.id, users.name, COUNT(*) OVER() AS total_users_count FROM team_members mem, users WHERE mem.team_id = ${id} AND mem.user_id = users.id + AND users.org_id = ${organizationId} ORDER BY UPPER(users.name) ` if (limit) { @@ -313,7 +316,6 @@ function loadTeamPolicies (job, next) { } var teamOps = { - /** * List the teams in an organization * @@ -323,47 +325,51 @@ var teamOps = { listOrgTeams: function listOrgTeams (params, cb) { let { organizationId, limit, page } = params - let sqlQuery = SQL` - WITH total AS ( - SELECT COUNT(*) AS cnt + Joi.validate({ organizationId, page, limit }, validationRules.listOrgTeams, function (err) { + if (err) return cb(Boom.badRequest(err)) + + let sqlQuery = SQL` + WITH total AS ( + SELECT COUNT(*) AS cnt + FROM teams + WHERE org_id = ${organizationId} + ) + SELECT + teams.id, + teams.name, + teams.description, + teams.path, + teams.org_id, + t.cnt::INTEGER AS total, + COUNT(team_members.team_id) AS users_count FROM teams + LEFT JOIN team_members ON team_members.team_id = teams.id + INNER JOIN total AS t ON 1=1 WHERE org_id = ${organizationId} - ) - SELECT - teams.id, - teams.name, - teams.description, - teams.path, - teams.org_id, - t.cnt::INTEGER AS total, - COUNT(team_members.team_id) AS users_count - FROM teams - LEFT JOIN team_members ON team_members.team_id = teams.id - INNER JOIN total AS t ON 1=1 - WHERE org_id = ${organizationId} - GROUP BY teams.id, teams.name, teams.description, teams.path, teams.org_id, t.cnt - ORDER BY UPPER(name) - ` + GROUP BY teams.id, teams.name, teams.description, teams.path, teams.org_id, t.cnt + ORDER BY UPPER(name) + ` - if (limit) { - sqlQuery.append(SQL` LIMIT ${limit}`) - } - if (limit && page) { - let offset = (page - 1) * limit - sqlQuery.append(SQL` OFFSET ${offset}`) - } + if (limit) { + sqlQuery.append(SQL` LIMIT ${limit}`) + } + if (limit && page) { + let offset = (page - 1) * limit + sqlQuery.append(SQL` OFFSET ${offset}`) + } - db.query(sqlQuery, function (err, result) { - if (err) return cb(err) - let total = result.rows.length > 0 ? result.rows[0].total : 0 - return cb(null, result.rows.map(mapping.team.list), total) + db.query(sqlQuery, function (err, result) { + if (err) return cb(err) + let total = result.rows.length > 0 ? result.rows[0].total : 0 + return cb(null, result.rows.map(mapping.team.list), total) + }) }) }, /** * Creates a new team * - * @param {Object} params { name, description, parentId, organizationId, user } + * @param {Object} params { id, name, description, parentId, organizationId, user } * @param {Object} opts { createOnly } * @param {Function} cb */ @@ -375,6 +381,16 @@ var teamOps = { const { createOnly } = opts const tasks = [ + (job, next) => { + const { id, name, description, parentId, organizationId, user } = params + + // We should not use boom bur return specific errors that will be then handled out side the udaru.js module + Joi.validate({ id, name, description, parentId, organizationId, user }, validationRules.createTeam, (err) => { + if (err) return next(Boom.badRequest(err)) + + next() + }) + }, (job, next) => { job.params = params next() @@ -397,36 +413,6 @@ var teamOps = { }) }, - /** - * Fetch the users data from a team - * - * @param {params} params { id, page, limit } - * @param {Function} cb - */ - readTeamUsers: function readTeamUsers ({ id, page = 1, limit }, cb) { - const pageLimit = limit || conf.get('authorization.defaultPageSize') - const offset = (page - 1) * pageLimit - - const job = { - id: id, - offset: offset, - limit: pageLimit, - team: {} - } - - loadTeamUsers(job, (err) => { - if (err) return cb(err) - const pageSize = pageLimit || job.totalUsersCount - const result = { - page: page, - limit: pageSize, - total: job.totalUsersCount, - data: job.team.users - } - return cb(null, result) - }) - }, - /** * Fetch specific team data * @@ -439,6 +425,13 @@ var teamOps = { } async.applyEachSeries([ + (job, next) => { + Joi.validate({ id, organizationId }, validationRules.readTeam, (err) => { + if (err) return next(Boom.badRequest(err)) + + next() + }) + }, (job, next) => { job.id = id job.organizationId = organizationId @@ -454,29 +447,34 @@ var teamOps = { }) }, - /** - * @param {Object} params {id, name, description, organizationId } - * @param {Function} cb + /** + * Uodate team data + * @param {Object} params {id, name, description, organizationId } + * @param {Function} cb */ updateTeam: function updateTeam (params, cb) { const { id, name, description, organizationId } = params - const updates = [] - const sql = SQL` UPDATE teams SET ` - if (name) { updates.push(SQL`name = ${name}`) } - if (description) { updates.push(SQL`description = ${description}`) } - sql.append(sql.glue(updates, ' , ')) - sql.append(SQL` - WHERE id = ${id} - AND org_id = ${organizationId} - `) + Joi.validate({ id, name, description, organizationId }, Joi.object().keys(validationRules.updateTeam).or('name', 'description'), function (err) { + if (err) return cb(Boom.badRequest(err)) + const updates = [] + const sql = SQL` UPDATE teams SET ` + if (name) { updates.push(SQL`name = ${name}`) } + if (description) { updates.push(SQL`description = ${description}`) } + sql.append(sql.glue(updates, ' , ')) + sql.append(SQL` + WHERE id = ${id} + AND org_id = ${organizationId} + `) - db.query(sql, (err, res) => { - if (err) return cb(Boom.badImplementation(err)) - if (res.rowCount === 0) return cb(Boom.notFound(`Team with id ${id} could not be found`)) - teamOps.readTeam({ id, organizationId }, cb) + db.query(sql, (err, res) => { + if (err) return cb(Boom.badImplementation(err)) + if (res.rowCount === 0) return cb(Boom.notFound(`Team with id ${id} could not be found`)) + + teamOps.readTeam({ id, organizationId }, cb) + }) }) }, @@ -488,6 +486,15 @@ var teamOps = { */ deleteTeam: function deleteTeam (params, cb) { db.withTransaction([ + (job, next) => { + const { id, organizationId } = params + + Joi.validate({ id, organizationId }, validationRules.deleteTeam, (err) => { + if (err) return next(Boom.badRequest(err)) + + next() + }) + }, (job, next) => { job.teamId = params.id job.organizationId = params.organizationId @@ -515,6 +522,13 @@ var teamOps = { const { id, organizationId } = params db.withTransaction([ + (job, next) => { + Joi.validate({ id, organizationId }, validationRules.moveTeam, (err) => { + if (err) return next(Boom.badRequest(err)) + + next() + }) + }, (job, next) => { job.params = params next() @@ -529,6 +543,30 @@ var teamOps = { }) }, + /** + * Add one or more policies to a team + * + * @param {Object} params { id, organizationId, policies } + * @param {Function} cb + */ + addTeamPolicies: function addTeamPolicies (params, cb) { + const { id, organizationId, policies } = params + + Joi.validate({ id, organizationId, policies }, validationRules.addTeamPolicies, function (err) { + if (err) return cb(Boom.badRequest(err)) + + utils.checkPoliciesOrg(db, policies, organizationId, (err) => { + if (err) return cb(err) + + insertTeamPolicies({ client: db, teamId: id, policies }, (err, res) => { + if (err) return cb(err) + + teamOps.readTeam({ id, organizationId }, cb) + }) + }) + }) + }, + /** * Replace team poilicies * @@ -538,6 +576,13 @@ var teamOps = { replaceTeamPolicies: function replaceTeamPolicies (params, cb) { const { id, organizationId, policies } = params const tasks = [ + (job, next) => { + Joi.validate({ id, organizationId, policies }, validationRules.replaceTeamPolicies, (err) => { + if (err) return next(Boom.badRequest(err)) + + next() + }) + }, (job, next) => { job.teamId = id job.organizationId = organizationId @@ -560,18 +605,18 @@ var teamOps = { }, /** - * Add one or more policies to a team + * Remove all team's policies * - * @param {Object} params { id, organizationId, policies } + * @param {Object} params { id, organizationId } * @param {Function} cb */ - addTeamPolicies: function addTeamPolicies (params, cb) { - const { id, organizationId, policies } = params + deleteTeamPolicies: function deleteTeamPolicies (params, cb) { + const { id, organizationId } = params - utils.checkPoliciesOrg(db, policies, organizationId, (err) => { - if (err) return cb(err) + Joi.validate({ id, organizationId }, validationRules.deleteTeamPolicies, function (err) { + if (err) return cb(Boom.badRequest(err)) - insertTeamPolicies({ client: db, teamId: id, policies }, (err, res) => { + clearTeamPolicies({ teamId: id, client: db }, (err, res) => { if (err) return cb(err) teamOps.readTeam({ id, organizationId }, cb) @@ -580,34 +625,57 @@ var teamOps = { }, /** - * Remove all team's policies + * Remove a specific team policy * - * @param {Object} params { id, organizationId } + * @param {Object} params { userId, organizationId, policyId } * @param {Function} cb */ - deleteTeamPolicies: function deleteTeamPolicies (params, cb) { - const { id, organizationId } = params + deleteTeamPolicy: function deleteTeamPolicy (params, cb) { + const { teamId, organizationId, policyId } = params - clearTeamPolicies({ teamId: id, client: db }, (err, res) => { - if (err) return cb(err) + Joi.validate({ teamId, organizationId, policyId }, validationRules.deleteTeamPolicy, function (err) { + if (err) return cb(Boom.badRequest(err)) - teamOps.readTeam({ id, organizationId }, cb) + removeTeamPolicy({ client: db, teamId, policyId }, (err, res) => { + if (err) return cb(err) + + teamOps.readTeam({ id: teamId, organizationId }, cb) + }) }) }, /** - * Remove a specific team policy + * Fetch the users data from a team * - * @param {Object} params { userId, organizationId, policyId } + * @param {params} params { id, page, limit } * @param {Function} cb */ - deleteTeamPolicy: function deleteTeamPolicy (params, cb) { - const { teamId, organizationId, policyId } = params - - removeTeamPolicy({ client: db, teamId, policyId }, (err, res) => { - if (err) return cb(err) + readTeamUsers: function readTeamUsers ({ id, page = 1, limit, organizationId }, cb) { + Joi.validate({ id, page, limit, organizationId }, validationRules.readTeamUsers, function (err) { + if (err) return cb(Boom.badRequest(err)) + + const pageLimit = limit || conf.get('authorization.defaultPageSize') + const offset = (page - 1) * pageLimit + + const job = { + id: id, + organizationId: organizationId, + offset: offset, + limit: pageLimit, + team: {} + } - teamOps.readTeam({ id: teamId, organizationId }, cb) + loadTeamUsers(job, (err) => { + if (err) return cb(err) + const pageSize = pageLimit || job.totalUsersCount + const result = { + page: page, + limit: pageSize, + total: job.totalUsersCount, + data: job.team.users + } + return cb(null, result) + }) }) }, @@ -618,8 +686,15 @@ var teamOps = { * @param {Function} cb */ addUsersToTeam: function addUsersToTeam (params, cb) { - const { id, organizationId } = params + const { id, users, organizationId } = params const tasks = [ + (job, next) => { + Joi.validate({ id, users, organizationId }, validationRules.addUsersToTeam, (err) => { + if (err) return next(Boom.badRequest(err)) + + next() + }) + }, (job, next) => { job.teamId = id job.organizationId = organizationId @@ -648,8 +723,15 @@ var teamOps = { * @param {Function} cb */ replaceUsersInTeam: function replaceUsersInTeam (params, cb) { - const { id, organizationId } = params + const { id, users, organizationId } = params const tasks = [ + (job, next) => { + Joi.validate({ id, users, organizationId }, validationRules.replaceUsersInTeam, (err) => { + if (err) return next(Boom.badRequest(err)) + + next() + }) + }, (job, next) => { job.teamId = params.id job.organizationId = params.organizationId @@ -682,6 +764,13 @@ var teamOps = { const { id, organizationId } = params const tasks = [ + (job, next) => { + Joi.validate({ id, organizationId }, validationRules.deleteTeamMembers, (err) => { + if (err) return next(Boom.badRequest(err)) + + next() + }) + }, (job, next) => { job.teamId = id job.organizationId = organizationId @@ -708,6 +797,13 @@ var teamOps = { deleteTeamMember: function deleteTeamMember (params, cb) { const { id, userId, organizationId } = params const tasks = [ + (job, next) => { + Joi.validate({ id, userId, organizationId }, validationRules.deleteTeamMember, (err) => { + if (err) return next(Boom.badRequest(err)) + + next() + }) + }, (job, next) => { job.teamId = id job.organizationId = organizationId @@ -727,4 +823,20 @@ var teamOps = { } } +teamOps.deleteTeamMembers.validate = validationRules.deleteTeamMembers +teamOps.deleteTeamMember.validate = validationRules.deleteTeamMember +teamOps.replaceTeamPolicies.validate = validationRules.replaceTeamPolicies +teamOps.deleteTeamPolicies.validate = validationRules.deleteTeamPolicies +teamOps.deleteTeamPolicy.validate = validationRules.deleteTeamPolicy +teamOps.readTeamUsers.validate = validationRules.readTeamUsers +teamOps.addUsersToTeam.validate = validationRules.addUsersToTeam +teamOps.replaceUsersInTeam.validate = validationRules.replaceUsersInTeam +teamOps.listOrgTeams.validate = validationRules.listOrgTeams +teamOps.createTeam.validate = validationRules.createTeam +teamOps.readTeam.validate = validationRules.readTeam +teamOps.updateTeam.validate = validationRules.updateTeam +teamOps.deleteTeam.validate = validationRules.deleteTeam +teamOps.moveTeam.validate = validationRules.moveTeam +teamOps.addTeamPolicies.validate = validationRules.addTeamPolicies + module.exports = teamOps diff --git a/src/lib/ops/userOps.js b/src/lib/ops/userOps.js index 10cc64f6..cb2db080 100644 --- a/src/lib/ops/userOps.js +++ b/src/lib/ops/userOps.js @@ -1,5 +1,6 @@ 'use strict' +const Joi = require('joi') const Boom = require('boom') const async = require('async') const uuidV4 = require('uuid/v4') @@ -7,8 +8,9 @@ const db = require('./../db') const SQL = require('./../db/SQL') const mapping = require('./../mapping') const utils = require('./utils') +const validationRules = require('./validation').users -const clearUserPolicies = (job, next) => { +function clearUserPolicies (job, next) { const { id } = job const sqlQuery = SQL` @@ -18,7 +20,7 @@ const clearUserPolicies = (job, next) => { job.client.query(sqlQuery, utils.boomErrorWrapper(next)) } -const removeUserPolicy = (job, next) => { +function removeUserPolicy (job, next) { const { id, policyId } = job const sqlQuery = SQL` @@ -29,7 +31,7 @@ const removeUserPolicy = (job, next) => { job.client.query(sqlQuery, utils.boomErrorWrapper(next)) } -const insertUserPolicies = (job, next) => { +function insertUserPolicies (job, next) { const { id: userId, policies } = job userOps.insertPolicies(job.client, userId, policies, utils.boomErrorWrapper(next)) @@ -45,130 +47,44 @@ const userOps = { /** * Get organization users, in alphabetical order * - * @param {Object} params { organizationId } + * @param {Object} params { organizationId, page, limit } * @param {Function} cb */ listOrgUsers: function listOrgUsers (params, cb) { - const { organizationId } = params + const { organizationId, page, limit } = params - const sqlQuery = SQL` - WITH total AS ( - SELECT COUNT(*)::INTEGER AS cnt + Joi.validate({ organizationId, page, limit }, validationRules.listOrgUsers, function (err) { + if (err) return cb(Boom.badRequest(err)) + + const sqlQuery = SQL` + WITH total AS ( + SELECT COUNT(*)::INTEGER AS cnt + FROM users + WHERE org_id = ${organizationId} + ) + SELECT *, t.cnt AS total FROM users + INNER JOIN total AS t on 1=1 WHERE org_id = ${organizationId} - ) - SELECT *, t.cnt AS total - FROM users - INNER JOIN total AS t on 1=1 - WHERE org_id = ${organizationId} - ORDER BY UPPER(name) - ` - db.query(sqlQuery, function (err, result) { - if (err) return cb(err) - let total = result.rows.length > 0 ? result.rows[0].total : 0 - return cb(null, result.rows.map(mapping.user), total) - }) - }, - - /** - * Insert a new user into the database - * - * @param {Object} client - * @param {String|null} options.id - * @param {String} options.name - * @param {String} options.organizationId - * @param {Function} cb - */ - insertUser: function insertUser (client, { id, name, organizationId }, cb) { - id = id || uuidV4() - - const sqlQuery = SQL` - INSERT INTO users ( - id, name, org_id - ) VALUES ( - ${id}, ${name}, ${organizationId} - ) - RETURNING id - ` + ORDER BY UPPER(name) + ` - client.query(sqlQuery, (err, result) => { - if (utils.isUniqueViolationError(err)) { - return cb(Boom.badRequest(`User with id ${id} already present`)) + if (limit) { + sqlQuery.append(SQL` LIMIT ${limit}`) + } + if (limit && page) { + let offset = (page - 1) * limit + sqlQuery.append(SQL` OFFSET ${offset}`) } - cb(err, result) - }) - }, - - insertPolicies: function insertPolicies (client, id, policies, cb) { - const sqlQuery = SQL` - INSERT INTO user_policies ( - policy_id, user_id - ) VALUES - ` - sqlQuery.append(SQL`(${policies[0]}, ${id})`) - policies.slice(1).forEach((policyId) => { - sqlQuery.append(SQL`, (${policyId}, ${id})`) - }) - sqlQuery.append(SQL` ON CONFLICT ON CONSTRAINT user_policy_link DO NOTHING`) - - client.query(sqlQuery, utils.boomErrorWrapper(cb)) - }, - - organizationExists: function organizationExists (id, cb) { - const sqlQuery = SQL` - SELECT id - FROM organizations - WHERE id = ${id} - ` - db.query(sqlQuery, function (err, result) { - if (err) return cb(err) - - return cb(null, result.rowCount !== 0) - }) - }, - - /** - * Create a new user - * - * @param {Object} params { id, name, organizationId } "id" can be null - * @param {Function} cb - */ - createUser: function createUser (params, cb) { - const { id, name, organizationId } = params - - userOps.organizationExists(organizationId, (err, res) => { - if (err) return cb(Boom.badImplementation(err)) - if (!res) return cb(Boom.badRequest(`Organization '${organizationId}' does not exists`)) - - userOps.insertUser(db, { id, name, organizationId }, (err, result) => { + db.query(sqlQuery, function (err, result) { if (err) return cb(err) - - userOps.readUser({ id: result.rows[0].id, organizationId }, utils.boomErrorWrapper(cb)) + let total = result.rows.length > 0 ? result.rows[0].total : 0 + return cb(null, result.rows.map(mapping.user), total) }) }) }, - /** - * Return the user organizationId - * - * @param {Number} id - * @param {Function} cb - */ - getUserOrganizationId: function getUserOrganizationId (id, cb) { - const sqlQuery = SQL` - SELECT org_id - FROM users - WHERE id = ${id} - ` - db.query(sqlQuery, function (err, result) { - if (err) return cb(Boom.badImplementation(err)) - if (result.rowCount === 0) return cb(Boom.notFound()) - - return cb(null, result.rows[0].org_id) - }) - }, - /** * Get user details * @@ -181,6 +97,14 @@ const userOps = { const tasks = [] + tasks.push((next) => { + Joi.validate({ id, organizationId }, validationRules.readUser, (err) => { + if (err) return next(Boom.badRequest(err)) + + next() + }) + }) + tasks.push((next) => { const sqlQuery = SQL` SELECT id, name, org_id @@ -234,6 +158,80 @@ const userOps = { }) }, + /** + * Create a new user + * + * @param {Object} params { id, name, organizationId } "id" can be null + * @param {Function} cb + */ + createUser: function createUser (params, cb) { + const { id, name, organizationId } = params + + Joi.validate({ id, name, organizationId }, validationRules.createUser, function (err) { + if (err) return cb(Boom.badRequest(err)) + + userOps.organizationExists(organizationId, (err, res) => { + if (err) return cb(Boom.badImplementation(err)) + if (!res) return cb(Boom.badRequest(`Organization '${organizationId}' does not exists`)) + + userOps.insertUser(db, { id, name, organizationId }, (err, result) => { + if (err) return cb(err) + + userOps.readUser({ id: result.rows[0].id, organizationId }, utils.boomErrorWrapper(cb)) + }) + }) + }) + }, + + /** + * Delete user + * + * @param {Object} { id, organizationId } + * @param {Function} cb + */ + deleteUser: function deleteUser (params, cb) { + const { id, organizationId } = params + const tasks = [ + (job, next) => { + Joi.validate({ id, organizationId }, validationRules.deleteUser, (err) => { + if (err) return next(Boom.badRequest(err)) + + next() + }) + }, + (job, next) => { + job.id = id + next() + }, + (job, next) => { + const sqlQuery = SQL`DELETE FROM user_policies WHERE user_id = ${id}` + + job.client.query(sqlQuery, utils.boomErrorWrapper(next)) + }, + (job, next) => { + const sqlQuery = SQL`DELETE FROM team_members WHERE user_id = ${id}` + + job.client.query(sqlQuery, utils.boomErrorWrapper(next)) + }, + (job, next) => { + const sqlQuery = SQL`DELETE FROM users WHERE id = ${id} AND org_id = ${organizationId}` + + job.client.query(sqlQuery, (err, result) => { + if (err) return next(Boom.badImplementation(err)) + if (result.rowCount === 0) return next(Boom.notFound(`User ${id} not found`)) + + next() + }) + } + ] + + db.withTransaction(tasks, (err, res) => { + if (err) return cb(err) + + cb() + }) + }, + /** * Update user details * @@ -243,17 +241,21 @@ const userOps = { updateUser: function updateUser (params, cb) { const { id, organizationId, name } = params - const sqlQuery = SQL` - UPDATE users - SET name = ${name} - WHERE id = ${id} - AND org_id = ${organizationId} - ` - db.query(sqlQuery, (err, result) => { - if (err) return cb(Boom.badImplementation(err)) - if (result.rowCount === 0) return cb(Boom.notFound(`User ${id} not found`)) + Joi.validate({ id, organizationId, name }, validationRules.updateUser, function (err) { + if (err) return cb(Boom.badRequest(err)) - userOps.readUser({ id, organizationId }, cb) + const sqlQuery = SQL` + UPDATE users + SET name = ${name} + WHERE id = ${id} + AND org_id = ${organizationId} + ` + db.query(sqlQuery, (err, result) => { + if (err) return cb(Boom.badImplementation(err)) + if (result.rowCount === 0) return cb(Boom.notFound(`User ${id} not found`)) + + userOps.readUser({ id, organizationId }, cb) + }) }) }, @@ -266,6 +268,13 @@ const userOps = { replaceUserPolicies: function replaceUserPolicies (params, cb) { const { id, organizationId, policies } = params const tasks = [ + (job, next) => { + Joi.validate({ id, organizationId, policies }, validationRules.replaceUserPolicies, (err) => { + if (err) return next(Boom.badRequest(err)) + + next() + }) + }, (job, next) => { job.id = id job.organizationId = organizationId @@ -306,6 +315,13 @@ const userOps = { } const tasks = [ + (job, next) => { + Joi.validate({ id, organizationId, policies }, validationRules.addUserPolicies, (err) => { + if (err) return next(Boom.badRequest(err)) + + next() + }) + }, (job, next) => { job.id = id job.policies = policies @@ -336,6 +352,13 @@ const userOps = { deleteUserPolicies: function deleteUserPolicies (params, cb) { const { id, organizationId } = params const tasks = [ + (job, next) => { + Joi.validate({ id, organizationId }, validationRules.deleteUserPolicies, (err) => { + if (err) return next(Boom.badRequest(err)) + + next() + }) + }, (job, next) => { job.id = id job.organizationId = organizationId @@ -364,6 +387,13 @@ const userOps = { deleteUserPolicy: function deleteUserPolicy (params, cb) { const { userId, organizationId, policyId } = params const tasks = [ + (job, next) => { + Joi.validate({ userId, organizationId, policyId }, validationRules.deleteUserPolicy, (err) => { + if (err) return next(Boom.badRequest(err)) + + next() + }) + }, (job, next) => { job.id = userId job.policyId = policyId @@ -385,46 +415,92 @@ const userOps = { }, /** - * Delete user + * Insert a new user into the database * - * @param {Object} { id, organizationId } - * @param {Function} cb + * @param {Object} client + * @param {String|null} options.id + * @param {String} options.name + * @param {String} options.organizationId + * @param {Function} cb */ - deleteUser: function deleteUser (params, cb) { - const { id, organizationId } = params - const tasks = [ - (job, next) => { - job.id = id - next() - }, - (job, next) => { - const sqlQuery = SQL`DELETE FROM user_policies WHERE user_id = ${id}` + insertUser: function insertUser (client, { id, name, organizationId }, cb) { + id = id || uuidV4() - job.client.query(sqlQuery, utils.boomErrorWrapper(next)) - }, - (job, next) => { - const sqlQuery = SQL`DELETE FROM team_members WHERE user_id = ${id}` + const sqlQuery = SQL` + INSERT INTO users ( + id, name, org_id + ) VALUES ( + ${id}, ${name}, ${organizationId} + ) + RETURNING id + ` - job.client.query(sqlQuery, utils.boomErrorWrapper(next)) - }, - (job, next) => { - const sqlQuery = SQL`DELETE FROM users WHERE id = ${id} AND org_id = ${organizationId}` + client.query(sqlQuery, (err, result) => { + if (utils.isUniqueViolationError(err)) { + return cb(Boom.badRequest(`User with id ${id} already present`)) + } - job.client.query(sqlQuery, (err, result) => { - if (err) return next(Boom.badImplementation(err)) - if (result.rowCount === 0) return next(Boom.notFound(`User ${id} not found`)) + cb(err, result) + }) + }, - next() - }) - } - ] + insertPolicies: function insertPolicies (client, id, policies, cb) { + const sqlQuery = SQL` + INSERT INTO user_policies ( + policy_id, user_id + ) VALUES + ` + sqlQuery.append(SQL`(${policies[0]}, ${id})`) + policies.slice(1).forEach((policyId) => { + sqlQuery.append(SQL`, (${policyId}, ${id})`) + }) + sqlQuery.append(SQL` ON CONFLICT ON CONSTRAINT user_policy_link DO NOTHING`) - db.withTransaction(tasks, (err, res) => { + client.query(sqlQuery, utils.boomErrorWrapper(cb)) + }, + + organizationExists: function organizationExists (id, cb) { + const sqlQuery = SQL` + SELECT id + FROM organizations + WHERE id = ${id} + ` + db.query(sqlQuery, function (err, result) { if (err) return cb(err) - cb() + return cb(null, result.rowCount !== 0) + }) + }, + + /** + * Return the user organizationId + * + * @param {Number} id + * @param {Function} cb + */ + getUserOrganizationId: function getUserOrganizationId (id, cb) { + const sqlQuery = SQL` + SELECT org_id + FROM users + WHERE id = ${id} + ` + db.query(sqlQuery, function (err, result) { + if (err) return cb(Boom.badImplementation(err)) + if (result.rowCount === 0) return cb(Boom.notFound()) + + return cb(null, result.rows[0].org_id) }) } } +userOps.listOrgUsers.validate = validationRules.listOrgUsers +userOps.readUser.validate = validationRules.readUser +userOps.createUser.validate = validationRules.createUser +userOps.deleteUser.validate = validationRules.deleteUser +userOps.updateUser.validate = validationRules.updateUser +userOps.replaceUserPolicies.validate = validationRules.replaceUserPolicies +userOps.addUserPolicies.validate = validationRules.addUserPolicies +userOps.deleteUserPolicies.validate = validationRules.deleteUserPolicies +userOps.deleteUserPolicy.validate = validationRules.deleteUserPolicy + module.exports = userOps diff --git a/src/lib/ops/validation.js b/src/lib/ops/validation.js new file mode 100644 index 00000000..c9e6c598 --- /dev/null +++ b/src/lib/ops/validation.js @@ -0,0 +1,233 @@ +'use strict' + +const Joi = require('joi') + +const requiredString = Joi.string().required() + +const validationRules = { + id: Joi.string().required(), + name: requiredString.description('Name'), + description: requiredString.description('Description'), + organizationId: requiredString.description('Organization ID'), + page: Joi.number().integer().min(1).description('Page number, starts from 1'), + limit: Joi.number().integer().min(1).description('Items per page'), + version: requiredString.description('Version number'), + + user: Joi.object().description('Default admin').keys({ + id: Joi.string().description('User ID'), + name: requiredString.description('User name') + }), + + parentId: Joi.string().description('Parent ID'), + policyId: requiredString.description('Policy ID'), + + users: Joi.array().required().items(requiredString).description('User IDs'), + policies: Joi.array().required().items(requiredString).description('Policies IDs'), + + statements: Joi.object({ + Statement: Joi.array().items(Joi.object({ + Effect: Joi.string(), + Action: Joi.array().items(Joi.string()), + Resource: Joi.array().items(Joi.string()), + Sid: Joi.string(), + Condition: Joi.object() + })) + }).required().description('policy statements') + +} + +const users = { + listOrgUsers: { + page: validationRules.page, + limit: validationRules.limit, + organizationId: validationRules.organizationId + }, + readUser: { + id: validationRules.id.description('User ID'), + organizationId: validationRules.organizationId + }, + createUser: { + id: validationRules.id.optional().allow('').description('User ID'), + name: validationRules.name, + organizationId: validationRules.organizationId + }, + deleteUser: { + id: validationRules.id.description('User ID'), + organizationId: validationRules.organizationId + }, + updateUser: { + id: validationRules.id.description('User ID'), + name: validationRules.name, + organizationId: validationRules.organizationId + }, + replaceUserPolicies: { + id: validationRules.id.description('User ID'), + policies: validationRules.policies, + organizationId: validationRules.organizationId + }, + addUserPolicies: { + id: validationRules.id.description('User ID'), + policies: validationRules.policies, + organizationId: validationRules.organizationId + }, + deleteUserPolicies: { + id: validationRules.id.description('User ID'), + organizationId: validationRules.organizationId + }, + deleteUserPolicy: { + userId: validationRules.id.description('User ID'), + policyId: validationRules.policyId, + organizationId: validationRules.organizationId + } +} + +const teams = { + listOrgTeams: { + page: validationRules.page, + limit: validationRules.limit, + organizationId: validationRules.organizationId + }, + createTeam: { + id: Joi.string().regex(/^[0-9a-zA-Z_]+$/).allow('').description('The ID to be used for the new team. Only alphanumeric characters and underscore are supported'), + parentId: Joi.any(), + name: requiredString.description('Team name'), + description: validationRules.description, + user: validationRules.user, + organizationId: validationRules.organizationId + }, + readTeam: { + id: validationRules.id.description('Team ID'), + organizationId: validationRules.organizationId + }, + updateTeam: { + id: validationRules.id.description('Team ID'), + name: validationRules.name.optional(), + description: validationRules.description.optional(), + organizationId: validationRules.organizationId + }, + deleteTeam: { + id: validationRules.id.description('Team ID'), + organizationId: validationRules.organizationId + }, + moveTeam: { + id: validationRules.id.description('Team ID'), + parentId: validationRules.parentId, + organizationId: validationRules.organizationId + }, + addTeamPolicies: { + id: validationRules.id.description('Team ID'), + policies: validationRules.policies, + organizationId: validationRules.organizationId + }, + replaceTeamPolicies: { + id: validationRules.id.description('Team ID'), + policies: validationRules.policies, + organizationId: validationRules.organizationId + }, + deleteTeamPolicies: { + id: validationRules.id.description('Team ID'), + organizationId: validationRules.organizationId + }, + deleteTeamPolicy: { + teamId: validationRules.id.description('Team ID'), + policyId: validationRules.policyId, + organizationId: validationRules.organizationId + }, + readTeamUsers: { + id: validationRules.id.description('Team ID'), + page: validationRules.page, + limit: validationRules.limit, + organizationId: validationRules.organizationId + }, + addUsersToTeam: { + id: validationRules.id.description('Team ID'), + users: validationRules.users, + organizationId: validationRules.organizationId + }, + replaceUsersInTeam: { + id: validationRules.id.description('Team ID'), + users: validationRules.users, + organizationId: validationRules.organizationId + }, + deleteTeamMembers: { + id: validationRules.id.description('Team ID'), + organizationId: validationRules.organizationId + }, + deleteTeamMember: { + id: validationRules.id.description('Team ID'), + userId: validationRules.id.description('User ID'), + organizationId: validationRules.organizationId + } +} + +const policies = { + listByOrganization: { + organizationId: validationRules.organizationId, + page: validationRules.page, + limit: validationRules.limit + }, + readPolicy: { + id: validationRules.id.description('Policy ID'), + organizationId: validationRules.organizationId + }, + createPolicy: { + id: Joi.string().allow('').description('policy id'), + version: validationRules.version, + name: validationRules.name, + organizationId: validationRules.organizationId, + statements: validationRules.statements + }, + updatePolicy: { + id: validationRules.id.description('Policy ID'), + organizationId: validationRules.organizationId, + version: validationRules.version, + name: validationRules.name, + statements: validationRules.statements + }, + deletePolicy: { + id: validationRules.id.description('Policy ID'), + organizationId: validationRules.organizationId + } +} + +const organizations = { + list: { + page: validationRules.page, + limit: validationRules.limit + }, + readById: validationRules.organizationId, + create: { + id: Joi.string().regex(/^[a-zA-Z0-9]{1,64}$/).required().description('Organization ID'), + name: validationRules.name, + description: validationRules.description, + user: validationRules.user + }, + deleteById: validationRules.organizationId, + update: { + id: validationRules.organizationId, + name: validationRules.name, + description: validationRules.description + } +} + +const authorize = { + isUserAuthorized: { + userId: validationRules.id.description('User ID'), + action: requiredString.description('The action to check'), + resource: requiredString.description('The resource that the user wants to perform the action on'), + organizationId: validationRules.organizationId + }, + listAuthorizations: { + userId: validationRules.id.description('User ID'), + resource: requiredString.description('The resource that the user wants to perform the action on'), + organizationId: validationRules.organizationId + } +} + +module.exports = { + users, + teams, + policies, + organizations, + authorize +} diff --git a/src/routes/private/policies.js b/src/routes/private/policies.js index ab1a2198..6d15a895 100644 --- a/src/routes/private/policies.js +++ b/src/routes/private/policies.js @@ -1,12 +1,13 @@ 'use strict' +const _ = require('lodash') const Joi = require('joi') const Boom = require('boom') const serviceKey = require('./../../security/serviceKey') const Action = require('./../../lib/config/config.auth').Action -const policyOps = require('./../../lib/ops/policyOps') const swagger = require('./../../swagger') const headers = require('./../headers') +const udaru = require('./../../udaru') exports.register = function (server, options, next) { @@ -27,7 +28,7 @@ exports.register = function (server, options, next) { statements } - policyOps.createPolicy(params, function (err, res) { + udaru.policies.create(params, function (err, res) { if (err) { return reply(err) } @@ -37,12 +38,7 @@ exports.register = function (server, options, next) { }, config: { validate: { - payload: { - id: Joi.string().allow('').description('Policy ID'), - version: Joi.string().required().description('Policy version'), - name: Joi.string().required().description('Policy name'), - statements: swagger.PolicyStatements.required().description('Policy statements') - }, + payload: _.pick(udaru.policies.create.validate, ['id', 'name', 'version', 'statements']), query: { sig: Joi.string().required() }, @@ -78,18 +74,12 @@ exports.register = function (server, options, next) { statements } - policyOps.updatePolicy(params, reply) + udaru.policies.update(params, reply) }, config: { validate: { - params: { - id: Joi.string().required().description('Policy ID') - }, - payload: { - version: Joi.string().required().description('Policy version'), - name: Joi.string().required().description('Policy name'), - statements: swagger.PolicyStatements.required().description('Policy statements') - }, + params: _.pick(udaru.policies.update.validate, ['id']), + payload: _.pick(udaru.policies.update.validate, ['version', 'name', 'statements']), query: { sig: Joi.string().required() }, @@ -117,7 +107,7 @@ exports.register = function (server, options, next) { const { id } = request.params const { organizationId } = request.udaru - policyOps.deletePolicy({ id, organizationId }, function (err, res) { + udaru.policies.delete({ id, organizationId }, function (err, res) { if (err) { return reply(err) } @@ -127,9 +117,7 @@ exports.register = function (server, options, next) { }, config: { validate: { - params: { - id: Joi.string().required().description('Policy ID') - }, + params: _.pick(udaru.policies.delete.validate, ['id']), query: { sig: Joi.string().required() }, diff --git a/src/routes/public/authorization.js b/src/routes/public/authorization.js index 2a796d69..c29f8639 100644 --- a/src/routes/public/authorization.js +++ b/src/routes/public/authorization.js @@ -1,8 +1,9 @@ 'use strict' +const _ = require('lodash') const Joi = require('joi') const Action = require('./../../lib/config/config.auth').Action -const authorize = require('./../../lib/ops/authorizeOps') +const udaru = require('./../../udaru') const headers = require('./../headers') const swagger = require('./../../swagger') @@ -22,7 +23,7 @@ exports.register = function (server, options, next) { organizationId } - authorize.isUserAuthorized(params, reply) + udaru.authorize.isUserAuthorized(params, reply) }, config: { plugins: { @@ -32,11 +33,7 @@ exports.register = function (server, options, next) { } }, validate: { - params: { - userId: Joi.string().required().description('The user that wants to perform the action on a given resource'), - action: Joi.string().required().description('The action to check'), - resource: Joi.string().required().description('The resource that the user wants to perform the action on') - }, + params: _.pick(udaru.authorize.isUserAuthorized.validate, ['userId', 'action', 'resource']), headers }, description: 'Authorize user action against a resource', @@ -58,7 +55,7 @@ exports.register = function (server, options, next) { organizationId } - authorize.listAuthorizations(params, reply) + udaru.authorize.listActions(params, reply) }, config: { plugins: { @@ -68,10 +65,7 @@ exports.register = function (server, options, next) { } }, validate: { - params: { - userId: Joi.string().required().description('The user that wants to perform the action on a given resource'), - resource: Joi.string().required().description('The resource that the user wants to perform the action on') - }, + params: _.pick(udaru.authorize.listActions.validate, ['userId', 'resource']), headers }, description: 'List all the actions a user can perform on a resource', diff --git a/src/routes/public/organizations.js b/src/routes/public/organizations.js index fca47b66..07682bae 100644 --- a/src/routes/public/organizations.js +++ b/src/routes/public/organizations.js @@ -1,7 +1,7 @@ 'use strict' -const Joi = require('joi') -const organizationOps = require('./../../lib/ops/organizationOps') +const _ = require('lodash') +const udaru = require('./../../udaru') const Action = require('./../../lib/config/config.auth').Action const conf = require('./../../lib/config') const swagger = require('./../../swagger') @@ -15,7 +15,7 @@ exports.register = function (server, options, next) { handler: function (request, reply) { const limit = request.query.limit || conf.get('authorization.defaultPageSize') const page = request.query.page || 1 - organizationOps.list({ + udaru.organizations.list({ limit: limit, page: page }, (err, data, total) => { @@ -41,10 +41,7 @@ exports.register = function (server, options, next) { }, validate: { headers, - query: Joi.object({ - page: Joi.number().integer().min(1).description('Page number, starts from 1'), - limit: Joi.number().integer().min(1).description('Items per page') - }).required() + query: udaru.organizations.list.validate }, response: {schema: swagger.List(swagger.Organization).label('PagedOrganizations')} } @@ -54,7 +51,7 @@ exports.register = function (server, options, next) { method: 'GET', path: '/authorization/organizations/{id}', handler: function (request, reply) { - organizationOps.readById(request.params.id, reply) + udaru.organizations.read(request.params.id, reply) }, config: { description: 'Get organization', @@ -68,7 +65,7 @@ exports.register = function (server, options, next) { }, validate: { params: { - id: Joi.string().required().description('Organization ID') + id: udaru.organizations.read.validate }, headers }, @@ -87,7 +84,7 @@ exports.register = function (server, options, next) { user: request.payload.user } - organizationOps.create(params, function (err, res) { + udaru.organizations.create(params, function (err, res) { if (err) { return reply(err) } @@ -97,15 +94,7 @@ exports.register = function (server, options, next) { }, config: { validate: { - payload: { - id: Joi.string().regex(/^[a-zA-Z0-9]{1,64}$/).required().description('Organization ID'), - name: Joi.string().required().description('Organization name'), - description: Joi.string().required().description('Organization description'), - user: Joi.object().keys({ - id: Joi.string().description('User ID'), - name: Joi.string().required().description('User name') - }) - }, + payload: udaru.organizations.create.validate, headers }, description: 'Create an organization', @@ -124,7 +113,7 @@ exports.register = function (server, options, next) { method: 'DELETE', path: '/authorization/organizations/{id}', handler: function (request, reply) { - organizationOps.deleteById(request.params.id, function (err, res) { + udaru.organizations.delete(request.params.id, function (err, res) { if (err) { return reply(err) } @@ -144,7 +133,7 @@ exports.register = function (server, options, next) { }, validate: { params: { - id: Joi.string().required().description('Organization ID') + id: udaru.organizations.delete.validate }, headers } @@ -158,17 +147,12 @@ exports.register = function (server, options, next) { const { id } = request.params const { name, description } = request.payload - organizationOps.update({id, name, description}, reply) + udaru.organizations.update({id, name, description}, reply) }, config: { validate: { - params: { - id: Joi.string().required().description('organization ID') - }, - payload: { - name: Joi.string().required().description('Organization name'), - description: Joi.string().required().description('Organization description') - }, + params: _.pick(udaru.organizations.update.validate, ['id']), + payload: _.pick(udaru.organizations.update.validate, ['name', 'description']), headers }, description: 'Update an organization', diff --git a/src/routes/public/policies.js b/src/routes/public/policies.js index 837e4a46..f0f8161b 100644 --- a/src/routes/public/policies.js +++ b/src/routes/public/policies.js @@ -1,7 +1,7 @@ 'use strict' -const Joi = require('joi') -const policyOps = require('./../../lib/ops/policyOps') +const _ = require('lodash') +const udaru = require('./../../udaru') const Action = require('./../../lib/config/config.auth').Action const conf = require('./../../lib/config') const swagger = require('./../../swagger') @@ -15,7 +15,7 @@ exports.register = function (server, options, next) { const { organizationId } = request.udaru const limit = request.query.limit || conf.get('authorization.defaultPageSize') const page = request.query.page || 1 - policyOps.listByOrganization({ + udaru.policies.list({ organizationId, limit: limit, page: page @@ -42,10 +42,7 @@ exports.register = function (server, options, next) { }, validate: { headers, - query: Joi.object({ - page: Joi.number().integer().min(1).description('Page number, starts from 1'), - limit: Joi.number().integer().min(1).description('Items per page') - }).required() + query: _.pick(udaru.policies.list.validate, ['page', 'limit']) }, response: {schema: swagger.List(swagger.Policy).label('PagedPolicies')} } @@ -58,13 +55,11 @@ exports.register = function (server, options, next) { const { organizationId } = request.udaru const { id } = request.params - policyOps.readPolicy({ id, organizationId }, reply) + udaru.policies.read({ id, organizationId }, reply) }, config: { validate: { - params: { - id: Joi.string().required().description('Policy ID') - }, + params: _.pick(udaru.policies.read.validate, ['id']), headers }, description: 'Fetch all the defined policies', diff --git a/src/routes/public/teams.js b/src/routes/public/teams.js index b7539323..fcb4aff6 100644 --- a/src/routes/public/teams.js +++ b/src/routes/public/teams.js @@ -1,7 +1,8 @@ 'use strict' +const _ = require('lodash') const Joi = require('joi') -const teamOps = require('./../../lib/ops/teamOps') +const udaru = require('./../../udaru') const Action = require('./../../lib/config/config.auth').Action const conf = require('./../../lib/config') const swagger = require('./../../swagger') @@ -16,7 +17,7 @@ exports.register = function (server, options, next) { const { organizationId } = request.udaru const limit = request.query.limit || conf.get('authorization.defaultPageSize') const page = request.query.page || 1 - teamOps.listOrgTeams({ + udaru.teams.list({ organizationId, limit: limit, page: page @@ -43,10 +44,7 @@ exports.register = function (server, options, next) { }, validate: { headers, - query: Joi.object({ - page: Joi.number().integer().min(1).description('Page number, starts from 1'), - limit: Joi.number().integer().min(1).description('Items per page') - }).required() + query: _.pick(udaru.teams.list.validate, ['page', 'limit']) }, response: {schema: swagger.List(swagger.Team).label('PagedTeams')} } @@ -68,7 +66,7 @@ exports.register = function (server, options, next) { user } - teamOps.createTeam(params, function (err, res) { + udaru.teams.create(params, function (err, res) { if (err) { return reply(err) } @@ -78,15 +76,7 @@ exports.register = function (server, options, next) { }, config: { validate: { - payload: { - id: Joi.string().regex(/^[0-9a-zA-Z_]+$/).allow('').description('The ID to be used for the new team. Only alphanumeric characters and underscore are supported'), - name: Joi.string().required().description('Name of the new team'), - description: Joi.string().required().description('Description of new team'), - user: Joi.object().description('Default admin of the team').keys({ - id: Joi.string().description('User ID'), - name: Joi.string().required('User name') - }) - }, + payload: _.pick(udaru.teams.create.validate, ['id', 'name', 'description', 'user']), headers }, description: 'Create a team', @@ -108,13 +98,11 @@ exports.register = function (server, options, next) { const { organizationId } = request.udaru const { id } = request.params - teamOps.readTeam({ id, organizationId }, reply) + udaru.teams.read({ id, organizationId }, reply) }, config: { validate: { - params: { - id: Joi.string().required().description('Team ID') - }, + params: _.pick(udaru.teams.read.validate, ['id']), headers }, description: 'Fetch a team given its identifier', @@ -145,17 +133,12 @@ exports.register = function (server, options, next) { organizationId } - teamOps.updateTeam(params, reply) + udaru.teams.update(params, reply) }, config: { validate: { - params: { - id: Joi.string().required().description('Team ID') - }, - payload: Joi.object().keys({ - name: Joi.string().description('Team name'), - description: Joi.string().description('Team description') - }).or('name', 'description'), + params: _.pick(udaru.teams.update.validate, ['id']), + payload: Joi.object(_.pick(udaru.teams.update.validate, ['name', 'description'])).or('name', 'description'), headers }, description: 'Update a team', @@ -178,7 +161,7 @@ exports.register = function (server, options, next) { const { id } = request.params const { organizationId } = request.udaru - teamOps.deleteTeam({ id, organizationId }, function (err, res) { + udaru.teams.delete({ id, organizationId }, function (err, res) { if (err) { return reply(err) } @@ -188,9 +171,7 @@ exports.register = function (server, options, next) { }, config: { validate: { - params: { - id: Joi.string().required().description('The team ID') - }, + params: _.pick(udaru.teams.delete.validate, ['id']), headers }, description: 'Delete a team', @@ -217,7 +198,7 @@ exports.register = function (server, options, next) { organizationId } - teamOps.moveTeam(params, function (err, res) { + udaru.teams.move(params, function (err, res) { if (err) { return reply(err) } @@ -227,11 +208,9 @@ exports.register = function (server, options, next) { }, config: { validate: { - params: { - id: Joi.string().required().description('Team ID') - }, + params: _.pick(udaru.teams.move.validate, ['id']), payload: { - parentId: Joi.string().required().description('The new parent ID') + parentId: udaru.teams.move.validate.parentId.required() }, headers }, @@ -260,7 +239,7 @@ exports.register = function (server, options, next) { organizationId } - teamOps.moveTeam(params, function (err, res) { + udaru.teams.move(params, function (err, res) { if (err) { return reply(err) } @@ -270,9 +249,7 @@ exports.register = function (server, options, next) { }, config: { validate: { - params: { - id: Joi.string().required().description('Team ID') - }, + params: _.pick(udaru.teams.move.validate, ['id']), headers }, description: 'Unnest a team', @@ -301,16 +278,12 @@ exports.register = function (server, options, next) { organizationId, policies } - teamOps.addTeamPolicies(params, reply) + udaru.teams.addPolicies(params, reply) }, config: { validate: { - params: { - id: Joi.string().required().description('Team ID') - }, - payload: { - policies: Joi.array().items(Joi.string()).required().description('Policy IDs') - }, + params: _.pick(udaru.teams.addPolicies.validate, ['id']), + payload: _.pick(udaru.teams.addPolicies.validate, ['policies']), headers }, description: 'Add one or more policies to a team', @@ -340,16 +313,12 @@ exports.register = function (server, options, next) { policies } - teamOps.replaceTeamPolicies(params, reply) + udaru.teams.replacePolicies(params, reply) }, config: { validate: { - params: { - id: Joi.string().required().description('Team ID') - }, - payload: { - policies: Joi.array().items(Joi.string()).required().description('Policy IDs') - }, + params: _.pick(udaru.teams.replacePolicies.validate, ['id']), + payload: _.pick(udaru.teams.replacePolicies.validate, ['policies']), headers }, description: 'Clear and replace policies for a team', @@ -372,7 +341,7 @@ exports.register = function (server, options, next) { const { id } = request.params const { organizationId } = request.udaru - teamOps.deleteTeamPolicies({ id, organizationId }, function (err, res) { + udaru.teams.deletePolicies({ id, organizationId }, function (err, res) { if (err) { return reply(err) } @@ -382,9 +351,7 @@ exports.register = function (server, options, next) { }, config: { validate: { - params: { - id: Joi.string().required().description('Team ID') - }, + params: _.pick(udaru.teams.deletePolicies.validate, ['id']), headers }, description: 'Clear all team policies', @@ -406,7 +373,7 @@ exports.register = function (server, options, next) { const { teamId, policyId } = request.params const { organizationId } = request.udaru - teamOps.deleteTeamPolicy({ teamId, policyId, organizationId }, function (err, res) { + udaru.teams.deletePolicy({ teamId, policyId, organizationId }, function (err, res) { if (err) { return reply(err) } @@ -416,10 +383,7 @@ exports.register = function (server, options, next) { }, config: { validate: { - params: { - teamId: Joi.string().required().description('Team ID'), - policyId: Joi.string().required().description('Policy ID') - }, + params: _.pick(udaru.teams.deletePolicy.validate, ['teamId', 'policyId']), headers }, description: 'Remove a team policy', @@ -439,20 +403,16 @@ exports.register = function (server, options, next) { path: '/authorization/teams/{id}/users', handler: function (request, reply) { const { id } = request.params + const { organizationId } = request.udaru const limit = request.query.limit || conf.get('authorization.defaultPageSize') const page = request.query.page || 1 - teamOps.readTeamUsers({ id, page, limit }, reply) + udaru.teams.listUsers({ id, page, limit, organizationId }, reply) }, config: { validate: { - params: { - id: Joi.string().required().description('Team ID') - }, - query: { - page: Joi.number().integer().min(1).required().description('Page number, starts from 1'), - limit: Joi.number().integer().min(1).required().description('Users per page') - }, + params: _.pick(udaru.teams.listUsers.validate, ['id']), + query: _.pick(udaru.teams.listUsers.validate, ['page', 'limit']), headers }, description: 'Fetch team users given its identifier', @@ -482,16 +442,12 @@ exports.register = function (server, options, next) { organizationId } - teamOps.addUsersToTeam(params, reply) + udaru.teams.addUsers(params, reply) }, config: { validate: { - params: { - id: Joi.string().required().description('The team ID') - }, - payload: Joi.object().keys({ - users: Joi.array().items(Joi.string()).description('User IDs') - }), + params: _.pick(udaru.teams.addUsers.validate, ['id']), + payload: _.pick(udaru.teams.addUsers.validate, ['users']), headers }, description: 'Add team users', @@ -521,16 +477,12 @@ exports.register = function (server, options, next) { organizationId } - teamOps.replaceUsersInTeam(params, reply) + udaru.teams.replaceUsers(params, reply) }, config: { validate: { - params: { - id: Joi.string().required().description('Team ID') - }, - payload: Joi.object().keys({ - users: Joi.array().items(Joi.string()).description('User IDs') - }), + params: _.pick(udaru.teams.replaceUsers.validate, ['id']), + payload: _.pick(udaru.teams.replaceUsers.validate, ['users']), headers }, description: 'Replace team users with the given ones', @@ -553,7 +505,7 @@ exports.register = function (server, options, next) { const { id } = request.params const { organizationId } = request.udaru - teamOps.deleteTeamMembers({ id, organizationId }, function (err, res) { + udaru.teams.deleteMembers({ id, organizationId }, function (err, res) { if (err) { return reply(err) } @@ -563,9 +515,7 @@ exports.register = function (server, options, next) { }, config: { validate: { - params: { - id: Joi.string().required().description('Team ID') - }, + params: _.pick(udaru.teams.deleteMembers.validate, ['id']), headers }, description: 'Delete all team users', @@ -587,7 +537,7 @@ exports.register = function (server, options, next) { const { id, userId } = request.params const { organizationId } = request.udaru - teamOps.deleteTeamMember({ id, userId, organizationId }, function (err, res) { + udaru.teams.deleteMember({ id, userId, organizationId }, function (err, res) { if (err) { return reply(err) } @@ -597,10 +547,7 @@ exports.register = function (server, options, next) { }, config: { validate: { - params: { - id: Joi.string().required().description('The team ID'), - userId: Joi.string().required().description('The user ID') - }, + params: _.pick(udaru.teams.deleteMember.validate, ['id', 'userId']), headers }, description: 'Delete one team member', diff --git a/src/routes/public/users.js b/src/routes/public/users.js index 44454d3b..f28a8975 100644 --- a/src/routes/public/users.js +++ b/src/routes/public/users.js @@ -1,14 +1,13 @@ 'use strict' -const Joi = require('joi') -const userOps = require('./../../lib/ops/userOps') +const _ = require('lodash') +const udaru = require('./../../udaru') const Action = require('./../../lib/config/config.auth').Action const conf = require('./../../lib/config') const swagger = require('./../../swagger') const headers = require('./../headers') exports.register = function (server, options, next) { - server.route({ method: 'GET', path: '/authorization/users', @@ -17,7 +16,7 @@ exports.register = function (server, options, next) { const limit = request.query.limit || conf.get('authorization.defaultPageSize') const page = request.query.page || 1 - userOps.listOrgUsers({organizationId, limit, page}, (err, data, total) => { + udaru.users.list({organizationId, limit, page}, (err, data, total) => { reply( err, err ? null : { @@ -40,10 +39,7 @@ exports.register = function (server, options, next) { }, validate: { headers, - query: Joi.object({ - page: Joi.number().integer().min(1).description('Page number, starts from 1'), - limit: Joi.number().integer().min(1).description('Users per page') - }).required() + query: _.pick(udaru.users.list.validate, ['page', 'limit']) }, response: {schema: swagger.List(swagger.User).label('PagedUsers')} } @@ -56,13 +52,11 @@ exports.register = function (server, options, next) { const { organizationId } = request.udaru const id = request.params.id - userOps.readUser({ id, organizationId }, reply) + udaru.users.read({ id, organizationId }, reply) }, config: { validate: { - params: { - id: Joi.string().required().description('User ID') - }, + params: _.pick(udaru.users.read.validate, ['id']), headers }, description: 'Fetch a user given its identifier', @@ -85,7 +79,7 @@ exports.register = function (server, options, next) { const { organizationId } = request.udaru const { id, name } = request.payload - userOps.createUser({ id, name, organizationId }, function (err, res) { + udaru.users.create({ id, name, organizationId }, function (err, res) { if (err) { return reply(err) } @@ -95,10 +89,7 @@ exports.register = function (server, options, next) { }, config: { validate: { - payload: { - id: Joi.string().description('User ID'), - name: Joi.string().required().description('User name') - }, + payload: _.pick(udaru.users.create.validate, ['id', 'name']), headers }, description: 'Create a new user', @@ -120,7 +111,7 @@ exports.register = function (server, options, next) { const { organizationId } = request.udaru const id = request.params.id - userOps.deleteUser({ id, organizationId }, function (err, res) { + udaru.users.delete({ id, organizationId }, function (err, res) { if (err) { return reply(err) } @@ -130,9 +121,7 @@ exports.register = function (server, options, next) { }, config: { validate: { - params: { - id: Joi.string().required().description('user ID') - }, + params: _.pick(udaru.users.delete.validate, ['id']), headers }, description: 'Delete a user', @@ -160,16 +149,12 @@ exports.register = function (server, options, next) { organizationId, name } - userOps.updateUser(params, reply) + udaru.users.update(params, reply) }, config: { validate: { - params: { - id: Joi.string().required().description('user ID') - }, - payload: { - name: Joi.string().required().description('user name') - }, + params: _.pick(udaru.users.update.validate, ['id']), + payload: _.pick(udaru.users.update.validate, ['name']), headers }, description: 'Update a user', @@ -198,16 +183,12 @@ exports.register = function (server, options, next) { organizationId, policies } - userOps.addUserPolicies(params, reply) + udaru.users.addPolicies(params, reply) }, config: { validate: { - params: { - id: Joi.string().required().description('User ID') - }, - payload: { - policies: Joi.array().required().items(Joi.string().required()) - }, + params: _.pick(udaru.users.addPolicies.validate, ['id']), + payload: _.pick(udaru.users.addPolicies.validate, ['policies']), headers }, description: 'Add one or more policies to a user', @@ -237,16 +218,12 @@ exports.register = function (server, options, next) { policies } - userOps.replaceUserPolicies(params, reply) + udaru.users.replacePolicies(params, reply) }, config: { validate: { - params: { - id: Joi.string().required().description('User ID') - }, - payload: { - policies: Joi.array().required().items(Joi.string().required()) - }, + params: _.pick(udaru.users.replacePolicies.validate, ['id']), + payload: _.pick(udaru.users.replacePolicies.validate, ['policies']), headers }, description: 'Clear and replace policies for a user', @@ -269,7 +246,7 @@ exports.register = function (server, options, next) { const { id } = request.params const { organizationId } = request.udaru - userOps.deleteUserPolicies({ id, organizationId }, function (err, res) { + udaru.users.deletePolicies({ id, organizationId }, function (err, res) { if (err) { return reply(err) } @@ -279,9 +256,7 @@ exports.register = function (server, options, next) { }, config: { validate: { - params: { - id: Joi.string().required().description('User ID') - }, + params: _.pick(udaru.users.deletePolicies.validate, ['id']), headers }, description: 'Clear all user\'s policies', @@ -303,7 +278,7 @@ exports.register = function (server, options, next) { const { userId, policyId } = request.params const { organizationId } = request.udaru - userOps.deleteUserPolicy({ userId, policyId, organizationId }, function (err, res) { + udaru.users.deletePolicy({ userId, policyId, organizationId }, function (err, res) { if (err) { return reply(err) } @@ -313,10 +288,7 @@ exports.register = function (server, options, next) { }, config: { validate: { - params: { - userId: Joi.string().required().description('User ID'), - policyId: Joi.string().required().description('Policy ID') - }, + params: _.pick(udaru.users.deletePolicy.validate, ['userId', 'policyId']), headers }, description: 'Remove a user\'s policy', diff --git a/src/security/hapi-auth-validation.js b/src/security/hapi-auth-validation.js index 445805a4..ba2298e0 100644 --- a/src/security/hapi-auth-validation.js +++ b/src/security/hapi-auth-validation.js @@ -38,8 +38,8 @@ function impersonate (job, next) { next() } -function checkAuthorization (userId, action, resource, done) { - const params = { userId, action, resource } +function checkAuthorization (userId, action, organizationId, resource, done) { + const params = { userId, action, organizationId, resource } authorizeOps.isUserAuthorized(params, (err, result) => { if (err) return done(err) @@ -99,8 +99,9 @@ function authorize (job, next) { const action = job.authParams.action const userId = job.currentUser.id + const organizationId = job.organizationId - async.any(resources, async.apply(checkAuthorization, userId, action), (err, valid) => { + async.any(resources, async.apply(checkAuthorization, userId, action, organizationId), (err, valid) => { if (err) return next(Boom.forbidden('Invalid credentials', 'udaru')) if (!valid) return next(Boom.forbidden('Invalid credentials', 'udaru')) diff --git a/src/swagger.js b/src/swagger.js index dd7029b0..ea665ba3 100644 --- a/src/swagger.js +++ b/src/swagger.js @@ -69,7 +69,7 @@ const List = (data) => { return Joi.object({ page: Joi.number().integer().min(1).description('Page number, starts from 1'), limit: Joi.number().integer().min(1).description('Items per page'), - total: Joi.number().integer().positive().description('Total number of entries matched by the query'), + total: Joi.number().integer().description('Total number of entries matched by the query'), data: Joi.array().items(data).label('Data') }).label('DataList') } diff --git a/src/udaru.js b/src/udaru.js new file mode 100644 index 00000000..83154eb8 --- /dev/null +++ b/src/udaru.js @@ -0,0 +1,60 @@ +'use strict' + +const userOps = require('./lib/ops/userOps') +const organizationOps = require('./lib/ops/organizationOps') +const authorizeOps = require('./lib/ops/authorizeOps') +const teamOps = require('./lib/ops/teamOps') +const policyOps = require('./lib/ops/policyOps') + +module.exports = { + authorize: { + isUserAuthorized: authorizeOps.isUserAuthorized, + listActions: authorizeOps.listAuthorizations + }, + + organizations: { + list: organizationOps.list, + create: organizationOps.create, + read: organizationOps.readById, + delete: organizationOps.deleteById, + update: organizationOps.update + }, + + policies: { + list: policyOps.listByOrganization, + read: policyOps.readPolicy, + create: policyOps.createPolicy, + update: policyOps.updatePolicy, + delete: policyOps.deletePolicy + }, + + teams: { + list: teamOps.listOrgTeams, + create: teamOps.createTeam, + read: teamOps.readTeam, + update: teamOps.updateTeam, + delete: teamOps.deleteTeam, + move: teamOps.moveTeam, + listUsers: teamOps.readTeamUsers, + replacePolicies: teamOps.replaceTeamPolicies, + addPolicies: teamOps.addTeamPolicies, + deletePolicies: teamOps.deleteTeamPolicies, + deletePolicy: teamOps.deleteTeamPolicy, + addUsers: teamOps.addUsersToTeam, + replaceUsers: teamOps.replaceUsersInTeam, + deleteMembers: teamOps.deleteTeamMembers, + deleteMember: teamOps.deleteTeamMember + }, + + users: { + list: userOps.listOrgUsers, + create: userOps.createUser, + read: userOps.readUser, + update: userOps.updateUser, + delete: userOps.deleteUser, + replacePolicies: userOps.replaceUserPolicies, + addPolicies: userOps.addUserPolicies, + deletePolicies: userOps.deleteUserPolicies, + deletePolicy: userOps.deleteUserPolicy + } +} diff --git a/test/endToEnd/authorization/usersTest.js b/test/endToEnd/authorization/usersTest.js index c5177007..196a0aec 100644 --- a/test/endToEnd/authorization/usersTest.js +++ b/test/endToEnd/authorization/usersTest.js @@ -29,7 +29,7 @@ lab.experiment('Routes Authorizations', () => { const records = Factory(lab, { teams: { - calledTeam: { name: 'called team', organizationId, users: ['called'] } + calledTeam: { name: 'called team', description: 'desc', organizationId, users: ['called'] } }, users: { caller: { name: 'caller', organizationId, policies: ['testedPolicy'] }, @@ -101,7 +101,7 @@ lab.experiment('Routes Authorizations', () => { const records = Factory(lab, { teams: { - calledTeam: { name: 'called team', organizationId, users: ['called'] } + calledTeam: { name: 'called team', description: 'desc', organizationId, users: ['called'] } }, users: { caller: { name: 'caller', organizationId, policies: ['testedPolicy'] }, @@ -164,7 +164,7 @@ lab.experiment('Routes Authorizations', () => { const records = Factory(lab, { teams: { - calledTeam: { name: 'called team', organizationId } + calledTeam: { name: 'called team', description: 'desc', organizationId } }, users: { caller: { name: 'caller', organizationId, policies: ['testedPolicy'] } @@ -229,7 +229,7 @@ lab.experiment('Routes Authorizations', () => { const records = Factory(lab, { teams: { - calledTeam: { name: 'called team', organizationId, users: ['called'] } + calledTeam: { name: 'called team', description: 'desc', organizationId, users: ['called'] } }, users: { caller: { name: 'caller', organizationId, policies: ['testedPolicy'] }, @@ -306,7 +306,7 @@ lab.experiment('Routes Authorizations', () => { const records = Factory(lab, { teams: { - calledTeam: { name: 'called team', organizationId, users: ['called'] } + calledTeam: { name: 'called team', description: 'desc', organizationId, users: ['called'] } }, users: { caller: { name: 'caller', organizationId, policies: ['testedPolicy'] }, @@ -380,7 +380,7 @@ lab.experiment('Routes Authorizations', () => { const records = Factory(lab, { teams: { - calledTeam: { name: 'called team', organizationId, users: ['called'] } + calledTeam: { name: 'called team', description: 'desc', organizationId, users: ['called'] } }, users: { caller: { name: 'caller', organizationId, policies: ['testedPolicy'] }, @@ -466,7 +466,7 @@ lab.experiment('Routes Authorizations', () => { const records = Factory(lab, { teams: { - calledTeam: { name: 'called team', organizationId, users: ['called'] } + calledTeam: { name: 'called team', description: 'desc', organizationId, users: ['called'] } }, users: { caller: { name: 'caller', organizationId, policies: ['testedPolicy'] }, @@ -552,7 +552,7 @@ lab.experiment('Routes Authorizations', () => { const records = Factory(lab, { teams: { - calledTeam: { name: 'called team', organizationId, users: ['called'] } + calledTeam: { name: 'called team', description: 'desc', organizationId, users: ['called'] } }, users: { caller: { name: 'caller', organizationId, policies: ['testedPolicy'] }, @@ -637,7 +637,7 @@ lab.experiment('Routes Authorizations', () => { const records = Factory(lab, { teams: { - calledTeam: { name: 'called team', organizationId, users: ['called'] } + calledTeam: { name: 'called team', description: 'desc', organizationId, users: ['called'] } }, users: { caller: { name: 'caller', organizationId, policies: ['testedPolicy'] }, diff --git a/test/endToEnd/authorizationTest.js b/test/endToEnd/authorizationTest.js index 0f4f4367..722d87dc 100644 --- a/test/endToEnd/authorizationTest.js +++ b/test/endToEnd/authorizationTest.js @@ -15,6 +15,7 @@ lab.experiment('Authorization', () => { server.inject(options, (response) => { const result = response.result + expect(response.statusCode).to.equal(200) expect(result).to.equal({ access: true }) diff --git a/test/endToEnd/teamsTest.js b/test/endToEnd/teamsTest.js index 70a5584c..65872828 100644 --- a/test/endToEnd/teamsTest.js +++ b/test/endToEnd/teamsTest.js @@ -18,7 +18,7 @@ const teamData = { lab.experiment('Teams - get/list', () => { - lab.test('get team list: pagination params are required', (done) => { + lab.test('get team list: with pagination params', (done) => { const options = utils.requestOptions({ method: 'GET', url: '/authorization/teams' @@ -32,6 +32,24 @@ lab.experiment('Teams - get/list', () => { }) }) + lab.test('get teams list from organization with no team', (done) => { + const options = utils.requestOptions({ + method: 'GET', + url: '/authorization/teams', + headers: { + authorization: 'ROOTid' + } + }) + + server.inject(options, (response) => { + expect(response.statusCode).to.equal(200) + expect(response.result.page).to.equal(1) + expect(response.result.limit).greaterThan(1) + expect(response.result.total).equal(0) + done() + }) + }) + lab.test('get team list: page 1', (done) => { const options = utils.requestOptions({ method: 'GET', @@ -799,7 +817,7 @@ lab.experiment('Teams - manage policies', () => { server.inject(options, (response) => { expect(response.statusCode).to.equal(204) - teamOps.replaceTeamPolicies({ id: 1, policies: ['policyId1'], organizationId: 'WONKA' }, done) + teamOps.replaceTeamPolicies({ id: '1', policies: ['policyId1'], organizationId: 'WONKA' }, done) }) }) diff --git a/test/endToEnd/usersTest.js b/test/endToEnd/usersTest.js index 20784a5b..5548f9b9 100644 --- a/test/endToEnd/usersTest.js +++ b/test/endToEnd/usersTest.js @@ -42,7 +42,7 @@ lab.experiment('Users: read - delete - update', () => { lab.test('get user list', (done) => { const options = utils.requestOptions({ method: 'GET', - url: '/authorization/users?page=1&limit=123' + url: '/authorization/users?page=1&limit=3' }) server.inject(options, (response) => { @@ -51,7 +51,8 @@ lab.experiment('Users: read - delete - update', () => { expect(response.statusCode).to.equal(200) expect(result.total).to.equal(7) expect(result.page).to.equal(1) - expect(result.limit).to.equal(123) + expect(result.limit).to.equal(3) + expect(result.data.length).to.equal(3) expect(result.data[0]).to.equal({ id: 'AugustusId', name: 'Augustus Gloop', @@ -424,7 +425,7 @@ lab.experiment('Users - checking org_id scoping', () => { if (err) return done(err) const policyData = { - version: 1, + version: '1', name: 'Documents Admin', organizationId: 'NEWORG', statements diff --git a/test/lib/integration/authorizeOpsTest.js b/test/lib/integration/authorizeOpsTest.js index 70ee89c6..7bdbf3ee 100644 --- a/test/lib/integration/authorizeOpsTest.js +++ b/test/lib/integration/authorizeOpsTest.js @@ -71,7 +71,7 @@ lab.experiment('AuthorizeOps', () => { }) lab.test('check authorization should return access true for allowed', (done) => { - authorize.isUserAuthorized({ userId: testUserId, resource: 'database:pg01:balancesheet', action: 'finance:ReadBalanceSheet' }, (err, result) => { + authorize.isUserAuthorized({ userId: testUserId, resource: 'database:pg01:balancesheet', action: 'finance:ReadBalanceSheet', organizationId }, (err, result) => { if (err) return done(err) expect(err).to.not.exist() @@ -87,7 +87,7 @@ lab.experiment('AuthorizeOps', () => { userOps.replaceUserPolicies({ id: testUserId, policies: ['policyId5'], organizationId }, (err, result) => { if (err) return done(err) - authorize.isUserAuthorized({ userId: testUserId, resource: 'database:pg01:balancesheet', action: 'database:dropTable' }, (err, result) => { + authorize.isUserAuthorized({ userId: testUserId, resource: 'database:pg01:balancesheet', action: 'database:dropTable', organizationId }, (err, result) => { if (err) return done(err) expect(err).to.not.exist() @@ -104,7 +104,7 @@ lab.experiment('AuthorizeOps', () => { userOps.replaceUserPolicies({ id: testUserId, policies: ['policyId6'], organizationId }, (err, result) => { if (err) return done(err) - authorize.isUserAuthorized({ userId: testUserId, resource: 'database:pg01:balancesheet', action: 'database:Read' }, (err, result) => { + authorize.isUserAuthorized({ userId: testUserId, resource: 'database:pg01:balancesheet', action: 'database:Read', organizationId }, (err, result) => { if (err) return done(err) expect(err).to.not.exist() @@ -120,7 +120,7 @@ lab.experiment('AuthorizeOps', () => { userOps.replaceUserPolicies({ id: testUserId, policies: ['policyId7'], organizationId }, (err, result) => { if (err) return done(err) - authorize.isUserAuthorized({ userId: testUserId, resource: 'database:pg01:balancesheet', action: 'database:Delete' }, (err, result) => { + authorize.isUserAuthorized({ userId: testUserId, resource: 'database:pg01:balancesheet', action: 'database:Delete', organizationId }, (err, result) => { if (err) return done(err) expect(err).to.not.exist() @@ -136,7 +136,7 @@ lab.experiment('AuthorizeOps', () => { userOps.replaceUserPolicies({ id: testUserId, policies: ['policyId8'], organizationId }, (err, result) => { if (err) return done(err) - authorize.isUserAuthorized({ userId: testUserId, resource: '/my/site/i/should/read/this', action: 'Read' }, (err, result) => { + authorize.isUserAuthorized({ userId: testUserId, resource: '/my/site/i/should/read/this', action: 'Read', organizationId }, (err, result) => { if (err) return done(err) expect(err).to.not.exist() @@ -152,7 +152,7 @@ lab.experiment('AuthorizeOps', () => { userOps.replaceUserPolicies({ id: testUserId, policies: ['policyId6'], organizationId }, (err, result) => { if (err) return done(err) - authorize.isUserAuthorized({ userId: testUserId, resource: 'database:pg01:balancesheet', action: 'database:Write' }, (err, result) => { + authorize.isUserAuthorized({ userId: testUserId, resource: 'database:pg01:balancesheet', action: 'database:Write', organizationId }, (err, result) => { if (err) return done(err) expect(err).to.not.exist() @@ -168,7 +168,7 @@ lab.experiment('AuthorizeOps', () => { userOps.replaceUserPolicies({ id: testUserId, policies: ['policyId6'], organizationId }, (err, result) => { if (err) return done(err) - authorize.isUserAuthorized({ userId: testUserId, resource: 'database:pg01:notMyTable', action: 'database:Write' }, (err, result) => { + authorize.isUserAuthorized({ userId: testUserId, resource: 'database:pg01:notMyTable', action: 'database:Write', organizationId }, (err, result) => { if (err) return done(err) expect(err).to.not.exist() @@ -191,7 +191,7 @@ lab.experiment('AuthorizeOps', () => { testUtils.deleteUserFromAllTeams(testUserId, cb) }) tasks.push((result, cb) => { - userOps.replaceUserPolicies({ id: testUserId, policies: [], organizationId }, cb) + userOps.deleteUserPolicies({ id: testUserId, organizationId }, cb) }) tasks.push((result, cb) => { @@ -219,7 +219,8 @@ lab.experiment('AuthorizeOps', () => { tasks.push((result, cb) => { authorize.listAuthorizations({ userId: testUserId, - resource: 'database:pg01:balancesheet' + resource: 'database:pg01:balancesheet', + organizationId }, (err, result) => { expect(err).to.not.exist() expect(result).to.exist() @@ -242,7 +243,8 @@ lab.experiment('AuthorizeOps', () => { tasks.push((result, cb) => { authorize.listAuthorizations({ userId: testUserId, - resource: 'database:pg01:balancesheet' + resource: 'database:pg01:balancesheet', + organizationId }, (err, result) => { expect(err).to.not.exist() expect(result).to.exist() @@ -267,7 +269,8 @@ lab.experiment('AuthorizeOps', () => { tasks.push((result, cb) => { authorize.listAuthorizations({ userId: testUserId, - resource: 'database:pg01:balancesheet' + resource: 'database:pg01:balancesheet', + organizationId }, (err, result) => { expect(err).to.not.exist() expect(result).to.exist() @@ -292,7 +295,8 @@ lab.experiment('AuthorizeOps', () => { tasks.push((result, cb) => { authorize.listAuthorizations({ userId: testUserId, - resource: 'database:pg01:balancesheet' + resource: 'database:pg01:balancesheet', + organizationId }, (err, result) => { expect(err).to.not.exist() expect(result).to.exist() diff --git a/test/lib/integration/organizationOpsTest.js b/test/lib/integration/organizationOpsTest.js index 6dfda951..10c8079f 100644 --- a/test/lib/integration/organizationOpsTest.js +++ b/test/lib/integration/organizationOpsTest.js @@ -186,7 +186,7 @@ lab.experiment('OrganizationOps', () => { }) lab.test('get a specific organization that does not exist', (done) => { - organizationOps.readById(['I_do_not_exist'], (err, result) => { + organizationOps.readById('I_do_not_exist', (err, result) => { expect(err).to.exist() expect(err.output.statusCode).to.equal(404) expect(result).to.not.exist() diff --git a/test/lib/integration/policyOpsTest.js b/test/lib/integration/policyOpsTest.js index f1a582ec..8df27af7 100644 --- a/test/lib/integration/policyOpsTest.js +++ b/test/lib/integration/policyOpsTest.js @@ -41,7 +41,7 @@ lab.experiment('PolicyOps', () => { lab.test('create, update and delete a policy', (done) => { const policyData = { - version: 1, + version: '1', name: 'Documents Admin', organizationId: 'WONKA', statements @@ -60,7 +60,7 @@ lab.experiment('PolicyOps', () => { const updateData = { id: policyId, organizationId: 'WONKA', - version: 2, + version: '2', name: 'Documents Admin v2', statements: { Statement: [{ Effect: 'Deny', Action: ['documents:Read'], Resource: ['wonka:documents:/public/*'] }] } } @@ -81,7 +81,7 @@ lab.experiment('PolicyOps', () => { lab.test('create policy with specific id', (done) => { const policyData = { id: 'MySpecialId', - version: 1, + version: '1', name: 'Documents Admin', organizationId: 'WONKA', statements diff --git a/test/lib/integration/teamOpsTest.js b/test/lib/integration/teamOpsTest.js index 97f2cadd..6e1c7d8c 100644 --- a/test/lib/integration/teamOpsTest.js +++ b/test/lib/integration/teamOpsTest.js @@ -31,7 +31,7 @@ lab.experiment('TeamOps', () => { users = fetchedUsers policyOps.createPolicy({ - version: 1, + version: '1', name: randomId(), organizationId: 'WONKA', statements @@ -41,7 +41,7 @@ lab.experiment('TeamOps', () => { policies.push(createdPolicy) policyOps.createPolicy({ - version: 1, + version: '1', name: randomId(), organizationId: 'WONKA', statements @@ -52,7 +52,7 @@ lab.experiment('TeamOps', () => { policyOps.createPolicy({ id: 'testPolicyId-1234', - version: 1, + version: '1', name: randomId(), organizationId: 'ROOT', statements @@ -185,7 +185,7 @@ lab.experiment('TeamOps', () => { }) lab.test('read users from a specific team', (done) => { - teamOps.readTeamUsers({ id: '2' }, (err, result) => { + teamOps.readTeamUsers({ id: '2', organizationId: 'WONKA' }, (err, result) => { expect(err).to.not.exist() expect(result).to.exist() expect(result.page).to.equal(1) @@ -202,7 +202,7 @@ lab.experiment('TeamOps', () => { }) lab.test('paginated read users from a specific team', (done) => { - teamOps.readTeamUsers({ id: '2', page: 2, limit: 1 }, (err, result) => { + teamOps.readTeamUsers({ id: '2', page: 2, limit: 1, organizationId: 'WONKA' }, (err, result) => { expect(err).to.not.exist() expect(result).to.exist() expect(result.page).to.equal(2) diff --git a/test/routes/public/authorizationTest.js b/test/routes/public/authorizationTest.js index 0d7dcb07..7f9a2e8c 100644 --- a/test/routes/public/authorizationTest.js +++ b/test/routes/public/authorizationTest.js @@ -7,17 +7,19 @@ const Boom = require('boom') var proxyquire = require('proxyquire') var utils = require('./../../utils') -var authorizeMock = {} -var authRoutes = proxyquire('./../../../src/routes/public/authorization', { './../../lib/ops/authorizeOps': authorizeMock }) +var udaru = {} +var authRoutes = proxyquire('./../../../src/routes/public/authorization', { './../../udaru': udaru }) var server = proxyquire('./../../../src/wiring-hapi', { './routes/public/authorization': authRoutes }) lab.experiment('Authorization', () => { lab.test('check authorization should return 500 for error case', (done) => { - authorizeMock.isUserAuthorized = (params, cb) => { - process.nextTick(() => { - cb(Boom.badImplementation()) - }) + udaru.authorize = { + isUserAuthorized: (params, cb) => { + process.nextTick(() => { + cb(Boom.badImplementation()) + }) + } } const options = utils.requestOptions({ @@ -35,10 +37,12 @@ lab.experiment('Authorization', () => { }) lab.test('list authorizations should return 500 for error case', (done) => { - authorizeMock.listAuthorizations = (params, cb) => { - process.nextTick(() => { - cb(Boom.badImplementation()) - }) + udaru.authorize = { + listActions: (params, cb) => { + process.nextTick(() => { + cb(Boom.badImplementation()) + }) + } } const options = utils.requestOptions({ diff --git a/test/routes/public/policiesTest.js b/test/routes/public/policiesTest.js index 550ff604..bb1ab79b 100644 --- a/test/routes/public/policiesTest.js +++ b/test/routes/public/policiesTest.js @@ -7,19 +7,21 @@ const Boom = require('boom') var proxyquire = require('proxyquire') var utils = require('./../../utils') -var policyOps = {} -var policiesRoutes = proxyquire('./../../../src/routes/public/policies', { './../../lib/ops/policyOps': policyOps }) +var udaru = {} +var policiesRoutes = proxyquire('./../../../src/routes/public/policies', { './../../udaru': udaru }) var server = proxyquire('./../../../src/wiring-hapi', { './routes/public/policies': policiesRoutes }) lab.experiment('Policies', () => { lab.test('get policy list should return error for error case', (done) => { - policyOps.listByOrganization = (params, cb) => { - expect(params).to.equal({ organizationId: 'WONKA', limit: 10, page: 1 }) - setImmediate(() => { - cb(Boom.badImplementation()) - }) + udaru.policies = { + list: (params, cb) => { + expect(params).to.equal({ organizationId: 'WONKA', limit: 10, page: 1 }) + setImmediate(() => { + cb(Boom.badImplementation()) + }) + } } const options = utils.requestOptions({ @@ -38,11 +40,13 @@ lab.experiment('Policies', () => { }) lab.test('get single policy should return error for error case', (done) => { - policyOps.readPolicy = (params, cb) => { - expect(params).to.equal({ id: '99', organizationId: 'WONKA' }) - process.nextTick(() => { - cb(Boom.badImplementation()) - }) + udaru.policies = { + read: (params, cb) => { + expect(params).to.equal({ id: '99', organizationId: 'WONKA' }) + process.nextTick(() => { + cb(Boom.badImplementation()) + }) + } } const options = utils.requestOptions({ diff --git a/test/routes/public/teamsTest.js b/test/routes/public/teamsTest.js index 055e4f99..d18c6d0d 100644 --- a/test/routes/public/teamsTest.js +++ b/test/routes/public/teamsTest.js @@ -7,18 +7,20 @@ const Boom = require('boom') var proxyquire = require('proxyquire') var utils = require('./../../utils') -var teamOps = {} -var teamsRoutes = proxyquire('./../../../src/routes/public/teams', { './../../lib/ops/teamOps': teamOps }) +var udaru = {} +var teamsRoutes = proxyquire('./../../../src/routes/public/teams', { './../../udaru': udaru }) var server = proxyquire('./../../../src/wiring-hapi', { './routes/public/teams': teamsRoutes }) lab.experiment('Teams', () => { lab.test('get team list should return error for error case', (done) => { - teamOps.listOrgTeams = (params, cb) => { - expect(params).to.equal({ organizationId: 'WONKA', limit: 1, page: 1 }) - process.nextTick(() => { - cb(Boom.badImplementation()) - }) + udaru.teams = { + list: (params, cb) => { + expect(params).to.equal({ organizationId: 'WONKA', limit: 1, page: 1 }) + process.nextTick(() => { + cb(Boom.badImplementation()) + }) + } } const options = utils.requestOptions({ @@ -38,10 +40,12 @@ lab.experiment('Teams', () => { lab.test('create new team should return error for error case', (done) => { - teamOps.createTeam = (params, cb) => { - process.nextTick(() => { - cb(Boom.badImplementation()) - }) + udaru.teams = { + create: (params, cb) => { + process.nextTick(() => { + cb(Boom.badImplementation()) + }) + } } const options = utils.requestOptions({ @@ -64,16 +68,18 @@ lab.experiment('Teams', () => { }) lab.test('update team should return error for error case', (done) => { - teamOps.updateTeam = (params, cb) => { - expect(params).to.equal({ - id: '2', - name: 'Team D', - description: 'Can Team C become Team D?', - organizationId: 'WONKA' - }) - process.nextTick(() => { - cb(Boom.badImplementation()) - }) + udaru.teams = { + update: (params, cb) => { + expect(params).to.equal({ + id: '2', + name: 'Team D', + description: 'Can Team C become Team D?', + organizationId: 'WONKA' + }) + process.nextTick(() => { + cb(Boom.badImplementation()) + }) + } } const options = utils.requestOptions({ @@ -96,11 +102,13 @@ lab.experiment('Teams', () => { }) lab.test('delete team should return error for error case', (done) => { - teamOps.deleteTeam = (params, cb) => { - expect(params).to.equal({ id: '1', organizationId: 'WONKA' }) - process.nextTick(() => { - cb(Boom.badImplementation()) - }) + udaru.teams = { + delete: (params, cb) => { + expect(params).to.equal({ id: '1', organizationId: 'WONKA' }) + process.nextTick(() => { + cb(Boom.badImplementation()) + }) + } } const options = utils.requestOptions({ diff --git a/test/routes/public/usersTest.js b/test/routes/public/usersTest.js index 7890d5c1..64be3cc9 100644 --- a/test/routes/public/usersTest.js +++ b/test/routes/public/usersTest.js @@ -7,18 +7,20 @@ const Boom = require('boom') var proxyquire = require('proxyquire') var utils = require('./../../utils') -var userOps = {} -var usersRoutes = proxyquire('./../../../src/routes/public/users', { './../../lib/ops/userOps': userOps }) +var udaru = {} +var usersRoutes = proxyquire('./../../../src/routes/public/users', { './../../udaru': udaru }) var server = proxyquire('./../../../src/wiring-hapi', { './routes/public/users': usersRoutes }) lab.experiment('Users', () => { lab.test('get user list should return error for error case', (done) => { - userOps.listOrgUsers = function (params, cb) { - expect(params).to.equal({ organizationId: 'WONKA', limit: 100, page: 1 }) - process.nextTick(() => { - cb(Boom.badImplementation()) - }) + udaru.users = { + list: function (params, cb) { + expect(params).to.equal({ organizationId: 'WONKA', limit: 100, page: 1 }) + process.nextTick(() => { + cb(Boom.badImplementation()) + }) + } } const options = utils.requestOptions({ @@ -37,11 +39,13 @@ lab.experiment('Users', () => { }) lab.test('get single user should return error for error case', (done) => { - userOps.readUser = function (params, cb) { - expect(params).to.equal({ id: 'Myid', organizationId: 'WONKA' }) - process.nextTick(() => { - cb(Boom.badImplementation()) - }) + udaru.users = { + read: function (params, cb) { + expect(params).to.equal({ id: 'Myid', organizationId: 'WONKA' }) + process.nextTick(() => { + cb(Boom.badImplementation()) + }) + } } const options = utils.requestOptions({ @@ -60,10 +64,12 @@ lab.experiment('Users', () => { }) lab.test('create user should return error for error case', (done) => { - userOps.createUser = function (params, cb) { - process.nextTick(() => { - cb(Boom.badImplementation()) - }) + udaru.users = { + create: function (params, cb) { + process.nextTick(() => { + cb(Boom.badImplementation()) + }) + } } const options = utils.requestOptions({ @@ -85,11 +91,13 @@ lab.experiment('Users', () => { }) lab.test('delete user should return error for error case', (done) => { - userOps.deleteUser = function (params, cb) { - expect(params).to.equal({ id: 'MyId', organizationId: 'WONKA' }) - process.nextTick(() => { - cb(Boom.badImplementation()) - }) + udaru.users = { + delete: function (params, cb) { + expect(params).to.equal({ id: 'MyId', organizationId: 'WONKA' }) + process.nextTick(() => { + cb(Boom.badImplementation()) + }) + } } const options = utils.requestOptions({ @@ -108,12 +116,14 @@ lab.experiment('Users', () => { }) lab.test('update user should return error for error case', (done) => { - userOps.updateUser = function (params, cb) { - expect(params.id).to.equal('MyId') - expect(params.organizationId).to.equal('WONKA') - process.nextTick(() => { - cb(Boom.badImplementation()) - }) + udaru.users = { + update: function (params, cb) { + expect(params.id).to.equal('MyId') + expect(params.organizationId).to.equal('WONKA') + process.nextTick(() => { + cb(Boom.badImplementation()) + }) + } } const options = utils.requestOptions({