mirror of
https://github.com/sasjs/server.git
synced 2026-01-07 06:30:06 +00:00
test(web): moved authorize specs from api to web
This commit is contained in:
@@ -85,21 +85,25 @@ if (MODE?.trim() !== 'server' || CORS?.trim() === 'enable') {
|
|||||||
* With Mongo Store *
|
* With Mongo Store *
|
||||||
***********************************/
|
***********************************/
|
||||||
if (MODE?.trim() === 'server') {
|
if (MODE?.trim() === 'server') {
|
||||||
|
let store: MongoStore | undefined
|
||||||
|
|
||||||
// NOTE: when exporting app.js as agent for supertest
|
// NOTE: when exporting app.js as agent for supertest
|
||||||
// we should exclude connecting to the real database
|
// we should exclude connecting to the real database
|
||||||
if (process.env.NODE_ENV !== 'test') {
|
if (process.env.NODE_ENV !== 'test') {
|
||||||
const clientPromise = connectDB().then((conn) => conn!.getClient() as any)
|
const clientPromise = connectDB().then((conn) => conn!.getClient() as any)
|
||||||
|
|
||||||
|
store = MongoStore.create({ clientPromise, collectionName: 'sessions' })
|
||||||
|
}
|
||||||
|
|
||||||
app.use(
|
app.use(
|
||||||
session({
|
session({
|
||||||
secret: process.env.SESSION_SECRET as string,
|
secret: process.env.SESSION_SECRET as string,
|
||||||
saveUninitialized: false, // don't create session until something stored
|
saveUninitialized: false, // don't create session until something stored
|
||||||
resave: false, //don't save session if unmodified
|
resave: false, //don't save session if unmodified
|
||||||
store: MongoStore.create({ clientPromise, collectionName: 'sessions' }),
|
store,
|
||||||
cookie: cookieOptions
|
cookie: cookieOptions
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
app.use(express.json({ limit: '100mb' }))
|
app.use(express.json({ limit: '100mb' }))
|
||||||
app.use(express.static(path.join(__dirname, '../public')))
|
app.use(express.static(path.join(__dirname, '../public')))
|
||||||
|
|||||||
@@ -108,6 +108,10 @@ const authorize = async (
|
|||||||
): Promise<AuthorizeResponse> => {
|
): Promise<AuthorizeResponse> => {
|
||||||
const userId = req.session.user?.userId
|
const userId = req.session.user?.userId
|
||||||
if (!userId) throw new Error('Invalid userId.')
|
if (!userId) throw new Error('Invalid userId.')
|
||||||
|
|
||||||
|
const client = await Client.findOne({ clientId })
|
||||||
|
if (!client) throw new Error('Invalid clientId.')
|
||||||
|
|
||||||
// generate authorization code against clientId
|
// generate authorization code against clientId
|
||||||
const userInfo: InfoJWT = {
|
const userInfo: InfoJWT = {
|
||||||
clientId,
|
clientId,
|
||||||
|
|||||||
@@ -49,114 +49,6 @@ describe('auth', () => {
|
|||||||
await mongoServer.stop()
|
await mongoServer.stop()
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('authorize', () => {
|
|
||||||
afterEach(async () => {
|
|
||||||
const collections = mongoose.connection.collections
|
|
||||||
const collection = collections['users']
|
|
||||||
await collection.deleteMany({})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should respond with authorization code', async () => {
|
|
||||||
await userController.createUser(user)
|
|
||||||
|
|
||||||
const res = await request(app)
|
|
||||||
.post('/SASjsApi/auth/authorize')
|
|
||||||
.send({
|
|
||||||
username: user.username,
|
|
||||||
password: user.password,
|
|
||||||
clientId
|
|
||||||
})
|
|
||||||
.expect(200)
|
|
||||||
|
|
||||||
expect(res.body).toHaveProperty('code')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should respond with Bad Request if username is missing', async () => {
|
|
||||||
const res = await request(app)
|
|
||||||
.post('/SASjsApi/auth/authorize')
|
|
||||||
.send({
|
|
||||||
password: user.password,
|
|
||||||
clientId
|
|
||||||
})
|
|
||||||
.expect(400)
|
|
||||||
|
|
||||||
expect(res.text).toEqual(`"username" is required`)
|
|
||||||
expect(res.body).toEqual({})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should respond with Bad Request if password is missing', async () => {
|
|
||||||
const res = await request(app)
|
|
||||||
.post('/SASjsApi/auth/authorize')
|
|
||||||
.send({
|
|
||||||
username: user.username,
|
|
||||||
clientId
|
|
||||||
})
|
|
||||||
.expect(400)
|
|
||||||
|
|
||||||
expect(res.text).toEqual(`"password" is required`)
|
|
||||||
expect(res.body).toEqual({})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should respond with Bad Request if clientId is missing', async () => {
|
|
||||||
const res = await request(app)
|
|
||||||
.post('/SASjsApi/auth/authorize')
|
|
||||||
.send({
|
|
||||||
username: user.username,
|
|
||||||
password: user.password
|
|
||||||
})
|
|
||||||
.expect(400)
|
|
||||||
|
|
||||||
expect(res.text).toEqual(`"clientId" is required`)
|
|
||||||
expect(res.body).toEqual({})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should respond with Forbidden if username is incorrect', async () => {
|
|
||||||
const res = await request(app)
|
|
||||||
.post('/SASjsApi/auth/authorize')
|
|
||||||
.send({
|
|
||||||
username: user.username,
|
|
||||||
password: user.password,
|
|
||||||
clientId
|
|
||||||
})
|
|
||||||
.expect(403)
|
|
||||||
|
|
||||||
expect(res.text).toEqual('Error: Username is not found.')
|
|
||||||
expect(res.body).toEqual({})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should respond with Forbidden if password is incorrect', async () => {
|
|
||||||
await userController.createUser(user)
|
|
||||||
|
|
||||||
const res = await request(app)
|
|
||||||
.post('/SASjsApi/auth/authorize')
|
|
||||||
.send({
|
|
||||||
username: user.username,
|
|
||||||
password: 'WrongPassword',
|
|
||||||
clientId
|
|
||||||
})
|
|
||||||
.expect(403)
|
|
||||||
|
|
||||||
expect(res.text).toEqual('Error: Invalid password.')
|
|
||||||
expect(res.body).toEqual({})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should respond with Forbidden if clientId is incorrect', async () => {
|
|
||||||
await userController.createUser(user)
|
|
||||||
|
|
||||||
const res = await request(app)
|
|
||||||
.post('/SASjsApi/auth/authorize')
|
|
||||||
.send({
|
|
||||||
username: user.username,
|
|
||||||
password: user.password,
|
|
||||||
clientId: 'WrongClientID'
|
|
||||||
})
|
|
||||||
.expect(403)
|
|
||||||
|
|
||||||
expect(res.text).toEqual('Error: Invalid clientId.')
|
|
||||||
expect(res.body).toEqual({})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('token', () => {
|
describe('token', () => {
|
||||||
const userInfo: InfoJWT = {
|
const userInfo: InfoJWT = {
|
||||||
clientId,
|
clientId,
|
||||||
|
|||||||
172
api/src/routes/api/spec/web.spec.ts
Normal file
172
api/src/routes/api/spec/web.spec.ts
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
import { Express } from 'express'
|
||||||
|
import mongoose, { Mongoose } from 'mongoose'
|
||||||
|
import { MongoMemoryServer } from 'mongodb-memory-server'
|
||||||
|
import request from 'supertest'
|
||||||
|
import appPromise from '../../../app'
|
||||||
|
import { UserController, ClientController } from '../../../controllers/'
|
||||||
|
|
||||||
|
const clientId = 'someclientID'
|
||||||
|
const clientSecret = 'someclientSecret'
|
||||||
|
const user = {
|
||||||
|
id: 1234,
|
||||||
|
displayName: 'Test User',
|
||||||
|
username: 'testUsername',
|
||||||
|
password: '87654321',
|
||||||
|
isAdmin: false,
|
||||||
|
isActive: true
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('web', () => {
|
||||||
|
let app: Express
|
||||||
|
let con: Mongoose
|
||||||
|
let mongoServer: MongoMemoryServer
|
||||||
|
let csrfToken: string
|
||||||
|
let cookies: string
|
||||||
|
const userController = new UserController()
|
||||||
|
const clientController = new ClientController()
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
app = await appPromise
|
||||||
|
;({ csrfToken, cookies } = await getCSRF(app))
|
||||||
|
|
||||||
|
mongoServer = await MongoMemoryServer.create()
|
||||||
|
con = await mongoose.connect(mongoServer.getUri())
|
||||||
|
await clientController.createClient({ clientId, clientSecret })
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
await con.connection.dropDatabase()
|
||||||
|
await con.connection.close()
|
||||||
|
await mongoServer.stop()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('home', () => {
|
||||||
|
it('should respond with CSRF Token', async () => {
|
||||||
|
await request(app)
|
||||||
|
.get('/')
|
||||||
|
.expect(
|
||||||
|
'set-cookie',
|
||||||
|
/_csrf=.*; Max-Age=86400000; Path=\/; HttpOnly,XSRF-TOKEN=.*; Path=\//
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
describe('SASLogon/login', () => {
|
||||||
|
afterEach(async () => {
|
||||||
|
const collections = mongoose.connection.collections
|
||||||
|
const collection = collections['users']
|
||||||
|
await collection.deleteMany({})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should respond with successful login', async () => {
|
||||||
|
await userController.createUser(user)
|
||||||
|
|
||||||
|
const res = await request(app)
|
||||||
|
.post('/SASLogon/login')
|
||||||
|
.set('Cookie', cookies)
|
||||||
|
.set('x-xsrf-token', csrfToken)
|
||||||
|
.send({
|
||||||
|
username: user.username,
|
||||||
|
password: user.password
|
||||||
|
})
|
||||||
|
.expect(200)
|
||||||
|
|
||||||
|
expect(res.body.loggedIn).toBeTruthy()
|
||||||
|
expect(res.body.user).toEqual({
|
||||||
|
username: user.username,
|
||||||
|
displayName: user.displayName
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('SASLogon/authorize', () => {
|
||||||
|
let authCookies: string
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
await userController.createUser(user)
|
||||||
|
|
||||||
|
const credentials = {
|
||||||
|
username: user.username,
|
||||||
|
password: user.password
|
||||||
|
}
|
||||||
|
|
||||||
|
;({ cookies: authCookies } = await performLogin(
|
||||||
|
app,
|
||||||
|
credentials,
|
||||||
|
cookies,
|
||||||
|
csrfToken
|
||||||
|
))
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
const collections = mongoose.connection.collections
|
||||||
|
const collection = collections['users']
|
||||||
|
await collection.deleteMany({})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should respond with authorization code', async () => {
|
||||||
|
const res = await request(app)
|
||||||
|
.post('/SASLogon/authorize')
|
||||||
|
.set('Cookie', [authCookies, cookies].join('; '))
|
||||||
|
.set('x-xsrf-token', csrfToken)
|
||||||
|
.send({ clientId })
|
||||||
|
|
||||||
|
expect(res.body).toHaveProperty('code')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should respond with Bad Request if clientId is missing', async () => {
|
||||||
|
const res = await request(app)
|
||||||
|
.post('/SASLogon/authorize')
|
||||||
|
.set('Cookie', [authCookies, cookies].join('; '))
|
||||||
|
.set('x-xsrf-token', csrfToken)
|
||||||
|
.send({})
|
||||||
|
.expect(400)
|
||||||
|
|
||||||
|
expect(res.text).toEqual(`"clientId" is required`)
|
||||||
|
expect(res.body).toEqual({})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should respond with Forbidden if clientId is incorrect', async () => {
|
||||||
|
const res = await request(app)
|
||||||
|
.post('/SASLogon/authorize')
|
||||||
|
.set('Cookie', [authCookies, cookies].join('; '))
|
||||||
|
.set('x-xsrf-token', csrfToken)
|
||||||
|
.send({
|
||||||
|
clientId: 'WrongClientID'
|
||||||
|
})
|
||||||
|
.expect(403)
|
||||||
|
|
||||||
|
expect(res.text).toEqual('Error: Invalid clientId.')
|
||||||
|
expect(res.body).toEqual({})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const getCSRF = async (app: Express) => {
|
||||||
|
// make request to get CSRF
|
||||||
|
const { header } = await request(app).get('/')
|
||||||
|
const cookies = header['set-cookie'].join()
|
||||||
|
|
||||||
|
const csrfToken = extractCSRF(cookies)
|
||||||
|
return { csrfToken, cookies }
|
||||||
|
}
|
||||||
|
|
||||||
|
const performLogin = async (
|
||||||
|
app: Express,
|
||||||
|
credentials: { username: string; password: string },
|
||||||
|
cookies: string,
|
||||||
|
csrfToken: string
|
||||||
|
) => {
|
||||||
|
const { header } = await request(app)
|
||||||
|
.post('/SASLogon/login')
|
||||||
|
.set('Cookie', cookies)
|
||||||
|
.set('x-xsrf-token', csrfToken)
|
||||||
|
.send(credentials)
|
||||||
|
|
||||||
|
const newCookies: string = header['set-cookie'].join()
|
||||||
|
return { cookies: newCookies }
|
||||||
|
}
|
||||||
|
|
||||||
|
const extractCSRF = (cookies: string) =>
|
||||||
|
/_csrf=(.*); Max-Age=86400000; Path=\/; HttpOnly,XSRF-TOKEN=(.*); Path=\//.exec(
|
||||||
|
cookies
|
||||||
|
)![2]
|
||||||
@@ -26,7 +26,7 @@ webRouter.post('/SASLogon/login', async (req, res) => {
|
|||||||
const response = await controller.login(req, body)
|
const response = await controller.login(req, body)
|
||||||
res.send(response)
|
res.send(response)
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
res.status(400).send(err.toString())
|
res.status(403).send(err.toString())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@ webRouter.post(
|
|||||||
const response = await controller.authorize(req, body)
|
const response = await controller.authorize(req, body)
|
||||||
res.send(response)
|
res.send(response)
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
res.status(400).send(err.toString())
|
res.status(403).send(err.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -51,7 +51,7 @@ webRouter.get('/logout', async (req, res) => {
|
|||||||
await controller.logout(req)
|
await controller.logout(req)
|
||||||
res.status(200).send('OK!')
|
res.status(200).send('OK!')
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
res.status(400).send(err.toString())
|
res.status(403).send(err.toString())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user