cbsorcery 0.8.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (135) hide show
  1. data/.document +5 -0
  2. data/.gitignore +56 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +40 -0
  5. data/CHANGELOG.md +263 -0
  6. data/Gemfile +6 -0
  7. data/LICENSE.txt +20 -0
  8. data/README.md +360 -0
  9. data/Rakefile +6 -0
  10. data/gemfiles/active_record-rails40.gemfile +7 -0
  11. data/gemfiles/active_record-rails41.gemfile +7 -0
  12. data/lib/generators/sorcery/USAGE +22 -0
  13. data/lib/generators/sorcery/helpers.rb +40 -0
  14. data/lib/generators/sorcery/install_generator.rb +95 -0
  15. data/lib/generators/sorcery/templates/initializer.rb +451 -0
  16. data/lib/generators/sorcery/templates/migration/activity_logging.rb +10 -0
  17. data/lib/generators/sorcery/templates/migration/brute_force_protection.rb +9 -0
  18. data/lib/generators/sorcery/templates/migration/core.rb +13 -0
  19. data/lib/generators/sorcery/templates/migration/external.rb +12 -0
  20. data/lib/generators/sorcery/templates/migration/remember_me.rb +8 -0
  21. data/lib/generators/sorcery/templates/migration/reset_password.rb +9 -0
  22. data/lib/generators/sorcery/templates/migration/user_activation.rb +9 -0
  23. data/lib/sorcery.rb +85 -0
  24. data/lib/sorcery/adapters/active_record_adapter.rb +120 -0
  25. data/lib/sorcery/adapters/base_adapter.rb +30 -0
  26. data/lib/sorcery/controller.rb +157 -0
  27. data/lib/sorcery/controller/config.rb +65 -0
  28. data/lib/sorcery/controller/submodules/activity_logging.rb +82 -0
  29. data/lib/sorcery/controller/submodules/brute_force_protection.rb +38 -0
  30. data/lib/sorcery/controller/submodules/external.rb +199 -0
  31. data/lib/sorcery/controller/submodules/http_basic_auth.rb +74 -0
  32. data/lib/sorcery/controller/submodules/remember_me.rb +81 -0
  33. data/lib/sorcery/controller/submodules/session_timeout.rb +56 -0
  34. data/lib/sorcery/crypto_providers/aes256.rb +51 -0
  35. data/lib/sorcery/crypto_providers/bcrypt.rb +97 -0
  36. data/lib/sorcery/crypto_providers/common.rb +35 -0
  37. data/lib/sorcery/crypto_providers/md5.rb +19 -0
  38. data/lib/sorcery/crypto_providers/sha1.rb +28 -0
  39. data/lib/sorcery/crypto_providers/sha256.rb +36 -0
  40. data/lib/sorcery/crypto_providers/sha512.rb +36 -0
  41. data/lib/sorcery/engine.rb +21 -0
  42. data/lib/sorcery/model.rb +183 -0
  43. data/lib/sorcery/model/config.rb +96 -0
  44. data/lib/sorcery/model/submodules/activity_logging.rb +70 -0
  45. data/lib/sorcery/model/submodules/brute_force_protection.rb +125 -0
  46. data/lib/sorcery/model/submodules/external.rb +100 -0
  47. data/lib/sorcery/model/submodules/remember_me.rb +62 -0
  48. data/lib/sorcery/model/submodules/reset_password.rb +131 -0
  49. data/lib/sorcery/model/submodules/user_activation.rb +149 -0
  50. data/lib/sorcery/model/temporary_token.rb +30 -0
  51. data/lib/sorcery/protocols/certs/ca-bundle.crt +5182 -0
  52. data/lib/sorcery/protocols/oauth.rb +42 -0
  53. data/lib/sorcery/protocols/oauth2.rb +47 -0
  54. data/lib/sorcery/providers/base.rb +27 -0
  55. data/lib/sorcery/providers/facebook.rb +63 -0
  56. data/lib/sorcery/providers/github.rb +51 -0
  57. data/lib/sorcery/providers/google.rb +51 -0
  58. data/lib/sorcery/providers/jira.rb +77 -0
  59. data/lib/sorcery/providers/linkedin.rb +66 -0
  60. data/lib/sorcery/providers/liveid.rb +53 -0
  61. data/lib/sorcery/providers/twitter.rb +59 -0
  62. data/lib/sorcery/providers/vk.rb +63 -0
  63. data/lib/sorcery/providers/xing.rb +64 -0
  64. data/lib/sorcery/railties/tasks.rake +6 -0
  65. data/lib/sorcery/test_helpers/internal.rb +78 -0
  66. data/lib/sorcery/test_helpers/internal/rails.rb +68 -0
  67. data/lib/sorcery/test_helpers/rails/controller.rb +21 -0
  68. data/lib/sorcery/test_helpers/rails/integration.rb +26 -0
  69. data/lib/sorcery/version.rb +3 -0
  70. data/sorcery.gemspec +34 -0
  71. data/spec/active_record/user_activation_spec.rb +18 -0
  72. data/spec/active_record/user_activity_logging_spec.rb +17 -0
  73. data/spec/active_record/user_brute_force_protection_spec.rb +16 -0
  74. data/spec/active_record/user_oauth_spec.rb +16 -0
  75. data/spec/active_record/user_remember_me_spec.rb +16 -0
  76. data/spec/active_record/user_reset_password_spec.rb +16 -0
  77. data/spec/active_record/user_spec.rb +37 -0
  78. data/spec/controllers/controller_activity_logging_spec.rb +124 -0
  79. data/spec/controllers/controller_brute_force_protection_spec.rb +43 -0
  80. data/spec/controllers/controller_http_basic_auth_spec.rb +68 -0
  81. data/spec/controllers/controller_oauth2_spec.rb +407 -0
  82. data/spec/controllers/controller_oauth_spec.rb +240 -0
  83. data/spec/controllers/controller_remember_me_spec.rb +117 -0
  84. data/spec/controllers/controller_session_timeout_spec.rb +80 -0
  85. data/spec/controllers/controller_spec.rb +215 -0
  86. data/spec/orm/active_record.rb +21 -0
  87. data/spec/rails_app/app/active_record/authentication.rb +3 -0
  88. data/spec/rails_app/app/active_record/user.rb +5 -0
  89. data/spec/rails_app/app/active_record/user_provider.rb +3 -0
  90. data/spec/rails_app/app/controllers/sorcery_controller.rb +265 -0
  91. data/spec/rails_app/app/helpers/application_helper.rb +2 -0
  92. data/spec/rails_app/app/mailers/sorcery_mailer.rb +32 -0
  93. data/spec/rails_app/app/views/application/index.html.erb +17 -0
  94. data/spec/rails_app/app/views/layouts/application.html.erb +14 -0
  95. data/spec/rails_app/app/views/sorcery_mailer/activation_email.html.erb +17 -0
  96. data/spec/rails_app/app/views/sorcery_mailer/activation_email.text.erb +9 -0
  97. data/spec/rails_app/app/views/sorcery_mailer/activation_needed_email.html.erb +17 -0
  98. data/spec/rails_app/app/views/sorcery_mailer/activation_success_email.html.erb +17 -0
  99. data/spec/rails_app/app/views/sorcery_mailer/activation_success_email.text.erb +9 -0
  100. data/spec/rails_app/app/views/sorcery_mailer/reset_password_email.html.erb +16 -0
  101. data/spec/rails_app/app/views/sorcery_mailer/reset_password_email.text.erb +8 -0
  102. data/spec/rails_app/app/views/sorcery_mailer/send_unlock_token_email.text.erb +1 -0
  103. data/spec/rails_app/config.ru +4 -0
  104. data/spec/rails_app/config/application.rb +56 -0
  105. data/spec/rails_app/config/boot.rb +4 -0
  106. data/spec/rails_app/config/database.yml +22 -0
  107. data/spec/rails_app/config/environment.rb +5 -0
  108. data/spec/rails_app/config/environments/test.rb +37 -0
  109. data/spec/rails_app/config/initializers/backtrace_silencers.rb +7 -0
  110. data/spec/rails_app/config/initializers/inflections.rb +10 -0
  111. data/spec/rails_app/config/initializers/mime_types.rb +5 -0
  112. data/spec/rails_app/config/initializers/secret_token.rb +7 -0
  113. data/spec/rails_app/config/initializers/session_store.rb +12 -0
  114. data/spec/rails_app/config/locales/en.yml +5 -0
  115. data/spec/rails_app/config/routes.rb +48 -0
  116. data/spec/rails_app/db/migrate/activation/20101224223622_add_activation_to_users.rb +17 -0
  117. data/spec/rails_app/db/migrate/activity_logging/20101224223624_add_activity_logging_to_users.rb +19 -0
  118. data/spec/rails_app/db/migrate/brute_force_protection/20101224223626_add_brute_force_protection_to_users.rb +13 -0
  119. data/spec/rails_app/db/migrate/core/20101224223620_create_users.rb +16 -0
  120. data/spec/rails_app/db/migrate/external/20101224223628_create_authentications_and_user_providers.rb +22 -0
  121. data/spec/rails_app/db/migrate/remember_me/20101224223623_add_remember_me_token_to_users.rb +15 -0
  122. data/spec/rails_app/db/migrate/reset_password/20101224223622_add_reset_password_to_users.rb +13 -0
  123. data/spec/rails_app/db/schema.rb +23 -0
  124. data/spec/rails_app/db/seeds.rb +7 -0
  125. data/spec/shared_examples/user_activation_shared_examples.rb +242 -0
  126. data/spec/shared_examples/user_activity_logging_shared_examples.rb +97 -0
  127. data/spec/shared_examples/user_brute_force_protection_shared_examples.rb +156 -0
  128. data/spec/shared_examples/user_oauth_shared_examples.rb +36 -0
  129. data/spec/shared_examples/user_remember_me_shared_examples.rb +57 -0
  130. data/spec/shared_examples/user_reset_password_shared_examples.rb +263 -0
  131. data/spec/shared_examples/user_shared_examples.rb +467 -0
  132. data/spec/sorcery_crypto_providers_spec.rb +198 -0
  133. data/spec/spec.opts +2 -0
  134. data/spec/spec_helper.rb +41 -0
  135. metadata +350 -0
@@ -0,0 +1,97 @@
1
+ shared_examples_for "rails_3_activity_logging_model" do
2
+ context "loaded plugin configuration" do
3
+ before(:all) do
4
+ sorcery_reload!([:activity_logging])
5
+ end
6
+
7
+ after(:each) do
8
+ User.sorcery_config.reset!
9
+ end
10
+
11
+ it "allows configuration option 'last_login_at_attribute_name'" do
12
+ sorcery_model_property_set(:last_login_at_attribute_name, :login_time)
13
+
14
+ expect(User.sorcery_config.last_login_at_attribute_name).to eq :login_time
15
+ end
16
+
17
+ it "allows configuration option 'last_logout_at_attribute_name'" do
18
+ sorcery_model_property_set(:last_logout_at_attribute_name, :logout_time)
19
+ expect(User.sorcery_config.last_logout_at_attribute_name).to eq :logout_time
20
+ end
21
+
22
+ it "allows configuration option 'last_activity_at_attribute_name'" do
23
+ sorcery_model_property_set(:last_activity_at_attribute_name, :activity_time)
24
+ expect(User.sorcery_config.last_activity_at_attribute_name).to eq :activity_time
25
+ end
26
+
27
+ it "allows configuration option 'last_login_from_ip_adress'" do
28
+ sorcery_model_property_set(:last_login_from_ip_address_name, :ip_address)
29
+ expect(User.sorcery_config.last_login_from_ip_address_name).to eq :ip_address
30
+ end
31
+
32
+ describe ".current_users" do
33
+ let(:user) { create_new_user }
34
+
35
+ it "is empty when no users are logged in" do
36
+ expect(User.current_users).to be_empty
37
+ end
38
+
39
+ it "holds the user object when 1 user is logged in" do
40
+ user.set_last_activity_at(Time.now.in_time_zone)
41
+
42
+ expect(User.current_users).to match([User.sorcery_adapter.find(user.id)])
43
+ end
44
+
45
+ it "'current_users' shows all current_users, whether they have logged out before or not." do
46
+ User.sorcery_adapter.delete_all
47
+ user1 = create_new_user({:username => 'gizmo1', :email => "bla1@bla.com", :password => 'secret1'})
48
+ user2 = create_new_user({:username => 'gizmo2', :email => "bla2@bla.com", :password => 'secret2'})
49
+ user3 = create_new_user({:username => 'gizmo3', :email => "bla3@bla.com", :password => 'secret3'})
50
+
51
+ now = Time.now.in_time_zone
52
+ [user1, user2, user3].each do |user|
53
+ user.set_last_login_at(now)
54
+ user.set_last_activity_at(now)
55
+ end
56
+
57
+ expect(User.current_users.map(&:id)).to match_array([user1, user2, user3].map(&:id))
58
+ Timecop.travel now + 5
59
+ user1.set_last_logout_at(Time.now.in_time_zone)
60
+ expect(User.current_users.map(&:id)).to match_array([user2, user3].map(&:id))
61
+ Timecop.return
62
+ end
63
+
64
+ end
65
+
66
+ it '.set_last_login_at update last_login_at' do
67
+ user = create_new_user
68
+ now = Time.now.in_time_zone
69
+ expect(user.sorcery_adapter).to receive(:update_attribute).with(:last_login_at, now)
70
+
71
+ user.set_last_login_at(now)
72
+ end
73
+
74
+ it '.set_last_logout_at update last_logout_at' do
75
+ user = create_new_user
76
+ now = Time.now.in_time_zone
77
+ expect(user.sorcery_adapter).to receive(:update_attribute).with(:last_logout_at, now)
78
+
79
+ user.set_last_logout_at(now)
80
+ end
81
+
82
+ it '.set_last_activity_at update last_activity_at' do
83
+ user = create_new_user
84
+ now = Time.now.in_time_zone
85
+ expect(user.sorcery_adapter).to receive(:update_attribute).with(:last_activity_at, now)
86
+
87
+ user.set_last_activity_at(now)
88
+ end
89
+
90
+ it '.set_last_ip_addess update last_login_from_ip_address' do
91
+ user = create_new_user
92
+ expect(user.sorcery_adapter).to receive(:update_attribute).with(:last_login_from_ip_address, '0.0.0.0')
93
+
94
+ user.set_last_ip_addess('0.0.0.0')
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,156 @@
1
+ shared_examples_for "rails_3_brute_force_protection_model" do
2
+ let(:user) { create_new_user }
3
+ before(:each) do
4
+ User.sorcery_adapter.delete_all
5
+ end
6
+
7
+
8
+ context "loaded plugin configuration" do
9
+
10
+ let(:config) { User.sorcery_config }
11
+
12
+ before(:all) do
13
+ sorcery_reload!([:brute_force_protection])
14
+ end
15
+
16
+ after(:each) do
17
+ User.sorcery_config.reset!
18
+ end
19
+
20
+ specify { expect(user).to respond_to(:failed_logins_count) }
21
+ specify { expect(user).to respond_to(:lock_expires_at) }
22
+
23
+ it "enables configuration option 'failed_logins_count_attribute_name'" do
24
+ sorcery_model_property_set(:failed_logins_count_attribute_name, :my_count)
25
+ expect(config.failed_logins_count_attribute_name).to eq :my_count
26
+ end
27
+
28
+ it "enables configuration option 'lock_expires_at_attribute_name'" do
29
+ sorcery_model_property_set(:lock_expires_at_attribute_name, :expires)
30
+ expect(config.lock_expires_at_attribute_name).to eq :expires
31
+ end
32
+
33
+ it "enables configuration option 'consecutive_login_retries_amount_allowed'" do
34
+ sorcery_model_property_set(:consecutive_login_retries_amount_limit, 34)
35
+ expect(config.consecutive_login_retries_amount_limit).to eq 34
36
+ end
37
+
38
+ it "enables configuration option 'login_lock_time_period'" do
39
+ sorcery_model_property_set(:login_lock_time_period, 2.hours)
40
+ expect(config.login_lock_time_period).to eq 2.hours
41
+ end
42
+
43
+ describe "#locked?" do
44
+ it "is locked" do
45
+ user.send("#{config.lock_expires_at_attribute_name}=", Time.now + 5.days)
46
+ expect(user).to be_locked
47
+ end
48
+
49
+ it "isn't locked" do
50
+ user.send("#{config.lock_expires_at_attribute_name}=", nil)
51
+ expect(user).not_to be_locked
52
+ end
53
+ end
54
+ end
55
+
56
+ describe "#register_failed_login!" do
57
+ it "locks user when number of retries reached the limit" do
58
+ expect(user.lock_expires_at).to be_nil
59
+
60
+ sorcery_model_property_set(:consecutive_login_retries_amount_limit, 1)
61
+ user.register_failed_login!
62
+ lock_expires_at = User.sorcery_adapter.find_by_id(user.id).lock_expires_at
63
+
64
+ expect(lock_expires_at).not_to be_nil
65
+ end
66
+
67
+ context "unlock_token_mailer_disabled is true" do
68
+ it "does not automatically send unlock email" do
69
+ sorcery_model_property_set(:unlock_token_mailer_disabled, true)
70
+ sorcery_model_property_set(:consecutive_login_retries_amount_limit, 2)
71
+ sorcery_model_property_set(:login_lock_time_period, 0)
72
+ sorcery_model_property_set(:unlock_token_mailer, SorceryMailer)
73
+
74
+ 3.times { user.register_failed_login! }
75
+
76
+ expect(ActionMailer::Base.deliveries.size).to eq 0
77
+
78
+ end
79
+ end
80
+
81
+ context "unlock_token_mailer_disabled is false" do
82
+ before do
83
+ sorcery_model_property_set(:unlock_token_mailer_disabled, false)
84
+ sorcery_model_property_set(:consecutive_login_retries_amount_limit, 2)
85
+ sorcery_model_property_set(:login_lock_time_period, 0)
86
+ sorcery_model_property_set(:unlock_token_mailer, SorceryMailer)
87
+ end
88
+
89
+ it "does not automatically send unlock email" do
90
+ 3.times { user.register_failed_login! }
91
+
92
+ expect(ActionMailer::Base.deliveries.size).to eq 1
93
+ end
94
+
95
+ it "generates unlock token before mail is sent" do
96
+ 3.times { user.register_failed_login! }
97
+
98
+ expect(ActionMailer::Base.deliveries.last.body.to_s.match(user.unlock_token)).not_to be_nil
99
+ end
100
+ end
101
+ end
102
+
103
+ context ".authenticate" do
104
+
105
+ it "unlocks after lock time period passes" do
106
+ sorcery_model_property_set(:consecutive_login_retries_amount_limit, 2)
107
+ sorcery_model_property_set(:login_lock_time_period, 0.2)
108
+ 2.times { user.register_failed_login! }
109
+
110
+ lock_expires_at = User.sorcery_adapter.find_by_id(user.id).lock_expires_at
111
+ expect(lock_expires_at).not_to be_nil
112
+
113
+ Timecop.travel(Time.now.in_time_zone + 0.3)
114
+ User.authenticate('bla@bla.com', 'secret')
115
+
116
+ lock_expires_at = User.sorcery_adapter.find_by_id(user.id).lock_expires_at
117
+ expect(lock_expires_at).to be_nil
118
+ Timecop.return
119
+ end
120
+
121
+ it "doest not unlock if time period is 0 (permanent lock)" do
122
+ sorcery_model_property_set(:consecutive_login_retries_amount_limit, 2)
123
+ sorcery_model_property_set(:login_lock_time_period, 0)
124
+
125
+ 2.times { user.register_failed_login! }
126
+
127
+ unlock_date = user.lock_expires_at
128
+ Timecop.travel(Time.now.in_time_zone + 1)
129
+
130
+ user.register_failed_login!
131
+
132
+ expect(user.lock_expires_at.to_s).to eq unlock_date.to_s
133
+ Timecop.return
134
+ end
135
+
136
+ end
137
+
138
+ describe "#unlock!" do
139
+ it "unlocks after entering unlock token" do
140
+ sorcery_model_property_set(:consecutive_login_retries_amount_limit, 2)
141
+ sorcery_model_property_set(:login_lock_time_period, 0)
142
+ sorcery_model_property_set(:unlock_token_mailer, SorceryMailer)
143
+ 3.times { user.register_failed_login! }
144
+
145
+ expect(user.unlock_token).not_to be_nil
146
+
147
+ token = user.unlock_token
148
+ user = User.load_from_unlock_token(token)
149
+
150
+ expect(user).not_to be_nil
151
+
152
+ user.unlock!
153
+ expect(User.load_from_unlock_token(user.unlock_token)).to be_nil
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,36 @@
1
+ shared_examples_for "rails_3_oauth_model" do
2
+ # ----------------- PLUGIN CONFIGURATION -----------------------
3
+
4
+ let(:external_user) { create_new_external_user :twitter }
5
+
6
+ describe "loaded plugin configuration" do
7
+
8
+ before(:all) do
9
+ Authentication.sorcery_adapter.delete_all
10
+ User.sorcery_adapter.delete_all
11
+
12
+ sorcery_reload!([:external])
13
+ sorcery_controller_property_set(:external_providers, [:twitter])
14
+ sorcery_model_property_set(:authentications_class, Authentication)
15
+ sorcery_controller_external_property_set(:twitter, :key, "eYVNBjBDi33aa9GkA3w")
16
+ sorcery_controller_external_property_set(:twitter, :secret, "XpbeSdCoaKSmQGSeokz5qcUATClRW5u08QWNfv71N8")
17
+ sorcery_controller_external_property_set(:twitter, :callback_url, "http://blabla.com")
18
+ end
19
+
20
+ it "responds to 'load_from_provider'" do
21
+ expect(User).to respond_to(:load_from_provider)
22
+ end
23
+
24
+ it "'load_from_provider' loads user if exists" do
25
+ external_user
26
+ expect(User.load_from_provider :twitter, 123).to eq external_user
27
+ end
28
+
29
+ it "'load_from_provider' returns nil if user doesn't exist" do
30
+ external_user
31
+ expect(User.load_from_provider :twitter, 980342).to be_nil
32
+ end
33
+
34
+ end
35
+
36
+ end
@@ -0,0 +1,57 @@
1
+ shared_examples_for "rails_3_remember_me_model" do
2
+ let(:user) { create_new_user }
3
+
4
+ describe "loaded plugin configuration" do
5
+
6
+ before(:all) do
7
+ sorcery_reload!([:remember_me])
8
+ end
9
+
10
+ after(:each) do
11
+ User.sorcery_config.reset!
12
+ end
13
+
14
+ it "allows configuration option 'remember_me_token_attribute_name'" do
15
+ sorcery_model_property_set(:remember_me_token_attribute_name, :my_token)
16
+
17
+ expect(User.sorcery_config.remember_me_token_attribute_name).to eq :my_token
18
+ end
19
+
20
+ it "allows configuration option 'remember_me_token_expires_at_attribute_name'" do
21
+ sorcery_model_property_set(:remember_me_token_expires_at_attribute_name, :my_expires)
22
+
23
+ expect(User.sorcery_config.remember_me_token_expires_at_attribute_name).to eq :my_expires
24
+ end
25
+
26
+ specify { expect(user).to respond_to :remember_me! }
27
+
28
+ specify { expect(user).to respond_to :forget_me! }
29
+
30
+ it "generates a new token on 'remember_me!'" do
31
+ expect(user.remember_me_token).to be_nil
32
+
33
+ user.remember_me!
34
+
35
+ expect(user.remember_me_token).not_to be_nil
36
+ end
37
+
38
+ # FIXME: assert on line 37 sometimes fails by a second
39
+ it "sets an expiration based on 'remember_me_for' attribute" do
40
+ sorcery_model_property_set(:remember_me_for, 2 * 60 * 60 * 24)
41
+ user.remember_me!
42
+
43
+ expect(user.remember_me_token_expires_at.utc.to_s).to eq (Time.now.in_time_zone + 2 * 60 * 60 * 24).utc.to_s
44
+ end
45
+
46
+ it "deletes the token and expiration on 'forget_me!'" do
47
+ user.remember_me!
48
+
49
+ expect(user.remember_me_token).not_to be_nil
50
+
51
+ user.forget_me!
52
+
53
+ expect(user.remember_me_token).to be_nil
54
+ expect(user.remember_me_token_expires_at).to be_nil
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,263 @@
1
+ shared_examples_for "rails_3_reset_password_model" do
2
+ # ----------------- PLUGIN CONFIGURATION -----------------------
3
+ let(:user) { create_new_user }
4
+
5
+ describe "loaded plugin configuration" do
6
+
7
+ before(:all) do
8
+ sorcery_reload!([:reset_password], :reset_password_mailer => ::SorceryMailer)
9
+ end
10
+
11
+ after(:each) do
12
+ User.sorcery_config.reset!
13
+ end
14
+
15
+ context "API" do
16
+
17
+ specify { expect(user).to respond_to :deliver_reset_password_instructions! }
18
+
19
+ specify { expect(user).to respond_to :change_password! }
20
+
21
+ it "responds to .load_from_reset_password_token" do
22
+ expect(User).to respond_to :load_from_reset_password_token
23
+ end
24
+ end
25
+
26
+ it "allows configuration option 'reset_password_token_attribute_name'" do
27
+ sorcery_model_property_set(:reset_password_token_attribute_name, :my_code)
28
+
29
+ expect(User.sorcery_config.reset_password_token_attribute_name).to eq :my_code
30
+ end
31
+
32
+ it "allows configuration option 'reset_password_mailer'" do
33
+ sorcery_model_property_set(:reset_password_mailer, TestUser)
34
+
35
+ expect(User.sorcery_config.reset_password_mailer).to eq TestUser
36
+ end
37
+
38
+ it "enables configuration option 'reset_password_mailer_disabled'" do
39
+ sorcery_model_property_set(:reset_password_mailer_disabled, :my_reset_password_mailer_disabled)
40
+
41
+ expect(User.sorcery_config.reset_password_mailer_disabled).to eq :my_reset_password_mailer_disabled
42
+ end
43
+
44
+ it "if mailer is nil and mailer is enabled, throw exception!" do
45
+ expect{sorcery_reload!([:reset_password], :reset_password_mailer_disabled => false)}.to raise_error(ArgumentError)
46
+ end
47
+
48
+ it "if mailer is disabled and mailer is nil, do NOT throw exception" do
49
+ expect{sorcery_reload!([:reset_password], :reset_password_mailer_disabled => true)}.to_not raise_error
50
+ end
51
+
52
+ it "allows configuration option 'reset_password_email_method_name'" do
53
+ sorcery_model_property_set(:reset_password_email_method_name, :my_mailer_method)
54
+
55
+ expect(User.sorcery_config.reset_password_email_method_name).to eq :my_mailer_method
56
+ end
57
+
58
+ it "allows configuration option 'reset_password_expiration_period'" do
59
+ sorcery_model_property_set(:reset_password_expiration_period, 16)
60
+
61
+ expect(User.sorcery_config.reset_password_expiration_period).to eq 16
62
+ end
63
+
64
+ it "allows configuration option 'reset_password_email_sent_at_attribute_name'" do
65
+ sorcery_model_property_set(:reset_password_email_sent_at_attribute_name, :blabla)
66
+
67
+ expect(User.sorcery_config.reset_password_email_sent_at_attribute_name).to eq :blabla
68
+ end
69
+
70
+ it "allows configuration option 'reset_password_time_between_emails'" do
71
+ sorcery_model_property_set(:reset_password_time_between_emails, 16)
72
+
73
+ expect(User.sorcery_config.reset_password_time_between_emails).to eq 16
74
+ end
75
+ end
76
+
77
+
78
+ describe "when activated with sorcery" do
79
+
80
+ before(:all) do
81
+ sorcery_reload!([:reset_password], :reset_password_mailer => ::SorceryMailer)
82
+ end
83
+
84
+ before(:each) do
85
+ User.sorcery_adapter.delete_all
86
+ user
87
+ end
88
+
89
+ after(:each) do
90
+ Timecop.return
91
+ end
92
+
93
+ it "load_from_reset_password_token returns user when token is found" do
94
+ user.generate_reset_password_token!
95
+ updated_user = User.sorcery_adapter.find(user.id)
96
+
97
+ expect(User.load_from_reset_password_token user.reset_password_token).to eq updated_user
98
+ end
99
+
100
+ it "load_from_reset_password_token does NOT return user when token is NOT found" do
101
+ user.generate_reset_password_token!
102
+
103
+ expect(User.load_from_reset_password_token "a").to be_nil
104
+ end
105
+
106
+ it "load_from_reset_password_token returns user when token is found and not expired" do
107
+ sorcery_model_property_set(:reset_password_expiration_period, 500)
108
+ user.generate_reset_password_token!
109
+ updated_user = User.sorcery_adapter.find(user.id)
110
+
111
+ expect(User.load_from_reset_password_token user.reset_password_token).to eq updated_user
112
+ end
113
+
114
+ it "load_from_reset_password_token does NOT return user when token is found and expired" do
115
+ sorcery_model_property_set(:reset_password_expiration_period, 0.1)
116
+ user.generate_reset_password_token!
117
+ Timecop.travel(Time.now.in_time_zone+0.5)
118
+
119
+ expect(User.load_from_reset_password_token user.reset_password_token).to be_nil
120
+ end
121
+
122
+ it "load_from_reset_password_token is always valid if expiration period is nil" do
123
+ sorcery_model_property_set(:reset_password_expiration_period, nil)
124
+ user.generate_reset_password_token!
125
+ updated_user = User.sorcery_adapter.find(user.id)
126
+
127
+ expect(User.load_from_reset_password_token user.reset_password_token).to eq updated_user
128
+ end
129
+
130
+ it "load_from_reset_password_token returns nil if token is blank" do
131
+ expect(User.load_from_reset_password_token nil).to be_nil
132
+ expect(User.load_from_reset_password_token "").to be_nil
133
+ end
134
+
135
+ it "'deliver_reset_password_instructions!' generates a reset_password_token" do
136
+ expect(user.reset_password_token).to be_nil
137
+
138
+ user.deliver_reset_password_instructions!
139
+
140
+ expect(user.reset_password_token).not_to be_nil
141
+ end
142
+
143
+ it "the reset_password_token is random" do
144
+ sorcery_model_property_set(:reset_password_time_between_emails, 0)
145
+ user.deliver_reset_password_instructions!
146
+ old_password_code = user.reset_password_token
147
+ user.deliver_reset_password_instructions!
148
+
149
+ expect(user.reset_password_token).not_to eq old_password_code
150
+ end
151
+
152
+ context "mailer is enabled" do
153
+ it "sends an email on reset" do
154
+ old_size = ActionMailer::Base.deliveries.size
155
+ user.deliver_reset_password_instructions!
156
+
157
+ expect(ActionMailer::Base.deliveries.size).to eq old_size + 1
158
+ end
159
+
160
+ it "calls send_reset_password_email! on reset" do
161
+ expect(user).to receive(:send_reset_password_email!).once
162
+
163
+ user.deliver_reset_password_instructions!
164
+ end
165
+
166
+ it "does not send an email if time between emails has not passed since last email" do
167
+ sorcery_model_property_set(:reset_password_time_between_emails, 10000)
168
+ old_size = ActionMailer::Base.deliveries.size
169
+ user.deliver_reset_password_instructions!
170
+
171
+ expect(ActionMailer::Base.deliveries.size).to eq old_size + 1
172
+
173
+ user.deliver_reset_password_instructions!
174
+
175
+ expect(ActionMailer::Base.deliveries.size).to eq old_size + 1
176
+ end
177
+
178
+ it "sends an email if time between emails has passed since last email" do
179
+ sorcery_model_property_set(:reset_password_time_between_emails, 0.5)
180
+ old_size = ActionMailer::Base.deliveries.size
181
+ user.deliver_reset_password_instructions!
182
+
183
+ expect(ActionMailer::Base.deliveries.size).to eq old_size + 1
184
+
185
+ Timecop.travel(Time.now.in_time_zone+0.5)
186
+ user.deliver_reset_password_instructions!
187
+
188
+ expect(ActionMailer::Base.deliveries.size).to eq old_size + 2
189
+ end
190
+ end
191
+
192
+ context "mailer is disabled" do
193
+
194
+ before(:all) do
195
+ sorcery_reload!([:reset_password], :reset_password_mailer_disabled => true, :reset_password_mailer => ::SorceryMailer)
196
+ end
197
+
198
+ it "sends an email on reset" do
199
+ old_size = ActionMailer::Base.deliveries.size
200
+ user.deliver_reset_password_instructions!
201
+
202
+ expect(ActionMailer::Base.deliveries.size).to eq old_size
203
+ end
204
+
205
+ it "does not call send_reset_password_email! on reset" do
206
+ expect(user).to receive(:send_reset_password_email!).never
207
+
208
+ user.deliver_reset_password_instructions!
209
+ end
210
+
211
+ it "does not send an email if time between emails has not passed since last email" do
212
+ sorcery_model_property_set(:reset_password_time_between_emails, 10000)
213
+ old_size = ActionMailer::Base.deliveries.size
214
+ user.deliver_reset_password_instructions!
215
+
216
+ expect(ActionMailer::Base.deliveries.size).to eq old_size
217
+
218
+ user.deliver_reset_password_instructions!
219
+
220
+ expect(ActionMailer::Base.deliveries.size).to eq old_size
221
+ end
222
+
223
+ it "sends an email if time between emails has passed since last email" do
224
+ sorcery_model_property_set(:reset_password_time_between_emails, 0.5)
225
+ old_size = ActionMailer::Base.deliveries.size
226
+ user.deliver_reset_password_instructions!
227
+
228
+ expect(ActionMailer::Base.deliveries.size).to eq old_size
229
+
230
+ Timecop.travel(Time.now.in_time_zone+0.5)
231
+ user.deliver_reset_password_instructions!
232
+
233
+ expect(ActionMailer::Base.deliveries.size).to eq old_size
234
+ end
235
+ end
236
+
237
+ it "when change_password! is called, deletes reset_password_token" do
238
+ user.deliver_reset_password_instructions!
239
+
240
+ expect(user.reset_password_token).not_to be_nil
241
+
242
+ user.change_password!("blabulsdf")
243
+ user.save!
244
+
245
+ expect(user.reset_password_token).to be_nil
246
+ end
247
+
248
+ it "returns false if time between emails has not passed since last email" do
249
+ sorcery_model_property_set(:reset_password_time_between_emails, 10000)
250
+ user.deliver_reset_password_instructions!
251
+
252
+ expect(user.deliver_reset_password_instructions!).to be false
253
+ end
254
+
255
+ it "encrypts properly on reset" do
256
+ user.deliver_reset_password_instructions!
257
+ user.change_password!("blagu")
258
+
259
+ expect(Sorcery::CryptoProviders::BCrypt.matches? user.crypted_password, "blagu", user.salt).to be true
260
+ end
261
+
262
+ end
263
+ end