devise 4.1.1 → 4.2.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of devise might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.travis.yml +9 -7
- data/CHANGELOG.md +46 -2
- data/CONTRIBUTING.md +30 -7
- data/Gemfile +14 -7
- data/Gemfile.lock +96 -81
- data/README.md +89 -37
- data/app/controllers/devise/omniauth_callbacks_controller.rb +3 -3
- data/app/controllers/devise/registrations_controller.rb +3 -3
- data/app/views/devise/registrations/edit.html.erb +4 -0
- data/gemfiles/Gemfile.rails-4.1-stable +4 -4
- data/gemfiles/Gemfile.rails-4.1-stable.lock +27 -23
- data/gemfiles/Gemfile.rails-4.2-stable +4 -4
- data/gemfiles/Gemfile.rails-4.2-stable.lock +58 -54
- data/guides/bug_report_templates/integration_test.rb +104 -0
- data/lib/devise.rb +21 -14
- data/lib/devise/controllers/helpers.rb +12 -1
- data/lib/devise/controllers/rememberable.rb +1 -1
- data/lib/devise/controllers/sign_in_out.rb +25 -10
- data/lib/devise/failure_app.rb +25 -17
- data/lib/devise/hooks/proxy.rb +1 -1
- data/lib/devise/models/authenticatable.rb +23 -2
- data/lib/devise/models/confirmable.rb +13 -7
- data/lib/devise/models/database_authenticatable.rb +0 -5
- data/lib/devise/models/recoverable.rb +10 -15
- data/lib/devise/omniauth/url_helpers.rb +0 -51
- data/lib/devise/orm/active_record.rb +3 -1
- data/lib/devise/orm/mongoid.rb +4 -2
- data/lib/devise/parameter_sanitizer.rb +0 -55
- data/lib/devise/rails.rb +3 -1
- data/lib/devise/test/controller_helpers.rb +162 -0
- data/lib/devise/test/integration_helpers.rb +61 -0
- data/lib/devise/test_helpers.rb +5 -129
- data/lib/devise/version.rb +1 -1
- data/lib/generators/templates/README +1 -8
- data/lib/generators/templates/devise.rb +6 -0
- data/test/controllers/custom_registrations_controller_test.rb +1 -1
- data/test/controllers/custom_strategy_test.rb +1 -1
- data/test/controllers/helpers_test.rb +4 -4
- data/test/controllers/internal_helpers_test.rb +1 -1
- data/test/controllers/passwords_controller_test.rb +1 -1
- data/test/controllers/sessions_controller_test.rb +2 -2
- data/test/devise_test.rb +9 -9
- data/test/failure_app_test.rb +18 -0
- data/test/integration/authenticatable_test.rb +36 -36
- data/test/integration/confirmable_test.rb +7 -7
- data/test/integration/database_authenticatable_test.rb +5 -5
- data/test/integration/http_authenticatable_test.rb +2 -2
- data/test/integration/lockable_test.rb +1 -1
- data/test/integration/mounted_engine_test.rb +36 -0
- data/test/integration/omniauthable_test.rb +1 -1
- data/test/integration/recoverable_test.rb +4 -4
- data/test/integration/registerable_test.rb +12 -6
- data/test/integration/rememberable_test.rb +10 -10
- data/test/integration/timeoutable_test.rb +5 -5
- data/test/mapping_test.rb +1 -1
- data/test/models/confirmable_test.rb +33 -25
- data/test/models/database_authenticatable_test.rb +13 -13
- data/test/models/lockable_test.rb +16 -16
- data/test/models/omniauthable_test.rb +1 -1
- data/test/models/recoverable_test.rb +10 -10
- data/test/models/registerable_test.rb +1 -1
- data/test/models/rememberable_test.rb +16 -3
- data/test/models/serializable_test.rb +5 -0
- data/test/models/timeoutable_test.rb +7 -7
- data/test/models/trackable_test.rb +1 -1
- data/test/models/validatable_test.rb +1 -1
- data/test/models_test.rb +2 -2
- data/test/parameter_sanitizer_test.rb +0 -56
- data/test/rails_app/app/controllers/users/omniauth_callbacks_controller.rb +1 -1
- data/test/rails_app/config/environments/production.rb +3 -1
- data/test/rails_app/config/environments/test.rb +5 -6
- data/test/rails_app/db/migrate/20100401102949_create_tables.rb +5 -1
- data/test/support/assertions.rb +0 -11
- data/test/{test_helpers_test.rb → test/controller_helpers_test.rb} +2 -2
- data/test/test/integration_helpers_test.rb +32 -0
- metadata +11 -6
- data/gemfiles/Gemfile.rails-5.0-beta +0 -37
- data/gemfiles/Gemfile.rails-5.0-beta.lock +0 -199
data/lib/devise/failure_app.rb
CHANGED
@@ -50,13 +50,11 @@ module Devise
|
|
50
50
|
end
|
51
51
|
|
52
52
|
def recall
|
53
|
-
|
54
|
-
|
55
|
-
header_info = if config.try(:relative_url_root)
|
56
|
-
base_path = Pathname.new(config.relative_url_root)
|
53
|
+
header_info = if relative_url_root?
|
54
|
+
base_path = Pathname.new(relative_url_root)
|
57
55
|
full_path = Pathname.new(attempted_path)
|
58
56
|
|
59
|
-
{ "SCRIPT_NAME" =>
|
57
|
+
{ "SCRIPT_NAME" => relative_url_root,
|
60
58
|
"PATH_INFO" => '/' + full_path.relative_path_from(base_path).to_s }
|
61
59
|
else
|
62
60
|
{ "PATH_INFO" => attempted_path }
|
@@ -66,7 +64,7 @@ module Devise
|
|
66
64
|
if request.respond_to?(:set_header)
|
67
65
|
request.set_header(var, value)
|
68
66
|
else
|
69
|
-
env[var] = value
|
67
|
+
request.env[var] = value
|
70
68
|
end
|
71
69
|
end
|
72
70
|
|
@@ -135,18 +133,16 @@ module Devise
|
|
135
133
|
|
136
134
|
def scope_url
|
137
135
|
opts = {}
|
136
|
+
|
137
|
+
# Initialize script_name with nil to prevent infinite loops in
|
138
|
+
# authenticated mounted engines in rails 4.2 and 5.0
|
139
|
+
opts[:script_name] = nil
|
140
|
+
|
138
141
|
route = route(scope)
|
139
|
-
opts[:format] = request_format unless skip_format?
|
140
142
|
|
141
|
-
|
143
|
+
opts[:format] = request_format unless skip_format?
|
142
144
|
|
143
|
-
if
|
144
|
-
# Rails 4.2 goes into an infinite loop if opts[:script_name] is unset
|
145
|
-
rails_4_2 = (Rails::VERSION::MAJOR >= 4) && (Rails::VERSION::MINOR >= 2)
|
146
|
-
if config.relative_url_root.present? || rails_4_2
|
147
|
-
opts[:script_name] = config.relative_url_root
|
148
|
-
end
|
149
|
-
end
|
145
|
+
opts[:script_name] = relative_url_root if relative_url_root?
|
150
146
|
|
151
147
|
router_name = Devise.mappings[scope].router_name || Devise.available_router_name
|
152
148
|
context = send(router_name)
|
@@ -206,11 +202,11 @@ module Devise
|
|
206
202
|
end
|
207
203
|
|
208
204
|
def warden
|
209
|
-
request.respond_to?(:get_header) ? request.get_header("warden") : env["warden"]
|
205
|
+
request.respond_to?(:get_header) ? request.get_header("warden") : request.env["warden"]
|
210
206
|
end
|
211
207
|
|
212
208
|
def warden_options
|
213
|
-
request.respond_to?(:get_header) ? request.get_header("warden.options") : env["warden.options"]
|
209
|
+
request.respond_to?(:get_header) ? request.get_header("warden.options") : request.env["warden.options"]
|
214
210
|
end
|
215
211
|
|
216
212
|
def warden_message
|
@@ -250,5 +246,17 @@ module Devise
|
|
250
246
|
def request_format
|
251
247
|
@request_format ||= request.format.try(:ref)
|
252
248
|
end
|
249
|
+
|
250
|
+
def relative_url_root
|
251
|
+
@relative_url_root ||= begin
|
252
|
+
config = Rails.application.config
|
253
|
+
|
254
|
+
config.try(:relative_url_root) || config.action_controller.try(:relative_url_root)
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
def relative_url_root?
|
259
|
+
relative_url_root.present?
|
260
|
+
end
|
253
261
|
end
|
254
262
|
end
|
data/lib/devise/hooks/proxy.rb
CHANGED
@@ -114,6 +114,15 @@ module Devise
|
|
114
114
|
super(options)
|
115
115
|
end
|
116
116
|
|
117
|
+
# Redefine inspect using serializable_hash, to ensure we don't accidentally
|
118
|
+
# leak passwords into exceptions.
|
119
|
+
def inspect
|
120
|
+
inspection = serializable_hash.collect do |k,v|
|
121
|
+
"#{k}: #{respond_to?(:attribute_for_inspect) ? attribute_for_inspect(k) : v.inspect}"
|
122
|
+
end
|
123
|
+
"#<#{self.class} #{inspection.join(", ")}>"
|
124
|
+
end
|
125
|
+
|
117
126
|
protected
|
118
127
|
|
119
128
|
def devise_mailer
|
@@ -143,13 +152,25 @@ module Devise
|
|
143
152
|
# if new_record? || changed?
|
144
153
|
# pending_notifications << [notification, args]
|
145
154
|
# else
|
146
|
-
# devise_mailer.send(notification, self, *args)
|
155
|
+
# message = devise_mailer.send(notification, self, *args)
|
156
|
+
# Remove once we move to Rails 4.2+ only.
|
157
|
+
# if message.respond_to?(:deliver_now)
|
158
|
+
# message.deliver_now
|
159
|
+
# else
|
160
|
+
# message.deliver
|
161
|
+
# end
|
147
162
|
# end
|
148
163
|
# end
|
149
164
|
#
|
150
165
|
# def send_pending_notifications
|
151
166
|
# pending_notifications.each do |notification, args|
|
152
|
-
# devise_mailer.send(notification, self, *args)
|
167
|
+
# message = devise_mailer.send(notification, self, *args)
|
168
|
+
# Remove once we move to Rails 4.2+ only.
|
169
|
+
# if message.respond_to?(:deliver_now)
|
170
|
+
# message.deliver_now
|
171
|
+
# else
|
172
|
+
# message.deliver
|
173
|
+
# end
|
153
174
|
# end
|
154
175
|
#
|
155
176
|
# # Empty the pending notifications array because the
|
@@ -43,7 +43,7 @@ module Devise
|
|
43
43
|
|
44
44
|
included do
|
45
45
|
before_create :generate_confirmation_token, if: :confirmation_required?
|
46
|
-
after_create :
|
46
|
+
after_create :skip_reconfirmation_in_callback!, if: :send_confirmation_notification?
|
47
47
|
if respond_to?(:after_commit) # ActiveRecord
|
48
48
|
after_commit :send_on_create_confirmation_instructions, on: :create, if: :send_confirmation_notification?
|
49
49
|
after_commit :send_reconfirmation_instructions, on: :update, if: :reconfirmation_required?
|
@@ -56,6 +56,7 @@ module Devise
|
|
56
56
|
|
57
57
|
def initialize(*args, &block)
|
58
58
|
@bypass_confirmation_postpone = false
|
59
|
+
@skip_reconfirmation_in_callback = false
|
59
60
|
@reconfirmation_required = false
|
60
61
|
@skip_confirmation_notification = false
|
61
62
|
@raw_confirmation_token = nil
|
@@ -97,11 +98,6 @@ module Devise
|
|
97
98
|
end
|
98
99
|
end
|
99
100
|
|
100
|
-
def confirm!(args={})
|
101
|
-
ActiveSupport::Deprecation.warn "confirm! is deprecated in favor of confirm"
|
102
|
-
confirm(args)
|
103
|
-
end
|
104
|
-
|
105
101
|
# Verifies whether a user is confirmed or not
|
106
102
|
def confirmed?
|
107
103
|
!!confirmed_at
|
@@ -170,6 +166,12 @@ module Devise
|
|
170
166
|
|
171
167
|
protected
|
172
168
|
|
169
|
+
# To not require reconfirmation after creating with #save called in a
|
170
|
+
# callback call skip_create_confirmation!
|
171
|
+
def skip_reconfirmation_in_callback!
|
172
|
+
@skip_reconfirmation_in_callback = true
|
173
|
+
end
|
174
|
+
|
173
175
|
# A callback method used to deliver confirmation
|
174
176
|
# instructions on creation. This can be overridden
|
175
177
|
# in models to map to a nice sign up e-mail.
|
@@ -258,7 +260,11 @@ module Devise
|
|
258
260
|
end
|
259
261
|
|
260
262
|
def postpone_email_change?
|
261
|
-
postpone = self.class.reconfirmable &&
|
263
|
+
postpone = self.class.reconfirmable &&
|
264
|
+
email_changed? &&
|
265
|
+
!@bypass_confirmation_postpone &&
|
266
|
+
self.email.present? &&
|
267
|
+
(!@skip_reconfirmation_in_callback || !self.email_was.nil?)
|
262
268
|
@bypass_confirmation_postpone = false
|
263
269
|
postpone
|
264
270
|
end
|
@@ -1,11 +1,6 @@
|
|
1
1
|
require 'devise/strategies/database_authenticatable'
|
2
2
|
|
3
3
|
module Devise
|
4
|
-
def self.bcrypt(klass, password)
|
5
|
-
ActiveSupport::Deprecation.warn "Devise.bcrypt is deprecated; use Devise::Encryptor.digest instead"
|
6
|
-
Devise::Encryptor.digest(klass, password)
|
7
|
-
end
|
8
|
-
|
9
4
|
module Models
|
10
5
|
# Authenticatable Module, responsible for hashing the password and
|
11
6
|
# validating the authenticity of a user while signing in.
|
@@ -27,11 +27,7 @@ module Devise
|
|
27
27
|
end
|
28
28
|
|
29
29
|
included do
|
30
|
-
before_update
|
31
|
-
if (respond_to?(:email_changed?) && email_changed?) || encrypted_password_changed?
|
32
|
-
clear_reset_password_token
|
33
|
-
end
|
34
|
-
end
|
30
|
+
before_update :clear_reset_password_token, if: :clear_reset_password_token?
|
35
31
|
end
|
36
32
|
|
37
33
|
# Update password saving the record and clearing token. Returns true if
|
@@ -40,19 +36,9 @@ module Devise
|
|
40
36
|
self.password = new_password
|
41
37
|
self.password_confirmation = new_password_confirmation
|
42
38
|
|
43
|
-
if respond_to?(:after_password_reset) && valid?
|
44
|
-
ActiveSupport::Deprecation.warn "after_password_reset is deprecated"
|
45
|
-
after_password_reset
|
46
|
-
end
|
47
|
-
|
48
39
|
save
|
49
40
|
end
|
50
41
|
|
51
|
-
def reset_password!(new_password, new_password_confirmation)
|
52
|
-
ActiveSupport::Deprecation.warn "reset_password! is deprecated in favor of reset_password"
|
53
|
-
reset_password(new_password, new_password_confirmation)
|
54
|
-
end
|
55
|
-
|
56
42
|
# Resets reset password token and send reset password instructions by email.
|
57
43
|
# Returns the token sent in the e-mail.
|
58
44
|
def send_reset_password_instructions
|
@@ -107,6 +93,15 @@ module Devise
|
|
107
93
|
send_devise_notification(:reset_password_instructions, token, {})
|
108
94
|
end
|
109
95
|
|
96
|
+
def clear_reset_password_token?
|
97
|
+
encrypted_password_changed = respond_to?(:encrypted_password_changed?) && encrypted_password_changed?
|
98
|
+
authentication_keys_changed = self.class.authentication_keys.any? do |attribute|
|
99
|
+
respond_to?("#{attribute}_changed?") && send("#{attribute}_changed?")
|
100
|
+
end
|
101
|
+
|
102
|
+
authentication_keys_changed || encrypted_password_changed
|
103
|
+
end
|
104
|
+
|
110
105
|
module ClassMethods
|
111
106
|
# Attempt to find a user by password reset token. If a user is found, return it
|
112
107
|
# If a user is not found, return nil
|
@@ -1,57 +1,6 @@
|
|
1
1
|
module Devise
|
2
2
|
module OmniAuth
|
3
3
|
module UrlHelpers
|
4
|
-
def self.define_helpers(mapping)
|
5
|
-
return unless mapping.omniauthable?
|
6
|
-
|
7
|
-
mapping = mapping.name
|
8
|
-
|
9
|
-
class_eval do
|
10
|
-
define_method("#{mapping}_omniauth_authorize_path") do |provider, *args|
|
11
|
-
ActiveSupport::Deprecation.warn(<<-DEPRECATION.strip_heredoc)
|
12
|
-
[Devise] #{mapping}_omniauth_authorize_path(#{provider.inspect}) is deprecated and it will be removed from Devise 4.2.
|
13
|
-
|
14
|
-
Please use #{mapping}_#{provider}_omniauth_authorize_path instead.
|
15
|
-
DEPRECATION
|
16
|
-
send("#{mapping}_#{provider}_omniauth_authorize_path", *args)
|
17
|
-
end
|
18
|
-
|
19
|
-
define_method("#{mapping}_omniauth_authorize_url") do |provider, *args|
|
20
|
-
ActiveSupport::Deprecation.warn(<<-DEPRECATION.strip_heredoc)
|
21
|
-
[Devise] #{mapping}_omniauth_authorize_url(#{provider.inspect}) is deprecated and it will be removed from Devise 4.2.
|
22
|
-
|
23
|
-
Please use #{mapping}_#{provider}_omniauth_authorize_url instead.
|
24
|
-
DEPRECATION
|
25
|
-
send("#{mapping}_#{provider}_omniauth_authorize_url", *args)
|
26
|
-
end
|
27
|
-
|
28
|
-
define_method("#{mapping}_omniauth_callback_path") do |provider, *args|
|
29
|
-
ActiveSupport::Deprecation.warn(<<-DEPRECATION.strip_heredoc)
|
30
|
-
[Devise] #{mapping}_omniauth_callback_path(#{provider.inspect}) is deprecated and it will be removed from Devise 4.2.
|
31
|
-
|
32
|
-
Please use #{mapping}_#{provider}_omniauth_callback_path instead.
|
33
|
-
DEPRECATION
|
34
|
-
send("#{mapping}_#{provider}_omniauth_callback_path", *args)
|
35
|
-
end
|
36
|
-
|
37
|
-
define_method("#{mapping}_omniauth_callback_url") do |provider, *args|
|
38
|
-
ActiveSupport::Deprecation.warn(<<-DEPRECATION.strip_heredoc)
|
39
|
-
[Devise] #{mapping}_omniauth_callback_url(#{provider.inspect}) is deprecated and it will be removed from Devise 4.2.
|
40
|
-
|
41
|
-
Please use #{mapping}_#{provider}_omniauth_callback_url instead.
|
42
|
-
DEPRECATION
|
43
|
-
send("#{mapping}_#{provider}_omniauth_callback_url", *args)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
ActiveSupport.on_load(:action_controller) do
|
48
|
-
if respond_to?(:helper_method)
|
49
|
-
helper_method "#{mapping}_omniauth_authorize_path", "#{mapping}_omniauth_authorize_url"
|
50
|
-
helper_method "#{mapping}_omniauth_callback_path", "#{mapping}_omniauth_callback_url"
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
4
|
def omniauth_authorize_path(resource_or_scope, provider, *args)
|
56
5
|
scope = Devise::Mapping.find_scope!(resource_or_scope)
|
57
6
|
_devise_route_context.send("#{scope}_#{provider}_omniauth_authorize_path", *args)
|
data/lib/devise/orm/mongoid.rb
CHANGED
@@ -68,12 +68,6 @@ module Devise
|
|
68
68
|
def sanitize(action)
|
69
69
|
permissions = @permitted[action]
|
70
70
|
|
71
|
-
# DEPRECATED: Remove this branch on Devise 4.2.
|
72
|
-
if respond_to?(action, true)
|
73
|
-
deprecate_instance_method_sanitization(action)
|
74
|
-
return cast_to_hash send(action)
|
75
|
-
end
|
76
|
-
|
77
71
|
if permissions.respond_to?(:call)
|
78
72
|
cast_to_hash permissions.call(default_params)
|
79
73
|
elsif permissions.present?
|
@@ -127,17 +121,6 @@ module Devise
|
|
127
121
|
end
|
128
122
|
end
|
129
123
|
|
130
|
-
# DEPRECATED: Remove this method on Devise 4.2.
|
131
|
-
def for(action, &block) # :nodoc:
|
132
|
-
if block_given?
|
133
|
-
deprecate_for_with_block(action)
|
134
|
-
permit(action, &block)
|
135
|
-
else
|
136
|
-
deprecate_for_without_block(action)
|
137
|
-
@permitted[action] or unknown_action!(action)
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
124
|
private
|
142
125
|
|
143
126
|
# Cast a sanitized +ActionController::Parameters+ to a +HashWithIndifferentAccess+
|
@@ -172,43 +155,5 @@ module Devise
|
|
172
155
|
devise_parameter_sanitizer.permit(:#{action}, keys: [:param1, :param2, :param3])
|
173
156
|
MESSAGE
|
174
157
|
end
|
175
|
-
|
176
|
-
def deprecate_for_with_block(action)
|
177
|
-
ActiveSupport::Deprecation.warn(<<-MESSAGE.strip_heredoc)
|
178
|
-
[Devise] Changing the sanitized parameters through "#{self.class.name}#for(#{action}) is deprecated and it will be removed from Devise 4.2.
|
179
|
-
Please use the `permit` method:
|
180
|
-
|
181
|
-
devise_parameter_sanitizer.permit(:#{action}) do |user|
|
182
|
-
# Your block here.
|
183
|
-
end
|
184
|
-
MESSAGE
|
185
|
-
end
|
186
|
-
|
187
|
-
def deprecate_for_without_block(action)
|
188
|
-
ActiveSupport::Deprecation.warn(<<-MESSAGE.strip_heredoc)
|
189
|
-
[Devise] Changing the sanitized parameters through "#{self.class.name}#for(#{action}) is deprecated and it will be removed from Devise 4.2.
|
190
|
-
Please use the `permit` method to add or remove any key:
|
191
|
-
|
192
|
-
To add any new key, use the `keys` keyword argument:
|
193
|
-
devise_parameter_sanitizer.permit(:#{action}, keys: [:param1, :param2, :param3])
|
194
|
-
|
195
|
-
To remove any existing key, use the `except` keyword argument:
|
196
|
-
devise_parameter_sanitizer.permit(:#{action}, except: [:email])
|
197
|
-
MESSAGE
|
198
|
-
end
|
199
|
-
|
200
|
-
def deprecate_instance_method_sanitization(action)
|
201
|
-
ActiveSupport::Deprecation.warn(<<-MESSAGE.strip_heredoc)
|
202
|
-
[Devise] Parameter sanitization through a "#{self.class.name}##{action}" method is deprecated and it will be removed from Devise 4.2.
|
203
|
-
Please use the `permit` method on your sanitizer `initialize` method.
|
204
|
-
|
205
|
-
class #{self.class.name} < Devise::ParameterSanitizer
|
206
|
-
def initialize(*)
|
207
|
-
super
|
208
|
-
permit(:#{action}, keys: [:param1, :param2, :param3])
|
209
|
-
end
|
210
|
-
end
|
211
|
-
MESSAGE
|
212
|
-
end
|
213
158
|
end
|
214
159
|
end
|
data/lib/devise/rails.rb
CHANGED
@@ -11,7 +11,9 @@ module Devise
|
|
11
11
|
end
|
12
12
|
|
13
13
|
# Force routes to be loaded if we are doing any eager load.
|
14
|
-
config.before_eager_load
|
14
|
+
config.before_eager_load do |app|
|
15
|
+
app.reload_routes! if Devise.reload_routes
|
16
|
+
end
|
15
17
|
|
16
18
|
initializer "devise.url_helpers" do
|
17
19
|
Devise.include_helpers(Devise::Controllers)
|
@@ -0,0 +1,162 @@
|
|
1
|
+
module Devise
|
2
|
+
module Test
|
3
|
+
# `Devise::Test::ControllerHelpers` provides a facility to test controllers
|
4
|
+
# in isolation when using `ActionController::TestCase` allowing you to
|
5
|
+
# quickly sign_in or sign_out a user. Do not use
|
6
|
+
# `Devise::Test::ControllerHelpers` in integration tests.
|
7
|
+
#
|
8
|
+
# Examples
|
9
|
+
#
|
10
|
+
# class PostsTest < ActionController::TestCase
|
11
|
+
# include Devise::Test::ControllerHelpers
|
12
|
+
#
|
13
|
+
# test 'authenticated users can GET index' do
|
14
|
+
# sign_in users(:bob)
|
15
|
+
#
|
16
|
+
# get :index
|
17
|
+
# assert_response :success
|
18
|
+
# end
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# Important: you should not test Warden specific behavior (like callbacks)
|
22
|
+
# using `Devise::Test::ControllerHelpers` since it is a stub of the actual
|
23
|
+
# behavior. Such callbacks should be tested in your integration suite instead.
|
24
|
+
module ControllerHelpers
|
25
|
+
extend ActiveSupport::Concern
|
26
|
+
|
27
|
+
included do
|
28
|
+
setup :setup_controller_for_warden, :warden
|
29
|
+
end
|
30
|
+
|
31
|
+
# Override process to consider warden.
|
32
|
+
def process(*)
|
33
|
+
_catch_warden { super }
|
34
|
+
|
35
|
+
@response
|
36
|
+
end
|
37
|
+
|
38
|
+
# We need to set up the environment variables and the response in the controller.
|
39
|
+
def setup_controller_for_warden #:nodoc:
|
40
|
+
@request.env['action_controller.instance'] = @controller
|
41
|
+
end
|
42
|
+
|
43
|
+
# Quick access to Warden::Proxy.
|
44
|
+
def warden #:nodoc:
|
45
|
+
@request.env['warden'] ||= begin
|
46
|
+
manager = Warden::Manager.new(nil) do |config|
|
47
|
+
config.merge! Devise.warden_config
|
48
|
+
end
|
49
|
+
Warden::Proxy.new(@request.env, manager)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# sign_in a given resource by storing its keys in the session.
|
54
|
+
# This method bypass any warden authentication callback.
|
55
|
+
#
|
56
|
+
# * +resource+ - The resource that should be authenticated
|
57
|
+
# * +scope+ - An optional +Symbol+ with the scope where the resource
|
58
|
+
# should be signed in with.
|
59
|
+
# Examples:
|
60
|
+
#
|
61
|
+
# sign_in users(:alice)
|
62
|
+
# sign_in users(:alice), scope: :admin
|
63
|
+
def sign_in(resource, deprecated = nil, scope: nil)
|
64
|
+
if deprecated.present?
|
65
|
+
scope = resource
|
66
|
+
resource = deprecated
|
67
|
+
|
68
|
+
ActiveSupport::Deprecation.warn <<-DEPRECATION
|
69
|
+
[Devise] sign_in(:#{scope}, resource) on controller tests is deprecated and will be removed from Devise.
|
70
|
+
Please use sign_in(resource, scope: :#{scope}) instead.
|
71
|
+
DEPRECATION
|
72
|
+
end
|
73
|
+
|
74
|
+
scope ||= Devise::Mapping.find_scope!(resource)
|
75
|
+
|
76
|
+
warden.instance_variable_get(:@users).delete(scope)
|
77
|
+
warden.session_serializer.store(resource, scope)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Sign out a given resource or scope by calling logout on Warden.
|
81
|
+
# This method bypass any warden logout callback.
|
82
|
+
#
|
83
|
+
# Examples:
|
84
|
+
#
|
85
|
+
# sign_out :user # sign_out(scope)
|
86
|
+
# sign_out @user # sign_out(resource)
|
87
|
+
#
|
88
|
+
def sign_out(resource_or_scope)
|
89
|
+
scope = Devise::Mapping.find_scope!(resource_or_scope)
|
90
|
+
@controller.instance_variable_set(:"@current_#{scope}", nil)
|
91
|
+
user = warden.instance_variable_get(:@users).delete(scope)
|
92
|
+
warden.session_serializer.delete(scope, user)
|
93
|
+
end
|
94
|
+
|
95
|
+
protected
|
96
|
+
|
97
|
+
# Catch warden continuations and handle like the middleware would.
|
98
|
+
# Returns nil when interrupted, otherwise the normal result of the block.
|
99
|
+
def _catch_warden(&block)
|
100
|
+
result = catch(:warden, &block)
|
101
|
+
|
102
|
+
env = @controller.request.env
|
103
|
+
|
104
|
+
result ||= {}
|
105
|
+
|
106
|
+
# Set the response. In production, the rack result is returned
|
107
|
+
# from Warden::Manager#call, which the following is modelled on.
|
108
|
+
case result
|
109
|
+
when Array
|
110
|
+
if result.first == 401 && intercept_401?(env) # does this happen during testing?
|
111
|
+
_process_unauthenticated(env)
|
112
|
+
else
|
113
|
+
result
|
114
|
+
end
|
115
|
+
when Hash
|
116
|
+
_process_unauthenticated(env, result)
|
117
|
+
else
|
118
|
+
result
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def _process_unauthenticated(env, options = {})
|
123
|
+
options[:action] ||= :unauthenticated
|
124
|
+
proxy = request.env['warden']
|
125
|
+
result = options[:result] || proxy.result
|
126
|
+
|
127
|
+
ret = case result
|
128
|
+
when :redirect
|
129
|
+
body = proxy.message || "You are being redirected to #{proxy.headers['Location']}"
|
130
|
+
[proxy.status, proxy.headers, [body]]
|
131
|
+
when :custom
|
132
|
+
proxy.custom_response
|
133
|
+
else
|
134
|
+
request.env["PATH_INFO"] = "/#{options[:action]}"
|
135
|
+
request.env["warden.options"] = options
|
136
|
+
Warden::Manager._run_callbacks(:before_failure, env, options)
|
137
|
+
|
138
|
+
status, headers, response = Devise.warden_config[:failure_app].call(env).to_a
|
139
|
+
@controller.response.headers.merge!(headers)
|
140
|
+
@controller.status = status
|
141
|
+
@controller.response.body = response.body
|
142
|
+
nil # causes process return @response
|
143
|
+
end
|
144
|
+
|
145
|
+
# ensure that the controller response is set up. In production, this is
|
146
|
+
# not necessary since warden returns the results to rack. However, at
|
147
|
+
# testing time, we want the response to be available to the testing
|
148
|
+
# framework to verify what would be returned to rack.
|
149
|
+
if ret.is_a?(Array)
|
150
|
+
status, headers, body = *ret
|
151
|
+
# ensure the controller response is set to our response.
|
152
|
+
@controller.response ||= @response
|
153
|
+
@response.status = status
|
154
|
+
@response.headers.merge!(headers)
|
155
|
+
@response.body = body
|
156
|
+
end
|
157
|
+
|
158
|
+
ret
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|