diff --git a/routes.rest b/routes.rest index 4044e93..91d8954 100644 --- a/routes.rest +++ b/routes.rest @@ -12,13 +12,23 @@ Content-Type: application/json "username": "username2", "password": "some password" } + ### -POST http://localhost:5000/SASjsApi/auth/authorize +POST http://localhost:5000/SASjsApi/client +Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRfaWQiOiJjbGllbnRJRDEiLCJ1c2VybmFtZSI6InNlY3JldHVzZXIiLCJpc2FkbWluIjp0cnVlLCJpc2FjdGl2ZSI6dHJ1ZSwiaWF0IjoxNjM1ODAzOTc3LCJleHAiOjE2MzU4OTAzNzd9.f-FLgLwryKvB5XrihdzaGZajO3d5E5OHEEuJI_03GRI Content-Type: application/json { - "username": "username1", - "password": "some password", + "client_id": "newClientID", + "client_secret": "newClientSecret" +} +### +POST https://sas.analytium.co.uk:5002/SASjsApi/auth/authorize +Content-Type: application/json + +{ + "username": "secretuser", + "password": "secretpassword", "client_id": "clientID1" } @@ -34,3 +44,14 @@ Content-Type: application/json ### DELETE http://localhost:5000/SASjsApi/auth/logout + + +Users + "username": "username1", + "password": "some password", + + "username": "username2", + "password": "some password", +Admins + "username": "secretuser", + "password": "secretpassword", \ No newline at end of file diff --git a/src/controllers/createClient.ts b/src/controllers/createClient.ts index b768d87..4d8f0d3 100644 --- a/src/controllers/createClient.ts +++ b/src/controllers/createClient.ts @@ -1,7 +1,7 @@ import Client from '../model/Client' export const createClient = async (data: any) => { - const { clientid, clientsecret } = data + const { client_id: clientid, client_secret: clientsecret } = data // Checking if client is already in the database const clientExist = await Client.findOne({ clientid }) @@ -16,7 +16,7 @@ export const createClient = async (data: any) => { const savedClient = await client.save() return { - clientid: savedClient.clientid, - clientsecret: savedClient.clientsecret + client_id: savedClient.clientid, + client_secret: savedClient.clientsecret } } diff --git a/src/routes/api/client.ts b/src/routes/api/client.ts new file mode 100644 index 0000000..875e769 --- /dev/null +++ b/src/routes/api/client.ts @@ -0,0 +1,22 @@ +import express from 'express' +import { createClient } from '../../controllers/createClient' +import { registerClientValidation } from '../../utils' + +const clientRouter = express.Router() + +clientRouter.post('/', async (req, res) => { + const { error, value: data } = registerClientValidation(req.body) + if (error) return res.status(400).send(error.details[0].message) + + try { + const savedClient = await createClient(data) + res.send({ + client_id: savedClient.client_id, + client_secret: savedClient.client_secret + }) + } catch (err: any) { + res.status(403).send(err.toString()) + } +}) + +export default clientRouter diff --git a/src/routes/api/index.ts b/src/routes/api/index.ts index f25bbd0..1e313aa 100644 --- a/src/routes/api/index.ts +++ b/src/routes/api/index.ts @@ -6,6 +6,7 @@ import { InfoJWT } from '../../types' import driveRouter from './drive' import stpRouter from './stp' import userRouter from './user' +import clientRouter from './client' import authRouter, { connectDB } from './auth' dotenv.config() @@ -16,6 +17,7 @@ const router = express.Router() router.use('/drive', authenticateToken, driveRouter) router.use('/stp', authenticateToken, stpRouter) router.use('/user', authenticateToken, verifyAdmin, userRouter) +router.use('/client', authenticateToken, verifyAdmin, clientRouter) router.use('/auth', authRouter) function authenticateToken(req: any, res: any, next: any) { diff --git a/src/routes/api/spec/auth.spec.ts b/src/routes/api/spec/auth.spec.ts index 6fe80ce..26683d4 100644 --- a/src/routes/api/spec/auth.spec.ts +++ b/src/routes/api/spec/auth.spec.ts @@ -8,8 +8,8 @@ import { generateAuthCode, populateClients, saveCode } from '../auth' import { InfoJWT } from '../../../types' const client = { - clientid: 'someclientID', - clientsecret: 'someclientSecret' + client_id: 'someclientID', + client_secret: 'someclientSecret' } const user = { displayname: 'Test User', @@ -51,7 +51,7 @@ describe('auth', () => { .send({ username: user.username, password: user.password, - client_id: client.clientid + client_id: client.client_id }) .expect(200) @@ -63,7 +63,7 @@ describe('auth', () => { .post('/SASjsApi/auth/authorize') .send({ password: user.password, - client_id: client.clientid + client_id: client.client_id }) .expect(400) @@ -76,7 +76,7 @@ describe('auth', () => { .post('/SASjsApi/auth/authorize') .send({ username: user.username, - client_id: client.clientid + client_id: client.client_id }) .expect(400) @@ -103,7 +103,7 @@ describe('auth', () => { .send({ username: user.username, password: user.password, - client_id: client.clientid + client_id: client.client_id }) .expect(403) @@ -119,7 +119,7 @@ describe('auth', () => { .send({ username: user.username, password: 'WrongPassword', - client_id: client.clientid + client_id: client.client_id }) .expect(403) @@ -146,7 +146,7 @@ describe('auth', () => { describe('token', () => { const userInfo: InfoJWT = { - client_id: client.clientid, + client_id: client.client_id, username: user.username, isadmin: user.isadmin, isactive: user.isactive @@ -166,8 +166,8 @@ describe('auth', () => { const res = await request(app) .post('/SASjsApi/auth/token') .send({ - client_id: client.clientid, - client_secret: client.clientsecret, + client_id: client.client_id, + client_secret: client.client_secret, code }) .expect(200) @@ -180,8 +180,8 @@ describe('auth', () => { const res = await request(app) .post('/SASjsApi/auth/token') .send({ - client_id: client.clientid, - client_secret: client.clientsecret + client_id: client.client_id, + client_secret: client.client_secret }) .expect(400) @@ -195,7 +195,7 @@ describe('auth', () => { const res = await request(app) .post('/SASjsApi/auth/token') .send({ - client_secret: client.clientsecret, + client_secret: client.client_secret, code }) .expect(400) @@ -210,7 +210,7 @@ describe('auth', () => { const res = await request(app) .post('/SASjsApi/auth/token') .send({ - client_id: client.clientid, + client_id: client.client_id, code }) .expect(400) @@ -223,8 +223,8 @@ describe('auth', () => { const res = await request(app) .post('/SASjsApi/auth/token') .send({ - client_id: client.clientid, - client_secret: client.clientsecret, + client_id: client.client_id, + client_secret: client.client_secret, code: 'InvalidCode' }) .expect(403) @@ -239,7 +239,7 @@ describe('auth', () => { .post('/SASjsApi/auth/token') .send({ client_id: 'WrongClientID', - client_secret: client.clientsecret, + client_secret: client.client_secret, code }) .expect(403) @@ -253,7 +253,7 @@ describe('auth', () => { const res = await request(app) .post('/SASjsApi/auth/token') .send({ - client_id: client.clientid, + client_id: client.client_id, client_secret: 'WrongClientSecret', code }) diff --git a/src/routes/api/spec/client.spec.ts b/src/routes/api/spec/client.spec.ts new file mode 100644 index 0000000..a06cce8 --- /dev/null +++ b/src/routes/api/spec/client.spec.ts @@ -0,0 +1,122 @@ +import mongoose, { Mongoose } from 'mongoose' +import { MongoMemoryServer } from 'mongodb-memory-server' +import request from 'supertest' +import app from '../../../app' +import { createClient } from '../../../controllers/createClient' +import { generateAccessToken } from '../auth' + +const client = { + client_id: 'newClientID', + client_secret: 'newClientSecret' +} + +describe('user', () => { + let con: Mongoose + let mongoServer: MongoMemoryServer + + beforeAll(async () => { + mongoServer = await MongoMemoryServer.create() + con = await mongoose.connect(mongoServer.getUri()) + }) + + afterAll(async () => { + await con.connection.dropDatabase() + await con.connection.close() + await mongoServer.stop() + }) + + describe('create', () => { + const adminAccessToken = generateAccessToken({ + client_id: 'someClientID', + username: 'someAdminUsername', + isadmin: true, + isactive: true + }) + + afterEach(async () => { + const collections = mongoose.connection.collections + const collection = collections['clients'] + await collection.deleteMany({}) + }) + + it('should respond with new client', async () => { + const res = await request(app) + .post('/SASjsApi/client') + .auth(adminAccessToken, { type: 'bearer' }) + .send(client) + .expect(200) + + expect(res.body.client_id).toEqual(client.client_id) + expect(res.body.client_secret).toEqual(client.client_secret) + }) + + it('should respond with Unauthorized if access token is not present', async () => { + const res = await request(app) + .post('/SASjsApi/client') + .send(client) + .expect(401) + + expect(res.text).toEqual('Unauthorized') + expect(res.body).toEqual({}) + }) + + it('should respond with Forbideen if access token is not of an admin account', async () => { + const accessToken = generateAccessToken({ + client_id: 'someClientID', + username: 'someUsername', + isadmin: false, + isactive: true + }) + + const res = await request(app) + .post('/SASjsApi/client') + .auth(accessToken, { type: 'bearer' }) + .send(client) + .expect(403) + + expect(res.text).toEqual('Admin account required') + expect(res.body).toEqual({}) + }) + + it('should respond with Forbidden if client_id is already present', async () => { + await createClient(client) + + const res = await request(app) + .post('/SASjsApi/client') + .auth(adminAccessToken, { type: 'bearer' }) + .send(client) + .expect(403) + + expect(res.text).toEqual('Error: Client ID already exists.') + expect(res.body).toEqual({}) + }) + + it('should respond with Bad Request if client_id is missing', async () => { + const res = await request(app) + .post('/SASjsApi/client') + .auth(adminAccessToken, { type: 'bearer' }) + .send({ + ...client, + client_id: undefined + }) + .expect(400) + + expect(res.text).toEqual(`"client_id" is required`) + expect(res.body).toEqual({}) + }) + + it('should respond with Bad Request if client_secret is missing', async () => { + const res = await request(app) + .post('/SASjsApi/client') + .auth(adminAccessToken, { type: 'bearer' }) + .send({ + ...client, + client_secret: undefined + }) + .expect(400) + + expect(res.text).toEqual(`"client_secret" is required`) + expect(res.body).toEqual({}) + }) + }) +}) diff --git a/src/routes/api/spec/user.spec.ts b/src/routes/api/spec/user.spec.ts index d0e6d1c..8855875 100644 --- a/src/routes/api/spec/user.spec.ts +++ b/src/routes/api/spec/user.spec.ts @@ -3,9 +3,7 @@ import { MongoMemoryServer } from 'mongodb-memory-server' import request from 'supertest' import app from '../../../app' import { createUser } from '../../../controllers/createUser' -import { createClient } from '../../../controllers/createClient' -import { generateAccessToken, populateClients } from '../auth' -import { InfoJWT } from '../../../types' +import { generateAccessToken } from '../auth' const client = { clientid: 'someclientID', diff --git a/src/routes/api/user.ts b/src/routes/api/user.ts index 0e33dec..7fa712b 100644 --- a/src/routes/api/user.ts +++ b/src/routes/api/user.ts @@ -1,11 +1,11 @@ import express from 'express' import { createUser } from '../../controllers/createUser' -import { registerValidation } from '../../utils' +import { registerUserValidation } from '../../utils' const userRouter = express.Router() userRouter.post('/', async (req, res) => { - const { error, value: data } = registerValidation(req.body) + const { error, value: data } = registerUserValidation(req.body) if (error) return res.status(400).send(error.details[0].message) try { diff --git a/src/utils/validation.ts b/src/utils/validation.ts index d31de06..f4f5491 100644 --- a/src/utils/validation.ts +++ b/src/utils/validation.ts @@ -17,7 +17,7 @@ export const tokenValidation = (data: any): Joi.ValidationResult => code: Joi.string().required() }).validate(data) -export const registerValidation = (data: any): Joi.ValidationResult => +export const registerUserValidation = (data: any): Joi.ValidationResult => Joi.object({ displayname: Joi.string().min(6).required(), username: usernameSchema, @@ -25,3 +25,9 @@ export const registerValidation = (data: any): Joi.ValidationResult => isadmin: Joi.boolean(), isactive: Joi.boolean() }).validate(data) + +export const registerClientValidation = (data: any): Joi.ValidationResult => + Joi.object({ + client_id: Joi.string().required(), + client_secret: Joi.string().required() + }).validate(data)