sorcery 0.8.6 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -1
  3. data/.travis.yml +75 -14
  4. data/CHANGELOG.md +32 -1
  5. data/Gemfile +1 -0
  6. data/README.md +138 -86
  7. data/gemfiles/active_record-rails40.gemfile +7 -0
  8. data/gemfiles/active_record-rails41.gemfile +3 -2
  9. data/gemfiles/mongo_mapper-rails40.gemfile +9 -0
  10. data/gemfiles/mongo_mapper-rails41.gemfile +2 -1
  11. data/gemfiles/mongoid-rails40.gemfile +9 -0
  12. data/gemfiles/mongoid-rails41.gemfile +3 -5
  13. data/gemfiles/mongoid3-rails32.gemfile +9 -0
  14. data/lib/generators/sorcery/USAGE +1 -1
  15. data/lib/generators/sorcery/install_generator.rb +19 -5
  16. data/lib/generators/sorcery/templates/initializer.rb +36 -10
  17. data/lib/generators/sorcery/templates/migration/brute_force_protection.rb +3 -1
  18. data/lib/generators/sorcery/templates/migration/core.rb +2 -2
  19. data/lib/generators/sorcery/templates/migration/external.rb +3 -1
  20. data/lib/sorcery/adapters/active_record_adapter.rb +120 -0
  21. data/lib/sorcery/adapters/base_adapter.rb +30 -0
  22. data/lib/sorcery/adapters/data_mapper_adapter.rb +176 -0
  23. data/lib/sorcery/adapters/mongo_mapper_adapter.rb +110 -0
  24. data/lib/sorcery/adapters/mongoid_adapter.rb +97 -0
  25. data/lib/sorcery/controller/config.rb +65 -0
  26. data/lib/sorcery/controller/submodules/activity_logging.rb +16 -21
  27. data/lib/sorcery/controller/submodules/brute_force_protection.rb +6 -6
  28. data/lib/sorcery/controller/submodules/external.rb +9 -29
  29. data/lib/sorcery/controller/submodules/remember_me.rb +4 -4
  30. data/lib/sorcery/controller/submodules/session_timeout.rb +10 -6
  31. data/lib/sorcery/controller.rb +5 -64
  32. data/lib/sorcery/model/config.rb +96 -0
  33. data/lib/sorcery/model/submodules/activity_logging.rb +29 -36
  34. data/lib/sorcery/model/submodules/brute_force_protection.rb +21 -37
  35. data/lib/sorcery/model/submodules/external.rb +53 -9
  36. data/lib/sorcery/model/submodules/remember_me.rb +12 -31
  37. data/lib/sorcery/model/submodules/reset_password.rb +21 -39
  38. data/lib/sorcery/model/submodules/user_activation.rb +21 -63
  39. data/lib/sorcery/model/temporary_token.rb +4 -4
  40. data/lib/sorcery/model.rb +47 -175
  41. data/lib/sorcery/providers/base.rb +11 -0
  42. data/lib/sorcery/providers/facebook.rb +16 -5
  43. data/lib/sorcery/providers/github.rb +11 -2
  44. data/lib/sorcery/providers/google.rb +1 -1
  45. data/lib/sorcery/providers/heroku.rb +57 -0
  46. data/lib/sorcery/providers/jira.rb +77 -0
  47. data/lib/sorcery/providers/linkedin.rb +1 -1
  48. data/lib/sorcery/providers/liveid.rb +1 -1
  49. data/lib/sorcery/providers/salesforce.rb +50 -0
  50. data/lib/sorcery/providers/twitter.rb +1 -1
  51. data/lib/sorcery/providers/vk.rb +6 -4
  52. data/lib/sorcery/providers/xing.rb +2 -2
  53. data/lib/sorcery/test_helpers/internal.rb +7 -3
  54. data/lib/sorcery/test_helpers/rails/controller.rb +5 -1
  55. data/lib/sorcery/version.rb +3 -0
  56. data/lib/sorcery.rb +75 -43
  57. data/sorcery.gemspec +6 -2
  58. data/spec/active_record/user_activity_logging_spec.rb +9 -0
  59. data/spec/controllers/controller_activity_logging_spec.rb +124 -0
  60. data/spec/controllers/controller_brute_force_protection_spec.rb +43 -0
  61. data/spec/{active_record → controllers}/controller_http_basic_auth_spec.rb +14 -11
  62. data/spec/{active_record → controllers}/controller_oauth2_spec.rb +151 -64
  63. data/spec/{active_record → controllers}/controller_oauth_spec.rb +94 -70
  64. data/spec/{active_record → controllers}/controller_remember_me_spec.rb +32 -12
  65. data/spec/{active_record → controllers}/controller_session_timeout_spec.rb +15 -5
  66. data/spec/{shared_examples/controller_shared_examples.rb → controllers/controller_spec.rb} +34 -19
  67. data/spec/{datamapper → data_mapper}/user_activation_spec.rb +1 -1
  68. data/spec/data_mapper/user_activity_logging_spec.rb +14 -0
  69. data/spec/{datamapper → data_mapper}/user_brute_force_protection_spec.rb +1 -1
  70. data/spec/{datamapper → data_mapper}/user_oauth_spec.rb +1 -1
  71. data/spec/{datamapper → data_mapper}/user_remember_me_spec.rb +1 -1
  72. data/spec/{datamapper → data_mapper}/user_reset_password_spec.rb +1 -1
  73. data/spec/{datamapper → data_mapper}/user_spec.rb +1 -1
  74. data/spec/mongoid/user_spec.rb +13 -0
  75. data/spec/orm/active_record.rb +12 -0
  76. data/spec/orm/{datamapper.rb → data_mapper.rb} +16 -2
  77. data/spec/orm/mongo_mapper.rb +0 -1
  78. data/spec/orm/mongoid.rb +4 -0
  79. data/spec/rails_app/app/controllers/sorcery_controller.rb +62 -1
  80. data/spec/rails_app/app/mongo_mapper/user.rb +2 -0
  81. data/spec/rails_app/config/routes.rb +9 -0
  82. data/spec/rails_app/db/migrate/core/20101224223620_create_users.rb +2 -2
  83. data/spec/shared_examples/user_activation_shared_examples.rb +7 -7
  84. data/spec/shared_examples/user_activity_logging_shared_examples.rb +73 -5
  85. data/spec/shared_examples/user_brute_force_protection_shared_examples.rb +127 -9
  86. data/spec/shared_examples/user_oauth_shared_examples.rb +3 -6
  87. data/spec/shared_examples/user_remember_me_shared_examples.rb +6 -3
  88. data/spec/shared_examples/user_reset_password_shared_examples.rb +10 -10
  89. data/spec/shared_examples/user_shared_examples.rb +146 -46
  90. data/spec/spec_helper.rb +7 -22
  91. metadata +36 -57
  92. data/Gemfile.rails4 +0 -22
  93. data/VERSION +0 -1
  94. data/lib/sorcery/model/adapters/active_record.rb +0 -54
  95. data/lib/sorcery/model/adapters/datamapper.rb +0 -123
  96. data/lib/sorcery/model/adapters/mongo_mapper.rb +0 -60
  97. data/lib/sorcery/model/adapters/mongoid.rb +0 -88
  98. data/lib/sorcery/test_helpers/rails.rb +0 -7
  99. data/spec/active_record/controller_activity_logging_spec.rb +0 -29
  100. data/spec/active_record/controller_brute_force_protection_spec.rb +0 -158
  101. data/spec/active_record/controller_spec.rb +0 -8
  102. data/spec/active_record/integration_spec.rb +0 -23
  103. data/spec/datamapper/controller_activity_logging_spec.rb +0 -17
  104. data/spec/datamapper/controller_spec.rb +0 -8
  105. data/spec/datamapper/user_activity_logging_spec.rb +0 -9
  106. data/spec/mongo_mapper/controller_spec.rb +0 -8
  107. data/spec/mongoid/controller_activity_logging_spec.rb +0 -16
  108. data/spec/mongoid/controller_spec.rb +0 -8
  109. data/spec/rails_app/public/404.html +0 -26
  110. data/spec/rails_app/public/422.html +0 -26
  111. data/spec/rails_app/public/500.html +0 -26
  112. data/spec/rails_app/public/favicon.ico +0 -0
  113. data/spec/rails_app/public/images/rails.png +0 -0
  114. data/spec/rails_app/public/javascripts/application.js +0 -2
  115. data/spec/rails_app/public/javascripts/controls.js +0 -965
  116. data/spec/rails_app/public/javascripts/dragdrop.js +0 -974
  117. data/spec/rails_app/public/javascripts/effects.js +0 -1123
  118. data/spec/rails_app/public/javascripts/prototype.js +0 -6001
  119. data/spec/rails_app/public/javascripts/rails.js +0 -175
  120. data/spec/rails_app/public/robots.txt +0 -5
  121. data/spec/rails_app/public/stylesheets/.gitkeep +0 -0
  122. data/spec/shared_examples/controller_activity_logging_shared_examples.rb +0 -125
  123. data/spec/shared_examples/controller_oauth2_shared_examples.rb +0 -52
  124. data/spec/shared_examples/controller_oauth_shared_examples.rb +0 -62
  125. /data/spec/rails_app/app/{datamapper → data_mapper}/authentication.rb +0 -0
  126. /data/spec/rails_app/app/{datamapper → data_mapper}/user.rb +0 -0
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  require 'rails_app/app/mailers/sorcery_mailer'
4
4
  require 'shared_examples/user_shared_examples'
5
5
 
6
- describe User, "with no submodules (core)", :datamapper => true do
6
+ describe User, "with no submodules (core)", :data_mapper => true do
7
7
  before(:all) do
8
8
  sorcery_reload!
9
9
  end
@@ -35,4 +35,17 @@ describe User, "with no submodules (core)", :mongoid => true do
35
35
  end
36
36
  end
37
37
 
38
+ describe "increment" do
39
+ it "increments attribute" do
40
+ User.class_eval do
41
+ field :some_number, type: Integer
42
+ end
43
+
44
+ user = User.new(some_number: 3)
45
+ user.sorcery_adapter.increment(:some_number)
46
+
47
+ expect(user.some_number).to eql 4
48
+ end
49
+ end
50
+
38
51
  end
@@ -7,3 +7,15 @@ ActiveRecord::Migration.verbose = false
7
7
  class TestUser < ActiveRecord::Base
8
8
  authenticates_with_sorcery!
9
9
  end
10
+
11
+ def setup_orm
12
+ ActiveRecord::Migrator.migrate(migrations_path)
13
+ end
14
+
15
+ def teardown_orm
16
+ ActiveRecord::Migrator.rollback(migrations_path)
17
+ end
18
+
19
+ def migrations_path
20
+ Rails.root.join("db", "migrate", "core")
21
+ end
@@ -30,5 +30,19 @@ class TestUser
30
30
  property :id, Serial
31
31
  authenticates_with_sorcery!
32
32
  end
33
- TestUser.finalize
34
- DataMapper.auto_migrate!
33
+
34
+ def setup_orm
35
+ TestUser.finalize
36
+ DataMapper.auto_migrate!
37
+ end
38
+
39
+ module Sorcery
40
+ module TestHelpers
41
+ module Internal
42
+ def update_model(&block)
43
+ User.class_exec(&block)
44
+ User.finalize
45
+ end
46
+ end
47
+ end
48
+ end
@@ -8,4 +8,3 @@ class TestUser
8
8
  include MongoMapper::Document
9
9
  authenticates_with_sorcery!
10
10
  end
11
-
data/spec/orm/mongoid.rb CHANGED
@@ -16,3 +16,7 @@ end
16
16
  class TestUser
17
17
  include Mongoid::Document
18
18
  end
19
+
20
+ def setup_orm
21
+ Mongoid.purge!
22
+ end
@@ -98,6 +98,18 @@ class SorceryController < ActionController::Base
98
98
  login_at(:liveid)
99
99
  end
100
100
 
101
+ def login_at_test_jira
102
+ login_at(:jira)
103
+ end
104
+
105
+ def login_at_test_vk
106
+ login_at(:vk)
107
+ end
108
+
109
+ def login_at_test_salesforce
110
+ login_at(:salesforce)
111
+ end
112
+
101
113
  def login_at_test_with_state
102
114
  login_at(:facebook, {state: 'bla'})
103
115
  end
@@ -144,6 +156,30 @@ class SorceryController < ActionController::Base
144
156
  end
145
157
  end
146
158
 
159
+ def test_login_from_vk
160
+ if @user = login_from(:vk)
161
+ redirect_to 'bla', notice: 'Success!'
162
+ else
163
+ redirect_to 'blu', alert: 'Failed!'
164
+ end
165
+ end
166
+
167
+ def test_login_from_jira
168
+ if @user = login_from(:jira)
169
+ redirect_to 'bla', notice: 'Success!'
170
+ else
171
+ redirect_to 'blu', alert: 'Failed!'
172
+ end
173
+ end
174
+
175
+ def test_login_from_salesforce
176
+ if @user = login_from(:salesforce)
177
+ redirect_to 'bla', notice: 'Success!'
178
+ else
179
+ redirect_to 'blu', alert: 'Failed!'
180
+ end
181
+ end
182
+
147
183
  def test_return_to_with_external_twitter
148
184
  if @user = login_from(:twitter)
149
185
  redirect_back_or_to 'bla', notice: 'Success!'
@@ -152,6 +188,14 @@ class SorceryController < ActionController::Base
152
188
  end
153
189
  end
154
190
 
191
+ def test_return_to_with_external_jira
192
+ if @user = login_from(:jira)
193
+ redirect_back_or_to 'bla', notice: 'Success!'
194
+ else
195
+ redirect_to 'blu', alert: 'Failed!'
196
+ end
197
+ end
198
+
155
199
  alias :test_return_to_with_external :test_return_to_with_external_twitter
156
200
 
157
201
  def test_return_to_with_external_facebook
@@ -186,6 +230,22 @@ class SorceryController < ActionController::Base
186
230
  end
187
231
  end
188
232
 
233
+ def test_return_to_with_external_vk
234
+ if @user = login_from(:vk)
235
+ redirect_back_or_to 'bla', notice: 'Success!'
236
+ else
237
+ redirect_to 'blu', alert: 'Failed!'
238
+ end
239
+ end
240
+
241
+ def test_return_to_with_external_salesforce
242
+ if @user = login_from(:salesforce)
243
+ redirect_back_or_to 'bla', notice: 'Success!'
244
+ else
245
+ redirect_to 'blu', alert: 'Failed!'
246
+ end
247
+ end
248
+
189
249
  def test_create_from_provider
190
250
  provider = params[:provider]
191
251
  login_from(provider)
@@ -212,7 +272,8 @@ class SorceryController < ActionController::Base
212
272
  login_from(provider)
213
273
  @user = create_from(provider) do |user|
214
274
  # check uniqueness of email
215
- User.where(email: user.email).empty?
275
+ # User.where(email: user.email).empty?
276
+ false
216
277
  end
217
278
  if @user
218
279
  redirect_to 'bla', notice: 'Success!'
@@ -1,5 +1,7 @@
1
1
  class User
2
2
  include MongoMapper::Document
3
3
 
4
+ key :username
5
+
4
6
  many :authentications, :dependent => :destroy
5
7
  end
@@ -21,18 +21,27 @@ AppRoot::Application.routes.draw do
21
21
  get :test_login_from_github
22
22
  get :test_login_from_google
23
23
  get :test_login_from_liveid
24
+ get :test_login_from_vk
25
+ get :test_login_from_jira
26
+ get :test_login_from_salesforce
24
27
  get :login_at_test
25
28
  get :login_at_test_twitter
26
29
  get :login_at_test_facebook
27
30
  get :login_at_test_github
28
31
  get :login_at_test_google
29
32
  get :login_at_test_liveid
33
+ get :login_at_test_vk
34
+ get :login_at_test_jira
35
+ get :login_at_test_salesforce
30
36
  get :test_return_to_with_external
31
37
  get :test_return_to_with_external_twitter
32
38
  get :test_return_to_with_external_facebook
33
39
  get :test_return_to_with_external_github
34
40
  get :test_return_to_with_external_google
35
41
  get :test_return_to_with_external_liveid
42
+ get :test_return_to_with_external_vk
43
+ get :test_return_to_with_external_jira
44
+ get :test_return_to_with_external_salesforce
36
45
  get :test_http_basic_auth
37
46
  get :some_action_making_a_non_persisted_change_to_the_user
38
47
  post :test_login_with_remember
@@ -3,8 +3,8 @@ class CreateUsers < ActiveRecord::Migration
3
3
  create_table :users do |t|
4
4
  t.string :username, :null => false
5
5
  t.string :email, :default => nil
6
- t.string :crypted_password, :default => nil
7
- t.string :salt, :default => nil
6
+ t.string :crypted_password
7
+ t.string :salt
8
8
 
9
9
  t.timestamps
10
10
  end
@@ -72,11 +72,11 @@ shared_examples_for "rails_3_activation_model" do
72
72
  it "clears activation code and change state to 'active' on activation" do
73
73
  activation_token = user.activation_token
74
74
  user.activate!
75
- user2 = User.find(user.id) # go to db to make sure it was saved and not just in memory
75
+ user2 = User.sorcery_adapter.find(user.id) # go to db to make sure it was saved and not just in memory
76
76
 
77
77
  expect(user2.activation_token).to be_nil
78
78
  expect(user2.activation_state).to eq "active"
79
- expect(User.find_by_activation_token activation_token).to be_nil
79
+ expect(User.sorcery_adapter.find_by_activation_token activation_token).to be_nil
80
80
  end
81
81
 
82
82
 
@@ -91,14 +91,14 @@ shared_examples_for "rails_3_activation_model" do
91
91
  it "calls send_activation_needed_email! method of user" do
92
92
  expect(new_user).to receive(:send_activation_needed_email!).once
93
93
 
94
- new_user.sorcery_save(:raise_on_failure => true)
94
+ new_user.sorcery_adapter.save(:raise_on_failure => true)
95
95
  end
96
96
 
97
97
  it "subsequent saves do not send activation email" do
98
98
  user
99
99
  old_size = ActionMailer::Base.deliveries.size
100
100
  user.email = "Shauli"
101
- user.sorcery_save(:raise_on_failure => true)
101
+ user.sorcery_adapter.save(:raise_on_failure => true)
102
102
 
103
103
  expect(ActionMailer::Base.deliveries.size).to eq old_size
104
104
  end
@@ -121,7 +121,7 @@ shared_examples_for "rails_3_activation_model" do
121
121
  user.activate!
122
122
  old_size = ActionMailer::Base.deliveries.size
123
123
  user.email = "Shauli"
124
- user.sorcery_save(:raise_on_failure => true)
124
+ user.sorcery_adapter.save(:raise_on_failure => true)
125
125
 
126
126
  expect(ActionMailer::Base.deliveries.size).to eq old_size
127
127
  end
@@ -158,7 +158,7 @@ shared_examples_for "rails_3_activation_model" do
158
158
 
159
159
  expect(user).to receive(:send_activation_needed_email!).never
160
160
 
161
- user.sorcery_save(:raise_on_failure => true)
161
+ user.sorcery_adapter.save(:raise_on_failure => true)
162
162
  end
163
163
 
164
164
  it "does not send the user an activation success email on successful activation" do
@@ -182,7 +182,7 @@ shared_examples_for "rails_3_activation_model" do
182
182
  end
183
183
 
184
184
  before(:each) do
185
- User.delete_all
185
+ User.sorcery_adapter.delete_all
186
186
  end
187
187
 
188
188
  it "does not allow a non-active user to authenticate" do
@@ -3,22 +3,22 @@ shared_examples_for "rails_3_activity_logging_model" do
3
3
  before(:all) do
4
4
  sorcery_reload!([:activity_logging])
5
5
  end
6
-
6
+
7
7
  after(:each) do
8
8
  User.sorcery_config.reset!
9
9
  end
10
-
10
+
11
11
  it "allows configuration option 'last_login_at_attribute_name'" do
12
12
  sorcery_model_property_set(:last_login_at_attribute_name, :login_time)
13
13
 
14
14
  expect(User.sorcery_config.last_login_at_attribute_name).to eq :login_time
15
15
  end
16
-
16
+
17
17
  it "allows configuration option 'last_logout_at_attribute_name'" do
18
18
  sorcery_model_property_set(:last_logout_at_attribute_name, :logout_time)
19
19
  expect(User.sorcery_config.last_logout_at_attribute_name).to eq :logout_time
20
20
  end
21
-
21
+
22
22
  it "allows configuration option 'last_activity_at_attribute_name'" do
23
23
  sorcery_model_property_set(:last_activity_at_attribute_name, :activity_time)
24
24
  expect(User.sorcery_config.last_activity_at_attribute_name).to eq :activity_time
@@ -28,5 +28,73 @@ shared_examples_for "rails_3_activity_logging_model" do
28
28
  sorcery_model_property_set(:last_login_from_ip_address_name, :ip_address)
29
29
  expect(User.sorcery_config.last_login_from_ip_address_name).to eq :ip_address
30
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
+ skip('unavailable in MongoMapper') if SORCERY_ORM == :mongo_mapper
37
+ expect(User.current_users).to be_empty
38
+ end
39
+
40
+ it "holds the user object when 1 user is logged in" do
41
+ skip('unavailable in MongoMapper') if SORCERY_ORM == :mongo_mapper
42
+ user.set_last_activity_at(Time.now.in_time_zone)
43
+
44
+ expect(User.current_users).to match([User.sorcery_adapter.find(user.id)])
45
+ end
46
+
47
+ it "'current_users' shows all current_users, whether they have logged out before or not." do
48
+ skip('unavailable in MongoMapper') if SORCERY_ORM == :mongo_mapper
49
+ User.sorcery_adapter.delete_all
50
+ user1 = create_new_user({:username => 'gizmo1', :email => "bla1@bla.com", :password => 'secret1'})
51
+ user2 = create_new_user({:username => 'gizmo2', :email => "bla2@bla.com", :password => 'secret2'})
52
+ user3 = create_new_user({:username => 'gizmo3', :email => "bla3@bla.com", :password => 'secret3'})
53
+
54
+ now = Time.now.in_time_zone
55
+ [user1, user2, user3].each do |user|
56
+ user.set_last_login_at(now)
57
+ user.set_last_activity_at(now)
58
+ end
59
+
60
+ expect(User.current_users.map(&:id)).to match_array([user1, user2, user3].map(&:id))
61
+ Timecop.travel now + 5
62
+ user1.set_last_logout_at(Time.now.in_time_zone)
63
+ expect(User.current_users.map(&:id)).to match_array([user2, user3].map(&:id))
64
+ Timecop.return
65
+ end
66
+
67
+ end
68
+
69
+ it '.set_last_login_at update last_login_at' do
70
+ user = create_new_user
71
+ now = Time.now.in_time_zone
72
+ expect(user.sorcery_adapter).to receive(:update_attribute).with(:last_login_at, now)
73
+
74
+ user.set_last_login_at(now)
75
+ end
76
+
77
+ it '.set_last_logout_at update last_logout_at' do
78
+ user = create_new_user
79
+ now = Time.now.in_time_zone
80
+ expect(user.sorcery_adapter).to receive(:update_attribute).with(:last_logout_at, now)
81
+
82
+ user.set_last_logout_at(now)
83
+ end
84
+
85
+ it '.set_last_activity_at update last_activity_at' do
86
+ user = create_new_user
87
+ now = Time.now.in_time_zone
88
+ expect(user.sorcery_adapter).to receive(:update_attribute).with(:last_activity_at, now)
89
+
90
+ user.set_last_activity_at(now)
91
+ end
92
+
93
+ it '.set_last_ip_addess update last_login_from_ip_address' do
94
+ user = create_new_user
95
+ expect(user.sorcery_adapter).to receive(:update_attribute).with(:last_login_from_ip_address, '0.0.0.0')
96
+
97
+ user.set_last_ip_addess('0.0.0.0')
98
+ end
31
99
  end
32
- end
100
+ end
@@ -1,38 +1,156 @@
1
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
+
2
8
  context "loaded plugin configuration" do
3
9
 
4
10
  let(:config) { User.sorcery_config }
5
- let(:user) { create_new_user }
6
-
11
+
7
12
  before(:all) do
8
13
  sorcery_reload!([:brute_force_protection])
9
14
  end
10
-
15
+
11
16
  after(:each) do
12
17
  User.sorcery_config.reset!
13
18
  end
14
-
19
+
15
20
  specify { expect(user).to respond_to(:failed_logins_count) }
16
21
  specify { expect(user).to respond_to(:lock_expires_at) }
17
-
22
+
18
23
  it "enables configuration option 'failed_logins_count_attribute_name'" do
19
24
  sorcery_model_property_set(:failed_logins_count_attribute_name, :my_count)
20
25
  expect(config.failed_logins_count_attribute_name).to eq :my_count
21
26
  end
22
-
27
+
23
28
  it "enables configuration option 'lock_expires_at_attribute_name'" do
24
29
  sorcery_model_property_set(:lock_expires_at_attribute_name, :expires)
25
30
  expect(config.lock_expires_at_attribute_name).to eq :expires
26
31
  end
27
-
32
+
28
33
  it "enables configuration option 'consecutive_login_retries_amount_allowed'" do
29
34
  sorcery_model_property_set(:consecutive_login_retries_amount_limit, 34)
30
35
  expect(config.consecutive_login_retries_amount_limit).to eq 34
31
36
  end
32
-
37
+
33
38
  it "enables configuration option 'login_lock_time_period'" do
34
39
  sorcery_model_property_set(:login_lock_time_period, 2.hours)
35
40
  expect(config.login_lock_time_period).to eq 2.hours
36
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
37
155
  end
38
- end
156
+ end
@@ -6,12 +6,9 @@ shared_examples_for "rails_3_oauth_model" do
6
6
  describe "loaded plugin configuration" do
7
7
 
8
8
  before(:all) do
9
- if defined?(DataMapper) && User.ancestors.include?(DataMapper::Resource)
10
- Authentication.all.destroy
11
- else
12
- Authentication.delete_all
13
- end
14
- User.delete_all
9
+ Authentication.sorcery_adapter.delete_all
10
+ User.sorcery_adapter.delete_all
11
+
15
12
  sorcery_reload!([:external])
16
13
  sorcery_controller_property_set(:external_providers, [:twitter])
17
14
  sorcery_model_property_set(:authentications_class, Authentication)
@@ -35,12 +35,15 @@ shared_examples_for "rails_3_remember_me_model" do
35
35
  expect(user.remember_me_token).not_to be_nil
36
36
  end
37
37
 
38
- # FIXME: assert on line 37 sometimes fails by a second
39
38
  it "sets an expiration based on 'remember_me_for' attribute" do
40
39
  sorcery_model_property_set(:remember_me_for, 2 * 60 * 60 * 24)
41
- user.remember_me!
42
40
 
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
41
+ ts = Time.now.in_time_zone
42
+ Timecop.freeze(ts) do
43
+ user.remember_me!
44
+ end
45
+
46
+ expect(user.remember_me_token_expires_at.utc.to_s).to eq (ts + 2 * 60 * 60 * 24).utc.to_s
44
47
  end
45
48
 
46
49
  it "deletes the token and expiration on 'forget_me!'" do
@@ -82,7 +82,7 @@ shared_examples_for "rails_3_reset_password_model" do
82
82
  end
83
83
 
84
84
  before(:each) do
85
- User.delete_all
85
+ User.sorcery_adapter.delete_all
86
86
  user
87
87
  end
88
88
 
@@ -91,29 +91,29 @@ shared_examples_for "rails_3_reset_password_model" do
91
91
  end
92
92
 
93
93
  it "load_from_reset_password_token returns user when token is found" do
94
- user.deliver_reset_password_instructions!
95
- updated_user = defined?(DataMapper) && user.class.ancestors.include?(DataMapper::Resource) ? User.find(user.id) : user
94
+ user.generate_reset_password_token!
95
+ updated_user = User.sorcery_adapter.find(user.id)
96
96
 
97
97
  expect(User.load_from_reset_password_token user.reset_password_token).to eq updated_user
98
98
  end
99
99
 
100
100
  it "load_from_reset_password_token does NOT return user when token is NOT found" do
101
- user.deliver_reset_password_instructions!
101
+ user.generate_reset_password_token!
102
102
 
103
103
  expect(User.load_from_reset_password_token "a").to be_nil
104
104
  end
105
105
 
106
106
  it "load_from_reset_password_token returns user when token is found and not expired" do
107
107
  sorcery_model_property_set(:reset_password_expiration_period, 500)
108
- user.deliver_reset_password_instructions!
109
- updated_user = defined?(DataMapper) && user.class.ancestors.include?(DataMapper::Resource) ? User.find(user.id) : user
108
+ user.generate_reset_password_token!
109
+ updated_user = User.sorcery_adapter.find(user.id)
110
110
 
111
111
  expect(User.load_from_reset_password_token user.reset_password_token).to eq updated_user
112
112
  end
113
113
 
114
114
  it "load_from_reset_password_token does NOT return user when token is found and expired" do
115
115
  sorcery_model_property_set(:reset_password_expiration_period, 0.1)
116
- user.deliver_reset_password_instructions!
116
+ user.generate_reset_password_token!
117
117
  Timecop.travel(Time.now.in_time_zone+0.5)
118
118
 
119
119
  expect(User.load_from_reset_password_token user.reset_password_token).to be_nil
@@ -121,8 +121,8 @@ shared_examples_for "rails_3_reset_password_model" do
121
121
 
122
122
  it "load_from_reset_password_token is always valid if expiration period is nil" do
123
123
  sorcery_model_property_set(:reset_password_expiration_period, nil)
124
- user.deliver_reset_password_instructions!
125
- updated_user = defined?(DataMapper) && user.class.ancestors.include?(DataMapper::Resource) ? User.find(user.id) : user
124
+ user.generate_reset_password_token!
125
+ updated_user = User.sorcery_adapter.find(user.id)
126
126
 
127
127
  expect(User.load_from_reset_password_token user.reset_password_token).to eq updated_user
128
128
  end
@@ -156,7 +156,7 @@ shared_examples_for "rails_3_reset_password_model" do
156
156
 
157
157
  expect(ActionMailer::Base.deliveries.size).to eq old_size + 1
158
158
  end
159
-
159
+
160
160
  it "calls send_reset_password_email! on reset" do
161
161
  expect(user).to receive(:send_reset_password_email!).once
162
162