Skip to content

Commit

Permalink
test: add acceptance tests for client secret hashing
Browse files Browse the repository at this point in the history
  • Loading branch information
eduardoboucas committed Feb 6, 2019
1 parent 0540d80 commit 0caa622
Show file tree
Hide file tree
Showing 4 changed files with 186 additions and 8 deletions.
77 changes: 77 additions & 0 deletions test/acceptance/acl/clients-api/post.js
@@ -1,8 +1,11 @@
const app = require('./../../../../dadi/lib')
const client = require('./../../../../dadi/lib/model/acl/client')
const bcrypt = require('bcrypt')
const config = require('./../../../../config')
const help = require('./../../help')
const request = require('supertest')
const should = require('should')
const sinon = require('sinon')

module.exports = () => {
let configBackup = config.get()
Expand Down Expand Up @@ -521,6 +524,80 @@ module.exports = () => {
})

describe('success states (the client has "create" access to the "clients" resource)', () => {
it('should hash client secrets and salt them using the number of rounds specified in the `auth.saltRounds` config property', done => {
config.set('auth.saltRounds', 5)

const spy = sinon.spy(bcrypt, 'hash')
const testClient = {
clientId: 'apiClient',
secret: 'someSecret',
resources: {
clients: {
create: true
}
}
}
const newClient1 = {
clientId: 'newClient1',
secret: 'aNewSecret1'
}
const newClient2 = {
clientId: 'newClient2',
secret: 'aNewSecret2'
}

help.createACLClient(testClient).then(() => {
client
.post(config.get('auth.tokenUrl'))
.set('content-type', 'application/json')
.send({
clientId: testClient.clientId,
secret: testClient.secret
})
.expect(200)
.expect('content-type', 'application/json')
.end((err, res) => {
if (err) return done(err)

const {accessToken} = res.body

client
.post('/api/clients')
.send(newClient1)
.set('content-type', 'application/json')
.set('Authorization', `Bearer ${accessToken}`)
.expect('content-type', 'application/json')
.end((err, res) => {
res.statusCode.should.eql(201)

spy.getCall(0).args[0].should.eql('aNewSecret1')
spy.getCall(0).args[1].should.eql(5)

config.set('auth.saltRounds', 8)

client
.post('/api/clients')
.send(newClient2)
.set('content-type', 'application/json')
.set('Authorization', `Bearer ${accessToken}`)
.expect('content-type', 'application/json')
.end((err, res) => {
res.statusCode.should.eql(201)

config.set('auth.saltRounds', configBackup.auth.saltRounds)

spy.getCall(1).args[0].should.eql('aNewSecret2')
spy.getCall(1).args[1].should.eql(8)

spy.restore()

done(err)
})
})
})
})
})

it('should create a client and return a 201', done => {
let testClient = {
clientId: 'apiClient',
Expand Down
76 changes: 76 additions & 0 deletions test/acceptance/acl/clients-api/put.js
@@ -1,8 +1,10 @@
const app = require('./../../../../dadi/lib')
const bcrypt = require('bcrypt')
const config = require('./../../../../config')
const help = require('./../../help')
const request = require('supertest')
const should = require('should')
const sinon = require('sinon')

module.exports = () => {
let configBackup = config.get()
Expand Down Expand Up @@ -134,6 +136,7 @@ module.exports = () => {
client
.put('/api/clients/johnnynobody')
.send({
currentSecret: 'whatevs',
secret: 'ssshhh!'
})
.set('content-type', 'application/json')
Expand Down Expand Up @@ -547,6 +550,79 @@ module.exports = () => {

describe('success states', () => {
describe('updating the secret', () => {
it('should hash the new secret and salt it using the number of rounds specified in the `auth.saltRounds` config property', done => {
let testClient = {
clientId: 'apiClient',
secret: 'someSecret'
}

help.createACLClient(testClient).then(() => {
client
.post(config.get('auth.tokenUrl'))
.set('content-type', 'application/json')
.send({
clientId: testClient.clientId,
secret: testClient.secret
})
.expect(200)
.expect('content-type', 'application/json')
.end((err, res) => {
if (err) return done(err)

res.body.accessToken.should.be.String

let bearerToken = res.body.accessToken

config.set('auth.saltRounds', 9)

const spy = sinon.spy(bcrypt, 'hash')
const update = {
currentSecret: 'someSecret',
secret: 'aNewSecret'
}

client
.put('/api/client')
.send(update)
.set('content-type', 'application/json')
.set('Authorization', `Bearer ${bearerToken}`)
.expect('content-type', 'application/json')
.end((err, res) => {
res.statusCode.should.eql(200)

res.body.results.should.be.Array
res.body.results.length.should.eql(1)
res.body.results[0].clientId.should.eql(testClient.clientId)

spy.getCall(0).args[0].should.eql(update.secret)
spy.getCall(0).args[1].should.eql(9)
spy.restore()

config.set('auth.saltRounds', configBackup.auth.saltRounds)

should.not.exist(res.body.results[0].secret)

client
.post(config.get('auth.tokenUrl'))
.set('content-type', 'application/json')
.send({
clientId: testClient.clientId,
secret: 'aNewSecret'
})
.expect(200)
.expect('content-type', 'application/json')
.end((err, res) => {
if (err) return done(err)

res.body.accessToken.should.be.String

done()
})
})
})
})
})

it('should allow a client to update their own secret on /api/clients/{ID}', done => {
let testClient = {
clientId: 'apiClient',
Expand Down
30 changes: 23 additions & 7 deletions test/acceptance/acl/token-store.js
@@ -1,11 +1,13 @@
const app = require('./../../../dadi/lib')
const bcrypt = require('bcrypt')
const config = require('./../../../config')
const fs = require('fs-extra')
const help = require('./../help')
const jwt = require('jsonwebtoken')
const path = require('path')
const request = require('supertest')
const should = require('should')
const sinon = require('sinon')

describe('Token store', () => {
let configBackup = config.get()
Expand Down Expand Up @@ -255,6 +257,7 @@ describe('Token store', () => {
__dirname,
'./../../acceptance/temp-workspace/endpoints/v1/endpoint.intercept-client.js'
)
let testClientHash

before(done => {
let endpointSource = `
Expand All @@ -272,14 +275,14 @@ describe('Token store', () => {
`

fs.writeFile(endpointPath, endpointSource).then(() => {
help.createClient(testClient, () => {
help.createClient(testClient, (err, client) => {
app.start(err => {
if (err) return done(err)

setTimeout(done, 500)
})
})
}).catch(console.log)
}).catch(done)
})

after(done => {
Expand All @@ -291,29 +294,42 @@ describe('Token store', () => {
})

it('should attach client data to the request object if the bearer token supplied is valid', done => {
client
const newClient = {
clientId: 'testClient1',
secret: 'superSecret1',
accessType: 'admin'
}
const spy = sinon.spy(bcrypt, 'compare')

help.createClient(newClient, (err, clientRecord) => {
client
.post(tokenRoute)
.send({
clientId: testClient.clientId,
secret: testClient.secret
clientId: newClient.clientId,
secret: newClient.secret
})
.expect('content-type', 'application/json')
.expect('pragma', 'no-cache')
.expect('Cache-Control', 'no-store')
.expect(200, (err, res) => {
res.body.accessToken.should.be.String

spy.getCall(0).args[0].should.eql(newClient.secret)
spy.getCall(0).args[1].should.eql(clientRecord.secret)
spy.restore()

client
.get('/v1/intercept-client')
.set('Authorization', `Bearer ${res.body.accessToken}`)
.expect('content-type', 'application/json')
.expect(200, (err, res) => {
res.body.clientId.should.eql(testClient.clientId)
res.body.accessType.should.eql(testClient.accessType)
res.body.clientId.should.eql(newClient.clientId)
res.body.accessType.should.eql(newClient.accessType)

done()
})
})
})
})

it('should attach an error to the request object if the bearer token supplied is invalid', done => {
Expand Down
11 changes: 10 additions & 1 deletion test/acceptance/help.js
@@ -1,4 +1,5 @@
const acl = require('./../../dadi/lib/model/acl')
const bcrypt = require('bcrypt')
const fs = require('fs-extra')
const path = require('path')
const should = require('should')
Expand Down Expand Up @@ -115,6 +116,10 @@ module.exports.createClient = function (client, done) {
}
}

client = Object.assign({}, client, {
secret: bcrypt.hashSync(client.secret, config.get('auth.saltRounds'))
})

var collectionName = config.get('auth.clientCollection')
var conn = connection({
override: true,
Expand All @@ -138,7 +143,7 @@ module.exports.createClient = function (client, done) {
}).then(res => {
res.results.length.should.eql(1)

done()
done(null, res.results[0])
})
}).catch((err) => {
done(err)
Expand All @@ -163,6 +168,10 @@ module.exports.createACLClient = function (client, callback) {
config.get('datastore')
)

client = Object.assign({}, client, {
secret: bcrypt.hashSync(client.secret, config.get('auth.saltRounds'))
})

return clientsConnection.datastore.insert({
data: client,
collection: config.get('auth.clientCollection'),
Expand Down

0 comments on commit 0caa622

Please sign in to comment.