AuthenticationManagerTests.coffee 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. sinon = require('sinon')
  2. chai = require('chai')
  3. should = chai.should()
  4. expect = chai.expect
  5. modulePath = "../../../../app/js/Features/Authentication/AuthenticationManager.js"
  6. SandboxedModule = require('sandboxed-module')
  7. events = require "events"
  8. ObjectId = require("mongojs").ObjectId
  9. describe "AuthenticationManager", ->
  10. beforeEach ->
  11. @settings = { security: { bcryptRounds: 12 } }
  12. @AuthenticationManager = SandboxedModule.require modulePath, requires:
  13. "../../models/User": User: @User = {}
  14. "../../infrastructure/mongojs":
  15. db: @db =
  16. users: {}
  17. ObjectId: ObjectId
  18. "bcrypt": @bcrypt = {}
  19. "settings-sharelatex": @settings
  20. @callback = sinon.stub()
  21. describe "authenticate", ->
  22. describe "when the user exists in the database", ->
  23. beforeEach ->
  24. @user =
  25. _id: "user-id"
  26. email: @email = "USER@sharelatex.com"
  27. @unencryptedPassword = "banana"
  28. @User.findOne = sinon.stub().callsArgWith(1, null, @user)
  29. describe "when the hashed password matches", ->
  30. beforeEach (done) ->
  31. @user.hashedPassword = @hashedPassword = "asdfjadflasdf"
  32. @bcrypt.compare = sinon.stub().callsArgWith(2, null, true)
  33. @bcrypt.getRounds = sinon.stub().returns 12
  34. @AuthenticationManager.authenticate email: @email, @unencryptedPassword, (error, user) =>
  35. @callback(error, user)
  36. done()
  37. it "should look up the correct user in the database", ->
  38. @User.findOne.calledWith(email: @email).should.equal true
  39. it "should check that the passwords match", ->
  40. @bcrypt.compare
  41. .calledWith(@unencryptedPassword, @hashedPassword)
  42. .should.equal true
  43. it "should return the user", ->
  44. @callback.calledWith(null, @user).should.equal true
  45. describe "when the encrypted passwords do not match", ->
  46. beforeEach ->
  47. @AuthenticationManager._encryptPassword = sinon.stub().returns("Not the encrypted password")
  48. @AuthenticationManager.authenticate(email: @email, @unencryptedPassword, @callback)
  49. it "should not return the user", ->
  50. @callback.calledWith(null, null).should.equal true
  51. describe "when the hashed password matches but the number of rounds is too low", ->
  52. beforeEach (done) ->
  53. @user.hashedPassword = @hashedPassword = "asdfjadflasdf"
  54. @bcrypt.compare = sinon.stub().callsArgWith(2, null, true)
  55. @bcrypt.getRounds = sinon.stub().returns 7
  56. @AuthenticationManager.setUserPassword = sinon.stub().callsArgWith(2, null)
  57. @AuthenticationManager.authenticate email: @email, @unencryptedPassword, (error, user) =>
  58. @callback(error, user)
  59. done()
  60. it "should look up the correct user in the database", ->
  61. @User.findOne.calledWith(email: @email).should.equal true
  62. it "should check that the passwords match", ->
  63. @bcrypt.compare
  64. .calledWith(@unencryptedPassword, @hashedPassword)
  65. .should.equal true
  66. it "should check the number of rounds", ->
  67. @bcrypt.getRounds.called.should.equal true
  68. it "should set the users password (with a higher number of rounds)", ->
  69. @AuthenticationManager.setUserPassword
  70. .calledWith("user-id", @unencryptedPassword)
  71. .should.equal true
  72. it "should return the user", ->
  73. @callback.calledWith(null, @user).should.equal true
  74. describe "when the user does not exist in the database", ->
  75. beforeEach ->
  76. @User.findOne = sinon.stub().callsArgWith(1, null, null)
  77. @AuthenticationManager.authenticate(email: @email, @unencrpytedPassword, @callback)
  78. it "should not return a user", ->
  79. @callback.calledWith(null, null).should.equal true
  80. describe "setUserPassword", ->
  81. beforeEach ->
  82. @user_id = ObjectId()
  83. @password = "banana"
  84. @hashedPassword = "asdkjfa;osiuvandf"
  85. @salt = "saltaasdfasdfasdf"
  86. @bcrypt.genSalt = sinon.stub().callsArgWith(1, null, @salt)
  87. @bcrypt.hash = sinon.stub().callsArgWith(2, null, @hashedPassword)
  88. @db.users.update = sinon.stub().callsArg(2)
  89. describe "too long", ->
  90. beforeEach ->
  91. @settings.passwordStrengthOptions =
  92. length:
  93. max:10
  94. @password = "dsdsadsadsadsadsadkjsadjsadjsadljs"
  95. it "should return and error", (done)->
  96. @AuthenticationManager.setUserPassword @user_id, @password, (err)->
  97. expect(err).to.exist
  98. done()
  99. it "should not start the bcrypt process", (done)->
  100. @AuthenticationManager.setUserPassword @user_id, @password, (err)=>
  101. @bcrypt.genSalt.called.should.equal false
  102. @bcrypt.hash.called.should.equal false
  103. done()
  104. describe "too short", ->
  105. beforeEach ->
  106. @settings.passwordStrengthOptions =
  107. length:
  108. max:10
  109. min:6
  110. @password = "dsd"
  111. it "should return and error", (done)->
  112. @AuthenticationManager.setUserPassword @user_id, @password, (err)->
  113. expect(err).to.exist
  114. done()
  115. it "should not start the bcrypt process", (done)->
  116. @AuthenticationManager.setUserPassword @user_id, @password, (err)=>
  117. @bcrypt.genSalt.called.should.equal false
  118. @bcrypt.hash.called.should.equal false
  119. done()
  120. describe "successful set", ->
  121. beforeEach ->
  122. @AuthenticationManager.setUserPassword(@user_id, @password, @callback)
  123. it "should update the user's password in the database", ->
  124. args = @db.users.update.lastCall.args
  125. expect(args[0]).to.deep.equal {_id: ObjectId(@user_id.toString())}
  126. expect(args[1]).to.deep.equal {
  127. $set: {
  128. "hashedPassword": @hashedPassword
  129. }
  130. $unset: password: true
  131. }
  132. it "should hash the password", ->
  133. @bcrypt.genSalt
  134. .calledWith(12)
  135. .should.equal true
  136. @bcrypt.hash
  137. .calledWith(@password, @salt)
  138. .should.equal true
  139. it "should call the callback", ->
  140. @callback.called.should.equal true