devise 3.0.0 → 4.8.0
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 +7 -0
- data/CHANGELOG.md +351 -0
- data/MIT-LICENSE +2 -1
- data/README.md +422 -130
- data/app/controllers/devise/confirmations_controller.rb +17 -6
- data/app/controllers/devise/omniauth_callbacks_controller.rb +12 -6
- data/app/controllers/devise/passwords_controller.rb +23 -8
- data/app/controllers/devise/registrations_controller.rb +70 -28
- data/app/controllers/devise/sessions_controller.rb +49 -17
- data/app/controllers/devise/unlocks_controller.rb +11 -4
- data/app/controllers/devise_controller.rb +74 -34
- data/app/helpers/devise_helper.rb +23 -18
- data/app/mailers/devise/mailer.rb +25 -10
- data/app/views/devise/confirmations/new.html.erb +9 -5
- data/app/views/devise/mailer/confirmation_instructions.html.erb +1 -1
- data/app/views/devise/mailer/email_changed.html.erb +7 -0
- data/app/views/devise/mailer/password_change.html.erb +3 -0
- data/app/views/devise/mailer/reset_password_instructions.html.erb +1 -1
- data/app/views/devise/mailer/unlock_instructions.html.erb +1 -1
- data/app/views/devise/passwords/edit.html.erb +16 -7
- data/app/views/devise/passwords/new.html.erb +9 -5
- data/app/views/devise/registrations/edit.html.erb +29 -15
- data/app/views/devise/registrations/new.html.erb +20 -9
- data/app/views/devise/sessions/new.html.erb +19 -10
- data/app/views/devise/shared/_error_messages.html.erb +15 -0
- data/app/views/devise/shared/{_links.erb → _links.html.erb} +10 -10
- data/app/views/devise/unlocks/new.html.erb +9 -5
- data/config/locales/en.yml +26 -20
- data/lib/devise/controllers/helpers.rb +122 -125
- data/lib/devise/controllers/rememberable.rb +14 -14
- data/lib/devise/controllers/scoped_views.rb +3 -1
- data/lib/devise/controllers/sign_in_out.rb +121 -0
- data/lib/devise/controllers/store_location.rb +76 -0
- data/lib/devise/controllers/url_helpers.rb +10 -8
- data/lib/devise/delegator.rb +2 -0
- data/lib/devise/encryptor.rb +24 -0
- data/lib/devise/failure_app.rb +132 -42
- data/lib/devise/hooks/activatable.rb +7 -6
- data/lib/devise/hooks/csrf_cleaner.rb +9 -0
- data/lib/devise/hooks/forgetable.rb +3 -1
- data/lib/devise/hooks/lockable.rb +5 -3
- data/lib/devise/hooks/proxy.rb +23 -0
- data/lib/devise/hooks/rememberable.rb +7 -4
- data/lib/devise/hooks/timeoutable.rb +18 -8
- data/lib/devise/hooks/trackable.rb +3 -1
- data/lib/devise/mailers/helpers.rb +15 -18
- data/lib/devise/mapping.rb +9 -3
- data/lib/devise/models/authenticatable.rb +102 -80
- data/lib/devise/models/confirmable.rb +154 -72
- data/lib/devise/models/database_authenticatable.rb +125 -25
- data/lib/devise/models/lockable.rb +50 -29
- data/lib/devise/models/omniauthable.rb +3 -1
- data/lib/devise/models/recoverable.rb +72 -50
- data/lib/devise/models/registerable.rb +4 -0
- data/lib/devise/models/rememberable.rb +65 -32
- data/lib/devise/models/timeoutable.rb +4 -8
- data/lib/devise/models/trackable.rb +20 -4
- data/lib/devise/models/validatable.rb +16 -9
- data/lib/devise/models.rb +6 -13
- data/lib/devise/modules.rb +12 -11
- data/lib/devise/omniauth/config.rb +2 -0
- data/lib/devise/omniauth/url_helpers.rb +14 -5
- data/lib/devise/omniauth.rb +4 -5
- data/lib/devise/orm/active_record.rb +5 -1
- data/lib/devise/orm/mongoid.rb +6 -2
- data/lib/devise/parameter_filter.rb +4 -0
- data/lib/devise/parameter_sanitizer.rb +144 -34
- data/lib/devise/rails/deprecated_constant_accessor.rb +39 -0
- data/lib/devise/rails/routes.rb +191 -127
- data/lib/devise/rails/warden_compat.rb +2 -1
- data/lib/devise/rails.rb +13 -20
- data/lib/devise/secret_key_finder.rb +27 -0
- data/lib/devise/strategies/authenticatable.rb +21 -22
- data/lib/devise/strategies/base.rb +3 -1
- data/lib/devise/strategies/database_authenticatable.rb +15 -4
- data/lib/devise/strategies/rememberable.rb +15 -3
- data/lib/devise/test/controller_helpers.rb +167 -0
- data/lib/devise/test/integration_helpers.rb +63 -0
- data/lib/devise/test_helpers.rb +7 -123
- data/lib/devise/time_inflector.rb +4 -2
- data/lib/devise/token_generator.rb +32 -0
- data/lib/devise/version.rb +3 -1
- data/lib/devise.rb +124 -78
- data/lib/generators/active_record/devise_generator.rb +64 -15
- data/lib/generators/active_record/templates/migration.rb +9 -8
- data/lib/generators/active_record/templates/migration_existing.rb +9 -8
- data/lib/generators/devise/controllers_generator.rb +46 -0
- data/lib/generators/devise/devise_generator.rb +10 -6
- data/lib/generators/devise/install_generator.rb +19 -1
- data/lib/generators/devise/orm_helpers.rb +17 -9
- data/lib/generators/devise/views_generator.rb +51 -28
- data/lib/generators/mongoid/devise_generator.rb +24 -24
- data/lib/generators/templates/README +13 -12
- data/lib/generators/templates/controllers/README +14 -0
- data/lib/generators/templates/controllers/confirmations_controller.rb +30 -0
- data/lib/generators/templates/controllers/omniauth_callbacks_controller.rb +30 -0
- data/lib/generators/templates/controllers/passwords_controller.rb +34 -0
- data/lib/generators/templates/controllers/registrations_controller.rb +62 -0
- data/lib/generators/templates/controllers/sessions_controller.rb +27 -0
- data/lib/generators/templates/controllers/unlocks_controller.rb +30 -0
- data/lib/generators/templates/devise.rb +118 -53
- data/lib/generators/templates/markerb/confirmation_instructions.markerb +1 -1
- data/lib/generators/templates/markerb/email_changed.markerb +7 -0
- data/lib/generators/templates/markerb/password_change.markerb +3 -0
- data/lib/generators/templates/markerb/reset_password_instructions.markerb +1 -1
- data/lib/generators/templates/markerb/unlock_instructions.markerb +1 -1
- data/lib/generators/templates/simple_form_for/confirmations/new.html.erb +6 -2
- data/lib/generators/templates/simple_form_for/passwords/edit.html.erb +12 -4
- data/lib/generators/templates/simple_form_for/passwords/new.html.erb +5 -2
- data/lib/generators/templates/simple_form_for/registrations/edit.html.erb +14 -6
- data/lib/generators/templates/simple_form_for/registrations/new.html.erb +12 -4
- data/lib/generators/templates/simple_form_for/sessions/new.html.erb +11 -6
- data/lib/generators/templates/simple_form_for/unlocks/new.html.erb +5 -2
- metadata +73 -294
- data/.gitignore +0 -10
- data/.travis.yml +0 -20
- data/.yardopts +0 -9
- data/CHANGELOG.rdoc +0 -941
- data/CONTRIBUTING.md +0 -14
- data/Gemfile +0 -31
- data/Gemfile.lock +0 -159
- data/Rakefile +0 -35
- data/app/views/devise/_links.erb +0 -3
- data/devise.gemspec +0 -26
- data/devise.png +0 -0
- data/gemfiles/Gemfile.rails-3.2.x +0 -31
- data/gemfiles/Gemfile.rails-3.2.x.lock +0 -156
- data/lib/devise/models/token_authenticatable.rb +0 -89
- data/lib/devise/strategies/token_authenticatable.rb +0 -91
- data/test/controllers/custom_strategy_test.rb +0 -62
- data/test/controllers/helpers_test.rb +0 -253
- data/test/controllers/internal_helpers_test.rb +0 -120
- data/test/controllers/passwords_controller_test.rb +0 -32
- data/test/controllers/sessions_controller_test.rb +0 -99
- data/test/controllers/url_helpers_test.rb +0 -59
- data/test/delegator_test.rb +0 -19
- data/test/devise_test.rb +0 -83
- data/test/failure_app_test.rb +0 -221
- data/test/generators/active_record_generator_test.rb +0 -73
- data/test/generators/devise_generator_test.rb +0 -39
- data/test/generators/install_generator_test.rb +0 -13
- data/test/generators/mongoid_generator_test.rb +0 -23
- data/test/generators/views_generator_test.rb +0 -67
- data/test/helpers/devise_helper_test.rb +0 -51
- data/test/integration/authenticatable_test.rb +0 -699
- data/test/integration/confirmable_test.rb +0 -299
- data/test/integration/database_authenticatable_test.rb +0 -84
- data/test/integration/http_authenticatable_test.rb +0 -115
- data/test/integration/lockable_test.rb +0 -242
- data/test/integration/omniauthable_test.rb +0 -133
- data/test/integration/recoverable_test.rb +0 -335
- data/test/integration/registerable_test.rb +0 -349
- data/test/integration/rememberable_test.rb +0 -165
- data/test/integration/timeoutable_test.rb +0 -150
- data/test/integration/token_authenticatable_test.rb +0 -205
- data/test/integration/trackable_test.rb +0 -92
- data/test/mailers/confirmation_instructions_test.rb +0 -111
- data/test/mailers/reset_password_instructions_test.rb +0 -92
- data/test/mailers/unlock_instructions_test.rb +0 -87
- data/test/mapping_test.rb +0 -127
- data/test/models/authenticatable_test.rb +0 -13
- data/test/models/confirmable_test.rb +0 -452
- data/test/models/database_authenticatable_test.rb +0 -226
- data/test/models/lockable_test.rb +0 -282
- data/test/models/omniauthable_test.rb +0 -7
- data/test/models/recoverable_test.rb +0 -222
- data/test/models/registerable_test.rb +0 -7
- data/test/models/rememberable_test.rb +0 -175
- data/test/models/serializable_test.rb +0 -49
- data/test/models/timeoutable_test.rb +0 -46
- data/test/models/token_authenticatable_test.rb +0 -55
- data/test/models/trackable_test.rb +0 -13
- data/test/models/validatable_test.rb +0 -127
- data/test/models_test.rb +0 -163
- data/test/omniauth/config_test.rb +0 -57
- data/test/omniauth/url_helpers_test.rb +0 -54
- data/test/orm/active_record.rb +0 -10
- data/test/orm/mongoid.rb +0 -13
- data/test/parameter_sanitizer_test.rb +0 -58
- data/test/rails_app/Rakefile +0 -6
- data/test/rails_app/app/active_record/admin.rb +0 -6
- data/test/rails_app/app/active_record/shim.rb +0 -2
- data/test/rails_app/app/active_record/user.rb +0 -6
- data/test/rails_app/app/controllers/admins/sessions_controller.rb +0 -6
- data/test/rails_app/app/controllers/admins_controller.rb +0 -11
- data/test/rails_app/app/controllers/application_controller.rb +0 -9
- data/test/rails_app/app/controllers/home_controller.rb +0 -25
- data/test/rails_app/app/controllers/publisher/registrations_controller.rb +0 -2
- data/test/rails_app/app/controllers/publisher/sessions_controller.rb +0 -2
- data/test/rails_app/app/controllers/users/omniauth_callbacks_controller.rb +0 -14
- data/test/rails_app/app/controllers/users_controller.rb +0 -31
- data/test/rails_app/app/helpers/application_helper.rb +0 -3
- data/test/rails_app/app/mailers/users/mailer.rb +0 -12
- data/test/rails_app/app/mongoid/admin.rb +0 -29
- data/test/rails_app/app/mongoid/shim.rb +0 -23
- data/test/rails_app/app/mongoid/user.rb +0 -42
- data/test/rails_app/app/views/admins/index.html.erb +0 -1
- data/test/rails_app/app/views/admins/sessions/new.html.erb +0 -2
- data/test/rails_app/app/views/home/admin_dashboard.html.erb +0 -1
- data/test/rails_app/app/views/home/index.html.erb +0 -1
- data/test/rails_app/app/views/home/join.html.erb +0 -1
- data/test/rails_app/app/views/home/private.html.erb +0 -1
- data/test/rails_app/app/views/home/user_dashboard.html.erb +0 -1
- data/test/rails_app/app/views/layouts/application.html.erb +0 -24
- data/test/rails_app/app/views/users/edit_form.html.erb +0 -1
- data/test/rails_app/app/views/users/index.html.erb +0 -1
- data/test/rails_app/app/views/users/mailer/confirmation_instructions.erb +0 -1
- data/test/rails_app/app/views/users/sessions/new.html.erb +0 -1
- data/test/rails_app/bin/bundle +0 -3
- data/test/rails_app/bin/rails +0 -4
- data/test/rails_app/bin/rake +0 -4
- data/test/rails_app/config/application.rb +0 -40
- data/test/rails_app/config/boot.rb +0 -8
- data/test/rails_app/config/database.yml +0 -18
- data/test/rails_app/config/environment.rb +0 -5
- data/test/rails_app/config/environments/development.rb +0 -34
- data/test/rails_app/config/environments/production.rb +0 -84
- data/test/rails_app/config/environments/test.rb +0 -36
- data/test/rails_app/config/initializers/backtrace_silencers.rb +0 -7
- data/test/rails_app/config/initializers/devise.rb +0 -178
- data/test/rails_app/config/initializers/inflections.rb +0 -2
- data/test/rails_app/config/initializers/secret_token.rb +0 -8
- data/test/rails_app/config/initializers/session_store.rb +0 -1
- data/test/rails_app/config/routes.rb +0 -104
- data/test/rails_app/config.ru +0 -4
- data/test/rails_app/db/migrate/20100401102949_create_tables.rb +0 -74
- data/test/rails_app/db/schema.rb +0 -52
- data/test/rails_app/lib/shared_admin.rb +0 -14
- data/test/rails_app/lib/shared_user.rb +0 -25
- data/test/rails_app/public/404.html +0 -26
- data/test/rails_app/public/422.html +0 -26
- data/test/rails_app/public/500.html +0 -26
- data/test/rails_app/public/favicon.ico +0 -0
- data/test/routes_test.rb +0 -250
- data/test/support/assertions.rb +0 -40
- data/test/support/helpers.rb +0 -91
- data/test/support/integration.rb +0 -92
- data/test/support/locale/en.yml +0 -4
- data/test/support/webrat/integrations/rails.rb +0 -24
- data/test/test_helper.rb +0 -34
- data/test/test_helpers_test.rb +0 -151
- data/test/test_models.rb +0 -26
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'devise/strategies/base'
|
|
2
4
|
|
|
3
5
|
module Devise
|
|
@@ -16,32 +18,26 @@ module Devise
|
|
|
16
18
|
valid_for_params_auth? || valid_for_http_auth?
|
|
17
19
|
end
|
|
18
20
|
|
|
21
|
+
# Override and set to false for things like OmniAuth that technically
|
|
22
|
+
# run through Authentication (user_set) very often, which would normally
|
|
23
|
+
# reset CSRF data in the session
|
|
24
|
+
def clean_up_csrf?
|
|
25
|
+
true
|
|
26
|
+
end
|
|
27
|
+
|
|
19
28
|
private
|
|
20
29
|
|
|
21
30
|
# Receives a resource and check if it is valid by calling valid_for_authentication?
|
|
22
|
-
#
|
|
23
|
-
# given as parameter. Check Devise::Models::
|
|
31
|
+
# A block that will be triggered while validating can be optionally
|
|
32
|
+
# given as parameter. Check Devise::Models::Authenticatable.valid_for_authentication?
|
|
24
33
|
# for more information.
|
|
25
34
|
#
|
|
26
35
|
# In case the resource can't be validated, it will fail with the given
|
|
27
36
|
# unauthenticated_message.
|
|
28
37
|
def validate(resource, &block)
|
|
29
|
-
unless resource
|
|
30
|
-
ActiveSupport::Deprecation.warn "an empty resource was given to #{self.class.name}#validate. " \
|
|
31
|
-
"Please ensure the resource is not nil", caller
|
|
32
|
-
end
|
|
33
|
-
|
|
34
38
|
result = resource && resource.valid_for_authentication?(&block)
|
|
35
39
|
|
|
36
|
-
case result
|
|
37
|
-
when Symbol, String
|
|
38
|
-
ActiveSupport::Deprecation.warn "valid_for_authentication? should return a boolean value"
|
|
39
|
-
fail!(result)
|
|
40
|
-
return false
|
|
41
|
-
end
|
|
42
|
-
|
|
43
40
|
if result
|
|
44
|
-
decorate(resource)
|
|
45
41
|
true
|
|
46
42
|
else
|
|
47
43
|
if resource
|
|
@@ -52,7 +48,7 @@ module Devise
|
|
|
52
48
|
end
|
|
53
49
|
|
|
54
50
|
# Get values from params and set in the resource.
|
|
55
|
-
def
|
|
51
|
+
def remember_me(resource)
|
|
56
52
|
resource.remember_me = remember_me? if resource.respond_to?(:remember_me=)
|
|
57
53
|
end
|
|
58
54
|
|
|
@@ -61,9 +57,9 @@ module Devise
|
|
|
61
57
|
valid_params? && Devise::TRUE_VALUES.include?(params_auth_hash[:remember_me])
|
|
62
58
|
end
|
|
63
59
|
|
|
64
|
-
# Check if this is
|
|
60
|
+
# Check if this is a valid strategy for http authentication by:
|
|
65
61
|
#
|
|
66
|
-
# * Validating if the model allows
|
|
62
|
+
# * Validating if the model allows http authentication;
|
|
67
63
|
# * If any of the authorization headers were sent;
|
|
68
64
|
# * If all authentication keys are present;
|
|
69
65
|
#
|
|
@@ -71,7 +67,7 @@ module Devise
|
|
|
71
67
|
http_authenticatable? && request.authorization && with_authentication_hash(:http_auth, http_auth_hash)
|
|
72
68
|
end
|
|
73
69
|
|
|
74
|
-
# Check if this is
|
|
70
|
+
# Check if this is a valid strategy for params authentication by:
|
|
75
71
|
#
|
|
76
72
|
# * Validating if the model allows params authentication;
|
|
77
73
|
# * If the request hits the sessions controller through POST;
|
|
@@ -114,14 +110,17 @@ module Devise
|
|
|
114
110
|
params_auth_hash.is_a?(Hash)
|
|
115
111
|
end
|
|
116
112
|
|
|
117
|
-
#
|
|
113
|
+
# Note: unlike `Model.valid_password?`, this method does not actually
|
|
114
|
+
# ensure that the password in the params matches the password stored in
|
|
115
|
+
# the database. It only checks if the password is *present*. Do not rely
|
|
116
|
+
# on this method for validating that a given password is correct.
|
|
118
117
|
def valid_password?
|
|
119
|
-
password.present?
|
|
118
|
+
password.present?
|
|
120
119
|
end
|
|
121
120
|
|
|
122
121
|
# Helper to decode credentials from HTTP.
|
|
123
122
|
def decode_credentials
|
|
124
|
-
return [] unless request.authorization && request.authorization =~ /^Basic (.*)/
|
|
123
|
+
return [] unless request.authorization && request.authorization =~ /^Basic (.*)/mi
|
|
125
124
|
Base64.decode64($1).split(/:/, 2)
|
|
126
125
|
end
|
|
127
126
|
|
|
@@ -1,17 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'devise/strategies/authenticatable'
|
|
2
4
|
|
|
3
5
|
module Devise
|
|
4
6
|
module Strategies
|
|
5
|
-
# Default strategy for signing in a user, based on
|
|
7
|
+
# Default strategy for signing in a user, based on their email and password in the database.
|
|
6
8
|
class DatabaseAuthenticatable < Authenticatable
|
|
7
9
|
def authenticate!
|
|
8
|
-
resource
|
|
9
|
-
|
|
10
|
+
resource = password.present? && mapping.to.find_for_database_authentication(authentication_hash)
|
|
11
|
+
hashed = false
|
|
10
12
|
|
|
11
|
-
if validate(resource){ resource.valid_password?(password) }
|
|
13
|
+
if validate(resource){ hashed = true; resource.valid_password?(password) }
|
|
14
|
+
remember_me(resource)
|
|
12
15
|
resource.after_database_authentication
|
|
13
16
|
success!(resource)
|
|
14
17
|
end
|
|
18
|
+
|
|
19
|
+
# In paranoid mode, hash the password even when a resource doesn't exist for the given authentication key.
|
|
20
|
+
# This is necessary to prevent enumeration attacks - e.g. the request is faster when a resource doesn't
|
|
21
|
+
# exist in the database if the password hashing algorithm is not called.
|
|
22
|
+
mapping.to.new.password = password if !hashed && Devise.paranoid
|
|
23
|
+
unless resource
|
|
24
|
+
Devise.paranoid ? fail(:invalid) : fail(:not_found_in_database)
|
|
25
|
+
end
|
|
15
26
|
end
|
|
16
27
|
end
|
|
17
28
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'devise/strategies/authenticatable'
|
|
2
4
|
|
|
3
5
|
module Devise
|
|
@@ -25,15 +27,25 @@ module Devise
|
|
|
25
27
|
end
|
|
26
28
|
|
|
27
29
|
if validate(resource)
|
|
30
|
+
remember_me(resource) if extend_remember_me?(resource)
|
|
31
|
+
resource.after_remembered
|
|
28
32
|
success!(resource)
|
|
29
33
|
end
|
|
30
34
|
end
|
|
31
35
|
|
|
36
|
+
# No need to clean up the CSRF when using rememberable.
|
|
37
|
+
# In fact, cleaning it up here would be a bug because
|
|
38
|
+
# rememberable is triggered on GET requests which means
|
|
39
|
+
# we would render a page on first access with all csrf
|
|
40
|
+
# tokens expired.
|
|
41
|
+
def clean_up_csrf?
|
|
42
|
+
false
|
|
43
|
+
end
|
|
44
|
+
|
|
32
45
|
private
|
|
33
46
|
|
|
34
|
-
def
|
|
35
|
-
|
|
36
|
-
resource.extend_remember_period = mapping.to.extend_remember_period if resource.respond_to?(:extend_remember_period=)
|
|
47
|
+
def extend_remember_me?(resource)
|
|
48
|
+
resource.respond_to?(:extend_remember_period) && resource.extend_remember_period
|
|
37
49
|
end
|
|
38
50
|
|
|
39
51
|
def remember_me?
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Devise
|
|
4
|
+
module Test
|
|
5
|
+
# `Devise::Test::ControllerHelpers` provides a facility to test controllers
|
|
6
|
+
# in isolation when using `ActionController::TestCase` allowing you to
|
|
7
|
+
# quickly sign_in or sign_out a user. Do not use
|
|
8
|
+
# `Devise::Test::ControllerHelpers` in integration tests.
|
|
9
|
+
#
|
|
10
|
+
# Examples
|
|
11
|
+
#
|
|
12
|
+
# class PostsTest < ActionController::TestCase
|
|
13
|
+
# include Devise::Test::ControllerHelpers
|
|
14
|
+
#
|
|
15
|
+
# test 'authenticated users can GET index' do
|
|
16
|
+
# sign_in users(:bob)
|
|
17
|
+
#
|
|
18
|
+
# get :index
|
|
19
|
+
# assert_response :success
|
|
20
|
+
# end
|
|
21
|
+
# end
|
|
22
|
+
#
|
|
23
|
+
# Important: you should not test Warden specific behavior (like callbacks)
|
|
24
|
+
# using `Devise::Test::ControllerHelpers` since it is a stub of the actual
|
|
25
|
+
# behavior. Such callbacks should be tested in your integration suite instead.
|
|
26
|
+
module ControllerHelpers
|
|
27
|
+
extend ActiveSupport::Concern
|
|
28
|
+
|
|
29
|
+
included do
|
|
30
|
+
setup :setup_controller_for_warden, :warden
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Override process to consider warden.
|
|
34
|
+
def process(*)
|
|
35
|
+
_catch_warden { super }
|
|
36
|
+
|
|
37
|
+
@response
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
ruby2_keywords(:process) if respond_to?(:ruby2_keywords, true)
|
|
41
|
+
|
|
42
|
+
# We need to set up the environment variables and the response in the controller.
|
|
43
|
+
def setup_controller_for_warden #:nodoc:
|
|
44
|
+
@request.env['action_controller.instance'] = @controller
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Quick access to Warden::Proxy.
|
|
48
|
+
def warden #:nodoc:
|
|
49
|
+
@request.env['warden'] ||= begin
|
|
50
|
+
manager = Warden::Manager.new(nil) do |config|
|
|
51
|
+
config.merge! Devise.warden_config
|
|
52
|
+
end
|
|
53
|
+
Warden::Proxy.new(@request.env, manager)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# sign_in a given resource by storing its keys in the session.
|
|
58
|
+
# This method bypass any warden authentication callback.
|
|
59
|
+
#
|
|
60
|
+
# * +resource+ - The resource that should be authenticated
|
|
61
|
+
# * +scope+ - An optional +Symbol+ with the scope where the resource
|
|
62
|
+
# should be signed in with.
|
|
63
|
+
# Examples:
|
|
64
|
+
#
|
|
65
|
+
# sign_in users(:alice)
|
|
66
|
+
# sign_in users(:alice), scope: :admin
|
|
67
|
+
def sign_in(resource, deprecated = nil, scope: nil)
|
|
68
|
+
if deprecated.present?
|
|
69
|
+
scope = resource
|
|
70
|
+
resource = deprecated
|
|
71
|
+
|
|
72
|
+
ActiveSupport::Deprecation.warn <<-DEPRECATION.strip_heredoc
|
|
73
|
+
[Devise] sign_in(:#{scope}, resource) on controller tests is deprecated and will be removed from Devise.
|
|
74
|
+
Please use sign_in(resource, scope: :#{scope}) instead.
|
|
75
|
+
DEPRECATION
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
scope ||= Devise::Mapping.find_scope!(resource)
|
|
79
|
+
|
|
80
|
+
warden.instance_variable_get(:@users).delete(scope)
|
|
81
|
+
warden.session_serializer.store(resource, scope)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Sign out a given resource or scope by calling logout on Warden.
|
|
85
|
+
# This method bypass any warden logout callback.
|
|
86
|
+
#
|
|
87
|
+
# Examples:
|
|
88
|
+
#
|
|
89
|
+
# sign_out :user # sign_out(scope)
|
|
90
|
+
# sign_out @user # sign_out(resource)
|
|
91
|
+
#
|
|
92
|
+
def sign_out(resource_or_scope)
|
|
93
|
+
scope = Devise::Mapping.find_scope!(resource_or_scope)
|
|
94
|
+
@controller.instance_variable_set(:"@current_#{scope}", nil)
|
|
95
|
+
user = warden.instance_variable_get(:@users).delete(scope)
|
|
96
|
+
warden.session_serializer.delete(scope, user)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
protected
|
|
100
|
+
|
|
101
|
+
# Catch warden continuations and handle like the middleware would.
|
|
102
|
+
# Returns nil when interrupted, otherwise the normal result of the block.
|
|
103
|
+
def _catch_warden(&block)
|
|
104
|
+
result = catch(:warden, &block)
|
|
105
|
+
|
|
106
|
+
env = @controller.request.env
|
|
107
|
+
|
|
108
|
+
result ||= {}
|
|
109
|
+
|
|
110
|
+
# Set the response. In production, the rack result is returned
|
|
111
|
+
# from Warden::Manager#call, which the following is modelled on.
|
|
112
|
+
case result
|
|
113
|
+
when Array
|
|
114
|
+
if result.first == 401 && intercept_401?(env) # does this happen during testing?
|
|
115
|
+
_process_unauthenticated(env)
|
|
116
|
+
else
|
|
117
|
+
result
|
|
118
|
+
end
|
|
119
|
+
when Hash
|
|
120
|
+
_process_unauthenticated(env, result)
|
|
121
|
+
else
|
|
122
|
+
result
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def _process_unauthenticated(env, options = {})
|
|
127
|
+
options[:action] ||= :unauthenticated
|
|
128
|
+
proxy = request.env['warden']
|
|
129
|
+
result = options[:result] || proxy.result
|
|
130
|
+
|
|
131
|
+
ret = case result
|
|
132
|
+
when :redirect
|
|
133
|
+
body = proxy.message || "You are being redirected to #{proxy.headers['Location']}"
|
|
134
|
+
[proxy.status, proxy.headers, [body]]
|
|
135
|
+
when :custom
|
|
136
|
+
proxy.custom_response
|
|
137
|
+
else
|
|
138
|
+
request.env["PATH_INFO"] = "/#{options[:action]}"
|
|
139
|
+
request.env["warden.options"] = options
|
|
140
|
+
Warden::Manager._run_callbacks(:before_failure, env, options)
|
|
141
|
+
|
|
142
|
+
status, headers, response = Devise.warden_config[:failure_app].call(env).to_a
|
|
143
|
+
@controller.response.headers.merge!(headers)
|
|
144
|
+
@controller.response.content_type = headers["Content-Type"] unless Rails::VERSION::MAJOR >= 5
|
|
145
|
+
@controller.status = status
|
|
146
|
+
@controller.response_body = response.body
|
|
147
|
+
nil # causes process return @response
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# ensure that the controller response is set up. In production, this is
|
|
151
|
+
# not necessary since warden returns the results to rack. However, at
|
|
152
|
+
# testing time, we want the response to be available to the testing
|
|
153
|
+
# framework to verify what would be returned to rack.
|
|
154
|
+
if ret.is_a?(Array)
|
|
155
|
+
status, headers, body = *ret
|
|
156
|
+
# ensure the controller response is set to our response.
|
|
157
|
+
@controller.response ||= @response
|
|
158
|
+
@response.status = status
|
|
159
|
+
@response.headers.merge!(headers)
|
|
160
|
+
@response.body = body
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
ret
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Devise
|
|
4
|
+
# Devise::Test::IntegrationHelpers is a helper module for facilitating
|
|
5
|
+
# authentication on Rails integration tests to bypass the required steps for
|
|
6
|
+
# signin in or signin out a record.
|
|
7
|
+
#
|
|
8
|
+
# Examples
|
|
9
|
+
#
|
|
10
|
+
# class PostsTest < ActionDispatch::IntegrationTest
|
|
11
|
+
# include Devise::Test::IntegrationHelpers
|
|
12
|
+
#
|
|
13
|
+
# test 'authenticated users can see posts' do
|
|
14
|
+
# sign_in users(:bob)
|
|
15
|
+
#
|
|
16
|
+
# get '/posts'
|
|
17
|
+
# assert_response :success
|
|
18
|
+
# end
|
|
19
|
+
# end
|
|
20
|
+
module Test
|
|
21
|
+
module IntegrationHelpers
|
|
22
|
+
def self.included(base)
|
|
23
|
+
base.class_eval do
|
|
24
|
+
include Warden::Test::Helpers
|
|
25
|
+
|
|
26
|
+
setup :setup_integration_for_devise
|
|
27
|
+
teardown :teardown_integration_for_devise
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Signs in a specific resource, mimicking a successful sign in
|
|
32
|
+
# operation through +Devise::SessionsController#create+.
|
|
33
|
+
#
|
|
34
|
+
# * +resource+ - The resource that should be authenticated
|
|
35
|
+
# * +scope+ - An optional +Symbol+ with the scope where the resource
|
|
36
|
+
# should be signed in with.
|
|
37
|
+
def sign_in(resource, scope: nil)
|
|
38
|
+
scope ||= Devise::Mapping.find_scope!(resource)
|
|
39
|
+
|
|
40
|
+
login_as(resource, scope: scope)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Signs out a specific scope from the session.
|
|
44
|
+
#
|
|
45
|
+
# * +resource_or_scope+ - The resource or scope that should be signed out.
|
|
46
|
+
def sign_out(resource_or_scope)
|
|
47
|
+
scope = Devise::Mapping.find_scope!(resource_or_scope)
|
|
48
|
+
|
|
49
|
+
logout scope
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
protected
|
|
53
|
+
|
|
54
|
+
def setup_integration_for_devise
|
|
55
|
+
Warden.test_mode!
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def teardown_integration_for_devise
|
|
59
|
+
Warden.test_reset!
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
data/lib/devise/test_helpers.rb
CHANGED
|
@@ -1,131 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Devise
|
|
2
|
-
# Devise::TestHelpers provides a facility to test controllers in isolation
|
|
3
|
-
# when using ActionController::TestCase allowing you to quickly sign_in or
|
|
4
|
-
# sign_out a user. Do not use Devise::TestHelpers in integration tests.
|
|
5
|
-
#
|
|
6
|
-
# Notice you should not test Warden specific behavior (like Warden callbacks)
|
|
7
|
-
# using Devise::TestHelpers since it is a stub of the actual behavior. Such
|
|
8
|
-
# callbacks should be tested in your integration suite instead.
|
|
9
4
|
module TestHelpers
|
|
10
5
|
def self.included(base)
|
|
11
6
|
base.class_eval do
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def process(*)
|
|
18
|
-
# Make sure we always return @response, a la ActionController::TestCase::Behaviour#process, even if warden interrupts
|
|
19
|
-
_catch_warden { super } || @response
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
# We need to setup the environment variables and the response in the controller.
|
|
23
|
-
def setup_controller_for_warden #:nodoc:
|
|
24
|
-
@request.env['action_controller.instance'] = @controller
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
# Quick access to Warden::Proxy.
|
|
28
|
-
def warden #:nodoc:
|
|
29
|
-
@warden ||= begin
|
|
30
|
-
manager = Warden::Manager.new(nil) do |config|
|
|
31
|
-
config.merge! Devise.warden_config
|
|
32
|
-
end
|
|
33
|
-
@request.env['warden'] = Warden::Proxy.new(@request.env, manager)
|
|
7
|
+
ActiveSupport::Deprecation.warn <<-DEPRECATION.strip_heredoc
|
|
8
|
+
[Devise] including `Devise::TestHelpers` is deprecated and will be removed from Devise.
|
|
9
|
+
For controller tests, please include `Devise::Test::ControllerHelpers` instead.
|
|
10
|
+
DEPRECATION
|
|
11
|
+
include Devise::Test::ControllerHelpers
|
|
34
12
|
end
|
|
35
13
|
end
|
|
36
|
-
|
|
37
|
-
# sign_in a given resource by storing its keys in the session.
|
|
38
|
-
# This method bypass any warden authentication callback.
|
|
39
|
-
#
|
|
40
|
-
# Examples:
|
|
41
|
-
#
|
|
42
|
-
# sign_in :user, @user # sign_in(scope, resource)
|
|
43
|
-
# sign_in @user # sign_in(resource)
|
|
44
|
-
#
|
|
45
|
-
def sign_in(resource_or_scope, resource=nil)
|
|
46
|
-
scope ||= Devise::Mapping.find_scope!(resource_or_scope)
|
|
47
|
-
resource ||= resource_or_scope
|
|
48
|
-
warden.instance_variable_get(:@users).delete(scope)
|
|
49
|
-
warden.session_serializer.store(resource, scope)
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
# Sign out a given resource or scope by calling logout on Warden.
|
|
53
|
-
# This method bypass any warden logout callback.
|
|
54
|
-
#
|
|
55
|
-
# Examples:
|
|
56
|
-
#
|
|
57
|
-
# sign_out :user # sign_out(scope)
|
|
58
|
-
# sign_out @user # sign_out(resource)
|
|
59
|
-
#
|
|
60
|
-
def sign_out(resource_or_scope)
|
|
61
|
-
scope = Devise::Mapping.find_scope!(resource_or_scope)
|
|
62
|
-
@controller.instance_variable_set(:"@current_#{scope}", nil)
|
|
63
|
-
user = warden.instance_variable_get(:@users).delete(scope)
|
|
64
|
-
warden.session_serializer.delete(scope, user)
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
protected
|
|
68
|
-
|
|
69
|
-
# Catch warden continuations and handle like the middleware would.
|
|
70
|
-
# Returns nil when interrupted, otherwise the normal result of the block.
|
|
71
|
-
def _catch_warden(&block)
|
|
72
|
-
result = catch(:warden, &block)
|
|
73
|
-
|
|
74
|
-
env = @controller.request.env
|
|
75
|
-
|
|
76
|
-
result ||= {}
|
|
77
|
-
|
|
78
|
-
# Set the response. In production, the rack result is returned
|
|
79
|
-
# from Warden::Manager#call, which the following is modelled on.
|
|
80
|
-
case result
|
|
81
|
-
when Array
|
|
82
|
-
if result.first == 401 && intercept_401?(env) # does this happen during testing?
|
|
83
|
-
_process_unauthenticated(env)
|
|
84
|
-
else
|
|
85
|
-
result
|
|
86
|
-
end
|
|
87
|
-
when Hash
|
|
88
|
-
_process_unauthenticated(env, result)
|
|
89
|
-
else
|
|
90
|
-
result
|
|
91
|
-
end
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
def _process_unauthenticated(env, options = {})
|
|
95
|
-
options[:action] ||= :unauthenticated
|
|
96
|
-
proxy = env['warden']
|
|
97
|
-
result = options[:result] || proxy.result
|
|
98
|
-
|
|
99
|
-
ret = case result
|
|
100
|
-
when :redirect
|
|
101
|
-
body = proxy.message || "You are being redirected to #{proxy.headers['Location']}"
|
|
102
|
-
[proxy.status, proxy.headers, [body]]
|
|
103
|
-
when :custom
|
|
104
|
-
proxy.custom_response
|
|
105
|
-
else
|
|
106
|
-
env["PATH_INFO"] = "/#{options[:action]}"
|
|
107
|
-
env["warden.options"] = options
|
|
108
|
-
Warden::Manager._run_callbacks(:before_failure, env, options)
|
|
109
|
-
|
|
110
|
-
status, headers, response = Devise.warden_config[:failure_app].call(env).to_a
|
|
111
|
-
@controller.send :render, :status => status, :text => response.body,
|
|
112
|
-
:content_type => headers["Content-Type"], :location => headers["Location"]
|
|
113
|
-
nil # causes process return @response
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
# ensure that the controller response is set up. In production, this is
|
|
117
|
-
# not necessary since warden returns the results to rack. However, at
|
|
118
|
-
# testing time, we want the response to be available to the testing
|
|
119
|
-
# framework to verify what would be returned to rack.
|
|
120
|
-
if ret.is_a?(Array)
|
|
121
|
-
# ensure the controller response is set to our response.
|
|
122
|
-
@controller.response ||= @response
|
|
123
|
-
@response.status = ret.first
|
|
124
|
-
@response.headers = ret.second
|
|
125
|
-
@response.body = ret.third
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
ret
|
|
129
|
-
end
|
|
130
14
|
end
|
|
131
15
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require "active_support/core_ext/module/delegation"
|
|
2
4
|
|
|
3
5
|
module Devise
|
|
@@ -6,9 +8,9 @@ module Devise
|
|
|
6
8
|
|
|
7
9
|
class << self
|
|
8
10
|
attr_reader :instance
|
|
9
|
-
delegate :time_ago_in_words, :
|
|
11
|
+
delegate :time_ago_in_words, to: :instance
|
|
10
12
|
end
|
|
11
13
|
|
|
12
14
|
@instance = new
|
|
13
15
|
end
|
|
14
|
-
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'openssl'
|
|
4
|
+
|
|
5
|
+
module Devise
|
|
6
|
+
class TokenGenerator
|
|
7
|
+
def initialize(key_generator, digest = "SHA256")
|
|
8
|
+
@key_generator = key_generator
|
|
9
|
+
@digest = digest
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def digest(klass, column, value)
|
|
13
|
+
value.present? && OpenSSL::HMAC.hexdigest(@digest, key_for(column), value.to_s)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def generate(klass, column)
|
|
17
|
+
key = key_for(column)
|
|
18
|
+
|
|
19
|
+
loop do
|
|
20
|
+
raw = Devise.friendly_token
|
|
21
|
+
enc = OpenSSL::HMAC.hexdigest(@digest, key, raw)
|
|
22
|
+
break [raw, enc] unless klass.to_adapter.find_first({ column => enc })
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def key_for(column)
|
|
29
|
+
@key_generator.generate_key("Devise #{column}")
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
data/lib/devise/version.rb
CHANGED