From 4b64e168dc0e3e12aa14cda28bd606d90f1bb42e Mon Sep 17 00:00:00 2001 From: david-rocca Date: Wed, 19 Jul 2023 13:26:59 -0400 Subject: [PATCH 1/6] #1018 Integration tests for new restrictions --- .../integration-tests/org/postOrgUsersTest.js | 187 ++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 test/integration-tests/org/postOrgUsersTest.js diff --git a/test/integration-tests/org/postOrgUsersTest.js b/test/integration-tests/org/postOrgUsersTest.js new file mode 100644 index 000000000..5890fde8f --- /dev/null +++ b/test/integration-tests/org/postOrgUsersTest.js @@ -0,0 +1,187 @@ +/* eslint-disable no-unused-expressions */ +const chai = require('chai') +chai.use(require('chai-http')) +const expect = chai.expect +const { faker } = require('@faker-js/faker') + +const constants = require('../constants.js') +const app = require('../../../src/index.js') +const getConstants = require('../../../src/constants').getConstants +const argon2 = require('argon2') +const _ = require('lodash') +const User = require('../../../src/model/user') +const cryptoRandomString = require('crypto-random-string') + +const shortName = { shortname: 'win_5' } + +describe.only('Testing user post endpoint', () => { + let orgUuid + context('Positive Tests', () => { + it('Allows creation of user', async () => { + await chai.request(app) + .post('/api/org/win_5/user') + .set({ ...constants.headers, ...shortName }) + .send({ + username: 'fakeuser999', + name: { + first: 'Dave', + last: 'FakeLastName', + middle: 'Cool', + suffix: 'Mr.' + }, + authority: { + active_roles: [ + 'ADMIN' + ] + } + }) + .then((res, err) => { + expect(err).to.be.undefined + orgUuid = res.body.created.org_UUID + }) + }) + }) + context('Negitive Test', () => { + it('Fails creation of user for bad long first name', async () => { + await chai.request(app) + .post('/api/org/win_5/user') + .set({ ...constants.headers, ...shortName }) + .send({ + username: 'fakeuser9999', + name: { + first: 'VerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnm1', + last: 'FakeLastName', + middle: 'Cool', + suffix: 'Mr.' + }, + authority: { + active_roles: [ + 'ADMIN' + ] + } + }) + .then((res, err) => { + expect(res).to.have.status(400) + expect(_.some(res.body.details, { msg: 'Invalid name.first. Name must be between 1 and 100 characters in length.' })).to.be.true + expect(err).to.be.undefined + }) + }) + it('Fails creation of user for bad long last name', async () => { + await chai.request(app) + .post('/api/org/win_5/user') + .set({ ...constants.headers, ...shortName }) + .send({ + username: 'fakeuser1000', + name: { + first: 'FirstName', + last: 'VerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnm1', + middle: 'Cool', + suffix: 'Mr.' + }, + authority: { + active_roles: [ + 'ADMIN' + ] + } + }) + .then((res, err) => { + expect(res).to.have.status(400) + expect(_.some(res.body.details, { msg: 'Invalid name.last. Name must be between 1 and 100 characters in length.' })).to.be.true + expect(err).to.be.undefined + }) + }) + it('Fails creation of user for bad long middle name', async () => { + await chai.request(app) + .post('/api/org/win_5/user') + .set({ ...constants.headers, ...shortName }) + .send({ + username: 'fakeuser1001', + name: { + first: 'FirstName', + last: 'LastName', + middle: 'VerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnm1', + suffix: 'Mr.' + }, + authority: { + active_roles: [ + 'ADMIN' + ] + } + }) + .then((res, err) => { + expect(res).to.have.status(400) + expect(_.some(res.body.details, { msg: 'Invalid name.middle. Name must be between 1 and 100 characters in length.' })).to.be.true + expect(err).to.be.undefined + }) + }) + it('Fails creation of user for bad long suffix name', async () => { + await chai.request(app) + .post('/api/org/win_5/user') + .set({ ...constants.headers, ...shortName }) + .send({ + username: 'fakeuser1002', + name: { + first: 'FirstName', + last: 'LastName', + middle: 'MiddleName', + suffix: 'VerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnm1' + }, + authority: { + active_roles: [ + 'ADMIN' + ] + } + }) + .then((res, err) => { + expect(res).to.have.status(400) + expect(_.some(res.body.details, { msg: 'Invalid name.suffix. Name must be between 1 and 100 characters in length.' })).to.be.true + expect(err).to.be.undefined + }) + }) + it('Fails creation of user for trying to add the 101th user', async () => { + const numberOfUsers = await User.where({ org_UUID: orgUuid }).countDocuments().exec() + for (let i = 0; i < (100 - numberOfUsers); i++) { + const newUser = new User() + + newUser.name.first = faker.name.firstName() + newUser.name.last = faker.name.lastName() + newUser.username = faker.internet.userName({ firstName: newUser.name.first, lastName: newUser.name.last }) + newUser.org_UUID = orgUuid + newUser.UUID = faker.datatype.uuid() + const randomKey = cryptoRandomString({ length: getConstants().CRYPTO_RANDOM_STRING_LENGTH }) + newUser.secret = await argon2.hash(randomKey) + + newUser.authority = { + active_roles: [ + 'ADMIN' + ] + } + + await User.findOneAndUpdate().byUserNameAndOrgUUID(newUser.userName, newUser.org_UUID).updateOne(newUser).setOptions({ upsert: true }) + } + + await chai.request(app) + .post('/api/org/win_5/user') + .set({ ...constants.headers, ...shortName }) + .send({ + username: 'Fake101User', + name: { + first: 'Dave', + last: 'FakeLastName', + middle: 'Cool', + suffix: 'Mr.' + }, + authority: { + active_roles: [ + 'ADMIN' + ] + } + }) + .then((res, err) => { + expect(err).to.be.undefined + expect(res).to.have.status(400) + expect(res.body.error).to.contain('NUMBER_OF_USERS_IN_ORG_LIMIT_REACHED') + }) + }) + }) +}) From d1caa7dd3979f05566ba6dfb19d76775f3f87e27 Mon Sep 17 00:00:00 2001 From: david-rocca Date: Wed, 19 Jul 2023 13:37:09 -0400 Subject: [PATCH 2/6] #1018 Updaing the post endpoint for creating users --- src/constants/index.js | 4 ++++ src/controller/org.controller/error.js | 7 +++++++ src/controller/org.controller/index.js | 8 ++++---- src/controller/org.controller/org.controller.js | 6 ++++++ src/middleware/errorMessages.js | 6 +++++- src/model/user.js | 4 ++++ src/repositories/userRepository.js | 4 ++++ 7 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/constants/index.js b/src/constants/index.js index 4675180b2..eebae31b9 100644 --- a/src/constants/index.js +++ b/src/constants/index.js @@ -92,6 +92,10 @@ function getConstants () { }, MAX_SHORTNAME_LENGTH: 32, MIN_SHORTNAME_LENGTH: 2, + MAX_FIRSTNAME_LENGTH: 100, + MAX_LASTNAME_LENGTH: 100, + MAX_MIDDLENAME_LENGTH: 100, + MAX_SUFFIX_LENGTH: 100, CVE_ID_PATTERN: cveSchemaV5.definitions.cveId.pattern, // Ajv's pattern validation uses the "u" (unicode) flag: // https://ajv.js.org/json-schema.html#pattern diff --git a/src/controller/org.controller/error.js b/src/controller/org.controller/error.js index bb83e2c3d..4c4df5fd3 100644 --- a/src/controller/org.controller/error.js +++ b/src/controller/org.controller/error.js @@ -84,6 +84,13 @@ class OrgControllerError extends idrErr.IDRError { err.message = 'Please have another admin user from your organization change your role.' return err } + + userLimitReached () { + const err = {} + err.error = 'NUMBER_OF_USERS_IN_ORG_LIMIT_REACHED' + err.message = 'The requested user can not be created and added to the organization because the organization has hit its limit of 100 users. Contact the Secretariat.' + return err + } } module.exports = { diff --git a/src/controller/org.controller/index.js b/src/controller/org.controller/index.js index 2be6777a6..4851a7fda 100644 --- a/src/controller/org.controller/index.js +++ b/src/controller/org.controller/index.js @@ -550,10 +550,10 @@ router.post('/org/:shortname/user', body(['username']).isString().trim().escape().notEmpty().custom(isValidUsername), body(['org_uuid']).optional().isString().trim().escape(), body(['uuid']).optional().isString().trim().escape(), - body(['name.first']).optional().isString().trim().escape(), - body(['name.last']).optional().isString().trim().escape(), - body(['name.middle']).optional().isString().trim().escape(), - body(['name.suffix']).optional().isString().trim().escape(), + body(['name.first']).optional().isString().trim().escape().isLength({ max: CONSTANTS.MAX_FIRSTNAME_LENGTH }).withMessage(errorMsgs.FIRSTNAME_LENGTH), + body(['name.last']).optional().isString().trim().escape().isLength({ max: CONSTANTS.MAX_LASTNAME_LENGTH }).withMessage(errorMsgs.LASTNAME_LENGTH), + body(['name.middle']).optional().isString().trim().escape().isLength({ max: CONSTANTS.MAX_MIDDLENAME_LENGTH }).withMessage(errorMsgs.MIDDLENAME_LENGTH), + body(['name.suffix']).optional().isString().trim().escape().isLength({ max: CONSTANTS.MAX_SUFFIX_LENGTH }).withMessage(errorMsgs.SUFFIX_LENGTH), body(['authority.active_roles']).optional() .custom(mw.isFlatStringArray) .customSanitizer(toUpperCaseArray) diff --git a/src/controller/org.controller/org.controller.js b/src/controller/org.controller/org.controller.js index bf0ae6573..62e38fe33 100644 --- a/src/controller/org.controller/org.controller.js +++ b/src/controller/org.controller/org.controller.js @@ -445,6 +445,12 @@ async function createUser (req, res, next) { return res.status(404).json(error.orgDnePathParam(orgShortName)) } + const users = await userRepo.findUsersByOrgUUID(orgUUID) + + if (users >= 100) { + return res.status(400).json(error.userLimitReached()) + } + Object.keys(req.ctx.body).forEach(k => { const key = k.toLowerCase() diff --git a/src/middleware/errorMessages.js b/src/middleware/errorMessages.js index 327850cfa..6f6a1b916 100644 --- a/src/middleware/errorMessages.js +++ b/src/middleware/errorMessages.js @@ -9,5 +9,9 @@ module.exports = { CVE_FILTERED_STATES: 'Invalid record state. Valid states are: PUBLISHED, REJECTED', COUNT_ONLY: 'Invalid count_only value. Value should be 1, true, or yes to indicate true, or 0, false, or no to indicate false', TIMESTAMP_FORMAT: "Bad date, or invalid timestamp format: valid format is yyyy-MM-ddTHH:mm:ss or yyyy-MM-ddTHH:mm:ssZZZZ (to use '+' in timezone offset, encode as '%2B)", - CNA_MODIFIED: 'Invalid cna_modified value. Value should be 1, true, or yes to indicate true, or 0, false, or no to indicate false' + CNA_MODIFIED: 'Invalid cna_modified value. Value should be 1, true, or yes to indicate true, or 0, false, or no to indicate false', + FIRSTNAME_LENGTH: 'Invalid name.first. Name must be between 1 and 100 characters in length.', + LASTNAME_LENGTH: 'Invalid name.last. Name must be between 1 and 100 characters in length.', + MIDDLENAME_LENGTH: 'Invalid name.middle. Name must be between 1 and 100 characters in length.', + SUFFIX_LENGTH: 'Invalid name.suffix. Name must be between 1 and 100 characters in length.' } diff --git a/src/model/user.js b/src/model/user.js index b34f6b60f..e536c07df 100644 --- a/src/model/user.js +++ b/src/model/user.js @@ -33,6 +33,10 @@ UserSchema.query.byUUID = function (uuid) { return this.where({ UUID: uuid }) } +UserSchema.query.byOrgUUID = function (orgUUID) { + return this.where({ org_UUID: orgUUID }) +} + UserSchema.query.byUserNameAndOrgUUID = function (username, orgUUID) { return this.where({ username: username, org_UUID: orgUUID }) } diff --git a/src/repositories/userRepository.js b/src/repositories/userRepository.js index 26204d9dd..4aa255a42 100644 --- a/src/repositories/userRepository.js +++ b/src/repositories/userRepository.js @@ -23,6 +23,10 @@ class UserRepository extends BaseRepository { return this.collection.findOne().byUUID(UUID) } + async findUsersByOrgUUID (orgUUID) { + return this.collection.find().byOrgUUID(orgUUID).countDocuments().exec() + } + async findOneByUserNameAndOrgUUID (userName, orgUUID) { return this.collection.findOne().byUserNameAndOrgUUID(userName, orgUUID) } From 7745bbd00b84eec8f87dc208e7ecdf8c30a4907d Mon Sep 17 00:00:00 2001 From: david-rocca Date: Wed, 19 Jul 2023 13:42:49 -0400 Subject: [PATCH 3/6] #1018 Update put endpoint for users to use new limits --- src/controller/org.controller/index.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/controller/org.controller/index.js b/src/controller/org.controller/index.js index 4851a7fda..25b69e8a5 100644 --- a/src/controller/org.controller/index.js +++ b/src/controller/org.controller/index.js @@ -722,10 +722,10 @@ router.put('/org/:shortname/user/:username', query(['active']).optional().isBoolean({ loose: true }), query(['new_username']).optional().isString().trim().escape().notEmpty().custom(isValidUsername), query(['org_short_name']).optional().isString().trim().escape().notEmpty().isLength({ min: CONSTANTS.MIN_SHORTNAME_LENGTH, max: CONSTANTS.MAX_SHORTNAME_LENGTH }), - query(['name.first']).optional().isString().trim().escape(), - query(['name.last']).optional().isString().trim().escape(), - query(['name.middle']).optional().isString().trim().escape(), - query(['name.suffix']).optional().isString().trim().escape(), + body(['name.first']).optional().isString().trim().escape().isLength({ max: CONSTANTS.MAX_FIRSTNAME_LENGTH }).withMessage(errorMsgs.FIRSTNAME_LENGTH), + body(['name.last']).optional().isString().trim().escape().isLength({ max: CONSTANTS.MAX_LASTNAME_LENGTH }).withMessage(errorMsgs.LASTNAME_LENGTH), + body(['name.middle']).optional().isString().trim().escape().isLength({ max: CONSTANTS.MAX_MIDDLENAME_LENGTH }).withMessage(errorMsgs.MIDDLENAME_LENGTH), + body(['name.suffix']).optional().isString().trim().escape().isLength({ max: CONSTANTS.MAX_SUFFIX_LENGTH }).withMessage(errorMsgs.SUFFIX_LENGTH), query(['active_roles.add']).optional().toArray() .custom(isFlatStringArray) .customSanitizer(toUpperCaseArray) From 51c6565f01fc1cf3c4948a8311373018974c70de Mon Sep 17 00:00:00 2001 From: david-rocca Date: Fri, 21 Jul 2023 13:11:24 -0400 Subject: [PATCH 4/6] #1018 updated unit tests to new format --- test/unit-tests/user/userCreateTest.js | 556 ++++--------------------- 1 file changed, 70 insertions(+), 486 deletions(-) diff --git a/test/unit-tests/user/userCreateTest.js b/test/unit-tests/user/userCreateTest.js index 7c527104b..167bf984f 100644 --- a/test/unit-tests/user/userCreateTest.js +++ b/test/unit-tests/user/userCreateTest.js @@ -1,506 +1,90 @@ -const express = require('express') -const app = express() + +const sinon = require('sinon') const chai = require('chai') const expect = chai.expect -chai.use(require('chai-http')) - -// Body Parser Middleware -app.use(express.json()) // Allows us to handle raw JSON data -app.use(express.urlencoded({ extended: false })) // Allows us to handle url encoded data -const middleware = require('../../../src/middleware/middleware') -app.use(middleware.createCtxAndReqUUID) - -const getConstants = require('../../../src/constants').getConstants -const errors = require('../../../src/controller/org.controller/error') -const error = new errors.OrgControllerError() - -const userFixtures = require('./mockObjects.user') -const orgController = require('../../../src/controller/org.controller/org.controller') -const orgParams = require('../../../src/controller/org.controller/org.middleware') - -class NullUserRepo { - async getUserUUID () { - return null - } - - async findOneByUserNameAndOrgUUID () { - return null - } - - async isAdmin () { - return null - } -} - -class OrgCreatedUserOrgUndefined { - async isSecretariatUUID () { - return true - } - - async getOrgUUID () { - return userFixtures.existentOrg.UUID - } - - async findOneByUUID () { - return userFixtures.existentOrg - } -} - -class UserCreatedOrgUndefined { - async findOneByUserNameAndOrgUUID () { - return null - } - - async updateByUserNameAndOrgUUID () { - return null - } - - async getUserUUID () { - return null - } - - async isAdminUUID () { - return false - } -} - -class OrgCreatedUserWithRole { - async isSecretariatUUID () { - return true - } - - async getOrgUUID () { - return userFixtures.existentOrgDummy.UUID - } - - async findOneByUUID () { - return userFixtures.existentOrgDummy - } -} +const { faker } = require('@faker-js/faker') -class UserCreatedAdminWithRole { - constructor () { - const CONSTANTS = getConstants() +const { USER_CREATE_SINGLE } = require('../../../src/controller/org.controller/org.controller') - this.testRes1 = JSON.parse(JSON.stringify(userFixtures.userC)) - this.testRes1.authority.active_roles[0] = CONSTANTS.USER_ROLE_ENUM.ADMIN - } +const UserRepository = require('../../../src/repositories/userRepository') +const OrgRepository = require('../../../src/repositories/orgRepository') +const { async } = require('crypto-random-string') - async findOneByUserNameAndOrgUUID () { - return null - } - - async isAdminUUID () { - return true - } - - async updateByUserNameAndOrgUUID () { - return null - } - - async getUserUUID () { - return null - } +const stubOrgUUID = faker.datatype.uuid() - async aggregate () { - return [this.testRes1] +const stubOrg = { + short_name: 'stubOrg', + name: 'test_user', + UUID: stubOrgUUID, + authority: { + active_roles: ['ADMIN', 'CNA'] } } -class OrgCantCreateUserOrgDoesNotMatch { - async getOrgUUID () { - return userFixtures.existentOrg.UUID - } +const stubUser = { + username: 'stubUser', + org_UUID: stubOrgUUID, + UUID: faker.datatype.uuid() } describe('Testing the POST /org/:shortname/user endpoint in Org Controller', () => { - context('Negative Tests', () => { - it('User is not created because org does not exist', (done) => { - class OrgCantCreateUserOrgDoesNotExist { - async getOrgUUID () { - return null - } - } - - app.route('/user-not-created-org-does-not-exist/:shortname') - .post((req, res, next) => { - const factory = { - getOrgRepository: () => { return new OrgCantCreateUserOrgDoesNotExist() }, - getUserRepository: () => { return new NullUserRepo() } - } - req.ctx.repositories = factory - next() - }, orgParams.parsePostParams, orgController.USER_CREATE_SINGLE) - - chai.request(app) - .post(`/user-not-created-org-does-not-exist/${userFixtures.nonExistentOrg.short_name}`) - .set(userFixtures.secretariatHeader) - .send(userFixtures.nonExistentUser) - .end((err, res) => { - if (err) { - done(err) - } - - expect(res).to.have.status(404) - expect(res).to.have.property('body').and.to.be.a('object') - const errObj = error.orgDnePathParam(userFixtures.nonExistentOrg.short_name) - expect(res.body.error).to.equal(errObj.error) - expect(res.body.message).to.equal(errObj.message) - done() - }) - }) - - it('Param org\'s UUID is provided', (done) => { - app.route('/user-not-created-org-uuid-provided/:shortname') - .post((req, res, next) => { - const factory = { - getOrgRepository: () => { return new OrgCantCreateUserOrgDoesNotMatch() }, - getUserRepository: () => { return new NullUserRepo() } - } - req.ctx.repositories = factory - next() - }, orgParams.parsePostParams, orgController.USER_CREATE_SINGLE) - - chai.request(app) - .post(`/user-not-created-org-uuid-provided/${userFixtures.existentOrg.short_name}`) - .set(userFixtures.secretariatHeader) - .send(userFixtures.existentUser) - .end((err, res) => { - if (err) { - done(err) - } - - expect(res).to.have.status(400) - expect(res).to.have.property('body').and.to.be.a('object') - const errObj = error.uuidProvided('user') - expect(res.body.error).to.equal(errObj.error) - expect(res.body.message).to.equal(errObj.message) - done() - }) - }) - - it('Param user\'s UUID is provided', (done) => { - app.route('/user-not-created-user-uuid-provided/:shortname') - .post((req, res, next) => { - const factory = { - getOrgRepository: () => { return new OrgCantCreateUserOrgDoesNotMatch() }, - getUserRepository: () => { return new UserCreatedOrgUndefined() } - } - req.ctx.repositories = factory - next() - }, orgParams.parsePostParams, orgController.USER_CREATE_SINGLE) - - chai.request(app) - .post(`/user-not-created-user-uuid-provided/${userFixtures.existentOrg.short_name}`) - .set(userFixtures.secretariatHeader) - .send(userFixtures.nonExistentUser) - .end((err, res) => { - if (err) { - done(err) - } - - expect(res).to.have.status(400) - expect(res).to.have.property('body').and.to.be.a('object') - const errObj = error.uuidProvided('user') - expect(res.body.error).to.equal(errObj.error) - expect(res.body.message).to.equal(errObj.message) - done() - }) - }) - - it('User is not created because it already exists', (done) => { - class UserNotCreatedAlreadyExists { - async findOneByUserNameAndOrgUUID () { - return userFixtures.existentUser - } - - async isAdminUUID () { - return false - } - } - - app.route('/user-not-created-already-exists/:shortname') - .post((req, res, next) => { - const factory = { - getOrgRepository: () => { return new OrgCreatedUserOrgUndefined() }, - getUserRepository: () => { return new UserNotCreatedAlreadyExists() } - } - req.ctx.repositories = factory - next() - }, orgParams.parsePostParams, orgController.USER_CREATE_SINGLE) - - const testUser = Object.assign({}, userFixtures.existentUser) - delete testUser.UUID - delete testUser.org_UUID - - chai.request(app) - .post(`/user-not-created-already-exists/${userFixtures.existentOrg.short_name}`) - .set(userFixtures.secretariatHeader) - .send(testUser) - .end((err, res) => { - if (err) { - done(err) - } - - expect(res).to.have.status(400) - expect(res).to.have.property('body').and.to.be.a('object') - const errObj = error.userExists(userFixtures.existentUser.username) - expect(res.body.error).to.equal(errObj.error) - expect(res.body.message).to.equal(errObj.message) - done() - }) - }) - - it('User is not created because the requester is not an Org Admin user from the same org and is not the secretariat', done => { - class UserNotCreated { - async isAdminUUID () { - return true + let status, json, res, next, orgRepo, getOrgRepository, getUserRepository, userRepo, req, getOrg + + beforeEach(() => { + status = sinon.stub() + json = sinon.spy() + res = { json, status } + next = sinon.spy() + status.returns(res) + + userRepo = new UserRepository() + getUserRepository = sinon.stub() + getUserRepository.returns(userRepo) + + orgRepo = new OrgRepository() + getOrgRepository = sinon.stub() + getOrgRepository.returns(orgRepo) + // May have to replace this based on tests + getOrg = sinon.stub(orgRepo, 'getOrgUUID').returns(stubOrgUUID) + sinon.stub(userRepo, 'findUsersByOrgUUID').returns(1) + sinon.stub(orgRepo, 'isSecretariatUUID').returns(false) + sinon.stub(userRepo, 'isAdminUUID').returns(true) + sinon.stub(userRepo, 'findOneByUserNameAndOrgUUID').returns(null) + sinon.stub(userRepo, 'updateByUserNameAndOrgUUID').returns(true) + sinon.stub(userRepo, 'aggregate').returns([stubUser]) + sinon.stub(userRepo, 'getUserUUID').returns(stubUser.UUID) + + req = { + ctx: { + org: stubOrg.short_name, + uuid: stubOrg.UUID, + params: { + + }, + repositories: { + getOrgRepository, + getUserRepository + }, + body: { + stubUser } } - - class OrgCantCreateUserNotSecretariatOrAdmin { - async isSecretariatUUID () { - return false - } - - async getOrgUUID (shortname) { - if (shortname === userFixtures.existentOrgDummy.short_name) { - return userFixtures.existentOrgDummy.UUID - } - - return userFixtures.owningOrg.UUID - } - - async findOneByUUID (orgUUID) { - if (orgUUID === userFixtures.existentOrgDummy.UUID) { - return userFixtures.existentOrgDummy - } - - return userFixtures.owningOrg - } - } - - app.route('/user-not-created-not-secretariat-not-same-org-admin/:shortname') - .post((req, res, next) => { - const factory = { - getOrgRepository: () => { return new OrgCantCreateUserNotSecretariatOrAdmin() }, - getUserRepository: () => { return new UserNotCreated() } - } - req.ctx.repositories = factory - next() - }, orgParams.parsePostParams, orgController.USER_CREATE_SINGLE) - - const testUser = Object.assign({}, userFixtures.userA) - delete testUser.UUID - delete testUser.org_UUID - testUser.authority = { - active_roles: ['ADMIN'] - } - - chai.request(app) - .post(`/user-not-created-not-secretariat-not-same-org-admin/${userFixtures.existentOrgDummy.short_name}`) - .set(userFixtures.owningOrgHeader) - .send(testUser) - .end((err, res) => { - if (err) { - done(err) - } - - expect(res).to.have.status(403) - expect(res).to.have.property('body').and.to.be.a('object') - const errObj = error.notOrgAdminOrSecretariat() - expect(res.body.error).to.equal(errObj.error) - expect(res.body.message).to.equal(errObj.message) - done() - }) - }) + } }) - context('Positive Tests', () => { - it('Requester is secretariat and not Admin: User is created with the "ADMIN" role', done => { - class UserCreatedWithRole { - constructor () { - const CONSTANTS = getConstants() - - this.testRes1 = JSON.parse(JSON.stringify(userFixtures.userA)) - this.testRes1.authority.active_roles[0] = CONSTANTS.USER_ROLE_ENUM.ADMIN - } - - async findOneByUserNameAndOrgUUID () { - return null - } - - async isAdminUUID () { - return false - } - - async updateByUserNameAndOrgUUID () { - return null - } - - async getUserUUID () { - return null - } - - async aggregate () { - return [this.testRes1] - } - } - - app.route('/user-created-secretariat-not-admin/:shortname') - .post((req, res, next) => { - const factory = { - getOrgRepository: () => { return new OrgCreatedUserWithRole() }, - getUserRepository: () => { return new UserCreatedWithRole() } - } - req.ctx.repositories = factory - next() - }, orgParams.parsePostParams, orgController.USER_CREATE_SINGLE) - - const testUser = JSON.parse(JSON.stringify(userFixtures.userA)) - delete testUser.UUID - delete testUser.org_UUID - testUser.authority = { - active_roles: ['ADMIN'] - } - - chai.request(app) - .post(`/user-created-secretariat-not-admin/${userFixtures.existentOrgDummy.short_name}`) - .set(userFixtures.secretariatHeader) - .send(testUser) - .end((err, res) => { - if (err) { - done(err) - } - - expect(res).to.have.status(200) - expect(res).to.have.property('body').and.to.be.a('object') - expect(res.body).to.have.property('message').and.to.be.a('string') - expect(res.body.message).to.equal(testUser.username + ' was successfully created.') - expect(res.body).to.have.property('created').and.to.be.a('object') - expect(res.body.created).to.have.property('org_UUID').and.to.equal(userFixtures.existentOrgDummy.UUID) - expect(res.body.created).to.have.property('username').and.to.equal(testUser.username) - expect(res.body.created).to.have.nested.property('authority.active_roles').and.to.have.lengthOf(1) - expect(res.body.created.authority.active_roles[0]).to.equal(testUser.authority.active_roles[0]) - done() - }) - }) - - it('Requester is Admin and is not secretariat: User is created with the "ADMIN" role', done => { - class OrgCreatedUserAdminWithRole { - async isSecretariatUUID () { - return false - } - - async getOrgUUID () { - return userFixtures.existentOrgDummy.UUID - } - - async findOneByUUID () { - return userFixtures.existentOrgDummy - } - } - - app.route('/user-created-not-secretariat-same-org-admin/:shortname') - .post((req, res, next) => { - const factory = { - getOrgRepository: () => { return new OrgCreatedUserAdminWithRole() }, - getUserRepository: () => { return new UserCreatedAdminWithRole() } - } - req.ctx.repositories = factory - next() - }, orgParams.parsePostParams, orgController.USER_CREATE_SINGLE) - - userFixtures.userA.authority.active_roles = ['ADMIN'] - - const testUser = JSON.parse(JSON.stringify(userFixtures.userC)) - delete testUser.UUID - delete testUser.org_UUID - testUser.authority = { - active_roles: ['ADMIN'] - } - - chai.request(app) - .post(`/user-created-not-secretariat-same-org-admin/${userFixtures.existentOrgDummy.short_name}`) - .set(userFixtures.userAHeader) - .send(testUser) - .end((err, res) => { - if (err) { - done(err) - } - - expect(res).to.have.status(200) - expect(res).to.have.property('body').and.to.be.a('object') - expect(res.body).to.have.property('message').and.to.be.a('string') - expect(res.body.message).to.equal(testUser.username + ' was successfully created.') - expect(res.body).to.have.property('created').and.to.be.a('object') - expect(res.body.created).to.have.property('org_UUID').and.to.equal(userFixtures.existentOrgDummy.UUID) - expect(res.body.created).to.have.property('username').and.to.equal(testUser.username) - expect(res.body.created).to.have.nested.property('authority.active_roles').and.to.have.lengthOf(1) - expect(res.body.created.authority.active_roles[0]).to.equal(testUser.authority.active_roles[0]) - userFixtures.userA.authority.active_roles = [] - done() - }) + it('User is created', async () => { + await USER_CREATE_SINGLE(req, res, next) + expect(status.args[0][0]).to.equal(200) + expect(res.json.args[0][0].message).contains('was successfully created') }) - - it('Requester is secretariat and Admin: User is created without a user role', done => { - class UserCreatedAdminWithoutRole { - async findOneByUserNameAndOrgUUID () { - return null - } - - async isAdminUUID () { - return true - } - - async updateByUserNameAndOrgUUID () { - return null - } - - async getUserUUID () { - return null - } - - async aggregate () { - return [userFixtures.userA] - } - } - - app.route('/user-created-secretariat-same-org-admin/:shortname') - .post((req, res, next) => { - const factory = { - getOrgRepository: () => { return new OrgCreatedUserWithRole() }, - getUserRepository: () => { return new UserCreatedAdminWithoutRole() } - } - req.ctx.repositories = factory - next() - }, orgParams.parsePostParams, orgController.USER_CREATE_SINGLE) - - userFixtures.existentUser.authority.active_roles = ['ADMIN'] - const testUser = JSON.parse(JSON.stringify(userFixtures.userA)) - delete testUser.UUID - delete testUser.org_UUID - - chai.request(app) - .post(`/user-created-secretariat-same-org-admin/${userFixtures.existentOrgDummy.short_name}`) - .set(userFixtures.secretariatHeader) - .send(testUser) - .end((err, res) => { - if (err) { - done(err) - } - - expect(res).to.have.status(200) - expect(res).to.have.property('body').and.to.be.a('object') - expect(res.body).to.have.property('message').and.to.be.a('string') - expect(res.body.message).to.equal(userFixtures.userA.username + ' was successfully created.') - expect(res.body).to.have.property('created').and.to.be.a('object') - expect(res.body.created).to.have.property('org_UUID').and.to.equal(userFixtures.existentOrgDummy.UUID) - expect(res.body.created).to.have.property('username').and.to.equal(userFixtures.userA.username) - expect(res.body.created).to.have.nested.property('authority.active_roles').and.to.have.lengthOf(0) - userFixtures.existentUser.authority.active_roles = [] - done() - }) + }) + context('Negitive tests', () => { + it('User Fails to be created because not in the same org', async () => { + req.ctx.org = 'FakeShortName' + getOrg.withArgs('FakeShortName').returns('FAKEUUID') + await USER_CREATE_SINGLE(req, res, next) + expect(status.args[0][0]).to.equal(403) + expect(res.json.args[0][0].error).contains('NOT_ORG_ADMIN_OR_SECRETARIAT') }) }) }) From e839fd5189d3b2f20e2df305ab2372d59d343c8c Mon Sep 17 00:00:00 2001 From: david-rocca Date: Fri, 21 Jul 2023 13:35:36 -0400 Subject: [PATCH 5/6] #1018 removed rogue import --- test/unit-tests/user/userCreateTest.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/unit-tests/user/userCreateTest.js b/test/unit-tests/user/userCreateTest.js index 167bf984f..ea3b1fce2 100644 --- a/test/unit-tests/user/userCreateTest.js +++ b/test/unit-tests/user/userCreateTest.js @@ -8,7 +8,6 @@ const { USER_CREATE_SINGLE } = require('../../../src/controller/org.controller/o const UserRepository = require('../../../src/repositories/userRepository') const OrgRepository = require('../../../src/repositories/orgRepository') -const { async } = require('crypto-random-string') const stubOrgUUID = faker.datatype.uuid() From 9ea204044da185a78e0bce009deff3b87ba18e86 Mon Sep 17 00:00:00 2001 From: david-rocca Date: Tue, 25 Jul 2023 10:20:36 -0400 Subject: [PATCH 6/6] #1018 remove rogue only --- test/integration-tests/org/postOrgUsersTest.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration-tests/org/postOrgUsersTest.js b/test/integration-tests/org/postOrgUsersTest.js index 5890fde8f..6ca02003a 100644 --- a/test/integration-tests/org/postOrgUsersTest.js +++ b/test/integration-tests/org/postOrgUsersTest.js @@ -14,7 +14,7 @@ const cryptoRandomString = require('crypto-random-string') const shortName = { shortname: 'win_5' } -describe.only('Testing user post endpoint', () => { +describe('Testing user post endpoint', () => { let orgUuid context('Positive Tests', () => { it('Allows creation of user', async () => {