diff --git a/api-docs/openapi.json b/api-docs/openapi.json index 4ece901f6..9784a0051 100644 --- a/api-docs/openapi.json +++ b/api-docs/openapi.json @@ -11,7 +11,7 @@ }, "servers": [ { - "url": "urlplaceholder" + "url": "https://cveawg-dev.mitre.org/api" } ], "paths": { diff --git a/src/controller/audit.controller/audit.controller.js b/src/controller/audit.controller/audit.controller.js index dd3103a2d..467b698f1 100644 --- a/src/controller/audit.controller/audit.controller.js +++ b/src/controller/audit.controller/audit.controller.js @@ -291,10 +291,10 @@ async function getOrgAuditByOrgIdentifier (req, res, next) { if (!targetOrg) { logger.info({ uuid: req.ctx.uuid, - message: `No organization found with ${identifierIsUUID ? 'UUID' : 'shortname'} ${identifier}` + message: `No organization found with ${identifierIsUUID ? 'UUID' : 'shortname'} ${identifier}; returning empty audit history.` }) await session.abortTransaction() - return res.status(404).json(error.orgDne(identifier)) + return res.status(200).json([]) } // Get the org's UUID for audit lookup diff --git a/src/controller/registry-org.controller/error.js b/src/controller/registry-org.controller/error.js index b105e373e..1b350b417 100644 --- a/src/controller/registry-org.controller/error.js +++ b/src/controller/registry-org.controller/error.js @@ -22,6 +22,13 @@ class RegistryOrgControllerError extends idrErr.IDRError { return err } + notOrgAdminOrSecretariatUpdate () { + const err = {} + err.error = 'NOT_ORG_ADMIN_OR_SECRETARIAT_UPDATE' + err.message = 'Organizations can only be updated by the Secretariat or an Org Admin.' + return err + } + notAllowedToChangeOrganization () { const err = {} err.error = 'NOT_ALLOWED_TO_CHANGE_ORGANIZATION' diff --git a/src/controller/registry-org.controller/registry-org.controller.js b/src/controller/registry-org.controller/registry-org.controller.js index 1fcceb843..a1ad89135 100644 --- a/src/controller/registry-org.controller/registry-org.controller.js +++ b/src/controller/registry-org.controller/registry-org.controller.js @@ -321,12 +321,18 @@ async function updateOrg (req, res, next) { ? await authContext.isRequesterSameOrg(req, repo, org, { session }) : await authContext.isRequesterSameOrg(req, repo, shortName, { session }) - if (!isSecretariat && (!isAdmin || !requesterSameOrg)) { + if (!isSecretariat && !requesterSameOrg) { logger.info({ uuid: req.ctx.uuid, message: shortName + ' organization can only be updated by the users of the same organization or the Secretariat.' }) await session.abortTransaction() return res.status(403).json(error.notSameOrgOrSecretariat()) } + if (!isSecretariat && !isAdmin) { + logger.info({ uuid: req.ctx.uuid, message: shortName + ' organization can only be updated by the Secretariat or an Org Admin.' }) + await session.abortTransaction() + return res.status(403).json(error.notOrgAdminOrSecretariatUpdate()) + } + if (!isSecretariat) { const secretariatOnlyFields = getConstants().SECRETARIAT_ONLY_FIELDS const restrictedFieldsSent = secretariatOnlyFields.filter(field => _.has(body, field)) diff --git a/src/repositories/baseOrgRepository.js b/src/repositories/baseOrgRepository.js index 3654f4018..d51acf16f 100644 --- a/src/repositories/baseOrgRepository.js +++ b/src/repositories/baseOrgRepository.js @@ -203,12 +203,13 @@ class BaseOrgRepository extends BaseRepository { * @param {string} UUID - The UUID of the organization. * @param {object} [options={}] - Optional settings for the repository query. * @param {boolean} [returnLegacyFormat=false] - If true, returns the legacy format. + * @param {object} [projection={}] - Optional projection for fields to include or exclude. * @returns {Promise} The organization object. */ async findOneByUUID (UUID, options = {}, returnLegacyFormat = false, projection = {}) { const OrgRepository = require('./orgRepository') const legacyOrgRepo = new OrgRepository() - if (returnLegacyFormat) return await legacyOrgRepo.findOneByUUID(UUID, options) + if (returnLegacyFormat) return await legacyOrgRepo.findOneByUUID(UUID, options, projection) return await BaseOrgModel.findOne({ UUID: UUID }, projection, options) } diff --git a/src/repositories/orgRepository.js b/src/repositories/orgRepository.js index e2f86b9d8..3eb5d7684 100644 --- a/src/repositories/orgRepository.js +++ b/src/repositories/orgRepository.js @@ -12,8 +12,8 @@ class OrgRepository extends BaseRepository { return this.collection.findOne(query, projection, options) } - async findOneByUUID (UUID) { - return this.collection.findOne().byUUID(UUID) + async findOneByUUID (UUID, options = {}, projection = {}) { + return this.collection.findOne({ UUID: UUID }, projection, options) } async getOrgUUID (shortName, options = {}) { diff --git a/test/integration-tests/audit/auditTest.js b/test/integration-tests/audit/auditTest.js index 5b23e2a9a..cd6967b1c 100644 --- a/test/integration-tests/audit/auditTest.js +++ b/test/integration-tests/audit/auditTest.js @@ -256,6 +256,32 @@ describe('Testing Audit Org endpoints', () => { }) }) + it('Should return an empty array when getting audit history for a non-existent org shortname', async () => { + const fakeShortname = uuid.v4().slice(0, 32) + + await chai.request(app) + .get(`/api/audit/org/${fakeShortname}`) + .set(constants.headers) + .then((res, err) => { + expect(err).to.be.undefined + expect(res).to.have.status(200) + expect(res.body).to.deep.equal([]) + }) + }) + + it('Should return an empty array when getting audit history for a non-existent org UUID', async () => { + const fakeUUID = uuid.v4() + + await chai.request(app) + .get(`/api/audit/org/${fakeUUID}`) + .set(constants.headers) + .then((res, err) => { + expect(err).to.be.undefined + expect(res).to.have.status(200) + expect(res.body).to.deep.equal([]) + }) + }) + it('Should fail to get last X changes with invalid number', async () => { const invalidNumber = -5 await chai.request(app) diff --git a/test/integration-tests/org/getOrgTest.js b/test/integration-tests/org/getOrgTest.js new file mode 100644 index 000000000..d739b481b --- /dev/null +++ b/test/integration-tests/org/getOrgTest.js @@ -0,0 +1,38 @@ +/* eslint-disable no-unused-expressions */ +const chai = require('chai') +chai.use(require('chai-http')) +const expect = chai.expect + +const constants = require('../constants.js') +const app = require('../../../src/index.js') + +describe('Testing legacy Org GET endpoint', () => { + context('Positive Tests', () => { + it('Does not return Mongo fields when retrieving an org by UUID', async () => { + let orgUUID + + await chai.request(app) + .get('/api/org/mitre') + .set(constants.headers) + .then((res, err) => { + expect(err).to.be.undefined + expect(res).to.have.status(200) + orgUUID = res.body.UUID + }) + + await chai.request(app) + .get(`/api/org/${orgUUID}`) + .set(constants.headers) + .then((res, err) => { + expect(err).to.be.undefined + expect(res).to.have.status(200) + expect(res.body).to.have.property('UUID', orgUUID) + + const mongoFields = ['_id', '__v', '__t', 'inUse', 'in_use'] + mongoFields.forEach(field => { + expect(res.body).to.not.haveOwnProperty(field) + }) + }) + }) + }) +}) diff --git a/test/integration-tests/org/regularUsersTestRegistry.js b/test/integration-tests/org/regularUsersTestRegistry.js index b8cc596a5..2dda89f20 100644 --- a/test/integration-tests/org/regularUsersTestRegistry.js +++ b/test/integration-tests/org/regularUsersTestRegistry.js @@ -398,6 +398,19 @@ describe('Testing regular user permissions for /api/registry/org/ endpoints with describe('Testing ORG PUT endpoint with /api/registry/org', () => { /* Negative Tests */ context('Negative Test', () => { + it('regular user cannot update their own organization', async () => { + const org = constants.nonSecretariatUserHeaders['CVE-API-ORG'] + await chai.request(app) + .put(`/api/registry/org/${org}`) + .set(constants.nonSecretariatUserHeaders) + .send({ + }) + .then((res) => { + expect(res).to.have.status(403) + expect(res.body.error).to.contain('NOT_ORG_ADMIN_OR_SECRETARIAT_UPDATE') + expect(res.body.message).to.equal('Organizations can only be updated by the Secretariat or an Org Admin.') + }) + }) it('regular user cannot update an organization', async () => { const org = faker.datatype.uuid().slice(0, MAX_SHORTNAME_LENGTH) await chai.request(app)