devise 3.4.1 → 3.5.10
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 +28 -19
- data/CHANGELOG.md +193 -104
- data/CODE_OF_CONDUCT.md +22 -0
- data/CONTRIBUTING.md +2 -0
- data/Gemfile +3 -2
- data/Gemfile.lock +90 -95
- data/MIT-LICENSE +1 -1
- data/README.md +55 -34
- data/Rakefile +2 -1
- data/app/controllers/devise/confirmations_controller.rb +4 -0
- data/app/controllers/devise/omniauth_callbacks_controller.rb +4 -0
- data/app/controllers/devise/passwords_controller.rb +14 -4
- data/app/controllers/devise/registrations_controller.rb +10 -11
- data/app/controllers/devise/sessions_controller.rb +7 -2
- data/app/controllers/devise/unlocks_controller.rb +3 -0
- data/app/controllers/devise_controller.rb +34 -18
- data/app/mailers/devise/mailer.rb +4 -0
- data/app/views/devise/confirmations/new.html.erb +1 -1
- data/app/views/devise/mailer/password_change.html.erb +3 -0
- data/app/views/devise/passwords/edit.html.erb +3 -0
- data/app/views/devise/registrations/new.html.erb +1 -1
- data/app/views/devise/shared/_links.html.erb +1 -1
- data/config/locales/en.yml +2 -0
- data/devise.gemspec +0 -2
- data/gemfiles/Gemfile.rails-3.2-stable.lock +52 -49
- data/gemfiles/Gemfile.rails-4.0-stable +1 -0
- data/gemfiles/Gemfile.rails-4.0-stable.lock +61 -60
- data/gemfiles/Gemfile.rails-4.1-stable +1 -0
- data/gemfiles/Gemfile.rails-4.1-stable.lock +66 -65
- data/gemfiles/Gemfile.rails-4.2-stable +30 -0
- data/gemfiles/Gemfile.rails-4.2-stable.lock +193 -0
- data/lib/devise/controllers/helpers.rb +12 -6
- data/lib/devise/controllers/rememberable.rb +9 -2
- data/lib/devise/controllers/sign_in_out.rb +2 -8
- data/lib/devise/controllers/store_location.rb +3 -1
- data/lib/devise/controllers/url_helpers.rb +7 -9
- data/lib/devise/encryptor.rb +22 -0
- data/lib/devise/failure_app.rb +48 -13
- data/lib/devise/hooks/timeoutable.rb +5 -7
- data/lib/devise/mapping.rb +1 -0
- data/lib/devise/models/authenticatable.rb +20 -26
- data/lib/devise/models/confirmable.rb +51 -17
- data/lib/devise/models/database_authenticatable.rb +17 -11
- data/lib/devise/models/lockable.rb +5 -1
- data/lib/devise/models/recoverable.rb +23 -15
- data/lib/devise/models/rememberable.rb +56 -22
- data/lib/devise/models/timeoutable.rb +0 -6
- data/lib/devise/models/trackable.rb +1 -2
- data/lib/devise/models/validatable.rb +3 -3
- data/lib/devise/models.rb +1 -1
- data/lib/devise/rails/routes.rb +27 -18
- data/lib/devise/rails.rb +1 -1
- data/lib/devise/strategies/authenticatable.rb +7 -4
- data/lib/devise/strategies/database_authenticatable.rb +1 -1
- data/lib/devise/strategies/rememberable.rb +13 -6
- data/lib/devise/test_helpers.rb +2 -2
- data/lib/devise/version.rb +1 -1
- data/lib/devise.rb +37 -36
- data/lib/generators/active_record/templates/migration.rb +1 -1
- data/lib/generators/active_record/templates/migration_existing.rb +1 -1
- data/lib/generators/devise/views_generator.rb +14 -3
- data/lib/generators/templates/controllers/README +2 -2
- data/lib/generators/templates/controllers/omniauth_callbacks_controller.rb +1 -1
- data/lib/generators/templates/controllers/registrations_controller.rb +2 -2
- data/lib/generators/templates/controllers/sessions_controller.rb +1 -1
- data/lib/generators/templates/devise.rb +17 -11
- data/lib/generators/templates/markerb/confirmation_instructions.markerb +1 -1
- 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/passwords/edit.html.erb +1 -1
- data/lib/generators/templates/simple_form_for/registrations/new.html.erb +1 -1
- data/test/controllers/custom_registrations_controller_test.rb +6 -1
- data/test/controllers/helper_methods_test.rb +21 -0
- data/test/controllers/helpers_test.rb +5 -0
- data/test/controllers/inherited_controller_i18n_messages_test.rb +51 -0
- data/test/controllers/internal_helpers_test.rb +4 -4
- data/test/controllers/load_hooks_controller_test.rb +19 -0
- data/test/controllers/passwords_controller_test.rb +1 -1
- data/test/controllers/sessions_controller_test.rb +3 -3
- data/test/devise_test.rb +3 -3
- data/test/failure_app_test.rb +40 -0
- data/test/generators/views_generator_test.rb +7 -0
- data/test/integration/database_authenticatable_test.rb +11 -0
- data/test/integration/omniauthable_test.rb +12 -10
- data/test/integration/recoverable_test.rb +13 -0
- data/test/integration/rememberable_test.rb +50 -3
- data/test/integration/timeoutable_test.rb +13 -18
- data/test/mailers/confirmation_instructions_test.rb +1 -1
- data/test/mapping_test.rb +6 -0
- data/test/models/confirmable_test.rb +93 -37
- data/test/models/database_authenticatable_test.rb +20 -0
- data/test/models/lockable_test.rb +29 -7
- data/test/models/recoverable_test.rb +62 -7
- data/test/models/rememberable_test.rb +68 -97
- data/test/models/validatable_test.rb +5 -5
- data/test/models_test.rb +15 -6
- data/test/rails_app/app/active_record/user_without_email.rb +8 -0
- data/test/rails_app/app/controllers/admins_controller.rb +0 -5
- data/test/rails_app/app/controllers/custom/registrations_controller.rb +10 -0
- data/test/rails_app/app/mongoid/user_without_email.rb +33 -0
- data/test/rails_app/config/application.rb +1 -1
- data/test/rails_app/config/environments/production.rb +6 -2
- data/test/rails_app/config/environments/test.rb +7 -2
- data/test/rails_app/config/initializers/devise.rb +12 -15
- data/test/rails_app/config/routes.rb +6 -3
- data/test/rails_app/lib/shared_user.rb +1 -1
- data/test/rails_app/lib/shared_user_without_email.rb +26 -0
- data/test/rails_test.rb +9 -0
- data/test/support/helpers.rb +4 -0
- data/test/support/integration.rb +2 -2
- data/test/test_helpers_test.rb +22 -7
- data/test/test_models.rb +2 -2
- data/test/time_helpers.rb +137 -0
- metadata +26 -4
@@ -8,15 +8,13 @@ module Devise
|
|
8
8
|
# Recoverable adds the following options to devise_for:
|
9
9
|
#
|
10
10
|
# * +reset_password_keys+: the keys you want to use when recovering the password for an account
|
11
|
+
# * +reset_password_within+: the time period within which the password must be reset or the token expires.
|
12
|
+
# * +sign_in_after_reset_password+: whether or not to sign in the user automatically after a password reset.
|
11
13
|
#
|
12
14
|
# == Examples
|
13
15
|
#
|
14
16
|
# # resets the user password and save the record, true if valid passwords are given, otherwise false
|
15
|
-
# User.find(1).reset_password
|
16
|
-
#
|
17
|
-
# # only resets the user password, without saving the record
|
18
|
-
# user = User.find(1)
|
19
|
-
# user.reset_password('password123', 'password123')
|
17
|
+
# User.find(1).reset_password('password123', 'password123')
|
20
18
|
#
|
21
19
|
# # creates a new token and send it with instructions about how to reset the password
|
22
20
|
# User.find(1).send_reset_password_instructions
|
@@ -28,20 +26,33 @@ module Devise
|
|
28
26
|
[:reset_password_sent_at, :reset_password_token]
|
29
27
|
end
|
30
28
|
|
29
|
+
included do
|
30
|
+
before_update do
|
31
|
+
if (respond_to?(:email_changed?) && email_changed?) || encrypted_password_changed?
|
32
|
+
clear_reset_password_token
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
31
37
|
# Update password saving the record and clearing token. Returns true if
|
32
38
|
# the passwords are valid and the record was saved, false otherwise.
|
33
|
-
def reset_password
|
39
|
+
def reset_password(new_password, new_password_confirmation)
|
34
40
|
self.password = new_password
|
35
41
|
self.password_confirmation = new_password_confirmation
|
36
42
|
|
37
|
-
if valid?
|
38
|
-
|
43
|
+
if respond_to?(:after_password_reset) && valid?
|
44
|
+
ActiveSupport::Deprecation.warn "after_password_reset is deprecated"
|
39
45
|
after_password_reset
|
40
46
|
end
|
41
47
|
|
42
48
|
save
|
43
49
|
end
|
44
50
|
|
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
|
+
|
45
56
|
# Resets reset password token and send reset password instructions by email.
|
46
57
|
# Returns the token sent in the e-mail.
|
47
58
|
def send_reset_password_instructions
|
@@ -72,7 +83,7 @@ module Devise
|
|
72
83
|
# reset_password_period_valid? # will always return false
|
73
84
|
#
|
74
85
|
def reset_password_period_valid?
|
75
|
-
reset_password_sent_at && reset_password_sent_at.utc >= self.class.reset_password_within.ago
|
86
|
+
reset_password_sent_at && reset_password_sent_at.utc >= self.class.reset_password_within.ago.utc
|
76
87
|
end
|
77
88
|
|
78
89
|
protected
|
@@ -83,9 +94,6 @@ module Devise
|
|
83
94
|
self.reset_password_sent_at = nil
|
84
95
|
end
|
85
96
|
|
86
|
-
def after_password_reset
|
87
|
-
end
|
88
|
-
|
89
97
|
def set_reset_password_token
|
90
98
|
raw, enc = Devise.token_generator.generate(self.class, :reset_password_token)
|
91
99
|
|
@@ -130,17 +138,17 @@ module Devise
|
|
130
138
|
|
131
139
|
if recoverable.persisted?
|
132
140
|
if recoverable.reset_password_period_valid?
|
133
|
-
recoverable.reset_password
|
141
|
+
recoverable.reset_password(attributes[:password], attributes[:password_confirmation])
|
134
142
|
else
|
135
143
|
recoverable.errors.add(:reset_password_token, :expired)
|
136
144
|
end
|
137
145
|
end
|
138
146
|
|
139
|
-
recoverable.reset_password_token = original_token
|
147
|
+
recoverable.reset_password_token = original_token if recoverable.reset_password_token.present?
|
140
148
|
recoverable
|
141
149
|
end
|
142
150
|
|
143
|
-
Devise::Models.config(self, :reset_password_keys, :reset_password_within)
|
151
|
+
Devise::Models.config(self, :reset_password_keys, :reset_password_within, :sign_in_after_reset_password)
|
144
152
|
end
|
145
153
|
end
|
146
154
|
end
|
@@ -39,17 +39,17 @@ module Devise
|
|
39
39
|
module Rememberable
|
40
40
|
extend ActiveSupport::Concern
|
41
41
|
|
42
|
-
attr_accessor :remember_me
|
42
|
+
attr_accessor :remember_me
|
43
43
|
|
44
44
|
def self.required_fields(klass)
|
45
45
|
[:remember_created_at]
|
46
46
|
end
|
47
47
|
|
48
|
-
#
|
49
|
-
#
|
50
|
-
def remember_me!(
|
51
|
-
self.remember_token
|
52
|
-
self.remember_created_at
|
48
|
+
# TODO: We were used to receive a extend period argument but we no longer do.
|
49
|
+
# Remove this for Devise 4.0.
|
50
|
+
def remember_me!(*)
|
51
|
+
self.remember_token ||= self.class.remember_token if respond_to?(:remember_token)
|
52
|
+
self.remember_created_at ||= Time.now.utc
|
53
53
|
save(validate: false) if self.changed?
|
54
54
|
end
|
55
55
|
|
@@ -57,25 +57,28 @@ module Devise
|
|
57
57
|
# it exists), and save the record without validations.
|
58
58
|
def forget_me!
|
59
59
|
return unless persisted?
|
60
|
-
self.remember_token = nil if respond_to?(:remember_token
|
60
|
+
self.remember_token = nil if respond_to?(:remember_token)
|
61
61
|
self.remember_created_at = nil if self.class.expire_all_remember_me_on_sign_out
|
62
62
|
save(validate: false)
|
63
63
|
end
|
64
64
|
|
65
65
|
# Remember token should be expired if expiration time not overpass now.
|
66
66
|
def remember_expired?
|
67
|
-
remember_created_at.nil?
|
67
|
+
remember_created_at.nil?
|
68
68
|
end
|
69
69
|
|
70
|
-
# Remember token expires at created time + remember_for configuration
|
71
70
|
def remember_expires_at
|
72
|
-
|
71
|
+
self.class.remember_for.from_now
|
72
|
+
end
|
73
|
+
|
74
|
+
def extend_remember_period
|
75
|
+
self.class.extend_remember_period
|
73
76
|
end
|
74
77
|
|
75
78
|
def rememberable_value
|
76
79
|
if respond_to?(:remember_token)
|
77
80
|
remember_token
|
78
|
-
elsif respond_to?(:authenticatable_salt) && (salt = authenticatable_salt)
|
81
|
+
elsif respond_to?(:authenticatable_salt) && (salt = authenticatable_salt.presence)
|
79
82
|
salt
|
80
83
|
else
|
81
84
|
raise "authenticable_salt returned nil for the #{self.class.name} model. " \
|
@@ -89,29 +92,60 @@ module Devise
|
|
89
92
|
self.class.rememberable_options
|
90
93
|
end
|
91
94
|
|
92
|
-
|
95
|
+
# A callback initiated after successfully being remembered. This can be
|
96
|
+
# used to insert your own logic that is only run after the user is
|
97
|
+
# remembered.
|
98
|
+
#
|
99
|
+
# Example:
|
100
|
+
#
|
101
|
+
# def after_remembered
|
102
|
+
# self.update_attribute(:invite_code, nil)
|
103
|
+
# end
|
104
|
+
#
|
105
|
+
def after_remembered
|
106
|
+
end
|
107
|
+
|
108
|
+
def remember_me?(token, generated_at)
|
109
|
+
# TODO: Normalize the JSON type coercion along with the Timeoutable hook
|
110
|
+
# in a single place https://github.com/plataformatec/devise/blob/ffe9d6d406e79108cf32a2c6a1d0b3828849c40b/lib/devise/hooks/timeoutable.rb#L14-L18
|
111
|
+
if generated_at.is_a?(String)
|
112
|
+
generated_at = time_from_json(generated_at)
|
113
|
+
end
|
93
114
|
|
94
|
-
|
95
|
-
|
115
|
+
# The token is only valid if:
|
116
|
+
# 1. we have a date
|
117
|
+
# 2. the current time does not pass the expiry period
|
118
|
+
# 3. the record has a remember_created_at date
|
119
|
+
# 4. the token date is bigger than the remember_created_at
|
120
|
+
# 5. the token matches
|
121
|
+
generated_at.is_a?(Time) &&
|
122
|
+
(self.class.remember_for.ago < generated_at) &&
|
123
|
+
(generated_at > (remember_created_at || Time.now).utc) &&
|
124
|
+
Devise.secure_compare(rememberable_value, token)
|
96
125
|
end
|
97
126
|
|
98
|
-
|
99
|
-
|
100
|
-
def
|
101
|
-
|
127
|
+
private
|
128
|
+
|
129
|
+
def time_from_json(value)
|
130
|
+
if value =~ /\A\d+\.\d+\Z/
|
131
|
+
Time.at(value.to_f)
|
132
|
+
else
|
133
|
+
Time.parse(value) rescue nil
|
134
|
+
end
|
102
135
|
end
|
103
136
|
|
104
137
|
module ClassMethods
|
105
138
|
# Create the cookie key using the record id and remember_token
|
106
139
|
def serialize_into_cookie(record)
|
107
|
-
[record.to_key, record.rememberable_value]
|
140
|
+
[record.to_key, record.rememberable_value, Time.now.utc.to_f.to_s]
|
108
141
|
end
|
109
142
|
|
110
143
|
# Recreate the user based on the stored cookie
|
111
|
-
def serialize_from_cookie(
|
144
|
+
def serialize_from_cookie(*args)
|
145
|
+
id, token, generated_at = *args
|
146
|
+
|
112
147
|
record = to_adapter.get(id)
|
113
|
-
record if record &&
|
114
|
-
Devise.secure_compare(record.rememberable_value, remember_token)
|
148
|
+
record if record && record.remember_me?(token, generated_at)
|
115
149
|
end
|
116
150
|
|
117
151
|
# Generate a token checking if one does not already exist in the database.
|
@@ -26,7 +26,6 @@ module Devise
|
|
26
26
|
|
27
27
|
# Checks whether the user session has expired based on configured time.
|
28
28
|
def timedout?(last_access)
|
29
|
-
return false if remember_exists_and_not_expired?
|
30
29
|
!timeout_in.nil? && last_access && last_access <= timeout_in.ago
|
31
30
|
end
|
32
31
|
|
@@ -36,11 +35,6 @@ module Devise
|
|
36
35
|
|
37
36
|
private
|
38
37
|
|
39
|
-
def remember_exists_and_not_expired?
|
40
|
-
return false unless respond_to?(:remember_created_at) && respond_to?(:remember_expired?)
|
41
|
-
remember_created_at && !remember_expired?
|
42
|
-
end
|
43
|
-
|
44
38
|
module ClassMethods
|
45
39
|
Devise::Models.config(self, :timeout_in)
|
46
40
|
end
|
@@ -30,8 +30,7 @@ module Devise
|
|
30
30
|
|
31
31
|
def update_tracked_fields!(request)
|
32
32
|
update_tracked_fields(request)
|
33
|
-
save(validate: false)
|
34
|
-
"Please make sure a model using trackable can be saved at sign in."
|
33
|
+
save(validate: false)
|
35
34
|
end
|
36
35
|
end
|
37
36
|
end
|
@@ -10,12 +10,12 @@ module Devise
|
|
10
10
|
# Validatable adds the following options to devise_for:
|
11
11
|
#
|
12
12
|
# * +email_regexp+: the regular expression used to validate e-mails;
|
13
|
-
# * +password_length+: a range expressing password length. Defaults to 8..
|
13
|
+
# * +password_length+: a range expressing password length. Defaults to 8..72.
|
14
14
|
#
|
15
15
|
module Validatable
|
16
16
|
# All validations used by this module.
|
17
|
-
VALIDATIONS = [
|
18
|
-
|
17
|
+
VALIDATIONS = [:validates_presence_of, :validates_uniqueness_of, :validates_format_of,
|
18
|
+
:validates_confirmation_of, :validates_length_of].freeze
|
19
19
|
|
20
20
|
def self.required_fields(klass)
|
21
21
|
[]
|
data/lib/devise/models.rb
CHANGED
@@ -12,7 +12,7 @@ module Devise
|
|
12
12
|
|
13
13
|
# Creates configuration values for Devise and for the given module.
|
14
14
|
#
|
15
|
-
# Devise::Models.config(Devise::
|
15
|
+
# Devise::Models.config(Devise::DatabaseAuthenticatable, :stretches)
|
16
16
|
#
|
17
17
|
# The line above creates:
|
18
18
|
#
|
data/lib/devise/rails/routes.rb
CHANGED
@@ -94,10 +94,24 @@ module ActionDispatch::Routing
|
|
94
94
|
#
|
95
95
|
# devise_for :users, path: 'accounts'
|
96
96
|
#
|
97
|
-
# * singular: setup the singular name for the given resource. This is used as the
|
98
|
-
#
|
97
|
+
# * singular: setup the singular name for the given resource. This is used as the helper methods
|
98
|
+
# names in controller ("authenticate_#{singular}!", "#{singular}_signed_in?", "current_#{singular}"
|
99
|
+
# and "#{singular}_session"), as the scope name in routes and as the scope given to warden.
|
99
100
|
#
|
100
|
-
# devise_for :
|
101
|
+
# devise_for :admins, singular: :manager
|
102
|
+
#
|
103
|
+
# devise_scope :manager do
|
104
|
+
# ...
|
105
|
+
# end
|
106
|
+
#
|
107
|
+
# class ManagerController < ApplicationController
|
108
|
+
# before_filter authenticate_manager!
|
109
|
+
#
|
110
|
+
# def show
|
111
|
+
# @manager = current_manager
|
112
|
+
# ...
|
113
|
+
# end
|
114
|
+
# end
|
101
115
|
#
|
102
116
|
# * path_names: configure different path names to overwrite defaults :sign_in, :sign_out, :sign_up,
|
103
117
|
# :password, :confirmation, :unlock.
|
@@ -119,7 +133,7 @@ module ActionDispatch::Routing
|
|
119
133
|
# * sign_out_via: the HTTP method(s) accepted for the :sign_out action (default: :get),
|
120
134
|
# if you wish to restrict this to accept only :post or :delete requests you should do:
|
121
135
|
#
|
122
|
-
# devise_for :users, sign_out_via: [
|
136
|
+
# devise_for :users, sign_out_via: [:post, :delete]
|
123
137
|
#
|
124
138
|
# You need to make sure that your sign_out controls trigger a request with a matching HTTP method.
|
125
139
|
#
|
@@ -402,21 +416,16 @@ module ActionDispatch::Routing
|
|
402
416
|
def devise_omniauth_callback(mapping, controllers) #:nodoc:
|
403
417
|
if mapping.fullpath =~ /:[a-zA-Z_]/
|
404
418
|
raise <<-ERROR
|
405
|
-
Devise does not support scoping
|
419
|
+
Devise does not support scoping OmniAuth callbacks under a dynamic segment
|
406
420
|
and you have set #{mapping.fullpath.inspect}. You can work around by passing
|
407
|
-
`skip: :omniauth_callbacks`
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
match "/users/auth/:action/callback",
|
416
|
-
constraints: { action: /google|facebook/ },
|
417
|
-
to: "devise/omniauth_callbacks",
|
418
|
-
as: :omniauth_callback,
|
419
|
-
via: [:get, :post]
|
421
|
+
`skip: :omniauth_callbacks` to the `devise_for` call and extract omniauth
|
422
|
+
options to another `devise_for` call outside the scope. Here is an example:
|
423
|
+
|
424
|
+
devise_for :users, only: :omniauth_callbacks, controllers: {omniauth_callbacks: 'users/omniauth_callbacks'}
|
425
|
+
|
426
|
+
scope '/(:locale)', locale: /ru|en/ do
|
427
|
+
devise_for :users, skip: :omniauth_callbacks
|
428
|
+
end
|
420
429
|
ERROR
|
421
430
|
end
|
422
431
|
|
data/lib/devise/rails.rb
CHANGED
@@ -17,7 +17,7 @@ module Devise
|
|
17
17
|
Devise.include_helpers(Devise::Controllers)
|
18
18
|
end
|
19
19
|
|
20
|
-
initializer "devise.omniauth" do |app|
|
20
|
+
initializer "devise.omniauth", after: :load_config_initializers, before: :build_middleware_stack do |app|
|
21
21
|
Devise.omniauth_configs.each do |provider, config|
|
22
22
|
app.middleware.use config.strategy_class, *config.args do |strategy|
|
23
23
|
config.strategy = strategy
|
@@ -27,7 +27,7 @@ module Devise
|
|
27
27
|
|
28
28
|
# Receives a resource and check if it is valid by calling valid_for_authentication?
|
29
29
|
# An optional block that will be triggered while validating can be optionally
|
30
|
-
# given as parameter. Check Devise::Models::
|
30
|
+
# given as parameter. Check Devise::Models::Authenticatable.valid_for_authentication?
|
31
31
|
# for more information.
|
32
32
|
#
|
33
33
|
# In case the resource can't be validated, it will fail with the given
|
@@ -57,7 +57,7 @@ module Devise
|
|
57
57
|
|
58
58
|
# Check if this is a valid strategy for http authentication by:
|
59
59
|
#
|
60
|
-
# * Validating if the model allows
|
60
|
+
# * Validating if the model allows http authentication;
|
61
61
|
# * If any of the authorization headers were sent;
|
62
62
|
# * If all authentication keys are present;
|
63
63
|
#
|
@@ -108,14 +108,17 @@ module Devise
|
|
108
108
|
params_auth_hash.is_a?(Hash)
|
109
109
|
end
|
110
110
|
|
111
|
-
#
|
111
|
+
# Note: unlike `Model.valid_password?`, this method does not actually
|
112
|
+
# ensure that the password in the params matches the password stored in
|
113
|
+
# the database. It only checks if the password is *present*. Do not rely
|
114
|
+
# on this method for validating that a given password is correct.
|
112
115
|
def valid_password?
|
113
116
|
password.present?
|
114
117
|
end
|
115
118
|
|
116
119
|
# Helper to decode credentials from HTTP.
|
117
120
|
def decode_credentials
|
118
|
-
return [] unless request.authorization && request.authorization =~ /^Basic (.*)/
|
121
|
+
return [] unless request.authorization && request.authorization =~ /^Basic (.*)/mi
|
119
122
|
Base64.decode64($1).split(/:/, 2)
|
120
123
|
end
|
121
124
|
|
@@ -5,7 +5,7 @@ module Devise
|
|
5
5
|
# Default strategy for signing in a user, based on their email and password in the database.
|
6
6
|
class DatabaseAuthenticatable < Authenticatable
|
7
7
|
def authenticate!
|
8
|
-
resource =
|
8
|
+
resource = password.present? && mapping.to.find_for_database_authentication(authentication_hash)
|
9
9
|
encrypted = false
|
10
10
|
|
11
11
|
if validate(resource){ encrypted = true; resource.valid_password?(password) }
|
@@ -25,18 +25,25 @@ module Devise
|
|
25
25
|
end
|
26
26
|
|
27
27
|
if validate(resource)
|
28
|
-
remember_me(resource)
|
29
|
-
|
28
|
+
remember_me(resource) if extend_remember_me?(resource)
|
29
|
+
resource.after_remembered
|
30
30
|
success!(resource)
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
+
# No need to clean up the CSRF when using rememberable.
|
35
|
+
# In fact, cleaning it up here would be a bug because
|
36
|
+
# rememberable is triggered on GET requests which means
|
37
|
+
# we would render a page on first access with all csrf
|
38
|
+
# tokens expired.
|
39
|
+
def clean_up_csrf?
|
40
|
+
false
|
41
|
+
end
|
42
|
+
|
34
43
|
private
|
35
44
|
|
36
|
-
def
|
37
|
-
|
38
|
-
resource.extend_remember_period = mapping.to.extend_remember_period
|
39
|
-
end
|
45
|
+
def extend_remember_me?(resource)
|
46
|
+
resource.respond_to?(:extend_remember_period) && resource.extend_remember_period
|
40
47
|
end
|
41
48
|
|
42
49
|
def remember_me?
|
data/lib/devise/test_helpers.rb
CHANGED
@@ -26,11 +26,11 @@ module Devise
|
|
26
26
|
|
27
27
|
# Quick access to Warden::Proxy.
|
28
28
|
def warden #:nodoc:
|
29
|
-
@warden ||= begin
|
29
|
+
@request.env['warden'] ||= begin
|
30
30
|
manager = Warden::Manager.new(nil) do |config|
|
31
31
|
config.merge! Devise.warden_config
|
32
32
|
end
|
33
|
-
|
33
|
+
Warden::Proxy.new(@request.env, manager)
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
data/lib/devise/version.rb
CHANGED
data/lib/devise.rb
CHANGED
@@ -8,6 +8,7 @@ require 'responders'
|
|
8
8
|
|
9
9
|
module Devise
|
10
10
|
autoload :Delegator, 'devise/delegator'
|
11
|
+
autoload :Encryptor, 'devise/encryptor'
|
11
12
|
autoload :FailureApp, 'devise/failure_app'
|
12
13
|
autoload :OmniAuth, 'devise/omniauth'
|
13
14
|
autoload :ParameterFilter, 'devise/parameter_filter'
|
@@ -57,22 +58,6 @@ module Devise
|
|
57
58
|
mattr_accessor :secret_key
|
58
59
|
@@secret_key = nil
|
59
60
|
|
60
|
-
[ :allow_insecure_token_lookup,
|
61
|
-
:allow_insecure_sign_in_after_confirmation,
|
62
|
-
:token_authentication_key ].each do |method|
|
63
|
-
class_eval <<-RUBY
|
64
|
-
def self.#{method}
|
65
|
-
ActiveSupport::Deprecation.warn "Devise.#{method} is deprecated " \
|
66
|
-
"and has no effect"
|
67
|
-
end
|
68
|
-
|
69
|
-
def self.#{method}=(val)
|
70
|
-
ActiveSupport::Deprecation.warn "Devise.#{method}= is deprecated " \
|
71
|
-
"and has no effect"
|
72
|
-
end
|
73
|
-
RUBY
|
74
|
-
end
|
75
|
-
|
76
61
|
# Custom domain or key for cookies. Not set by default
|
77
62
|
mattr_accessor :rememberable_options
|
78
63
|
@@rememberable_options = {}
|
@@ -87,7 +72,7 @@ module Devise
|
|
87
72
|
|
88
73
|
# Keys used when authenticating a user.
|
89
74
|
mattr_accessor :authentication_keys
|
90
|
-
@@authentication_keys = [
|
75
|
+
@@authentication_keys = [:email]
|
91
76
|
|
92
77
|
# Request keys used when authenticating a user.
|
93
78
|
mattr_accessor :request_keys
|
@@ -95,7 +80,7 @@ module Devise
|
|
95
80
|
|
96
81
|
# Keys that should be case-insensitive.
|
97
82
|
mattr_accessor :case_insensitive_keys
|
98
|
-
@@case_insensitive_keys = [
|
83
|
+
@@case_insensitive_keys = [:email]
|
99
84
|
|
100
85
|
# Keys that should have whitespace stripped.
|
101
86
|
mattr_accessor :strip_whitespace_keys
|
@@ -121,7 +106,7 @@ module Devise
|
|
121
106
|
# an one (and only one) @ exists in the given string. This is mainly
|
122
107
|
# to give user feedback and not to assert the e-mail validity.
|
123
108
|
mattr_accessor :email_regexp
|
124
|
-
@@email_regexp = /\A[^@\s]+@([^@\s]+\.)+[^@\
|
109
|
+
@@email_regexp = /\A[^@\s]+@([^@\s]+\.)+[^@\W]+\z/
|
125
110
|
|
126
111
|
# Range validation for password length
|
127
112
|
mattr_accessor :password_length
|
@@ -150,7 +135,7 @@ module Devise
|
|
150
135
|
|
151
136
|
# Defines which key will be used when confirming an account.
|
152
137
|
mattr_accessor :confirmation_keys
|
153
|
-
@@confirmation_keys = [
|
138
|
+
@@confirmation_keys = [:email]
|
154
139
|
|
155
140
|
# Defines if email should be reconfirmable.
|
156
141
|
# False by default for backwards compatibility.
|
@@ -161,14 +146,14 @@ module Devise
|
|
161
146
|
mattr_accessor :timeout_in
|
162
147
|
@@timeout_in = 30.minutes
|
163
148
|
|
164
|
-
# Authentication token expiration on timeout
|
165
|
-
mattr_accessor :expire_auth_token_on_timeout
|
166
|
-
@@expire_auth_token_on_timeout = false
|
167
|
-
|
168
149
|
# Used to encrypt password. Please generate one with rake secret.
|
169
150
|
mattr_accessor :pepper
|
170
151
|
@@pepper = nil
|
171
152
|
|
153
|
+
# Used to enable sending notification to user when their password is changed
|
154
|
+
mattr_accessor :send_password_change_notification
|
155
|
+
@@send_password_change_notification = false
|
156
|
+
|
172
157
|
# Scoped views. Since it relies on fallbacks to render default views, it's
|
173
158
|
# turned off by default.
|
174
159
|
mattr_accessor :scoped_views
|
@@ -181,7 +166,7 @@ module Devise
|
|
181
166
|
|
182
167
|
# Defines which key will be used when locking and unlocking an account
|
183
168
|
mattr_accessor :unlock_keys
|
184
|
-
@@unlock_keys = [
|
169
|
+
@@unlock_keys = [:email]
|
185
170
|
|
186
171
|
# Defines which strategy can be used to unlock an account.
|
187
172
|
# Values: :email, :time, :both
|
@@ -198,12 +183,16 @@ module Devise
|
|
198
183
|
|
199
184
|
# Defines which key will be used when recovering the password for an account
|
200
185
|
mattr_accessor :reset_password_keys
|
201
|
-
@@reset_password_keys = [
|
186
|
+
@@reset_password_keys = [:email]
|
202
187
|
|
203
188
|
# Time interval you can reset your password with a reset password key
|
204
189
|
mattr_accessor :reset_password_within
|
205
190
|
@@reset_password_within = 6.hours
|
206
191
|
|
192
|
+
# When set to false, resetting a password does not automatically sign in a user
|
193
|
+
mattr_accessor :sign_in_after_reset_password
|
194
|
+
@@sign_in_after_reset_password = true
|
195
|
+
|
207
196
|
# The default scope which is used by warden.
|
208
197
|
mattr_accessor :default_scope
|
209
198
|
@@default_scope = nil
|
@@ -246,7 +235,7 @@ module Devise
|
|
246
235
|
mattr_accessor :router_name
|
247
236
|
@@router_name = nil
|
248
237
|
|
249
|
-
# Set the
|
238
|
+
# Set the OmniAuth path prefix so it can be overridden when
|
250
239
|
# Devise is used in a mountable engine
|
251
240
|
mattr_accessor :omniauth_path_prefix
|
252
241
|
@@omniauth_path_prefix = nil
|
@@ -261,7 +250,7 @@ module Devise
|
|
261
250
|
mattr_reader :mappings
|
262
251
|
@@mappings = ActiveSupport::OrderedHash.new
|
263
252
|
|
264
|
-
#
|
253
|
+
# OmniAuth configurations.
|
265
254
|
mattr_reader :omniauth_configs
|
266
255
|
@@omniauth_configs = ActiveSupport::OrderedHash.new
|
267
256
|
|
@@ -340,7 +329,12 @@ module Devise
|
|
340
329
|
mapping
|
341
330
|
end
|
342
331
|
|
343
|
-
#
|
332
|
+
# Register available devise modules. For the standard modules that Devise provides, this method is
|
333
|
+
# called from lib/devise/modules.rb. Third-party modules need to be added explicitly using this method.
|
334
|
+
#
|
335
|
+
# Note that adding a module using this method does not cause it to be used in the authentication
|
336
|
+
# process. That requires that the module be listed in the arguments passed to the 'devise' method
|
337
|
+
# in the model class definition.
|
344
338
|
#
|
345
339
|
# == Options:
|
346
340
|
#
|
@@ -348,6 +342,7 @@ module Devise
|
|
348
342
|
# +controller+ - Symbol representing the name of an existing or custom *controller* for this module.
|
349
343
|
# +route+ - Symbol representing the named *route* helper for this module.
|
350
344
|
# +strategy+ - Symbol representing if this module got a custom *strategy*.
|
345
|
+
# +insert_at+ - Integer representing the order in which this module's model will be included
|
351
346
|
#
|
352
347
|
# All values, except :model, accept also a boolean and will have the same name as the given module
|
353
348
|
# name.
|
@@ -357,10 +352,12 @@ module Devise
|
|
357
352
|
# Devise.add_module(:party_module)
|
358
353
|
# Devise.add_module(:party_module, strategy: true, controller: :sessions)
|
359
354
|
# Devise.add_module(:party_module, model: 'party_module/model')
|
355
|
+
# Devise.add_module(:party_module, insert_at: 0)
|
360
356
|
#
|
361
357
|
def self.add_module(module_name, options = {})
|
362
|
-
|
363
|
-
|
358
|
+
options.assert_valid_keys(:strategy, :model, :controller, :route, :no_input, :insert_at)
|
359
|
+
|
360
|
+
ALL.insert (options[:insert_at] || -1), module_name
|
364
361
|
|
365
362
|
if strategy = options[:strategy]
|
366
363
|
strategy = (strategy == true ? module_name : strategy)
|
@@ -417,7 +414,7 @@ module Devise
|
|
417
414
|
@@warden_config_blocks << block
|
418
415
|
end
|
419
416
|
|
420
|
-
# Specify an
|
417
|
+
# Specify an OmniAuth provider.
|
421
418
|
#
|
422
419
|
# config.omniauth :github, APP_ID, APP_SECRET
|
423
420
|
#
|
@@ -445,8 +442,8 @@ module Devise
|
|
445
442
|
Devise::Controllers::UrlHelpers.generate_helpers!
|
446
443
|
end
|
447
444
|
|
448
|
-
# A method used internally to setup warden manager
|
449
|
-
#
|
445
|
+
# A method used internally to complete the setup of warden manager after routes are loaded.
|
446
|
+
# See lib/devise/rails/routes.rb - ActionDispatch::Routing::RouteSet#finalize_with_devise!
|
450
447
|
def self.configure_warden! #:nodoc:
|
451
448
|
@@warden_configured ||= begin
|
452
449
|
warden_config.failure_app = Devise::Delegator.new
|
@@ -474,8 +471,12 @@ module Devise
|
|
474
471
|
end
|
475
472
|
|
476
473
|
# Generate a friendly string randomly to be used as token.
|
477
|
-
|
478
|
-
|
474
|
+
# By default, length is 20 characters.
|
475
|
+
def self.friendly_token(length = 20)
|
476
|
+
# To calculate real characters, we must perform this operation.
|
477
|
+
# See SecureRandom.urlsafe_base64
|
478
|
+
rlength = (length * 3) / 4
|
479
|
+
SecureRandom.urlsafe_base64(rlength).tr('lIO0', 'sxyz')
|
479
480
|
end
|
480
481
|
|
481
482
|
# constant-time comparison algorithm to prevent timing attacks
|