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.
- checksums.yaml +4 -4
- data/.gitignore +2 -1
- data/.travis.yml +75 -14
- data/CHANGELOG.md +32 -1
- data/Gemfile +1 -0
- data/README.md +138 -86
- data/gemfiles/active_record-rails40.gemfile +7 -0
- data/gemfiles/active_record-rails41.gemfile +3 -2
- data/gemfiles/mongo_mapper-rails40.gemfile +9 -0
- data/gemfiles/mongo_mapper-rails41.gemfile +2 -1
- data/gemfiles/mongoid-rails40.gemfile +9 -0
- data/gemfiles/mongoid-rails41.gemfile +3 -5
- data/gemfiles/mongoid3-rails32.gemfile +9 -0
- data/lib/generators/sorcery/USAGE +1 -1
- data/lib/generators/sorcery/install_generator.rb +19 -5
- data/lib/generators/sorcery/templates/initializer.rb +36 -10
- data/lib/generators/sorcery/templates/migration/brute_force_protection.rb +3 -1
- data/lib/generators/sorcery/templates/migration/core.rb +2 -2
- data/lib/generators/sorcery/templates/migration/external.rb +3 -1
- data/lib/sorcery/adapters/active_record_adapter.rb +120 -0
- data/lib/sorcery/adapters/base_adapter.rb +30 -0
- data/lib/sorcery/adapters/data_mapper_adapter.rb +176 -0
- data/lib/sorcery/adapters/mongo_mapper_adapter.rb +110 -0
- data/lib/sorcery/adapters/mongoid_adapter.rb +97 -0
- data/lib/sorcery/controller/config.rb +65 -0
- data/lib/sorcery/controller/submodules/activity_logging.rb +16 -21
- data/lib/sorcery/controller/submodules/brute_force_protection.rb +6 -6
- data/lib/sorcery/controller/submodules/external.rb +9 -29
- data/lib/sorcery/controller/submodules/remember_me.rb +4 -4
- data/lib/sorcery/controller/submodules/session_timeout.rb +10 -6
- data/lib/sorcery/controller.rb +5 -64
- data/lib/sorcery/model/config.rb +96 -0
- data/lib/sorcery/model/submodules/activity_logging.rb +29 -36
- data/lib/sorcery/model/submodules/brute_force_protection.rb +21 -37
- data/lib/sorcery/model/submodules/external.rb +53 -9
- data/lib/sorcery/model/submodules/remember_me.rb +12 -31
- data/lib/sorcery/model/submodules/reset_password.rb +21 -39
- data/lib/sorcery/model/submodules/user_activation.rb +21 -63
- data/lib/sorcery/model/temporary_token.rb +4 -4
- data/lib/sorcery/model.rb +47 -175
- data/lib/sorcery/providers/base.rb +11 -0
- data/lib/sorcery/providers/facebook.rb +16 -5
- data/lib/sorcery/providers/github.rb +11 -2
- data/lib/sorcery/providers/google.rb +1 -1
- data/lib/sorcery/providers/heroku.rb +57 -0
- data/lib/sorcery/providers/jira.rb +77 -0
- data/lib/sorcery/providers/linkedin.rb +1 -1
- data/lib/sorcery/providers/liveid.rb +1 -1
- data/lib/sorcery/providers/salesforce.rb +50 -0
- data/lib/sorcery/providers/twitter.rb +1 -1
- data/lib/sorcery/providers/vk.rb +6 -4
- data/lib/sorcery/providers/xing.rb +2 -2
- data/lib/sorcery/test_helpers/internal.rb +7 -3
- data/lib/sorcery/test_helpers/rails/controller.rb +5 -1
- data/lib/sorcery/version.rb +3 -0
- data/lib/sorcery.rb +75 -43
- data/sorcery.gemspec +6 -2
- data/spec/active_record/user_activity_logging_spec.rb +9 -0
- data/spec/controllers/controller_activity_logging_spec.rb +124 -0
- data/spec/controllers/controller_brute_force_protection_spec.rb +43 -0
- data/spec/{active_record → controllers}/controller_http_basic_auth_spec.rb +14 -11
- data/spec/{active_record → controllers}/controller_oauth2_spec.rb +151 -64
- data/spec/{active_record → controllers}/controller_oauth_spec.rb +94 -70
- data/spec/{active_record → controllers}/controller_remember_me_spec.rb +32 -12
- data/spec/{active_record → controllers}/controller_session_timeout_spec.rb +15 -5
- data/spec/{shared_examples/controller_shared_examples.rb → controllers/controller_spec.rb} +34 -19
- data/spec/{datamapper → data_mapper}/user_activation_spec.rb +1 -1
- data/spec/data_mapper/user_activity_logging_spec.rb +14 -0
- data/spec/{datamapper → data_mapper}/user_brute_force_protection_spec.rb +1 -1
- data/spec/{datamapper → data_mapper}/user_oauth_spec.rb +1 -1
- data/spec/{datamapper → data_mapper}/user_remember_me_spec.rb +1 -1
- data/spec/{datamapper → data_mapper}/user_reset_password_spec.rb +1 -1
- data/spec/{datamapper → data_mapper}/user_spec.rb +1 -1
- data/spec/mongoid/user_spec.rb +13 -0
- data/spec/orm/active_record.rb +12 -0
- data/spec/orm/{datamapper.rb → data_mapper.rb} +16 -2
- data/spec/orm/mongo_mapper.rb +0 -1
- data/spec/orm/mongoid.rb +4 -0
- data/spec/rails_app/app/controllers/sorcery_controller.rb +62 -1
- data/spec/rails_app/app/mongo_mapper/user.rb +2 -0
- data/spec/rails_app/config/routes.rb +9 -0
- data/spec/rails_app/db/migrate/core/20101224223620_create_users.rb +2 -2
- data/spec/shared_examples/user_activation_shared_examples.rb +7 -7
- data/spec/shared_examples/user_activity_logging_shared_examples.rb +73 -5
- data/spec/shared_examples/user_brute_force_protection_shared_examples.rb +127 -9
- data/spec/shared_examples/user_oauth_shared_examples.rb +3 -6
- data/spec/shared_examples/user_remember_me_shared_examples.rb +6 -3
- data/spec/shared_examples/user_reset_password_shared_examples.rb +10 -10
- data/spec/shared_examples/user_shared_examples.rb +146 -46
- data/spec/spec_helper.rb +7 -22
- metadata +36 -57
- data/Gemfile.rails4 +0 -22
- data/VERSION +0 -1
- data/lib/sorcery/model/adapters/active_record.rb +0 -54
- data/lib/sorcery/model/adapters/datamapper.rb +0 -123
- data/lib/sorcery/model/adapters/mongo_mapper.rb +0 -60
- data/lib/sorcery/model/adapters/mongoid.rb +0 -88
- data/lib/sorcery/test_helpers/rails.rb +0 -7
- data/spec/active_record/controller_activity_logging_spec.rb +0 -29
- data/spec/active_record/controller_brute_force_protection_spec.rb +0 -158
- data/spec/active_record/controller_spec.rb +0 -8
- data/spec/active_record/integration_spec.rb +0 -23
- data/spec/datamapper/controller_activity_logging_spec.rb +0 -17
- data/spec/datamapper/controller_spec.rb +0 -8
- data/spec/datamapper/user_activity_logging_spec.rb +0 -9
- data/spec/mongo_mapper/controller_spec.rb +0 -8
- data/spec/mongoid/controller_activity_logging_spec.rb +0 -16
- data/spec/mongoid/controller_spec.rb +0 -8
- data/spec/rails_app/public/404.html +0 -26
- data/spec/rails_app/public/422.html +0 -26
- data/spec/rails_app/public/500.html +0 -26
- data/spec/rails_app/public/favicon.ico +0 -0
- data/spec/rails_app/public/images/rails.png +0 -0
- data/spec/rails_app/public/javascripts/application.js +0 -2
- data/spec/rails_app/public/javascripts/controls.js +0 -965
- data/spec/rails_app/public/javascripts/dragdrop.js +0 -974
- data/spec/rails_app/public/javascripts/effects.js +0 -1123
- data/spec/rails_app/public/javascripts/prototype.js +0 -6001
- data/spec/rails_app/public/javascripts/rails.js +0 -175
- data/spec/rails_app/public/robots.txt +0 -5
- data/spec/rails_app/public/stylesheets/.gitkeep +0 -0
- data/spec/shared_examples/controller_activity_logging_shared_examples.rb +0 -125
- data/spec/shared_examples/controller_oauth2_shared_examples.rb +0 -52
- data/spec/shared_examples/controller_oauth_shared_examples.rb +0 -62
- /data/spec/rails_app/app/{datamapper → data_mapper}/authentication.rb +0 -0
- /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)", :
|
|
6
|
+
describe User, "with no submodules (core)", :data_mapper => true do
|
|
7
7
|
before(:all) do
|
|
8
8
|
sorcery_reload!
|
|
9
9
|
end
|
data/spec/mongoid/user_spec.rb
CHANGED
|
@@ -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
|
data/spec/orm/active_record.rb
CHANGED
|
@@ -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
|
-
|
|
34
|
-
|
|
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
|
data/spec/orm/mongo_mapper.rb
CHANGED
data/spec/orm/mongoid.rb
CHANGED
|
@@ -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!'
|
|
@@ -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
|
|
7
|
-
t.string :salt
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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
|
-
|
|
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.
|
|
95
|
-
updated_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.
|
|
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.
|
|
109
|
-
updated_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.
|
|
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.
|
|
125
|
-
updated_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
|
|