Skip to content

Commit 45f8668

Browse files
authored
Merge branch 'dev' into af-1856
2 parents 0143ef4 + 007f895 commit 45f8668

4 files changed

Lines changed: 233 additions & 7 deletions

File tree

src/controller/org.controller/org.controller.js

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,7 @@ async function updateOrg (req, res, next) {
339339

340340
const session = await mongoose.startSession({ causalConsistency: false })
341341
let responseMessage
342+
let payload
342343
// Get the query parameters as JSON
343344
// These are validated by the middleware in org/index.js
344345
const queryParametersJson = req.ctx.query
@@ -402,10 +403,14 @@ async function updateOrg (req, res, next) {
402403
const updatedOrg = await orgRepository.updateOrg(shortNameUrlParameter, queryParametersJson, { session }, !req.useRegistry, requestingUserUUID, isAdmin, isSecretariat)
403404

404405
responseMessage = { message: `${updatedOrg.short_name} organization was successfully updated.`, updated: updatedOrg } // Clarify message
405-
const payload = { action: 'update_org', change: `${updatedOrg.short_name} organization was successfully updated.`, org: updatedOrg }
406-
payload.user_UUID = await userRepo.getUserUUID(req.ctx.user, updatedOrg.UUID)
407-
payload.org_UUID = updatedOrg.UUID
408-
payload.req_UUID = req.ctx.uuid
406+
payload = {
407+
action: 'update_org',
408+
change: `${updatedOrg.short_name} organization was successfully updated.`,
409+
req_UUID: req.ctx.uuid,
410+
org_UUID: updatedOrg.UUID,
411+
user_UUID: requestingUserUUID,
412+
org: updatedOrg
413+
}
409414
await session.commitTransaction()
410415
} catch (error) {
411416
await session.abortTransaction()
@@ -414,6 +419,7 @@ async function updateOrg (req, res, next) {
414419
await session.endSession()
415420
}
416421

422+
logger.info(JSON.stringify(payload))
417423
return res.status(200).json(responseMessage)
418424
} catch (err) {
419425
next(err)

src/controller/registry-org.controller/registry-org.controller.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,7 @@ async function updateOrg (req, res, next) {
422422
action: 'update_registry_org',
423423
change: body?.short_name + 'organization was successfully updated, but joint approval is required for some fields. Check the ReviewObject for your org to check for a reply from the Secretariat about Joint Approval items.',
424424
req_UUID: req.ctx.uuid,
425-
org_UUID: await repo.getOrgUUID(req.ctx.org),
425+
org_UUID: updatedOrg.UUID,
426426
org: updatedOrg
427427
}
428428

@@ -438,7 +438,7 @@ async function updateOrg (req, res, next) {
438438
action: 'update_registry_org',
439439
change: body?.short_name + ' was successfully updated.',
440440
req_UUID: req.ctx.uuid,
441-
org_UUID: await repo.getOrgUUID(req.ctx.org),
441+
org_UUID: updatedOrg.UUID,
442442
org: updatedOrg
443443
}
444444
logger.info(JSON.stringify(payload))
@@ -466,6 +466,7 @@ async function deleteOrg (req, res, next) {
466466
const session = await mongoose.startSession({ causalConsistency: false })
467467
const repo = req.ctx.repositories.getBaseOrgRepository()
468468
const shortName = req.ctx.params.identifier
469+
let targetOrgUUID
469470

470471
try {
471472
session.startTransaction()
@@ -476,6 +477,7 @@ async function deleteOrg (req, res, next) {
476477
return res.status(404).json(error.orgDnePathParam(shortName))
477478
}
478479

480+
targetOrgUUID = org.UUID
479481
await repo.deleteOrg(shortName, { session })
480482
await session.commitTransaction()
481483
} catch (deleteErr) {
@@ -493,7 +495,7 @@ async function deleteOrg (req, res, next) {
493495
action: 'delete_registry_org',
494496
change: shortName + ' was successfully deleted.',
495497
req_UUID: req.ctx.uuid,
496-
org_UUID: await repo.getOrgUUID(req.ctx.org)
498+
org_UUID: targetOrgUUID
497499
}
498500
logger.info(JSON.stringify(payload))
499501
return res.status(200).json(responseMessage)

test/unit-tests/org/orgUpdateTest.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const error = new errors.OrgControllerError()
1919
const orgFixtures = require('./mockObjects.org')
2020
const orgController = require('../../../src/controller/org.controller/org.controller')
2121
const orgParams = require('../../../src/controller/org.controller/org.middleware')
22+
const logger = require('../../../src/middleware/logger')
2223

2324
class NullUserRepo {
2425
async getUserUUID () {
@@ -229,6 +230,56 @@ describe('Testing the PUT /org/:shortname endpoint in Org Controller', () => {
229230
})
230231
})
231232

233+
it('Org update logs the audit payload with the requesting user UUID', async () => {
234+
const requesterUserUUID = 'b48b4f8e-b82a-45ff-9e3b-3bf1534ad663'
235+
const logStub = sinon.stub(logger, 'info')
236+
const getUserUUID = sinon.stub().callsFake((username, orgShortName) => {
237+
if (orgShortName === orgFixtures.owningOrg.UUID) {
238+
throw new Error('Requester user UUID should not be looked up by the updated org UUID')
239+
}
240+
return requesterUserUUID
241+
})
242+
const userRepo = {
243+
getUserUUID,
244+
isAdmin: sinon.stub().resolves(false)
245+
}
246+
247+
app.route('/org-updated-logs-payload/:shortname')
248+
.put((req, res, next) => {
249+
const factory = {
250+
getBaseOrgRepository: () => { return new OrgUpdatedAddingRole() },
251+
getBaseUserRepository: () => { return userRepo }
252+
}
253+
req.ctx.repositories = factory
254+
next()
255+
}, orgParams.parsePostParams, orgController.ORG_UPDATE_SINGLE)
256+
257+
const res = await chai.request(app)
258+
.put(`/org-updated-logs-payload/${orgFixtures.owningOrg.short_name}?active_roles.add=ROOT`)
259+
.set(orgFixtures.secretariatHeader)
260+
261+
const updateLogCall = logStub.getCalls().find(call => {
262+
try {
263+
return JSON.parse(call.args[0]).action === 'update_org'
264+
} catch (err) {
265+
return false
266+
}
267+
})
268+
269+
expect(res).to.have.status(200)
270+
expect(getUserUUID.calledOnce).to.equal(true)
271+
expect(getUserUUID.firstCall.args[0]).to.equal(orgFixtures.secretariatHeader['CVE-API-USER'])
272+
expect(getUserUUID.firstCall.args[1]).to.equal(orgFixtures.secretariatHeader['CVE-API-ORG'])
273+
expect(updateLogCall).to.not.equal(undefined)
274+
const payload = JSON.parse(updateLogCall.args[0])
275+
expect(payload.action).to.equal('update_org')
276+
expect(payload.change).to.equal(`${orgFixtures.owningOrg.short_name} organization was successfully updated.`)
277+
expect(payload.org_UUID).to.equal(orgFixtures.owningOrg.UUID)
278+
expect(payload.user_UUID).to.equal(requesterUserUUID)
279+
expect(payload.req_UUID).to.be.a('string')
280+
expect(payload.org.short_name).to.equal(orgFixtures.owningOrg.short_name)
281+
})
282+
232283
it('Org is unchanged: Adding a role that the org already have', (done) => {
233284
const CONSTANTS = getConstants()
234285

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
const chai = require('chai')
2+
const sinon = require('sinon')
3+
const mongoose = require('mongoose')
4+
const expect = chai.expect
5+
6+
const registryOrgController = require('../../../src/controller/registry-org.controller/registry-org.controller')
7+
const logger = require('../../../src/middleware/logger')
8+
9+
describe('Registry org payload logging', () => {
10+
let mockSession
11+
12+
beforeEach(() => {
13+
mockSession = {
14+
startTransaction: sinon.stub(),
15+
commitTransaction: sinon.stub().resolves(),
16+
abortTransaction: sinon.stub().resolves(),
17+
endSession: sinon.stub().resolves()
18+
}
19+
sinon.stub(mongoose, 'startSession').resolves(mockSession)
20+
sinon.stub(logger, 'info')
21+
})
22+
23+
afterEach(() => {
24+
sinon.restore()
25+
})
26+
27+
function createResponse () {
28+
return {
29+
status: sinon.stub().returnsThis(),
30+
json: sinon.stub().returnsThis()
31+
}
32+
}
33+
34+
function getLoggedPayload (action) {
35+
const logCall = logger.info.getCalls().find(call => {
36+
try {
37+
return JSON.parse(call.args[0]).action === action
38+
} catch (err) {
39+
return false
40+
}
41+
})
42+
43+
expect(logCall).to.not.equal(undefined)
44+
return JSON.parse(logCall.args[0])
45+
}
46+
47+
async function updateRegistryOrg (updatedOrg) {
48+
const callerOrgUUID = '54f5fa83-86f6-44fd-b45a-290087680ac0'
49+
const org = {
50+
UUID: updatedOrg.UUID,
51+
short_name: updatedOrg.short_name,
52+
toObject: () => ({ ...updatedOrg })
53+
}
54+
const repo = {
55+
isSecretariatByShortName: sinon.stub().resolves(true),
56+
findOneByShortName: sinon.stub().resolves(org),
57+
validateOrg: sinon.stub().returns({ isValid: true }),
58+
checkAliasCollisions: sinon.stub().resolves(null),
59+
getOrgUUID: sinon.stub().callsFake(shortName => {
60+
if (shortName === updatedOrg.short_name) return updatedOrg.UUID
61+
if (shortName === 'mitre') return callerOrgUUID
62+
return null
63+
}),
64+
updateOrgFull: sinon.stub().resolves(updatedOrg)
65+
}
66+
const userRepo = {
67+
isAdmin: sinon.stub().resolves(false),
68+
findOneByUsernameAndOrgShortname: sinon.stub().resolves({ UUID: 'requesting-user-uuid' })
69+
}
70+
const conversationRepo = {
71+
getAllByTargetUUID: sinon.stub().resolves([])
72+
}
73+
const reviewRepo = {
74+
getOrgReviewObjectByOrgShortname: sinon.stub().resolves(null)
75+
}
76+
const req = {
77+
ctx: {
78+
uuid: 'request-uuid',
79+
org: 'mitre',
80+
user: 'test_secretariat_0@mitre.org',
81+
params: { shortname: updatedOrg.short_name },
82+
body: {
83+
short_name: updatedOrg.short_name,
84+
long_name: 'Target Org',
85+
authority: ['CNA']
86+
},
87+
repositories: {
88+
getBaseOrgRepository: () => repo,
89+
getBaseUserRepository: () => userRepo,
90+
getConversationRepository: () => conversationRepo,
91+
getReviewObjectRepository: () => reviewRepo
92+
}
93+
}
94+
}
95+
const res = createResponse()
96+
const next = sinon.stub()
97+
98+
await registryOrgController.UPDATE_ORG(req, res, next)
99+
100+
return { payload: getLoggedPayload('update_registry_org'), res, next, callerOrgUUID }
101+
}
102+
103+
it('logs the updated registry org UUID for update_registry_org', async () => {
104+
const updatedOrg = {
105+
UUID: 'cc5f9414-acf2-4e43-8071-67e8ea810113',
106+
short_name: 'target_org',
107+
authority: ['CNA'],
108+
joint_approval_required: false
109+
}
110+
111+
const { payload, res, next, callerOrgUUID } = await updateRegistryOrg(updatedOrg)
112+
expect(res.status.calledWith(200)).to.equal(true)
113+
expect(next.notCalled).to.equal(true)
114+
expect(payload.org_UUID).to.equal(updatedOrg.UUID)
115+
expect(payload.org_UUID).to.not.equal(callerOrgUUID)
116+
expect(payload.org.UUID).to.equal(updatedOrg.UUID)
117+
})
118+
119+
it('logs the updated registry org UUID for update_registry_org when joint approval is required', async () => {
120+
const updatedOrg = {
121+
UUID: '895cdd1b-9825-4f10-b031-bffad6650c26',
122+
short_name: 'target_org',
123+
authority: ['CNA'],
124+
joint_approval_required: true
125+
}
126+
127+
const { payload, res, next, callerOrgUUID } = await updateRegistryOrg(updatedOrg)
128+
expect(res.status.calledWith(200)).to.equal(true)
129+
expect(next.notCalled).to.equal(true)
130+
expect(payload.org_UUID).to.equal(updatedOrg.UUID)
131+
expect(payload.org_UUID).to.not.equal(callerOrgUUID)
132+
expect(payload.org.UUID).to.equal(updatedOrg.UUID)
133+
})
134+
135+
it('logs the deleted registry org UUID for delete_registry_org', async () => {
136+
const targetOrg = {
137+
UUID: '8db8e7ed-a43f-40b8-9ebb-d68aa8dc2216',
138+
short_name: 'target_org'
139+
}
140+
const repo = {
141+
findOneByShortName: sinon.stub().resolves(targetOrg),
142+
deleteOrg: sinon.stub().resolves(),
143+
getOrgUUID: sinon.stub().throws(new Error('delete payload should not look up the caller org UUID'))
144+
}
145+
const req = {
146+
ctx: {
147+
uuid: 'request-uuid',
148+
org: 'mitre',
149+
params: { identifier: targetOrg.short_name },
150+
repositories: {
151+
getBaseOrgRepository: () => repo
152+
}
153+
}
154+
}
155+
const res = createResponse()
156+
const next = sinon.stub()
157+
158+
await registryOrgController.DELETE_ORG(req, res, next)
159+
160+
const payload = getLoggedPayload('delete_registry_org')
161+
expect(res.status.calledWith(200)).to.equal(true)
162+
expect(next.notCalled).to.equal(true)
163+
expect(repo.deleteOrg.calledWith(targetOrg.short_name)).to.equal(true)
164+
expect(repo.getOrgUUID.notCalled).to.equal(true)
165+
expect(payload.org_UUID).to.equal(targetOrg.UUID)
166+
})
167+
})

0 commit comments

Comments
 (0)