Skip to content
This repository has been archived by the owner on Aug 19, 2022. It is now read-only.

Commit

Permalink
Merge branch 'master' into repackaging-docs
Browse files Browse the repository at this point in the history
  • Loading branch information
dberesford committed Mar 30, 2018
2 parents 7814b5b + 475b82a commit 4cfa27b
Show file tree
Hide file tree
Showing 28 changed files with 695 additions and 102 deletions.
3 changes: 3 additions & 0 deletions CHANGES.md
Expand Up @@ -3,6 +3,9 @@ Features, enhancements:
- Lerna package split, udaru-core, udaru-plugin and udaru-server now in separate npm packages [commit](https://github.com/nearform/udaru/pull/444)
- **Breaking change**: 404 not found on endpoint GET /authorization/teams/${teamId}/users if team does not exist [commit](https://github.com/nearform/udaru/pull/444)
- **Breaking change**: 404 not found on endpoint /authorization/users/${userId}/teams if user does not exist [commit](https://github.com/nearform/udaru/pull/444)
- SQL module extracted and placed in own npm module (https://www.npmjs.com/package/@nearform/sql)
- Policy instance now returned when associating policy with user,team,org, which can be passed as param to DELETE to delete a specific instance
- Policy context variables added, which can be used in policy resources and policy condition elements
- SQL module extracted and placed in own npm module ([@nearform/sql](https://www.npmjs.com/package/@nearform/sql))

## 4.1.0 - March 12, 2018
Expand Down
5 changes: 3 additions & 2 deletions docs/overview.md
Expand Up @@ -230,12 +230,13 @@ And then provide the value for `documentId` when assigning the Policy to a User

This will reduce the number of Policies required, while still being specific on the documents a User can read.


Policy Templates are actually regular Policies that use variables. The difference is that the value of the variables, rather than being obtained from context at run time, is defined on Policy assignment.

When a Policy is assigned to a User (or a Team) an additional object can be provided whose properties will be used as the value for the variables in the Policy itself.

Currently we support variables in the Resource part of the Policy statement (similar to what PBAC already does)
Currently we support variables in the Resource part of the Policy statement (similar to what PBAC already does).

Once a Policy Instance is created, it is assigned an Instance id, which is returned as a property of the Policy Instance in the Policies array. This can be used to identify and delete that single Instance of the Policy using the query param 'instance' using the same endpoints to disassociate policies from Users, Teams and Organizations.

### Shared Policies

Expand Down
2 changes: 1 addition & 1 deletion docs/swagger/swagger-json.js

Large diffs are not rendered by default.

28 changes: 14 additions & 14 deletions docs/swagger/swagger-ui-bundle.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/swagger/swagger-ui-bundle.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/swagger/swagger-ui-standalone-preset.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/swagger/swagger-ui-standalone-preset.js.map

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions docs/swagger/swagger-ui.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/swagger/swagger-ui.js.map

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions packages/udaru-core/database/migrations/008.do.sql
@@ -0,0 +1,3 @@
ALTER TABLE organization_policies ADD COLUMN policy_instance serial;
ALTER TABLE team_policies ADD COLUMN policy_instance serial;
ALTER TABLE user_policies ADD COLUMN policy_instance serial;
3 changes: 3 additions & 0 deletions packages/udaru-core/database/migrations/008.undo.sql
@@ -0,0 +1,3 @@
ALTER TABLE user_policies DROP COLUMN policy_instance;
ALTER TABLE team_policies DROP COLUMN policy_instance;
ALTER TABLE organization_policies DROP COLUMN policy_instance;
3 changes: 2 additions & 1 deletion packages/udaru-core/lib/mapping.js
Expand Up @@ -54,7 +54,8 @@ function mapPolicySimple (row) {
id: row.id,
name: row.name,
version: row.version,
variables: row.variables || {}
variables: row.variables || {},
instance: row.policy_instance
}
}

Expand Down
16 changes: 11 additions & 5 deletions packages/udaru-core/lib/ops/organizationOps.js
Expand Up @@ -74,13 +74,18 @@ function buildOrganizationOps (db, config) {
}

function clearOrganizationAttachedPolicy (job, next) {
const { id, policyId } = job
const { id, policyId, instance } = job

const sqlQuery = SQL`
DELETE FROM organization_policies
WHERE org_id = ${id}
AND policy_id = ${policyId}
`

if (instance) {
sqlQuery.append(SQL`AND policy_instance = ${instance}`)
}

job.client.query(sqlQuery, utils.boomErrorWrapper(next))
}

Expand Down Expand Up @@ -228,7 +233,7 @@ function buildOrganizationOps (db, config) {

tasks.push((next) => {
const sqlQuery = SQL`
SELECT pol.id, pol.name, pol.version, org_pol.variables
SELECT pol.id, pol.name, pol.version, org_pol.variables, org_pol.policy_instance
FROM organization_policies org_pol, policies pol
WHERE org_pol.org_id = ${id} AND org_pol.policy_id = pol.id
ORDER BY UPPER(pol.name)
Expand Down Expand Up @@ -475,21 +480,22 @@ function buildOrganizationOps (db, config) {
/**
* Remove one organization policy
*
* @param {Object} params { id, policyId }
* @param {Object} params { id, policyId, instance } "instance" optional
* @param {Function} cb
*/
deleteOrganizationAttachedPolicy: function deleteOrganizationAttachedPolicy (params, cb) {
const { id, policyId } = params
const { id, policyId, instance } = params
const tasks = [
(job, next) => {
Joi.validate({ id, policyId }, validationRules.deleteOrganizationPolicy, (err) => {
Joi.validate({ id, policyId, instance }, validationRules.deleteOrganizationPolicy, (err) => {
if (err) return next(Boom.badRequest(err))
next()
})
},
(job, next) => {
job.id = id
job.policyId = policyId
job.instance = instance

next()
},
Expand Down
17 changes: 11 additions & 6 deletions packages/udaru-core/lib/ops/teamOps.js
Expand Up @@ -180,13 +180,18 @@ function buildTeamOps (db, config) {
}

function removeTeamPolicy (job, next) {
const { teamId, policyId } = job
const { teamId, policyId, instance } = job

const sqlQuery = SQL`
DELETE FROM team_policies
WHERE team_id = ${teamId}
AND policy_id = ${policyId}
`

if (instance) {
sqlQuery.append(SQL`AND policy_instance = ${instance}`)
}

job.client.query(sqlQuery, utils.boomErrorWrapper(next))
}

Expand Down Expand Up @@ -266,7 +271,7 @@ function buildTeamOps (db, config) {
function loadTeamPolicies (job, next) {
const { id } = job
const sql = SQL`
SELECT pol.id, pol.name, pol.version, tpol.variables
SELECT pol.id, pol.name, pol.version, tpol.variables, tpol.policy_instance
FROM team_policies tpol, policies pol
WHERE tpol.team_id = ${id}
AND tpol.policy_id = pol.id
Expand Down Expand Up @@ -672,16 +677,16 @@ function buildTeamOps (db, config) {
/**
* Remove a specific team policy
*
* @param {Object} params { userId, organizationId, policyId }
* @param {Object} params { userId, organizationId, policyId, instance } "instance" optional
* @param {Function} cb
*/
deleteTeamPolicy: function deleteTeamPolicy (params, cb) {
const { teamId, organizationId, policyId } = params
const { teamId, organizationId, policyId, instance } = params

Joi.validate({ teamId, organizationId, policyId }, validationRules.deleteTeamPolicy, function (err) {
Joi.validate({ teamId, organizationId, policyId, instance }, validationRules.deleteTeamPolicy, function (err) {
if (err) return cb(Boom.badRequest(err))

removeTeamPolicy({ client: db, teamId, policyId }, (err, res) => {
removeTeamPolicy({ client: db, teamId, policyId, instance }, (err, res) => {
if (err) return cb(err)
teamOps.readTeam({ id: teamId, organizationId }, cb)
})
Expand Down
15 changes: 10 additions & 5 deletions packages/udaru-core/lib/ops/userOps.js
Expand Up @@ -69,13 +69,17 @@ function buildUserOps (db, config) {
}

function removeUserPolicy (job, next) {
const { id, policyId } = job
const { id, policyId, instance } = job

const sqlQuery = SQL`
let sqlQuery = SQL`
DELETE FROM user_policies
WHERE user_id = ${id}
AND policy_id = ${policyId}
`
if (instance) {
sqlQuery.append(SQL`AND policy_instance = ${instance}`)
}

job.client.query(sqlQuery, utils.boomErrorWrapper(next))
}

Expand Down Expand Up @@ -190,7 +194,7 @@ function buildUserOps (db, config) {

tasks.push((next) => {
const sqlQuery = SQL`
SELECT pol.id, pol.name, pol.version, user_pol.variables
SELECT pol.id, pol.name, pol.version, user_pol.variables, user_pol.policy_instance
FROM user_policies user_pol, policies pol
WHERE user_pol.user_id = ${id} AND user_pol.policy_id = pol.id
ORDER BY UPPER(pol.name)
Expand Down Expand Up @@ -431,10 +435,10 @@ function buildUserOps (db, config) {
* @param {Function} cb
*/
deleteUserPolicy: function deleteUserPolicy (params, cb) {
const { userId, organizationId, policyId } = params
const { userId, organizationId, policyId, instance } = params
const tasks = [
(job, next) => {
Joi.validate({ userId, organizationId, policyId }, validationRules.deleteUserPolicy, (err) => {
Joi.validate({ userId, organizationId, policyId, instance }, validationRules.deleteUserPolicy, (err) => {
if (err) return next(Boom.badRequest(err))
next()
})
Expand All @@ -443,6 +447,7 @@ function buildUserOps (db, config) {
job.id = userId
job.policyId = policyId
job.organizationId = organizationId
job.instance = instance

next()
},
Expand Down
10 changes: 7 additions & 3 deletions packages/udaru-core/lib/ops/validation.js
Expand Up @@ -50,6 +50,7 @@ const validationRules = {
userId: requiredStringId.description('User ID'),
teamId: requiredStringId.description('Team ID'),
organizationId: requiredStringId.description('Organization ID'),
policyInstance: Joi.number().integer().optional().description('Policy Instance 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'),
Expand Down Expand Up @@ -112,7 +113,8 @@ const users = {
deleteUserPolicy: {
userId: validationRules.userId,
policyId: validationRules.policyId,
organizationId: validationRules.organizationId
organizationId: validationRules.organizationId,
instance: validationRules.policyInstance
},
listUserTeams: {
id: validationRules.userId,
Expand Down Expand Up @@ -193,7 +195,8 @@ const teams = {
deleteTeamPolicy: {
teamId: validationRules.teamId,
policyId: validationRules.policyId,
organizationId: validationRules.organizationId
organizationId: validationRules.organizationId,
instance: validationRules.policyInstance
},
readTeamUsers: {
id: validationRules.teamId,
Expand Down Expand Up @@ -316,7 +319,8 @@ const organizations = {
},
deleteOrganizationPolicy: {
id: validationRules.organizationId,
policyId: validationRules.policyId
policyId: validationRules.policyId,
instance: validationRules.policyInstance
}
}

Expand Down
106 changes: 102 additions & 4 deletions packages/udaru-core/test/integration/organizationOps.test.js
Expand Up @@ -6,6 +6,7 @@ const Lab = require('lab')
const lab = exports.lab = Lab.script()
const async = require('async')
const udaru = require('../..')()
const u = require('@nearform/udaru-test/utils')

const config = require('../../config')()
const defaultPolicies = config.get('authorization.organizations.defaultPolicies', { 'organizationId': 'nearForm' })
Expand Down Expand Up @@ -1049,7 +1050,7 @@ lab.experiment('OrganizationOps', () => {
expect(res).to.exist()
expect(res.id).to.equal(organizationId)
expect(res.policies.length).to.equal(2)
expect(res.policies).to.include([{
expect(u.PoliciesWithoutInstance(res.policies)).to.include([{
id: testPolicy.id,
name: testPolicy.name,
version: testPolicy.version,
Expand All @@ -1063,7 +1064,7 @@ lab.experiment('OrganizationOps', () => {
expect(err).to.not.exist()
expect(res).to.exist()
expect(res.policies.length).to.equal(2)
expect(res.policies).to.include([{
expect(u.PoliciesWithoutInstance(res.policies)).to.include([{
id: testPolicy.id,
name: testPolicy.name,
version: testPolicy.version,
Expand All @@ -1082,6 +1083,103 @@ lab.experiment('OrganizationOps', () => {
async.series(tasks, done)
})

lab.test('test policy instance addition and removal', (done) => {
const tasks = []

var firstInstance
tasks.push((next) => {
udaru.organizations.read(organizationId, (err, res) => {
expect(err).to.not.exist()
expect(res).to.exist()
expect(res.policies.length).to.equal(0)
next(err, res)
})
})
tasks.push((next) => {
const policies = [{
id: testPolicy.id,
variables: {var1: 'value1'}
}]
udaru.organizations.addPolicies({id: organizationId, policies}, (err, res) => {
expect(err).to.not.exist()
expect(res).to.exist()
expect(res.id).to.equal(organizationId)
expect(res.policies.length).to.equal(1)
expect(res.policies[0].id).to.equal(testPolicy.id)
expect(res.policies[0].name).to.equal(testPolicy.name)
expect(res.policies[0].version).to.equal(testPolicy.version)
expect(res.policies[0].variables).to.equal({var1: 'value1'})
expect(res.policies[0].instance).to.exist()
firstInstance = res.policies[0].instance
next(err, res)
})
})
tasks.push((next) => {
const policies = [{
id: testPolicy.id,
variables: {var1: 'value2'}
}]
udaru.organizations.addPolicies({id: organizationId, policies}, (err, res) => {
expect(err).to.not.exist()
expect(res).to.exist()
expect(res.id).to.equal(organizationId)
expect(res.policies.length).to.equal(2)
expect(u.PoliciesWithoutInstance(res.policies)).to.include([{
id: testPolicy.id,
name: testPolicy.name,
version: testPolicy.version,
variables: {var1: 'value2'}
}])
next(err, res)
})
})
tasks.push((next) => {
const policies = [{
id: testPolicy.id,
variables: {var1: 'value3'}
}]
udaru.organizations.addPolicies({id: organizationId, policies}, (err, res) => {
expect(err).to.not.exist()
expect(res).to.exist()
expect(res.id).to.equal(organizationId)
expect(res.policies.length).to.equal(3)
expect(u.PoliciesWithoutInstance(res.policies)).to.include([{
id: testPolicy.id,
name: testPolicy.name,
version: testPolicy.version,
variables: {var1: 'value3'}
}])
next(err, res)
})
})
tasks.push((next) => { // delete the first policy instance
udaru.organizations.deletePolicy({id: organizationId, policyId: testPolicy.id, instance: firstInstance}, (err, res) => {
expect(err).to.not.exist()
expect(res).to.exist()
expect(res.id).to.equal(organizationId)
expect(res.policies.length).to.equal(2)
expect(u.PoliciesWithoutInstance(res.policies)).to.not.include([{
id: testPolicy.id,
name: testPolicy.name,
version: testPolicy.version,
variables: {var1: 'value1'}
}])
next(err, res)
})
})
tasks.push((next) => { // delete remaining instances
udaru.organizations.deletePolicy({id: organizationId, policyId: testPolicy.id}, (err, res) => {
expect(err).to.not.exist()
expect(res).to.exist()
expect(res.id).to.equal(organizationId)
expect(res.policies.length).to.equal(0)
next(err, res)
})
})

async.series(tasks, done)
})

lab.test('with same variables do nothing', (done) => {
const tasks = []

Expand Down Expand Up @@ -1140,7 +1238,7 @@ lab.experiment('OrganizationOps', () => {
expect(res).to.exist()
expect(res.id).to.equal(organizationId)
expect(res.policies.length).to.equal(1)
expect(res.policies).to.include([{
expect(u.PoliciesWithoutInstance(res.policies)).to.include([{
id: testPolicy.id,
name: testPolicy.name,
version: testPolicy.version,
Expand All @@ -1154,7 +1252,7 @@ lab.experiment('OrganizationOps', () => {
expect(err).to.not.exist()
expect(res).to.exist()
expect(res.policies.length).to.equal(1)
expect(res.policies).to.include([{
expect(u.PoliciesWithoutInstance(res.policies)).to.include([{
id: testPolicy.id,
name: testPolicy.name,
version: testPolicy.version,
Expand Down

0 comments on commit 4cfa27b

Please sign in to comment.