sorcery 0.10.3 → 0.11.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 834f45ceded7dd7507da33d0cafad5b379998102
4
- data.tar.gz: 194d9e21b374a802866f293df90142725a632c66
3
+ metadata.gz: bc71bccb13f8e3fcbbf0b94f660a98bc34cc4826
4
+ data.tar.gz: 9c60fb5db29c7a41378e7c45234b0b0e9df47501
5
5
  SHA512:
6
- metadata.gz: 87cc0189f538838548bb214779dadf2ee384f7d024e38db8a58ad4fbaf0ba6ea04872d745d307c47665bc2ad6016eb98cdd14eb9be64d41ce44310122e3082d0
7
- data.tar.gz: bb35b65397c6ed3f8285d5d098edb475b8f7733eef644e95b0d9c56a7bad36090f6f4e92e59c5f7d332b837fde0e93948b642ce2e767d8ab77f30b6e687d2bda
6
+ metadata.gz: c557af8ef3828be476750ba465ea4d3c7a34f5ccbf975c5c731d0841891de4f77d56fa867dfd55be9424a2eea0eed768cdfe1a104e6ed70ae643207bb2573eb1
7
+ data.tar.gz: 582ea847785099a70c4866feee1b1f891a411e4f572ff89497ac353914cffe78669102d8a7a6b76c208976894ca932f83e61e590645306e7b5a9c3ebc6868bc2
@@ -1,4 +1,11 @@
1
1
  # Changelog
2
+ ## HEAD
3
+
4
+ ## 0.11.0
5
+
6
+ * Refer to User before calling remove_const to avoid NameError [#58](https://github.com/Sorcery/sorcery/pull/58)
7
+ * Resurrect block authentication, showing auth failure reason. [#41](https://github.com/Sorcery/sorcery/pull/41)
8
+ * Add github scope option to initializer.rb [#50](https://github.com/Sorcery/sorcery/pull/50)
2
9
 
3
10
  ## 0.10.3
4
11
 
@@ -109,12 +109,14 @@ Rails.application.config.sorcery.configure do |config|
109
109
  # config.facebook.user_info_mapping = {:email => "name"}
110
110
  # config.facebook.access_permissions = ["email", "publish_actions"]
111
111
  # config.facebook.display = "page"
112
- # config.facebook.api_version = "v2.2"
112
+ # config.facebook.api_version = "v2.3"
113
+ # config.facebook.parse = :json
113
114
  #
114
115
  # config.github.key = ""
115
116
  # config.github.secret = ""
116
117
  # config.github.callback_url = "http://0.0.0.0:3000/oauth/callback?provider=github"
117
118
  # config.github.user_info_mapping = {:email => "name"}
119
+ # config.github.scope = ""
118
120
  #
119
121
  # config.paypal.key = ""
120
122
  # config.paypal.secret = ""
@@ -30,8 +30,16 @@ module Sorcery
30
30
  # Runs hooks after login or failed login.
31
31
  def login(*credentials)
32
32
  @current_user = nil
33
- user = user_class.authenticate(*credentials)
34
- if user
33
+
34
+ user_class.authenticate(*credentials) do |user, failure_reason|
35
+ if failure_reason
36
+ after_failed_login!(credentials)
37
+
38
+ yield(user, failure_reason) if block_given?
39
+
40
+ return
41
+ end
42
+
35
43
  old_session = session.dup.to_hash
36
44
  reset_sorcery_session
37
45
  old_session.each_pair do |k, v|
@@ -41,10 +49,8 @@ module Sorcery
41
49
 
42
50
  auto_login(user)
43
51
  after_login!(user, credentials)
44
- current_user
45
- else
46
- after_failed_login!(credentials)
47
- nil
52
+
53
+ block_given? ? yield(current_user, nil) : current_user
48
54
  end
49
55
  end
50
56
 
@@ -80,10 +80,12 @@ module Sorcery
80
80
  # Takes a username and password,
81
81
  # Finds the user by the username and compares the user's password to the one supplied to the method.
82
82
  # returns the user if success, nil otherwise.
83
- def authenticate(*credentials)
83
+ def authenticate(*credentials, &block)
84
84
  raise ArgumentError, 'at least 2 arguments required' if credentials.size < 2
85
85
 
86
- return false if credentials[0].blank?
86
+ if credentials[0].blank?
87
+ return authentication_response(return_value: false, failure: :invalid_login, &block)
88
+ end
87
89
 
88
90
  if @sorcery_config.downcase_username_before_authenticating
89
91
  credentials[0].downcase!
@@ -91,13 +93,29 @@ module Sorcery
91
93
 
92
94
  user = sorcery_adapter.find_by_credentials(credentials)
93
95
 
94
- if user.respond_to?(:active_for_authentication?)
95
- return nil unless user.active_for_authentication?
96
+ unless user
97
+ return authentication_response(failure: :invalid_login, &block)
96
98
  end
97
99
 
98
100
  set_encryption_attributes
99
101
 
100
- user if user && @sorcery_config.before_authenticate.all? { |c| user.send(c) } && user.valid_password?(credentials[1])
102
+ unless user.valid_password?(credentials[1])
103
+ return authentication_response(user: user, failure: :invalid_password, &block)
104
+ end
105
+
106
+ if user.respond_to?(:active_for_authentication?) && !user.active_for_authentication?
107
+ return authentication_response(user: user, failure: :inactive, &block)
108
+ end
109
+
110
+ @sorcery_config.before_authenticate.each do |callback|
111
+ success, reason = user.send(callback)
112
+
113
+ unless success
114
+ return authentication_response(user: user, failure: reason, &block)
115
+ end
116
+ end
117
+
118
+ authentication_response(user: user, return_value: user, &block)
101
119
  end
102
120
 
103
121
  # encrypt tokens using current encryption_provider.
@@ -112,6 +130,12 @@ module Sorcery
112
130
 
113
131
  protected
114
132
 
133
+ def authentication_response(options = {})
134
+ yield(options[:user], options[:failure]) if block_given?
135
+
136
+ options[:return_value]
137
+ end
138
+
115
139
  def set_encryption_attributes
116
140
  @sorcery_config.encryption_provider.stretches = @sorcery_config.stretches if @sorcery_config.encryption_provider.respond_to?(:stretches) && @sorcery_config.stretches
117
141
  @sorcery_config.encryption_provider.join_token = @sorcery_config.salt_join_token if @sorcery_config.encryption_provider.respond_to?(:join_token) && @sorcery_config.salt_join_token
@@ -41,10 +41,15 @@ module Sorcery
41
41
  end
42
42
 
43
43
  module ClassMethods
44
- def load_from_unlock_token(token)
45
- return nil if token.blank?
46
- user = sorcery_adapter.find_by_token(sorcery_config.unlock_token_attribute_name, token)
47
- user
44
+ # This doesn't check to see if the account is still locked
45
+ def load_from_unlock_token(token, &block)
46
+ return if token.blank?
47
+
48
+ load_from_token(
49
+ token,
50
+ sorcery_config.unlock_token_attribute_name,
51
+ &block
52
+ )
48
53
  end
49
54
 
50
55
  protected
@@ -116,7 +121,10 @@ module Sorcery
116
121
  if !login_unlocked? && config.login_lock_time_period != 0
117
122
  login_unlock! if send(config.lock_expires_at_attribute_name) <= Time.now.in_time_zone
118
123
  end
119
- login_unlocked?
124
+
125
+ return false, :locked unless login_unlocked?
126
+
127
+ true
120
128
  end
121
129
  end
122
130
  end
@@ -55,10 +55,13 @@ module Sorcery
55
55
  module ClassMethods
56
56
  # Find user by token, also checks for expiration.
57
57
  # Returns the user if token found and is valid.
58
- def load_from_reset_password_token(token)
59
- token_attr_name = @sorcery_config.reset_password_token_attribute_name
60
- token_expiration_date_attr = @sorcery_config.reset_password_token_expires_at_attribute_name
61
- load_from_token(token, token_attr_name, token_expiration_date_attr)
58
+ def load_from_reset_password_token(token, &block)
59
+ load_from_token(
60
+ token,
61
+ @sorcery_config.reset_password_token_attribute_name,
62
+ @sorcery_config.reset_password_token_expires_at_attribute_name,
63
+ &block
64
+ )
62
65
  end
63
66
 
64
67
  protected
@@ -59,10 +59,13 @@ module Sorcery
59
59
  module ClassMethods
60
60
  # Find user by token, also checks for expiration.
61
61
  # Returns the user if token found and is valid.
62
- def load_from_activation_token(token)
63
- token_attr_name = @sorcery_config.activation_token_attribute_name
64
- token_expiration_date_attr = @sorcery_config.activation_token_expires_at_attribute_name
65
- load_from_token(token, token_attr_name, token_expiration_date_attr)
62
+ def load_from_activation_token(token, &block)
63
+ load_from_token(
64
+ token,
65
+ @sorcery_config.activation_token_attribute_name,
66
+ @sorcery_config.activation_token_expires_at_attribute_name,
67
+ &block
68
+ )
66
69
  end
67
70
 
68
71
  protected
@@ -128,7 +131,14 @@ module Sorcery
128
131
 
129
132
  def prevent_non_active_login
130
133
  config = sorcery_config
131
- config.prevent_non_active_users_to_login ? send(config.activation_state_attribute_name) == 'active' : true
134
+
135
+ if config.prevent_non_active_users_to_login
136
+ unless send(config.activation_state_attribute_name) == 'active'
137
+ return false, :inactive
138
+ end
139
+ end
140
+
141
+ true
132
142
  end
133
143
  end
134
144
  end
@@ -16,13 +16,34 @@ module Sorcery
16
16
  end
17
17
 
18
18
  module ClassMethods
19
- def load_from_token(token, token_attr_name, token_expiration_date_attr)
20
- return nil if token.blank?
19
+ def load_from_token(token, token_attr_name, token_expiration_date_attr = nil, &block)
20
+ return token_response(failure: :invalid_token, &block) if token.blank?
21
+
21
22
  user = sorcery_adapter.find_by_token(token_attr_name, token)
22
- if !user.blank? && !user.send(token_expiration_date_attr).nil?
23
- return Time.now.in_time_zone < user.send(token_expiration_date_attr) ? user : nil
23
+
24
+ return token_response(failure: :user_not_found, &block) unless user
25
+
26
+ unless check_expiration_date(user, token_expiration_date_attr)
27
+ return token_response(user: user, failure: :token_expired, &block)
24
28
  end
25
- user
29
+
30
+ token_response(user: user, return_value: user, &block)
31
+ end
32
+
33
+ protected
34
+
35
+ def check_expiration_date(user, token_expiration_date_attr)
36
+ return true unless token_expiration_date_attr
37
+
38
+ expires_at = user.send(token_expiration_date_attr)
39
+
40
+ !expires_at || (Time.now.in_time_zone < expires_at)
41
+ end
42
+
43
+ def token_response(options = {})
44
+ yield(options[:user], options[:failure]) if block_given?
45
+
46
+ options[:return_value]
26
47
  end
27
48
  end
28
49
  end
@@ -9,9 +9,9 @@ module Sorcery
9
9
  class Facebook < Base
10
10
  include Protocols::Oauth2
11
11
 
12
- attr_reader :mode, :param_name, :parse
12
+ attr_reader :mode, :param_name
13
13
  attr_accessor :access_permissions, :display, :scope, :token_url,
14
- :user_info_path, :auth_path, :api_version
14
+ :user_info_path, :auth_path, :api_version, :parse
15
15
 
16
16
  def initialize
17
17
  super
@@ -24,7 +24,7 @@ module Sorcery
24
24
  @token_url = 'oauth/access_token'
25
25
  @auth_path = 'dialog/oauth'
26
26
  @mode = :query
27
- @parse = :query
27
+ @parse = :json
28
28
  @param_name = 'access_token'
29
29
  end
30
30
 
@@ -67,7 +67,7 @@ module Sorcery
67
67
  # reload user class between specs
68
68
  # so it will be possible to test the different submodules in isolation
69
69
  def reload_user_class
70
- Object.send(:remove_const, 'User')
70
+ User && Object.send(:remove_const, 'User')
71
71
  load 'user.rb'
72
72
  if User.respond_to?(:reset_column_information)
73
73
  User.reset_column_information
@@ -1,3 +1,3 @@
1
1
  module Sorcery
2
- VERSION = '0.10.3'
2
+ VERSION = '0.11.0'
3
3
  end
@@ -20,7 +20,7 @@ describe SorceryController, type: :controller do
20
20
  end
21
21
 
22
22
  it 'counts login retries' do
23
- allow(User).to receive(:authenticate)
23
+ allow(User).to receive(:authenticate) { |&block| block.call(nil, :other) }
24
24
  allow(User.sorcery_adapter).to receive(:find_by_credentials).with(['bla@bla.com', 'blabla']).and_return(user)
25
25
 
26
26
  expect(user).to receive(:register_failed_login!).exactly(3).times
@@ -32,7 +32,7 @@ describe SorceryController, type: :controller do
32
32
  # dirty hack for rails 4
33
33
  allow(@controller).to receive(:register_last_activity_time_to_db)
34
34
 
35
- allow(User).to receive(:authenticate).and_return(user)
35
+ allow(User).to receive(:authenticate) { |&block| block.call(user, nil) }
36
36
  expect(user).to receive_message_chain(:sorcery_adapter, :update_attribute).with(:failed_logins_count, 0)
37
37
 
38
38
  get :test_login, params: { email: 'bla@bla.com', password: 'secret' }
@@ -22,7 +22,7 @@ describe SorceryController, type: :controller do
22
22
  end
23
23
 
24
24
  it 'sets cookie on remember_me!' do
25
- expect(User).to receive(:authenticate).with('bla@bla.com', 'secret').and_return(user)
25
+ expect(User).to receive(:authenticate).with('bla@bla.com', 'secret') { |&block| block.call(user, nil) }
26
26
  expect(user).to receive(:remember_me!)
27
27
 
28
28
  post :test_login_with_remember, params: { email: 'bla@bla.com', password: 'secret' }
@@ -45,7 +45,7 @@ describe SorceryController, type: :controller do
45
45
  end
46
46
 
47
47
  it 'login(email,password,remember_me) logs user in and remembers' do
48
- expect(User).to receive(:authenticate).with('bla@bla.com', 'secret', '1').and_return(user)
48
+ expect(User).to receive(:authenticate).with('bla@bla.com', 'secret', '1') { |&block| block.call(user, nil) }
49
49
  expect(user).to receive(:remember_me!)
50
50
  expect(user).to receive(:remember_me_token).and_return('abracadabra').twice
51
51
 
@@ -39,7 +39,7 @@ describe SorceryController, type: :controller do
39
39
  it 'works if the session is stored as a string or a Time' do
40
40
  session[:login_time] = Time.now.to_s
41
41
  # TODO: ???
42
- expect(User).to receive(:authenticate).with('bla@bla.com', 'secret').and_return(user)
42
+ expect(User).to receive(:authenticate).with('bla@bla.com', 'secret') { |&block| block.call(user, nil) }
43
43
 
44
44
  get :test_login, params: { email: 'bla@bla.com', password: 'secret' }
45
45
 
@@ -50,7 +50,7 @@ describe SorceryController, type: :controller do
50
50
  context "with 'session_timeout_from_last_action'" do
51
51
  it 'does not logout if there was activity' do
52
52
  sorcery_controller_property_set(:session_timeout_from_last_action, true)
53
- expect(User).to receive(:authenticate).with('bla@bla.com', 'secret').and_return(user)
53
+ expect(User).to receive(:authenticate).with('bla@bla.com', 'secret') { |&block| block.call(user, nil) }
54
54
 
55
55
  get :test_login, params: { email: 'bla@bla.com', password: 'secret' }
56
56
  Timecop.travel(Time.now.in_time_zone + 0.3)
@@ -52,7 +52,7 @@ describe SorceryController, type: :controller do
52
52
  describe '#login' do
53
53
  context 'when succeeds' do
54
54
  before do
55
- expect(User).to receive(:authenticate).with('bla@bla.com', 'secret').and_return(user)
55
+ expect(User).to receive(:authenticate).with('bla@bla.com', 'secret') { |&block| block.call(user, nil) }
56
56
  get :test_login, params: { email: 'bla@bla.com', password: 'secret' }
57
57
  end
58
58
 
@@ -235,6 +235,27 @@ shared_examples_for 'rails_3_activation_model' do
235
235
 
236
236
  expect(User.authenticate(user.email, 'secret')).to be_truthy
237
237
  end
238
+
239
+ context 'in block mode' do
240
+ it 'does not allow a non-active user to authenticate' do
241
+ sorcery_model_property_set(:prevent_non_active_users_to_login, true)
242
+
243
+ User.authenticate(user.email, 'secret') do |user2, failure|
244
+ expect(user2).to eq user
245
+ expect(user2.activation_state).to eq 'pending'
246
+ expect(failure).to eq :inactive
247
+ end
248
+ end
249
+
250
+ it 'allows a non-active user to authenticate if configured so' do
251
+ sorcery_model_property_set(:prevent_non_active_users_to_login, false)
252
+
253
+ User.authenticate(user.email, 'secret') do |user2, failure|
254
+ expect(user2).to eq user
255
+ expect(failure).to be_nil
256
+ end
257
+ end
258
+ end
238
259
  end
239
260
 
240
261
  describe 'load_from_activation_token' do
@@ -279,5 +300,62 @@ shared_examples_for 'rails_3_activation_model' do
279
300
 
280
301
  expect(User.load_from_activation_token(user.activation_token)).to eq user
281
302
  end
303
+
304
+ describe '#load_from_activation_token' do
305
+ context 'in block mode' do
306
+ it 'yields user when token is found' do
307
+ User.load_from_activation_token(user.activation_token) do |user2, failure|
308
+ expect(user2).to eq user
309
+ expect(failure).to be_nil
310
+ end
311
+ end
312
+
313
+ it 'does NOT yield user when token is NOT found' do
314
+ User.load_from_activation_token('a') do |user2, failure|
315
+ expect(user2).to be_nil
316
+ expect(failure).to eq :user_not_found
317
+ end
318
+ end
319
+
320
+ it 'yields user when token is found and not expired' do
321
+ sorcery_model_property_set(:activation_token_expiration_period, 500)
322
+
323
+ User.load_from_activation_token(user.activation_token) do |user2, failure|
324
+ expect(user2).to eq user
325
+ expect(failure).to be_nil
326
+ end
327
+ end
328
+
329
+ it 'yields the user and failure reason when token is found and expired' do
330
+ sorcery_model_property_set(:activation_token_expiration_period, 0.1)
331
+ user
332
+
333
+ Timecop.travel(Time.now.in_time_zone + 0.5)
334
+
335
+ User.load_from_activation_token(user.activation_token) do |user2, failure|
336
+ expect(user2).to eq user
337
+ expect(failure).to eq :token_expired
338
+ end
339
+ end
340
+
341
+ it 'yields a failure reason if token is blank' do
342
+ [nil, ''].each do |token|
343
+ User.load_from_activation_token(token) do |user2, failure|
344
+ expect(user2).to be_nil
345
+ expect(failure).to eq :invalid_token
346
+ end
347
+ end
348
+ end
349
+
350
+ it 'is always valid if expiration period is nil' do
351
+ sorcery_model_property_set(:activation_token_expiration_period, nil)
352
+
353
+ User.load_from_activation_token(user.activation_token) do |user2, failure|
354
+ expect(user2).to eq user
355
+ expect(failure).to be_nil
356
+ end
357
+ end
358
+ end
359
+ end
282
360
  end
283
361
  end
@@ -128,6 +128,71 @@ shared_examples_for 'rails_3_reset_password_model' do
128
128
  expect(User.load_from_reset_password_token('')).to be_nil
129
129
  end
130
130
 
131
+ describe '#load_from_reset_password_token' do
132
+ context 'in block mode' do
133
+ it 'yields user when token is found' do
134
+ user.generate_reset_password_token!
135
+ updated_user = User.sorcery_adapter.find(user.id)
136
+
137
+ User.load_from_reset_password_token(user.reset_password_token) do |user2, failure|
138
+ expect(user2).to eq updated_user
139
+ expect(failure).to be_nil
140
+ end
141
+ end
142
+
143
+ it 'does NOT yield user when token is NOT found' do
144
+ user.generate_reset_password_token!
145
+
146
+ User.load_from_reset_password_token('a') do |user2, failure|
147
+ expect(user2).to be_nil
148
+ expect(failure).to eq :user_not_found
149
+ end
150
+ end
151
+
152
+ it 'yields user when token is found and not expired' do
153
+ sorcery_model_property_set(:reset_password_expiration_period, 500)
154
+ user.generate_reset_password_token!
155
+ updated_user = User.sorcery_adapter.find(user.id)
156
+
157
+ User.load_from_reset_password_token(user.reset_password_token) do |user2, failure|
158
+ expect(user2).to eq updated_user
159
+ expect(failure).to be_nil
160
+ end
161
+ end
162
+
163
+ it 'yields user and failure reason when token is found and expired' do
164
+ sorcery_model_property_set(:reset_password_expiration_period, 0.1)
165
+ user.generate_reset_password_token!
166
+ Timecop.travel(Time.now.in_time_zone + 0.5)
167
+
168
+ User.load_from_reset_password_token(user.reset_password_token) do |user2, failure|
169
+ expect(user2).to eq user
170
+ expect(failure).to eq :token_expired
171
+ end
172
+ end
173
+
174
+ it 'is always valid if expiration period is nil' do
175
+ sorcery_model_property_set(:reset_password_expiration_period, nil)
176
+ user.generate_reset_password_token!
177
+ updated_user = User.sorcery_adapter.find(user.id)
178
+
179
+ User.load_from_reset_password_token(user.reset_password_token) do |user2, failure|
180
+ expect(user2).to eq updated_user
181
+ expect(failure).to be_nil
182
+ end
183
+ end
184
+
185
+ it 'returns nil if token is blank' do
186
+ [nil, ''].each do |token|
187
+ User.load_from_reset_password_token(token) do |user2, failure|
188
+ expect(user2).to be_nil
189
+ expect(failure).to eq :invalid_token
190
+ end
191
+ end
192
+ end
193
+ end
194
+ end
195
+
131
196
  it "'deliver_reset_password_instructions!' generates a reset_password_token" do
132
197
  expect(user.reset_password_token).to be_nil
133
198
 
@@ -146,6 +146,31 @@ shared_examples_for 'rails_3_core_model' do
146
146
  expect(User.authenticate(user.email, 'secret')).to be_nil
147
147
  end
148
148
  end
149
+
150
+ context 'in block mode' do
151
+ it 'yields the user if credentials are good' do
152
+ User.authenticate(user.email, 'secret') do |user2, failure|
153
+ expect(user2).to eq user
154
+ expect(failure).to be_nil
155
+ end
156
+ end
157
+
158
+ it 'yields the user and proper error if credentials are bad' do
159
+ User.authenticate(user.email, 'wrong!') do |user2, failure|
160
+ expect(user2).to eq user
161
+ expect(failure).to eq :invalid_password
162
+ end
163
+ end
164
+
165
+ it 'yields the proper error if no user exists' do
166
+ [nil, '', 'not@a.user'].each do |email|
167
+ User.authenticate(email, 'wrong!') do |user2, failure|
168
+ expect(user2).to be_nil
169
+ expect(failure).to eq :invalid_login
170
+ end
171
+ end
172
+ end
173
+ end
149
174
  end
150
175
 
151
176
  specify { expect(User).to respond_to(:encrypt) }
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.10.3
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Noam Ben Ari
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2017-03-24 00:00:00.000000000 Z
14
+ date: 2017-05-16 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: oauth
@@ -327,3 +327,4 @@ signing_key:
327
327
  specification_version: 4
328
328
  summary: Magical authentication for Rails applications
329
329
  test_files: []
330
+ has_rdoc: