Skip to content
This repository was archived by the owner on Sep 20, 2022. It is now read-only.

Commit 17e387a

Browse files
author
Hans Kristian Flaatten
committed
Merge branch 'crypto-refactor'
2 parents 63aaed8 + 4856e75 commit 17e387a

6 files changed

+348
-267
lines changed

src/auth.coffee

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
crypto = require 'crypto'
1+
crypto = require './crypto'
22
request = require 'request'
33
async = require 'async'
44

@@ -41,7 +41,7 @@ TurbasenAuth.prototype._authUser = (email, password, user, cb) ->
4141
return cb hash.toString('base64') is user.pbkdf2.hash
4242

4343
TurbasenAuth.prototype._authUsers = (email, password, users, cb) ->
44-
iterator = async.apply @_authUser.bind(@), email, password
44+
iterator = async.apply crypto.authenticate, email, password
4545
async.detect users, iterator, (user) ->
4646
delete user.pbkdf2 if user?.pbkdf2
4747

@@ -74,4 +74,3 @@ TurbasenAuth.prototype.authenticate = (email, password, cb) ->
7474
@_authGroups email, password, body.documents, cb
7575

7676
module.exports = TurbasenAuth
77-

src/crypto.coffee

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
crypto = require 'crypto'
2+
3+
module.exports.pbkdf2 = (pwd, salt, itrs, dkLen, cb) ->
4+
pwd = new Buffer pwd, 'utf8'
5+
salt = new Buffer salt, 'base64'
6+
7+
try
8+
crypto.pbkdf2 pwd, salt, itrs, dkLen, (err, hash) ->
9+
cb err, hash?.toString 'base64'
10+
catch err
11+
process.nextTick -> cb err
12+
13+
module.exports.authenticate = (email, pass, user, cb) ->
14+
if email isnt user.epost
15+
return process.nextTick ->
16+
cb false, 'AUTH001', 'User email did not match'
17+
18+
if user.pbkdf2?.prf isnt 'HMAC-SHA1'
19+
return process.nextTick ->
20+
cb false, 'AUTH002', 'Unknown authentication schema'
21+
22+
salt = user.pbkdf2.salt
23+
itrs = user.pbkdf2.itrs
24+
dkLen = user.pbkdf2.dkLen
25+
26+
module.exports.pbkdf2 pass, salt, itrs, dkLen, (err, hash) ->
27+
return cb false, 'AUTH003', err if err
28+
if hash isnt user.pbkdf2.hash
29+
return cb false, 'AUTH004', 'User password hash did not match'
30+
31+
return cb true

test/auth-spec.coffee

+225
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
assert = require 'assert'
2+
TurbasenAuth = require '../src/auth'
3+
4+
auth = groups = _getGroups = _getGroup = null
5+
6+
beforeEach ->
7+
auth = new TurbasenAuth('node-turbasen-auth/v1.0.0', process.env.NTB_API_KEY)
8+
groups = [{
9+
_id: '507f1f77bcf86cd799439011'
10+
navn: 'Foo Group'
11+
privat:
12+
brukere: [{
13+
_password: 'Pa$w0rd'
14+
navn: 'Foo Bar'
15+
16+
pbkdf2:
17+
prf: 'HMAC-SHA1'
18+
itrs: 100
19+
salt: 'XO6rZj9WG1UsLEsAGQH16qgZpCM9D7VylFQzwpSmOEo='
20+
dkLen: 32
21+
hash: 'Ir/5WTFgyBJoI3pJ8SaH8qWxdgZ0my6qcOPVPHnYJQ4='
22+
},{
23+
_password: 'Pik4chu'
24+
navn: 'Bar Foo'
25+
26+
pbkdf2:
27+
prf: 'HMAC-SHA1'
28+
itrs: 100
29+
salt: 'XO6rZj9WG1UsLEsAGQH16qgZpCM9D7VylFQzwpSmOEa='
30+
dkLen: 32
31+
hash: '7oVtqDGrHf48OUYXwY/3qJks1q40Wg8f+bo+FFAI7oA='
32+
},{
33+
navn: 'Baz Bar'
34+
35+
}]
36+
},{
37+
_id: '507f191e810c19729de860ea'
38+
navn: 'Bar Group'
39+
privat:
40+
brukere: [{
41+
_password: 'Pik4chu'
42+
navn: 'Baz Bar'
43+
44+
pbkdf2:
45+
prf: 'HMAC-SHA1'
46+
itrs: 100
47+
salt: 'XO6rZj9WG1UsLEsAGQH16qgZpCM9D7VylFQzwpSmOEa='
48+
dkLen: 32
49+
hash: '7oVtqDGrHf48OUYXwY/3qJks1q40Wg8f+bo+FFAI7oA='
50+
}]
51+
}]
52+
53+
_getGroup = auth._getGroup
54+
_getGroups = auth._getGroups
55+
56+
auth._getGroups = (email, cb) ->
57+
res = statusCode: 200
58+
body = documents: [], count: 0, total: 0
59+
60+
switch email
61+
when "[email protected]" then body.documents.push groups[0]
62+
when "[email protected]" then body.documents.push groups[0]
63+
64+
body.documents.push groups[0]
65+
body.documents.push groups[1]
66+
67+
# @TODO remove private data from view
68+
69+
body.count = body.total = body.documents.length
70+
71+
cb null, res, body
72+
73+
auth._getGroup = (id, cb) ->
74+
res = statusCode: 200
75+
body = {}
76+
77+
switch id
78+
when "507f1f77bcf86cd799439011" then body = groups[0]
79+
when "507f191e810c19729de860ea" then body = groups[1]
80+
else
81+
res.statusCode = 404
82+
83+
if Object.keys(body).length isnt 0
84+
delete body.privat.brukere[key]._password for _, key in body.privat.brukere
85+
86+
cb null, res, body
87+
88+
describe 'Constructor', ->
89+
it 'should make new instance', ->
90+
assert auth instanceof TurbasenAuth
91+
92+
describe '#_authUsers()', ->
93+
users = []
94+
passwords = []
95+
96+
beforeEach ->
97+
users = groups[0].privat.brukere
98+
for user, key in users
99+
passwords.push user._password
100+
delete users[key]._password
101+
102+
it 'should return false if no match is found', (done) ->
103+
auth._authUsers '[email protected]', 'P4s$word', users, (err, user) ->
104+
assert.equal user, false
105+
done()
106+
107+
it 'should return true if a match is found', (done) ->
108+
auth._authUsers users[1].epost, passwords[1], users, (err, user) ->
109+
assert.deepEqual user,
110+
navn: users[1].navn
111+
epost: users[1].epost
112+
done()
113+
114+
describe '#_authGroup()', ->
115+
group = null
116+
beforeEach -> group = _id: 'abc123', navn: 'Awesome group'
117+
118+
it 'should return error for non 404 error code', (done) ->
119+
auth._getGroup = (id, cb) -> cb null, statusCode: 501, {}
120+
auth._authGroup 'email', 'pass', group, (err, match) ->
121+
assert /HTTP_ERR GET \/gruppe\/abc123 - 501/.test err
122+
done()
123+
124+
it 'should return false for HTTP error code is 404', (done) ->
125+
auth._getGroup = (id, cb) -> cb null, statusCode: 404, {}
126+
auth._authGroup 'email', 'pass', group, (err, match) ->
127+
assert.ifError err
128+
assert.equal match, false
129+
done()
130+
131+
it 'should return false for no group user object', (done) ->
132+
auth._authGroup 'email', 'pass', group, (err, match) ->
133+
assert.ifError err
134+
assert.equal match, false
135+
done()
136+
137+
#it 'should return false for unknown email', (done) ->
138+
# email = groups[0].privat.brukere[0].epost + 'A'
139+
# passw = groups[0].privat.brukere[0]._password
140+
# group = _id: groups[0]._id
141+
142+
# auth._authGroup email, passw, group, (err, match) ->
143+
# assert.ifError err
144+
# assert.equal match, false
145+
# done()
146+
147+
#it 'should return false for invalid password', (done) ->
148+
# email = groups[0].privat.brukere[0].epost
149+
# passw = groups[0].privat.brukere[0]._password + 'A'
150+
# group = _id: groups[0]._id
151+
152+
# auth._authGroup email, passw, group, (err, match) ->
153+
# assert.ifError err
154+
# assert.equal match, false
155+
# done()
156+
157+
it 'should return user credentials for matching email and password', (done) ->
158+
name = groups[0].privat.brukere[0].navn
159+
email = groups[0].privat.brukere[0].epost
160+
passw = groups[0].privat.brukere[0]._password
161+
group = _id: groups[0]._id, navn: groups[0].navn
162+
163+
auth._authGroup email, passw, group, (err, match) ->
164+
assert.ifError err
165+
assert.deepEqual match,
166+
navn: name
167+
epost: email
168+
gruppe: group
169+
done()
170+
171+
describe '_authGroups()', ->
172+
it 'should authenticate user ammong one matching group', (done) ->
173+
name = groups[0].privat.brukere[0].navn
174+
email = groups[0].privat.brukere[0].epost
175+
passw = groups[0].privat.brukere[0]._password
176+
group = _id: groups[0]._id, navn: groups[0].navn
177+
178+
auth._authGroups email, passw, [groups[0]], (err, user) ->
179+
assert.ifError err
180+
assert.deepEqual user,
181+
navn: name
182+
epost: email
183+
gruppe: group
184+
done()
185+
186+
it 'should authenticate user ammong several matching groups', (done) ->
187+
name = groups[0].privat.brukere[0].navn
188+
email = groups[0].privat.brukere[0].epost
189+
passw = groups[0].privat.brukere[0]._password
190+
group = _id: groups[0]._id, navn: groups[0].navn
191+
192+
auth._authGroups email, passw, groups, (err, user) ->
193+
assert.ifError err
194+
assert.deepEqual user,
195+
navn: name
196+
epost: email
197+
gruppe: group
198+
done()
199+
200+
describe '#authenticate()', ->
201+
it 'should authenticate user with valid credentials', (done) ->
202+
if process.env.INTEGRATION_TEST is 'true'
203+
@timeout 10000
204+
205+
auth._getGroups = _getGroups
206+
auth._getGroup = _getGroup
207+
208+
name = 'Destinasjon Trysil'
209+
email = process.env.INTEGRATION_TEST_EMAIL
210+
passw = process.env.INTEGRATION_TEST_PASSW
211+
group = _id: '52407f3c4ec4a138150001d7', navn: 'Destinasjon Trysil'
212+
213+
else
214+
name = groups[0].privat.brukere[0].navn
215+
email = groups[0].privat.brukere[0].epost
216+
passw = groups[0].privat.brukere[0]._password
217+
group = _id: groups[0]._id, navn: groups[0].navn
218+
219+
auth.authenticate email, passw, (err, user) ->
220+
assert.ifError err
221+
assert.deepEqual user,
222+
navn: name
223+
epost: email
224+
gruppe: group
225+
done()

test/crypto-spec.coffee

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
assert = require 'assert'
2+
crypto = require '../src/crypto'
3+
4+
user = null
5+
6+
beforeEach ->
7+
user =
8+
_password: 'Pa$w0rd'
9+
navn: 'Foo Bar'
10+
11+
pbkdf2:
12+
prf: 'HMAC-SHA1'
13+
itrs: 100
14+
salt: 'XO6rZj9WG1UsLEsAGQH16qgZpCM9D7VylFQzwpSmOEo='
15+
dkLen: 32
16+
hash: 'Ir/5WTFgyBJoI3pJ8SaH8qWxdgZ0my6qcOPVPHnYJQ4='
17+
18+
describe 'pbkdf2()', ->
19+
it 'returns pbkdf2 hash', (done) ->
20+
pwd = user._password
21+
itrs = user.pbkdf2.itrs
22+
dkLen = user.pbkdf2.dkLen
23+
salt = user.pbkdf2.salt
24+
hash = user.pbkdf2.hash
25+
26+
crypto.pbkdf2 pwd, salt, itrs, dkLen, (err, h) ->
27+
assert.ifError err
28+
assert.equal h, hash
29+
done()
30+
31+
describe 'authenticate()', ->
32+
it 'returns true for correct email and password', (done) ->
33+
email = user.epost
34+
pass = user._password
35+
36+
crypto.authenticate email, pass, user, (isAuth, code, msg) ->
37+
assert.equal isAuth, true
38+
assert.equal code, undefined
39+
assert.equal msg, undefined
40+
41+
done()
42+
43+
it 'returns code AUTH001 when email does not match', (done) ->
44+
email = 'foo'
45+
pass = user._password
46+
47+
crypto.authenticate email, pass, user, (isAuth, code, msg) ->
48+
assert.equal isAuth, false
49+
assert.equal code, 'AUTH001'
50+
assert.equal msg, 'User email did not match'
51+
52+
done()
53+
54+
it 'returns code AUTH002 for invalid auth schema', (done) ->
55+
email = user.epost
56+
pass = user._password
57+
user.pbkdf2 = undefined
58+
59+
crypto.authenticate email, pass, user, (isAuth, code, msg) ->
60+
assert.equal isAuth, false
61+
assert.equal code, 'AUTH002'
62+
assert.equal msg, 'Unknown authentication schema'
63+
64+
done()
65+
66+
it 'returns code AUTH003 when pbkdf2 fails', (done) ->
67+
email = user.epost
68+
pass = user._password
69+
user.pbkdf2.dkLen = -1
70+
71+
crypto.authenticate email, pass, user, (isAuth, code, msg) ->
72+
assert.equal isAuth, false
73+
assert.equal code, 'AUTH003'
74+
assert /TypeError: Bad key length/.test msg
75+
done()
76+
77+
it 'returns code AUTH004 when hash does not match', (done) ->
78+
email = user.epost
79+
pass = 'foo'
80+
81+
crypto.authenticate email, pass, user, (isAuth, code, msg) ->
82+
assert.equal isAuth, false
83+
assert.equal code, 'AUTH004'
84+
assert.equal msg, 'User password hash did not match'
85+
86+
done()

0 commit comments

Comments
 (0)