sorcery 0.13.0 → 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of sorcery might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.travis.yml +0 -26
- data/CHANGELOG.md +13 -0
- data/Gemfile +1 -1
- data/README.md +2 -1
- data/lib/generators/sorcery/templates/initializer.rb +85 -85
- data/lib/generators/sorcery/templates/migration/activity_logging.rb +4 -4
- data/lib/generators/sorcery/templates/migration/brute_force_protection.rb +3 -3
- data/lib/generators/sorcery/templates/migration/core.rb +2 -2
- data/lib/generators/sorcery/templates/migration/external.rb +3 -3
- data/lib/generators/sorcery/templates/migration/magic_login.rb +3 -3
- data/lib/generators/sorcery/templates/migration/remember_me.rb +2 -2
- data/lib/generators/sorcery/templates/migration/reset_password.rb +4 -4
- data/lib/generators/sorcery/templates/migration/user_activation.rb +3 -3
- data/lib/sorcery/controller/submodules/activity_logging.rb +10 -3
- data/lib/sorcery/controller/submodules/brute_force_protection.rb +7 -3
- data/lib/sorcery/controller/submodules/external.rb +1 -0
- data/lib/sorcery/controller/submodules/http_basic_auth.rb +4 -1
- data/lib/sorcery/controller/submodules/remember_me.rb +7 -2
- data/lib/sorcery/controller/submodules/session_timeout.rb +7 -2
- data/lib/sorcery/crypto_providers/aes256.rb +1 -1
- data/lib/sorcery/crypto_providers/bcrypt.rb +6 -1
- data/lib/sorcery/model.rb +1 -0
- data/lib/sorcery/model/config.rb +5 -0
- data/lib/sorcery/model/submodules/magic_login.rb +7 -4
- data/lib/sorcery/model/submodules/reset_password.rb +6 -2
- data/lib/sorcery/providers/line.rb +47 -0
- data/lib/sorcery/providers/linkedin.rb +20 -36
- data/lib/sorcery/version.rb +1 -1
- data/spec/controllers/controller_oauth2_spec.rb +8 -0
- data/spec/rails_app/app/controllers/sorcery_controller.rb +20 -0
- data/spec/rails_app/config/routes.rb +3 -0
- data/spec/shared_examples/user_reset_password_shared_examples.rb +18 -2
- data/spec/shared_examples/user_shared_examples.rb +63 -0
- data/spec/sorcery_crypto_providers_spec.rb +60 -0
- metadata +3 -5
- data/gemfiles/active_record_rails_40.gemfile +0 -6
- data/gemfiles/active_record_rails_41.gemfile +0 -6
- data/gemfiles/active_record_rails_42.gemfile +0 -6
@@ -216,6 +216,7 @@ describe SorceryController, active_record: true, type: :controller do
|
|
216
216
|
microsoft
|
217
217
|
instagram
|
218
218
|
auth0
|
219
|
+
line
|
219
220
|
]
|
220
221
|
)
|
221
222
|
|
@@ -257,6 +258,9 @@ describe SorceryController, active_record: true, type: :controller do
|
|
257
258
|
sorcery_controller_external_property_set(:auth0, :secret, 'XpbeSdCoaKSmQGSeokz5qcUATClRW5u08QWNfv71N8')
|
258
259
|
sorcery_controller_external_property_set(:auth0, :callback_url, 'http://blabla.com')
|
259
260
|
sorcery_controller_external_property_set(:auth0, :site, 'https://sorcery-test.auth0.com')
|
261
|
+
sorcery_controller_external_property_set(:line, :key, "eYVNBjBDi33aa9GkA3w")
|
262
|
+
sorcery_controller_external_property_set(:line, :secret, "XpbeSdCoaKSmQGSeokz5qcUATClRW5u08QWNfv71N8")
|
263
|
+
sorcery_controller_external_property_set(:line, :callback_url, "http://blabla.com")
|
260
264
|
end
|
261
265
|
|
262
266
|
after(:each) do
|
@@ -474,6 +478,7 @@ describe SorceryController, active_record: true, type: :controller do
|
|
474
478
|
microsoft
|
475
479
|
instagram
|
476
480
|
auth0
|
481
|
+
line
|
477
482
|
]
|
478
483
|
)
|
479
484
|
sorcery_controller_external_property_set(:facebook, :key, 'eYVNBjBDi33aa9GkA3w')
|
@@ -513,6 +518,9 @@ describe SorceryController, active_record: true, type: :controller do
|
|
513
518
|
sorcery_controller_external_property_set(:auth0, :secret, 'XpbeSdCoaKSmQGSeokz5qcUATClRW5u08QWNfv71N8')
|
514
519
|
sorcery_controller_external_property_set(:auth0, :callback_url, 'http://blabla.com')
|
515
520
|
sorcery_controller_external_property_set(:auth0, :site, 'https://sorcery-test.auth0.com')
|
521
|
+
sorcery_controller_external_property_set(:line, :key, "eYVNBjBDi33aa9GkA3w")
|
522
|
+
sorcery_controller_external_property_set(:line, :secret, "XpbeSdCoaKSmQGSeokz5qcUATClRW5u08QWNfv71N8")
|
523
|
+
sorcery_controller_external_property_set(:line, :callback_url, "http://blabla.com")
|
516
524
|
end
|
517
525
|
|
518
526
|
def provider_url(provider)
|
@@ -142,6 +142,10 @@ class SorceryController < ActionController::Base
|
|
142
142
|
login_at(:slack)
|
143
143
|
end
|
144
144
|
|
145
|
+
def login_at_test_line
|
146
|
+
login_at(:line)
|
147
|
+
end
|
148
|
+
|
145
149
|
def login_at_test_with_state
|
146
150
|
login_at(:facebook, state: 'bla')
|
147
151
|
end
|
@@ -268,6 +272,14 @@ class SorceryController < ActionController::Base
|
|
268
272
|
end
|
269
273
|
end
|
270
274
|
|
275
|
+
def test_login_from_line
|
276
|
+
if @user = login_from(:line)
|
277
|
+
redirect_to 'bla', notice: 'Success!'
|
278
|
+
else
|
279
|
+
redirect_to 'blu', alert: 'Failed!'
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
271
283
|
def test_return_to_with_external_twitter
|
272
284
|
if (@user = login_from(:twitter))
|
273
285
|
redirect_back_or_to 'bla', notice: 'Success!'
|
@@ -382,6 +394,14 @@ class SorceryController < ActionController::Base
|
|
382
394
|
end
|
383
395
|
end
|
384
396
|
|
397
|
+
def test_return_to_with_external_line
|
398
|
+
if @user = login_from(:line)
|
399
|
+
redirect_back_or_to 'bla', notice: 'Success!'
|
400
|
+
else
|
401
|
+
redirect_to 'blu', alert: 'Failed!'
|
402
|
+
end
|
403
|
+
end
|
404
|
+
|
385
405
|
def test_create_from_provider
|
386
406
|
provider = params[:provider]
|
387
407
|
login_from(provider)
|
@@ -32,6 +32,7 @@ AppRoot::Application.routes.draw do
|
|
32
32
|
get :test_login_from_slack
|
33
33
|
get :test_login_from_instagram
|
34
34
|
get :test_login_from_auth0
|
35
|
+
get :test_login_from_line
|
35
36
|
get :login_at_test
|
36
37
|
get :login_at_test_twitter
|
37
38
|
get :login_at_test_facebook
|
@@ -47,6 +48,7 @@ AppRoot::Application.routes.draw do
|
|
47
48
|
get :login_at_test_slack
|
48
49
|
get :login_at_test_instagram
|
49
50
|
get :login_at_test_auth0
|
51
|
+
get :login_at_test_line
|
50
52
|
get :test_return_to_with_external
|
51
53
|
get :test_return_to_with_external_twitter
|
52
54
|
get :test_return_to_with_external_facebook
|
@@ -62,6 +64,7 @@ AppRoot::Application.routes.draw do
|
|
62
64
|
get :test_return_to_with_external_slack
|
63
65
|
get :test_return_to_with_external_instagram
|
64
66
|
get :test_return_to_with_external_auth0
|
67
|
+
get :test_return_to_with_external_line
|
65
68
|
get :test_http_basic_auth
|
66
69
|
get :some_action_making_a_non_persisted_change_to_the_user
|
67
70
|
post :test_login_with_remember
|
@@ -14,6 +14,8 @@ shared_examples_for 'rails_3_reset_password_model' do
|
|
14
14
|
context 'API' do
|
15
15
|
specify { expect(user).to respond_to :deliver_reset_password_instructions! }
|
16
16
|
|
17
|
+
specify { expect(user).to respond_to :change_password }
|
18
|
+
|
17
19
|
specify { expect(user).to respond_to :change_password! }
|
18
20
|
|
19
21
|
it 'responds to .load_from_reset_password_token' do
|
@@ -314,13 +316,27 @@ shared_examples_for 'rails_3_reset_password_model' do
|
|
314
316
|
end
|
315
317
|
end
|
316
318
|
|
317
|
-
it 'when change_password! is called, deletes reset_password_token' do
|
319
|
+
it 'when change_password! is called, deletes reset_password_token and calls #save!' do
|
318
320
|
user.deliver_reset_password_instructions!
|
319
321
|
|
320
322
|
expect(user.reset_password_token).not_to be_nil
|
323
|
+
expect(user).to_not receive(:save)
|
324
|
+
expect(user).to receive(:save!)
|
321
325
|
|
322
326
|
user.change_password!('blabulsdf')
|
323
|
-
|
327
|
+
|
328
|
+
expect(user.reset_password_token).to be_nil
|
329
|
+
end
|
330
|
+
|
331
|
+
it 'when change_password is called, deletes reset_password_token and calls #save' do
|
332
|
+
new_password = 'blabulsdf'
|
333
|
+
|
334
|
+
user.deliver_reset_password_instructions!
|
335
|
+
expect(user.reset_password_token).not_to be_nil
|
336
|
+
expect(user).to_not receive(:save!)
|
337
|
+
expect(user).to receive(:save)
|
338
|
+
|
339
|
+
user.change_password(new_password)
|
324
340
|
|
325
341
|
expect(user.reset_password_token).to be_nil
|
326
342
|
end
|
@@ -54,6 +54,13 @@ shared_examples_for 'rails_3_core_model' do
|
|
54
54
|
expect(User.sorcery_config.custom_encryption_provider).to eq Array
|
55
55
|
end
|
56
56
|
|
57
|
+
it "enables configuration option 'pepper'" do
|
58
|
+
pepper = '*$%&%*++'
|
59
|
+
sorcery_model_property_set(:pepper, pepper)
|
60
|
+
|
61
|
+
expect(User.sorcery_config.pepper).to eq pepper
|
62
|
+
end
|
63
|
+
|
57
64
|
it "enables configuration option 'salt_join_token'" do
|
58
65
|
salt_join_token = '--%%*&-'
|
59
66
|
sorcery_model_property_set(:salt_join_token, salt_join_token)
|
@@ -459,6 +466,14 @@ shared_examples_for 'rails_3_core_model' do
|
|
459
466
|
expect(User.encrypt(@text)).to eq Sorcery::CryptoProviders::SHA512.encrypt(@text)
|
460
467
|
end
|
461
468
|
|
469
|
+
it 'if encryption algo is bcrypt it works' do
|
470
|
+
sorcery_model_property_set(:encryption_algorithm, :bcrypt)
|
471
|
+
|
472
|
+
# comparison is done using BCrypt::Password#==(raw_token), not by String#==
|
473
|
+
expect(User.encrypt(@text)).to be_an_instance_of BCrypt::Password
|
474
|
+
expect(User.encrypt(@text)).to eq @text
|
475
|
+
end
|
476
|
+
|
462
477
|
it 'salt is random for each user and saved in db' do
|
463
478
|
sorcery_model_property_set(:salt_attribute_name, :salt)
|
464
479
|
|
@@ -488,6 +503,54 @@ shared_examples_for 'rails_3_core_model' do
|
|
488
503
|
|
489
504
|
expect(user.crypted_password).to eq Sorcery::CryptoProviders::SHA512.encrypt('secret', user.salt)
|
490
505
|
end
|
506
|
+
|
507
|
+
it 'if pepper is set uses it to encrypt' do
|
508
|
+
sorcery_model_property_set(:salt_attribute_name, :salt)
|
509
|
+
sorcery_model_property_set(:pepper, '++@^$')
|
510
|
+
sorcery_model_property_set(:encryption_algorithm, :bcrypt)
|
511
|
+
|
512
|
+
# password comparison is done using BCrypt::Password#==(raw_token), not String#==
|
513
|
+
bcrypt_password = BCrypt::Password.new(user.crypted_password)
|
514
|
+
allow(::BCrypt::Password).to receive(:create) do |token, cost:|
|
515
|
+
# need to use common BCrypt's salt when genarating BCrypt::Password objects
|
516
|
+
# so that any generated password hashes can be compared each other
|
517
|
+
::BCrypt::Engine.hash_secret(token, bcrypt_password.salt)
|
518
|
+
end
|
519
|
+
|
520
|
+
expect(user.crypted_password).not_to eq Sorcery::CryptoProviders::BCrypt.encrypt('secret')
|
521
|
+
|
522
|
+
Sorcery::CryptoProviders::BCrypt.pepper = ''
|
523
|
+
|
524
|
+
expect(user.crypted_password).not_to eq Sorcery::CryptoProviders::BCrypt.encrypt('secret', user.salt)
|
525
|
+
|
526
|
+
Sorcery::CryptoProviders::BCrypt.pepper = User.sorcery_config.pepper
|
527
|
+
|
528
|
+
expect(user.crypted_password).to eq Sorcery::CryptoProviders::BCrypt.encrypt('secret', user.salt)
|
529
|
+
end
|
530
|
+
|
531
|
+
it 'if pepper is empty string (default) does not use pepper to encrypt' do
|
532
|
+
sorcery_model_property_set(:salt_attribute_name, :salt)
|
533
|
+
sorcery_model_property_set(:pepper, '')
|
534
|
+
sorcery_model_property_set(:encryption_algorithm, :bcrypt)
|
535
|
+
|
536
|
+
# password comparison is done using BCrypt::Password#==(raw_token), not String#==
|
537
|
+
bcrypt_password = BCrypt::Password.new(user.crypted_password)
|
538
|
+
allow(::BCrypt::Password).to receive(:create) do |token, cost:|
|
539
|
+
# need to use common BCrypt's salt when genarating BCrypt::Password objects
|
540
|
+
# so that any generated password hashes can be compared each other
|
541
|
+
::BCrypt::Engine.hash_secret(token, bcrypt_password.salt)
|
542
|
+
end
|
543
|
+
|
544
|
+
expect(user.crypted_password).not_to eq Sorcery::CryptoProviders::BCrypt.encrypt('secret')
|
545
|
+
|
546
|
+
Sorcery::CryptoProviders::BCrypt.pepper = 'some_pepper'
|
547
|
+
|
548
|
+
expect(user.crypted_password).not_to eq Sorcery::CryptoProviders::BCrypt.encrypt('secret', user.salt)
|
549
|
+
|
550
|
+
Sorcery::CryptoProviders::BCrypt.pepper = User.sorcery_config.pepper
|
551
|
+
|
552
|
+
expect(user.crypted_password).to eq Sorcery::CryptoProviders::BCrypt.encrypt('secret', user.salt)
|
553
|
+
end
|
491
554
|
end
|
492
555
|
|
493
556
|
describe 'ORM adapter' do
|
@@ -148,6 +148,7 @@ describe 'Crypto Providers wrappers' do
|
|
148
148
|
before(:all) do
|
149
149
|
Sorcery::CryptoProviders::BCrypt.cost = 1
|
150
150
|
@digest = BCrypt::Password.create('Noam Ben-Ari', cost: Sorcery::CryptoProviders::BCrypt.cost)
|
151
|
+
@tokens = %w[password gq18WBnJYNh2arkC1kgH]
|
151
152
|
end
|
152
153
|
|
153
154
|
after(:each) do
|
@@ -181,5 +182,64 @@ describe 'Crypto Providers wrappers' do
|
|
181
182
|
# stubbed in Sorcery::TestHelpers::Internal
|
182
183
|
expect(Sorcery::CryptoProviders::BCrypt.cost).to eq 1
|
183
184
|
end
|
185
|
+
|
186
|
+
it 'matches token encrypted with salt from upstream' do
|
187
|
+
# note: actual comparison is done by BCrypt::Password#==(raw_token)
|
188
|
+
expect(Sorcery::CryptoProviders::BCrypt.encrypt(@tokens)).to eq @tokens.flatten.join
|
189
|
+
end
|
190
|
+
|
191
|
+
it 'respond_to?(:pepper) returns true' do
|
192
|
+
expect(Sorcery::CryptoProviders::BCrypt.respond_to?(:pepper)).to be true
|
193
|
+
end
|
194
|
+
|
195
|
+
context 'when pepper is provided' do
|
196
|
+
before(:each) do
|
197
|
+
Sorcery::CryptoProviders::BCrypt.pepper = 'pepper'
|
198
|
+
@digest = Sorcery::CryptoProviders::BCrypt.encrypt(@tokens) # a BCrypt::Password object
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'matches token encrypted with salt and pepper from upstream' do
|
202
|
+
# note: actual comparison is done by BCrypt::Password#==(raw_token)
|
203
|
+
expect(@digest).to eq @tokens.flatten.join.concat('pepper')
|
204
|
+
end
|
205
|
+
|
206
|
+
it 'matches? returns true when matches' do
|
207
|
+
expect(Sorcery::CryptoProviders::BCrypt.matches?(@digest, *@tokens)).to be true
|
208
|
+
end
|
209
|
+
|
210
|
+
it 'matches? returns false when pepper is replaced with empty string' do
|
211
|
+
Sorcery::CryptoProviders::BCrypt.pepper = ''
|
212
|
+
expect(Sorcery::CryptoProviders::BCrypt.matches?(@digest, *@tokens)).to be false
|
213
|
+
end
|
214
|
+
|
215
|
+
it 'matches? returns false when no match' do
|
216
|
+
expect(Sorcery::CryptoProviders::BCrypt.matches?(@digest, 'a_random_incorrect_password')).to be false
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
context "when pepper is an empty string (default)" do
|
221
|
+
before(:each) do
|
222
|
+
Sorcery::CryptoProviders::BCrypt.pepper = ''
|
223
|
+
@digest = Sorcery::CryptoProviders::BCrypt.encrypt(@tokens) # a BCrypt::Password object
|
224
|
+
end
|
225
|
+
|
226
|
+
# make sure the default pepper '' does nothing
|
227
|
+
it 'matches token encrypted with salt only (without pepper)' do
|
228
|
+
expect(@digest).to eq @tokens.flatten.join # keep consistency with the older versions of #join_token
|
229
|
+
end
|
230
|
+
|
231
|
+
it 'matches? returns true when matches' do
|
232
|
+
expect(Sorcery::CryptoProviders::BCrypt.matches?(@digest, *@tokens)).to be true
|
233
|
+
end
|
234
|
+
|
235
|
+
it 'matches? returns false when pepper has changed' do
|
236
|
+
Sorcery::CryptoProviders::BCrypt.pepper = 'a new pepper'
|
237
|
+
expect(Sorcery::CryptoProviders::BCrypt.matches?(@digest, *@tokens)).to be false
|
238
|
+
end
|
239
|
+
|
240
|
+
it 'matches? returns false when no match' do
|
241
|
+
expect(Sorcery::CryptoProviders::BCrypt.matches?(@digest, 'a_random_incorrect_password')).to be false
|
242
|
+
end
|
243
|
+
end
|
184
244
|
end
|
185
245
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sorcery
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.14.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Noam Ben Ari
|
@@ -12,7 +12,7 @@ authors:
|
|
12
12
|
autorequire:
|
13
13
|
bindir: bin
|
14
14
|
cert_chain: []
|
15
|
-
date:
|
15
|
+
date: 2019-05-23 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: bcrypt
|
@@ -207,9 +207,6 @@ files:
|
|
207
207
|
- LICENSE.md
|
208
208
|
- README.md
|
209
209
|
- Rakefile
|
210
|
-
- gemfiles/active_record_rails_40.gemfile
|
211
|
-
- gemfiles/active_record_rails_41.gemfile
|
212
|
-
- gemfiles/active_record_rails_42.gemfile
|
213
210
|
- lib/generators/sorcery/USAGE
|
214
211
|
- lib/generators/sorcery/helpers.rb
|
215
212
|
- lib/generators/sorcery/install_generator.rb
|
@@ -263,6 +260,7 @@ files:
|
|
263
260
|
- lib/sorcery/providers/heroku.rb
|
264
261
|
- lib/sorcery/providers/instagram.rb
|
265
262
|
- lib/sorcery/providers/jira.rb
|
263
|
+
- lib/sorcery/providers/line.rb
|
266
264
|
- lib/sorcery/providers/linkedin.rb
|
267
265
|
- lib/sorcery/providers/liveid.rb
|
268
266
|
- lib/sorcery/providers/microsoft.rb
|