authenticate 0.2.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -4
  3. data/CHANGELOG.md +12 -0
  4. data/Gemfile +1 -0
  5. data/Gemfile.lock +21 -6
  6. data/app/controllers/authenticate/passwords_controller.rb +1 -1
  7. data/authenticate.gemspec +7 -3
  8. data/config/locales/authenticate.en.yml +1 -1
  9. data/gemfiles/rails42.gemfile +6 -1
  10. data/lib/authenticate/callbacks/brute_force.rb +3 -4
  11. data/lib/authenticate/configuration.rb +2 -2
  12. data/lib/authenticate/controller.rb +1 -2
  13. data/lib/authenticate/model/brute_force.rb +2 -2
  14. data/lib/authenticate/model/db_password.rb +2 -3
  15. data/lib/authenticate/model/email.rb +3 -6
  16. data/lib/authenticate/model/lifetimed.rb +1 -1
  17. data/lib/authenticate/model/password_reset.rb +1 -1
  18. data/lib/authenticate/model/timeoutable.rb +2 -2
  19. data/lib/authenticate/model/trackable.rb +1 -1
  20. data/lib/authenticate/model/username.rb +1 -1
  21. data/lib/authenticate/session.rb +0 -4
  22. data/lib/authenticate/user.rb +12 -0
  23. data/lib/authenticate/version.rb +1 -1
  24. data/spec/controllers/passwords_controller_spec.rb +119 -0
  25. data/spec/controllers/secured_controller_spec.rb +70 -0
  26. data/spec/controllers/sessions_controller_spec.rb +86 -0
  27. data/spec/controllers/users_controller_spec.rb +82 -0
  28. data/spec/dummy/app/controllers/application_controller.rb +2 -0
  29. data/spec/dummy/app/controllers/welcome_controller.rb +4 -0
  30. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  31. data/spec/dummy/app/views/welcome/index.html.erb +4 -0
  32. data/spec/dummy/config/application.rb +2 -0
  33. data/spec/dummy/config/environments/production.rb +12 -0
  34. data/spec/dummy/config/initializers/authenticate.rb +4 -11
  35. data/spec/dummy/config/routes.rb +3 -0
  36. data/spec/dummy/db/test.sqlite3 +0 -0
  37. data/spec/factories/users.rb +2 -4
  38. data/spec/features/brute_force_spec.rb +49 -0
  39. data/spec/features/max_session_lifetime_spec.rb +30 -0
  40. data/spec/features/password_reset_spec.rb +69 -0
  41. data/spec/features/password_update_spec.rb +41 -0
  42. data/spec/features/sign_in_spec.rb +29 -0
  43. data/spec/features/sign_out_spec.rb +22 -0
  44. data/spec/features/sign_up_spec.rb +42 -0
  45. data/spec/features/timeoutable_spec.rb +30 -0
  46. data/spec/model/brute_force_spec.rb +26 -29
  47. data/spec/model/configuration_spec.rb +61 -0
  48. data/spec/model/db_password_spec.rb +8 -9
  49. data/spec/model/email_spec.rb +0 -1
  50. data/spec/model/lifetimed_spec.rb +6 -18
  51. data/spec/model/password_reset_spec.rb +2 -9
  52. data/spec/model/session_spec.rb +16 -23
  53. data/spec/model/timeoutable_spec.rb +8 -7
  54. data/spec/model/trackable_spec.rb +0 -1
  55. data/spec/model/user_spec.rb +1 -2
  56. data/spec/spec_helper.rb +33 -131
  57. data/spec/support/controllers/controller_helpers.rb +24 -0
  58. data/spec/support/features/feature_helpers.rb +36 -0
  59. metadata +80 -8
  60. data/spec/configuration_spec.rb +0 -60
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ca8c03070d7634ba64d25f575271f6bebe6920fc
4
- data.tar.gz: bc353110b848819716f864a7ca66f7df46afae1b
3
+ metadata.gz: 314ba694f7183f9f3a7ed5c239c1ec1dc7e45298
4
+ data.tar.gz: dabffa423ced67c1f8bf767befdee51979ef3989
5
5
  SHA512:
6
- metadata.gz: 9c0d18c59f7373dbb3c817a92b7b02ff901d5f56c8c7ac5ab72c7c2dac611b044c15b25ebb0b93873986663825b00de386bc1ba25eccae537724d27171c767a1
7
- data.tar.gz: 0122cd40a252a9db8c946368529220bdc41f6750220fd1ad3f6c61df3744392eac0f8969d13365e26f3c124fe333a1451f95e15bfad83574b2386db45d7a4ccc
6
+ metadata.gz: 9e3cc55ad8b83ab460966a9bfd9000c7799ed5792cc0402c8ce90eb22d3f055b0b3dadf146038c46c844f5278e4a233c6237992febf2679ddc95838c0ad0d4b8
7
+ data.tar.gz: 24f500d3c8917867c2a16c7b3ba2f0bcf44c47dfe5ea83ffb949c9bb03c864f880a30ccab3f7e7f755cb4fa7039f12926b42cd01d30fbab9482a7c0851c8ff1a
data/.gitignore CHANGED
@@ -2,9 +2,9 @@
2
2
  authenticate-*.gem
3
3
  log/*.log
4
4
  pkg/
5
- test/dummy/db/*.sqlite3
6
- test/dummy/db/*.sqlite3-journal
7
- test/dummy/log/*.log
8
- test/dummy/tmp/
5
+ spec/dummy/db/*.sqlite3
6
+ spec/dummy/db/*.sqlite3-journal
7
+ spec/dummy/log/*.log
8
+ spec/dummy/tmp/
9
9
  spec/dummy/log/test.log
10
10
  spec/dummy/log/development.log
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Authenticate Changelog
2
2
 
3
+ ## [0.3.0] - February 24, 2016
4
+
5
+ Moved normalize_email and find_normalized_email methods to base User module.
6
+ Added full suite of controller and feature tests.
7
+ Bug fixes:
8
+ * failed login count fix was off by one.
9
+ * password validation now done only in correct circumstances
10
+
11
+ [0.3.0]: https://github.com/tomichj/authenticate/compare/v0.2.2...v0.3.0
12
+
13
+
14
+
3
15
  ## [0.2.3] - February 13, 2016
4
16
 
5
17
  Small bugfix for :username authentication.
data/Gemfile CHANGED
@@ -2,6 +2,7 @@ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
5
+ # gem 'capybara'
5
6
 
6
7
  # Declare your gem's dependencies in authenticate.gemspec.
7
8
  # Bundler will treat runtime dependencies like base dependencies, and
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- authenticate (0.2.2)
4
+ authenticate (0.3.0)
5
5
  bcrypt
6
6
  email_validator (~> 1.6)
7
7
  rails (>= 4.0, < 5.1)
@@ -44,20 +44,26 @@ GEM
44
44
  minitest (~> 5.1)
45
45
  thread_safe (~> 0.3, >= 0.3.4)
46
46
  tzinfo (~> 1.1)
47
+ addressable (2.4.0)
47
48
  arel (6.0.3)
48
49
  bcrypt (3.1.10)
49
50
  builder (3.2.2)
51
+ capybara (2.6.2)
52
+ addressable
53
+ mime-types (>= 1.16)
54
+ nokogiri (>= 1.3.3)
55
+ rack (>= 1.0.0)
56
+ rack-test (>= 0.5.4)
57
+ xpath (~> 2.0)
50
58
  coderay (1.1.0)
51
59
  concurrent-ruby (1.0.0)
60
+ database_cleaner (1.5.1)
52
61
  diff-lcs (1.2.5)
53
62
  email_validator (1.6.0)
54
63
  activemodel
55
64
  erubis (2.7.0)
56
65
  factory_girl (4.4.0)
57
66
  activesupport (>= 3.0.0)
58
- factory_girl_rails (4.4.1)
59
- factory_girl (~> 4.4.0)
60
- railties (>= 3.0.0)
61
67
  globalid (0.3.6)
62
68
  activesupport (>= 4.1.0)
63
69
  i18n (0.7.0)
@@ -120,6 +126,8 @@ GEM
120
126
  rspec-mocks (~> 3.1.0)
121
127
  rspec-support (~> 3.1.0)
122
128
  rspec-support (3.1.2)
129
+ shoulda-matchers (2.8.0)
130
+ activesupport (>= 3.0.0)
123
131
  slop (3.6.0)
124
132
  sprockets (3.5.2)
125
133
  concurrent-ruby (~> 1.0)
@@ -131,18 +139,25 @@ GEM
131
139
  sqlite3 (1.3.11)
132
140
  thor (0.19.1)
133
141
  thread_safe (0.3.5)
142
+ timecop (0.8.0)
134
143
  tzinfo (1.2.2)
135
144
  thread_safe (~> 0.1)
145
+ xpath (2.0.0)
146
+ nokogiri (~> 1.3)
136
147
 
137
148
  PLATFORMS
138
149
  ruby
139
150
 
140
151
  DEPENDENCIES
141
152
  authenticate!
142
- factory_girl_rails
153
+ capybara (~> 2.6.2)
154
+ database_cleaner (~> 1.5.1)
155
+ factory_girl
143
156
  pry
144
- rspec-rails
157
+ rspec-rails (~> 3.1.0)
158
+ shoulda-matchers (~> 2.8)
145
159
  sqlite3
160
+ timecop (~> 0.8.0)
146
161
 
147
162
  BUNDLED WITH
148
163
  1.11.2
@@ -68,7 +68,7 @@ class Authenticate::PasswordsController < Authenticate::AuthenticateController
68
68
  end
69
69
 
70
70
  def find_user_for_create
71
- Authenticate.configuration.user_model_class.find_by_email params[:password][:email]
71
+ Authenticate.configuration.user_model_class.find_by_normalized_email params[:password][:email]
72
72
  end
73
73
 
74
74
  def find_user_for_edit
data/authenticate.gemspec CHANGED
@@ -25,11 +25,15 @@ Gem::Specification.new do |s|
25
25
  s.add_dependency 'email_validator', '~> 1.6'
26
26
  s.add_dependency 'rails', '>= 4.0', '< 5.1'
27
27
 
28
- # s.add_development_dependency 'capybara'
29
- s.add_development_dependency 'factory_girl_rails'
30
- s.add_development_dependency 'rspec-rails'
28
+ # s.add_development_dependency 'factory_girl_rails', '~> 4.4.1'
29
+ s.add_development_dependency 'factory_girl'
30
+ s.add_development_dependency 'rspec-rails', '~> 3.1.0'
31
31
  s.add_development_dependency 'pry'
32
32
  s.add_development_dependency 'sqlite3'
33
+ s.add_development_dependency 'shoulda-matchers', '~> 2.8'
34
+ s.add_development_dependency 'capybara', '~> 2.6.2'
35
+ s.add_development_dependency 'database_cleaner', '~> 1.5.1'
36
+ s.add_development_dependency 'timecop', '~> 0.8.0'
33
37
 
34
38
  s.required_ruby_version = Gem::Requirement.new('>= 2.0')
35
39
  end
@@ -56,7 +56,7 @@ en:
56
56
  title: Sign up
57
57
  callbacks:
58
58
  authenticatable:
59
- failure: Bad id or password
59
+ failure: Invalid id or password
60
60
  brute_force:
61
61
  failure: "Your account is locked, will unlock in %{time_remaining}"
62
62
  lifetimed:
@@ -2,8 +2,13 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
+ gem 'shoulda-matchers', '~> 2.8'
6
+ gem 'capybara', '~> 2.6.2'
7
+ gem 'database_cleaner', '~> 1.5.1'
8
+ gem 'timecop', '~> 0.8.0'
9
+
5
10
  gem "bundler", "~> 1.3"
6
- gem "factory_girl_rails", "~> 4.2"
11
+ gem "factory_girl", "~> 4.4"
7
12
  gem "rspec-rails", "~> 3.1"
8
13
  gem "sqlite3", "~> 1.3"
9
14
  gem "pry", :require => false
@@ -6,7 +6,7 @@ Authenticate.lifecycle.prepend_after_authentication name: 'brute force protectio
6
6
  unless session.authenticated? || Authenticate.configuration.max_consecutive_bad_logins_allowed.nil?
7
7
  user_credentials = User.credentials(session.request.params)
8
8
  user ||= User.find_by_credentials(user_credentials)
9
- if user
9
+ if user && user.respond_to?(:register_failed_login!)
10
10
  user.register_failed_login!
11
11
  user.save!
12
12
  end
@@ -14,14 +14,13 @@ Authenticate.lifecycle.prepend_after_authentication name: 'brute force protectio
14
14
 
15
15
  # if user is locked, and we allow a lockout period, then unlock the user if they've waited
16
16
  # longer than the lockout period.
17
- if user && !Authenticate.configuration.bad_login_lockout_period.nil? && user.locked?
17
+ if user && user.respond_to?(:locked?) && user.locked? && !Authenticate.configuration.bad_login_lockout_period.nil?
18
18
  user.unlock! if user.lock_expires_at <= Time.now.utc
19
19
  end
20
20
 
21
21
  # if the user is still locked, let them know how long they are locked for.
22
- if user && user.locked?
22
+ if user && user.respond_to?(:locked?) && user.locked?
23
23
  remaining = time_ago_in_words(user.lock_expires_at)
24
- # throw(:failure, "Your account is locked, will unlock in #{remaining.to_s}")
25
24
  throw(:failure, I18n.t('callbacks.brute_force.failure', time_remaining: remaining.to_s))
26
25
  end
27
26
 
@@ -206,12 +206,12 @@ module Authenticate
206
206
 
207
207
  def user_model_route_key
208
208
  return :users if @user_model == '::User' # avoid nil in generator
209
- Authenticate.configuration.user_model_class.model_name.route_key
209
+ user_model_class.model_name.route_key
210
210
  end
211
211
 
212
212
  def user_model_param_key
213
213
  return :user if @user_model == '::User' # avoid nil in generator
214
- Authenticate.configuration.user_model_class.model_name.param_key
214
+ user_model_class.model_name.param_key
215
215
  end
216
216
 
217
217
  # The name of foreign key parameter for the configured user model.
@@ -12,9 +12,7 @@ module Authenticate
12
12
  # Validate a user's identity with (typically) email/ID & password, and return the User if valid, or nil.
13
13
  # After calling this, call login(user) to complete the process.
14
14
  def authenticate(params)
15
- # todo: get params from User model
16
15
  credentials = Authenticate.configuration.user_model_class.credentials(params)
17
- debug "Controller::credentials: #{credentials.inspect}"
18
16
  Authenticate.configuration.user_model_class.authenticate(credentials)
19
17
  end
20
18
 
@@ -102,6 +100,7 @@ module Authenticate
102
100
 
103
101
  # User is not authorized, bounce 'em to sign in
104
102
  def unauthorized(msg = t('flashes.failure_when_not_signed_in'))
103
+ authenticate_session.deauthenticate
105
104
  respond_to do |format|
106
105
  format.any(:js, :json, :xml) { head :unauthorized }
107
106
  format.any {
@@ -33,7 +33,7 @@ module Authenticate
33
33
  module BruteForce
34
34
  extend ActiveSupport::Concern
35
35
 
36
- def self.required_fields(klass)
36
+ def self.required_fields(_klass)
37
37
  [:failed_logins_count, :lock_expires_at]
38
38
  end
39
39
 
@@ -41,7 +41,7 @@ module Authenticate
41
41
  def register_failed_login!
42
42
  self.failed_logins_count ||= 0
43
43
  self.failed_logins_count += 1
44
- lock! if self.failed_logins_count >= max_bad_logins
44
+ lock! if self.failed_logins_count > max_bad_logins
45
45
  end
46
46
 
47
47
  def lock!
@@ -26,7 +26,7 @@ module Authenticate
26
26
  module DbPassword
27
27
  extend ActiveSupport::Concern
28
28
 
29
- def self.required_fields(klass)
29
+ def self.required_fields(_klass)
30
30
  [:encrypted_password]
31
31
  end
32
32
 
@@ -72,8 +72,7 @@ module Authenticate
72
72
 
73
73
  # If we already have an encrypted password and it's not changing, skip the validation.
74
74
  def skip_password_validation?
75
- # encrypted_password.present? && !password_changing
76
- false
75
+ encrypted_password.present? && !password_changing
77
76
  end
78
77
 
79
78
  end
@@ -25,7 +25,7 @@ module Authenticate
25
25
  module Email
26
26
  extend ActiveSupport::Concern
27
27
 
28
- def self.required_fields(klass)
28
+ def self.required_fields(_klass)
29
29
  [:email]
30
30
  end
31
31
 
@@ -41,6 +41,7 @@ module Authenticate
41
41
  module ClassMethods
42
42
 
43
43
  def credentials(params)
44
+ return [] if params.nil? || params[:session].nil?
44
45
  [params[:session][:email], params[:session][:password]]
45
46
  end
46
47
 
@@ -51,11 +52,7 @@ module Authenticate
51
52
 
52
53
  def find_by_credentials(credentials)
53
54
  email = credentials[0]
54
- find_by_email normalize_email(email)
55
- end
56
-
57
- def normalize_email(email)
58
- email.to_s.downcase.gsub(/\s+/, '')
55
+ find_by_normalized_email(email)
59
56
  end
60
57
 
61
58
  end
@@ -25,7 +25,7 @@ module Authenticate
25
25
  module Lifetimed
26
26
  extend ActiveSupport::Concern
27
27
 
28
- def self.required_fields(klass)
28
+ def self.required_fields(_klass)
29
29
  [:current_sign_in_at]
30
30
  end
31
31
 
@@ -16,7 +16,7 @@ module Authenticate
16
16
  module PasswordReset
17
17
  extend ActiveSupport::Concern
18
18
 
19
- def self.required_fields(klass)
19
+ def self.required_fields(_klass)
20
20
  [:password_reset_token, :password_reset_sent_at, :email]
21
21
  end
22
22
 
@@ -29,7 +29,7 @@ module Authenticate
29
29
  module Timeoutable
30
30
  extend ActiveSupport::Concern
31
31
 
32
- def self.required_fields(klass)
32
+ def self.required_fields(_klass)
33
33
  [:last_access_at]
34
34
  end
35
35
 
@@ -45,6 +45,6 @@ module Authenticate
45
45
  def timeout_in
46
46
  Authenticate.configuration.timeout_in
47
47
  end
48
- end
48
+ end
49
49
  end
50
50
  end
@@ -19,7 +19,7 @@ module Authenticate
19
19
  module Trackable
20
20
  extend ActiveSupport::Concern
21
21
 
22
- def self.required_fields(klass)
22
+ def self.required_fields(_klass)
23
23
  [:current_sign_in_at, :current_sign_in_ip, :last_sign_in_at, :last_sign_in_ip, :sign_in_count]
24
24
  end
25
25
 
@@ -17,7 +17,7 @@ module Authenticate
17
17
  module Username
18
18
  extend ActiveSupport::Concern
19
19
 
20
- def self.required_fields(klass)
20
+ def self.required_fields(_klass)
21
21
  [:username, :email]
22
22
  end
23
23
 
@@ -21,8 +21,6 @@ module Authenticate
21
21
  def login(user, &block)
22
22
  debug 'session.login()'
23
23
  @current_user = user
24
- debug "session.login @current_user: #{@current_user.inspect}"
25
- # todo extract token gen to two different strategies
26
24
  @current_user.generate_session_token if user.present?
27
25
 
28
26
  message = catch(:failure) do
@@ -44,7 +42,6 @@ module Authenticate
44
42
  end
45
43
  end
46
44
 
47
-
48
45
  # Get the user represented by this session.
49
46
  #
50
47
  # @return [User]
@@ -64,7 +61,6 @@ module Authenticate
64
61
  current_user.present?
65
62
  end
66
63
 
67
-
68
64
  # Invalidate the session token, unset the current user and remove the cookie.
69
65
  #
70
66
  # @return [void]
@@ -49,6 +49,18 @@ module Authenticate
49
49
  save validate: false
50
50
  end
51
51
 
52
+ module ClassMethods
53
+
54
+ def normalize_email(email)
55
+ email.to_s.downcase.gsub(/\s+/, '')
56
+ end
57
+
58
+ # We need to find users by email even if they don't use email to log in
59
+ def find_by_normalized_email(email)
60
+ find_by_email normalize_email(email)
61
+ end
62
+
63
+ end
52
64
 
53
65
  end
54
66
  end
@@ -1,3 +1,3 @@
1
1
  module Authenticate
2
- VERSION = '0.2.3'
2
+ VERSION = '0.3.0'
3
3
  end
@@ -0,0 +1,119 @@
1
+ require 'spec_helper'
2
+ require 'support/controllers/controller_helpers'
3
+
4
+ describe Authenticate::PasswordsController, type: :controller do
5
+ it { is_expected.to be_a Authenticate::Controller }
6
+
7
+ describe 'get to #new' do
8
+ it 'renders the new form' do
9
+ get :new
10
+ expect(response).to be_success
11
+ expect(response).to render_template(:new)
12
+ end
13
+ end
14
+
15
+ describe 'post to #create' do
16
+ context 'with email for an existing user' do
17
+ it 'generates a password_reset_token' do
18
+ user = create(:user)
19
+ post :create, password: { email: user.email.upcase }
20
+ expect(user.reload.password_reset_token).not_to be_nil
21
+ end
22
+ it 'sends a password reset email' do
23
+ ActionMailer::Base.deliveries.clear
24
+ user = create(:user)
25
+ post :create, password: { email: user.email }
26
+ email = ActionMailer::Base.deliveries.last
27
+ expect(email.subject).to match(/change your password/i)
28
+ end
29
+ end
30
+ context 'with email that does not belong to an existing user' do
31
+ bad_email = 'bunk_email_address@non_existent_domain.com'
32
+ it 'does not send an email' do
33
+ ActionMailer::Base.deliveries.clear
34
+ post :create, password: { email: bad_email}
35
+ expect(ActionMailer::Base.deliveries).to be_empty
36
+ end
37
+ it 'always responds with redirect to avoid leaking user information' do
38
+ post :create, password: { email: bad_email }
39
+ expect(response).to be_redirect
40
+ end
41
+ end
42
+ end
43
+
44
+ describe 'get to #edit' do
45
+ context 'with a valid password_reset_token and timestamp' do
46
+ it 'renders password update form' do
47
+ user = create(:user, :with_password_reset_token_and_timestamp)
48
+ get :edit, id: user.id, token: user.password_reset_token
49
+ expect(response).to be_success
50
+ expect(response).to render_template(:edit)
51
+ expect(assigns(:user)).to eq user
52
+ end
53
+ end
54
+ context 'with a valid timestamp but invalid password_reset_token' do
55
+ it 'renders #new password form with notice' do
56
+ user = create(:user, :with_password_reset_token_and_timestamp)
57
+ get :edit, id: user.id, token: 'bad token'
58
+ expect(response).to be_success
59
+ expect(response).to render_template(:new)
60
+ end
61
+ end
62
+ context 'with a valid password_reset_token but invalid timestamp' do
63
+ it 'renders #new password form with notice' do
64
+ user = create(:user, :with_password_reset_token_and_timestamp, password_reset_sent_at: 2.years.ago)
65
+ get :edit, id: user.id, token: user.password_reset_token
66
+ expect(response).to be_redirect
67
+ expect(flash[:notice]).to match /password change request has expired/
68
+ end
69
+ end
70
+ context 'with a blank password_reset_token' do
71
+ it 'renders #new password form with notice' do
72
+ user = create(:user)
73
+ get :edit, id: user.id, token: nil
74
+ expect(response).to be_success
75
+ expect(response).to render_template(:new)
76
+ end
77
+ end
78
+ end
79
+
80
+ describe 'put to #update' do
81
+ context 'with valid password_reset_token and new password' do
82
+ it 'updates the user password' do
83
+ user = create(:user, :with_password_reset_token_and_timestamp)
84
+ old_encrypted_password = user.encrypted_password
85
+ put :update, update_params(user, new_password: 'new_password')
86
+ expect(user.reload.encrypted_password).not_to eq old_encrypted_password
87
+ end
88
+ it 'signs in the user' do
89
+ user = create(:user, :with_password_reset_token_and_timestamp)
90
+ put :update, update_params(user, new_password: 'new_password')
91
+ expect(cookies[:authenticate_session_token]).to be_present
92
+ expect(cookies[:authenticate_session_token]).to eq user.reload.session_token
93
+ end
94
+ it 'redirects user' do
95
+ user = create(:user, :with_password_reset_token_and_timestamp)
96
+ put :update, update_params(user, new_password: 'new_password')
97
+ expect(response).to redirect_to(Authenticate.configuration.redirect_url)
98
+ end
99
+ end
100
+ context 'with invalid new password' do
101
+ it 're-renders password edit form' do
102
+ user = create(:user, :with_password_reset_token_and_timestamp)
103
+ put :update, update_params(user, new_password: 'short')
104
+ expect(response).to render_template(:edit)
105
+ end
106
+ end
107
+
108
+ end
109
+
110
+ def update_params(user, options = {})
111
+ new_password = options.fetch(:new_password)
112
+ {
113
+ id: user,
114
+ token: user.password_reset_token,
115
+ password_reset: { password: new_password }
116
+ }
117
+ end
118
+
119
+ end