devise 1.4.9 → 1.5.0.rc1
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.
- data/.travis.yml +1 -1
- data/CHANGELOG.rdoc +21 -0
- data/Gemfile +5 -3
- data/README.rdoc +25 -13
- data/app/controllers/devise/confirmations_controller.rb +2 -3
- data/app/controllers/devise/passwords_controller.rb +2 -3
- data/app/controllers/devise/registrations_controller.rb +2 -13
- data/app/controllers/devise/sessions_controller.rb +2 -2
- data/app/controllers/devise/unlocks_controller.rb +2 -3
- data/config/locales/en.yml +1 -1
- data/devise.gemspec +1 -1
- data/lib/devise.rb +6 -4
- data/lib/devise/controllers/helpers.rb +43 -27
- data/lib/devise/controllers/internal_helpers.rb +14 -8
- data/lib/devise/delegator.rb +16 -0
- data/lib/devise/encryptors/authlogic_sha512.rb +1 -1
- data/lib/devise/encryptors/clearance_sha1.rb +1 -1
- data/lib/devise/encryptors/restful_authentication_sha1.rb +1 -1
- data/lib/devise/encryptors/sha1.rb +1 -1
- data/lib/devise/encryptors/sha512.rb +1 -1
- data/lib/devise/failure_app.rb +2 -1
- data/lib/devise/hooks/timeoutable.rb +3 -1
- data/lib/devise/mailers/helpers.rb +0 -5
- data/lib/devise/mapping.rb +70 -44
- data/lib/devise/models/authenticatable.rb +14 -24
- data/lib/devise/models/confirmable.rb +3 -3
- data/lib/devise/models/database_authenticatable.rb +11 -1
- data/lib/devise/models/lockable.rb +7 -11
- data/lib/devise/models/recoverable.rb +3 -3
- data/lib/devise/models/trackable.rb +2 -2
- data/lib/devise/omniauth.rb +5 -4
- data/lib/devise/omniauth/config.rb +27 -5
- data/lib/devise/param_filter.rb +41 -0
- data/lib/devise/rails.rb +0 -11
- data/lib/devise/rails/routes.rb +10 -7
- data/lib/devise/strategies/authenticatable.rb +1 -11
- data/lib/devise/version.rb +1 -1
- data/lib/generators/active_record/templates/migration.rb +7 -1
- data/lib/generators/active_record/templates/migration_existing.rb +3 -3
- data/lib/generators/devise/views_generator.rb +30 -4
- data/lib/generators/templates/devise.rb +0 -1
- data/lib/generators/templates/markerb/confirmation_instructions.markerb +5 -0
- data/lib/generators/templates/markerb/reset_password_instructions.markerb +8 -0
- data/lib/generators/templates/markerb/unlock_instructions.markerb +7 -0
- data/test/controllers/helpers_test.rb +20 -11
- data/test/devise_test.rb +1 -1
- data/test/generators/active_record_generator_test.rb +16 -6
- data/test/generators/views_generator_test.rb +11 -4
- data/test/integration/authenticatable_test.rb +25 -3
- data/test/integration/confirmable_test.rb +27 -3
- data/test/integration/lockable_test.rb +17 -6
- data/test/integration/omniauthable_test.rb +6 -9
- data/test/integration/recoverable_test.rb +21 -2
- data/test/integration/registerable_test.rb +18 -1
- data/test/integration/timeoutable_test.rb +9 -0
- data/test/integration/trackable_test.rb +11 -0
- data/test/mailers/confirmation_instructions_test.rb +5 -0
- data/test/mailers/reset_password_instructions_test.rb +5 -0
- data/test/mailers/unlock_instructions_test.rb +5 -0
- data/test/models/database_authenticatable_test.rb +2 -19
- data/test/omniauth/config_test.rb +56 -0
- data/test/omniauth/my_other_strategy.rb +5 -0
- data/test/omniauth/omniauth-my_strategy.rb +5 -0
- data/test/omniauth/url_helpers_test.rb +4 -4
- data/test/rails_app/config/environments/development.rb +0 -1
- data/test/rails_app/config/initializers/devise.rb +2 -2
- data/test/rails_app/config/routes.rb +4 -4
- data/test/rails_app/lib/shared_admin.rb +1 -0
- data/test/support/helpers.rb +27 -0
- metadata +54 -77
@@ -91,6 +91,7 @@ MESSAGE
|
|
91
91
|
# Example:
|
92
92
|
# before_filter :require_no_authentication, :only => :new
|
93
93
|
def require_no_authentication
|
94
|
+
return unless is_navigational_format?
|
94
95
|
no_input = devise_mapping.no_input_strategies
|
95
96
|
args = no_input.dup.push :scope => resource_name
|
96
97
|
if no_input.present? && warden.authenticate?(*args)
|
@@ -100,15 +101,20 @@ MESSAGE
|
|
100
101
|
end
|
101
102
|
end
|
102
103
|
|
103
|
-
# Helper for use
|
104
|
-
#
|
105
|
-
|
106
|
-
|
107
|
-
|
104
|
+
# Helper for use after calling send_*_instructions methods on a resource.
|
105
|
+
# If we are in paranoid mode, we always act as if the resource was valid
|
106
|
+
# and instructions were sent.
|
107
|
+
def successfully_sent?(resource)
|
108
|
+
notice = if Devise.paranoid
|
108
109
|
resource.errors.clear
|
109
|
-
|
110
|
-
|
111
|
-
|
110
|
+
:send_paranoid_instructions
|
111
|
+
elsif resource.errors.empty?
|
112
|
+
:send_instructions
|
113
|
+
end
|
114
|
+
|
115
|
+
if notice
|
116
|
+
set_flash_message :notice, notice if is_navigational_format?
|
117
|
+
true
|
112
118
|
end
|
113
119
|
end
|
114
120
|
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Devise
|
2
|
+
# Checks the scope in the given environment and returns the associated failure app.
|
3
|
+
class Delegator
|
4
|
+
def call(env)
|
5
|
+
failure_app(env).call(env)
|
6
|
+
end
|
7
|
+
|
8
|
+
def failure_app(env)
|
9
|
+
app = env["warden.options"] &&
|
10
|
+
(scope = env["warden.options"][:scope]) &&
|
11
|
+
Devise.mappings[scope].failure_app
|
12
|
+
|
13
|
+
app || Devise::FailureApp
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -7,7 +7,7 @@ module Devise
|
|
7
7
|
# Warning: it uses Devise's stretches configuration to port Authlogic's one. Should be set to 20 in the initializer to simulate
|
8
8
|
# the default behavior.
|
9
9
|
class AuthlogicSha512 < Base
|
10
|
-
#
|
10
|
+
# Generates a default password digest based on salt, pepper and the
|
11
11
|
# incoming password.
|
12
12
|
def self.digest(password, stretches, salt, pepper)
|
13
13
|
digest = [password, salt].flatten.join('')
|
@@ -7,7 +7,7 @@ module Devise
|
|
7
7
|
# Warning: it uses Devise's pepper to port the concept of REST_AUTH_SITE_KEY
|
8
8
|
# Warning: it uses Devise's stretches configuration to port the concept of REST_AUTH_DIGEST_STRETCHES
|
9
9
|
class ClearanceSha1 < Base
|
10
|
-
#
|
10
|
+
# Generates a default password digest based on salt, pepper and the
|
11
11
|
# incoming password.
|
12
12
|
def self.digest(password, stretches, salt, pepper)
|
13
13
|
Digest::SHA1.hexdigest("--#{salt}--#{password}--")
|
@@ -9,7 +9,7 @@ module Devise
|
|
9
9
|
# the initializer to simulate the default behavior.
|
10
10
|
class RestfulAuthenticationSha1 < Base
|
11
11
|
|
12
|
-
#
|
12
|
+
# Generates a default password digest based on salt, pepper and the
|
13
13
|
# incoming password.
|
14
14
|
def self.digest(password, stretches, salt, pepper)
|
15
15
|
digest = pepper
|
@@ -5,7 +5,7 @@ module Devise
|
|
5
5
|
# = Sha1
|
6
6
|
# Uses the Sha1 hash algorithm to encrypt passwords.
|
7
7
|
class Sha1 < Base
|
8
|
-
#
|
8
|
+
# Generates a default password digest based on stretches, salt, pepper and the
|
9
9
|
# incoming password.
|
10
10
|
def self.digest(password, stretches, salt, pepper)
|
11
11
|
digest = pepper
|
@@ -5,7 +5,7 @@ module Devise
|
|
5
5
|
# = Sha512
|
6
6
|
# Uses the Sha512 hash algorithm to encrypt passwords.
|
7
7
|
class Sha512 < Base
|
8
|
-
#
|
8
|
+
# Generates a default password digest based on salt, pepper and the
|
9
9
|
# incoming password.
|
10
10
|
def self.digest(password, stretches, salt, pepper)
|
11
11
|
digest = pepper
|
data/lib/devise/failure_app.rb
CHANGED
@@ -17,6 +17,8 @@ Warden::Manager.after_set_user do |record, warden, options|
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
warden.
|
20
|
+
unless warden.request.env['devise.skip_trackable']
|
21
|
+
warden.session(scope)['last_request_at'] = Time.now.utc
|
22
|
+
end
|
21
23
|
end
|
22
24
|
end
|
@@ -10,11 +10,6 @@ module Devise
|
|
10
10
|
|
11
11
|
protected
|
12
12
|
|
13
|
-
def setup_mail(*args)
|
14
|
-
ActiveSupport::Deprecation.warn "setup_mail is deprecated, please use devise_mail instead", caller
|
15
|
-
devise_mail(*args)
|
16
|
-
end
|
17
|
-
|
18
13
|
# Configure default email options
|
19
14
|
def devise_mail(record, action)
|
20
15
|
initialize_from_record(record)
|
data/lib/devise/mapping.rb
CHANGED
@@ -23,7 +23,9 @@ module Devise
|
|
23
23
|
#
|
24
24
|
class Mapping #:nodoc:
|
25
25
|
attr_reader :singular, :scoped_path, :path, :controllers, :path_names,
|
26
|
-
:class_name, :sign_out_via, :format, :used_routes, :used_helpers
|
26
|
+
:class_name, :sign_out_via, :format, :used_routes, :used_helpers,
|
27
|
+
:constraints, :defaults, :failure_app
|
28
|
+
|
27
29
|
alias :name :singular
|
28
30
|
|
29
31
|
# Receives an object and find a scope for it. If a scope cannot be found,
|
@@ -51,46 +53,21 @@ module Devise
|
|
51
53
|
@singular = (options[:singular] || @scoped_path.tr('/', '_').singularize).to_sym
|
52
54
|
|
53
55
|
@class_name = (options[:class_name] || name.to_s.classify).to_s
|
54
|
-
@
|
56
|
+
@klass = Devise.ref(@class_name)
|
55
57
|
|
56
58
|
@path = (options[:path] || name).to_s
|
57
59
|
@path_prefix = options[:path_prefix]
|
58
60
|
|
59
|
-
mod = options[:module] || "devise"
|
60
|
-
@controllers = Hash.new { |h,k| h[k] = "#{mod}/#{k}" }
|
61
|
-
@controllers.merge!(options[:controllers] || {})
|
62
|
-
@controllers.each { |k,v| @controllers[k] = v.to_s }
|
63
|
-
|
64
|
-
@path_names = Hash.new { |h,k| h[k] = k.to_s }
|
65
|
-
@path_names.merge!(:registration => "")
|
66
|
-
@path_names.merge!(options[:path_names] || {})
|
67
|
-
|
68
|
-
@constraints = Hash.new { |h,k| h[k] = k.to_s }
|
69
|
-
@constraints.merge!(options[:constraints] || {})
|
70
|
-
|
71
|
-
@defaults = Hash.new { |h,k| h[k] = k.to_s }
|
72
|
-
@defaults.merge!(options[:defaults] || {})
|
73
|
-
|
74
61
|
@sign_out_via = options[:sign_out_via] || Devise.sign_out_via
|
75
62
|
@format = options[:format]
|
76
63
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
@used_routes = self.routes - Array(options[:skip]).map(&singularizer)
|
85
|
-
end
|
86
|
-
|
87
|
-
if options[:skip_helpers] == true
|
88
|
-
@used_helpers = @used_routes
|
89
|
-
elsif skip = options[:skip_helpers]
|
90
|
-
@used_helpers = self.routes - Array(skip).map(&singularizer)
|
91
|
-
else
|
92
|
-
@used_helpers = self.routes
|
93
|
-
end
|
64
|
+
default_failure_app(options)
|
65
|
+
default_controllers(options)
|
66
|
+
default_path_names(options)
|
67
|
+
default_constraints(options)
|
68
|
+
default_defaults(options)
|
69
|
+
default_used_route(options)
|
70
|
+
default_used_helpers(options)
|
94
71
|
end
|
95
72
|
|
96
73
|
# Return modules for the mapping.
|
@@ -100,7 +77,7 @@ module Devise
|
|
100
77
|
|
101
78
|
# Gives the class the mapping points to.
|
102
79
|
def to
|
103
|
-
@
|
80
|
+
@klass.get
|
104
81
|
end
|
105
82
|
|
106
83
|
def strategies
|
@@ -122,15 +99,7 @@ module Devise
|
|
122
99
|
def fullpath
|
123
100
|
"/#{@path_prefix}/#{@path}".squeeze("/")
|
124
101
|
end
|
125
|
-
|
126
|
-
def constraints
|
127
|
-
@constraints
|
128
|
-
end
|
129
|
-
|
130
|
-
def defaults
|
131
|
-
@defaults
|
132
|
-
end
|
133
|
-
|
102
|
+
|
134
103
|
# Create magic predicates for verifying what module is activated by this map.
|
135
104
|
# Example:
|
136
105
|
#
|
@@ -145,5 +114,62 @@ module Devise
|
|
145
114
|
end
|
146
115
|
METHOD
|
147
116
|
end
|
117
|
+
|
118
|
+
private
|
119
|
+
|
120
|
+
def default_failure_app(options)
|
121
|
+
@failure_app = options[:failure_app] || Devise::FailureApp
|
122
|
+
if @failure_app.is_a?(String)
|
123
|
+
ref = Devise.ref(@failure_app)
|
124
|
+
@failure_app = lambda { |env| ref.get.call(env) }
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def default_controllers(options)
|
129
|
+
mod = options[:module] || "devise"
|
130
|
+
@controllers = Hash.new { |h,k| h[k] = "#{mod}/#{k}" }
|
131
|
+
@controllers.merge!(options[:controllers]) if options[:controllers]
|
132
|
+
@controllers.each { |k,v| @controllers[k] = v.to_s }
|
133
|
+
end
|
134
|
+
|
135
|
+
def default_path_names(options)
|
136
|
+
@path_names = Hash.new { |h,k| h[k] = k.to_s }
|
137
|
+
@path_names[:registration] = ""
|
138
|
+
@path_names.merge!(options[:path_names]) if options[:path_names]
|
139
|
+
end
|
140
|
+
|
141
|
+
def default_constraints(options)
|
142
|
+
@constraints = Hash.new
|
143
|
+
@constraints.merge!(options[:constraints]) if options[:constraints]
|
144
|
+
end
|
145
|
+
|
146
|
+
def default_defaults(options)
|
147
|
+
@defaults = Hash.new
|
148
|
+
@defaults.merge!(options[:defaults]) if options[:defaults]
|
149
|
+
end
|
150
|
+
|
151
|
+
def default_used_route(options)
|
152
|
+
singularizer = lambda { |s| s.to_s.singularize.to_sym }
|
153
|
+
|
154
|
+
if options.has_key?(:only)
|
155
|
+
@used_routes = self.routes & Array(options[:only]).map(&singularizer)
|
156
|
+
elsif options[:skip] == :all
|
157
|
+
@used_routes = []
|
158
|
+
else
|
159
|
+
@used_routes = self.routes - Array(options[:skip]).map(&singularizer)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def default_used_helpers(options)
|
164
|
+
singularizer = lambda { |s| s.to_s.singularize.to_sym }
|
165
|
+
|
166
|
+
if options[:skip_helpers] == true
|
167
|
+
@used_helpers = @used_routes
|
168
|
+
elsif skip = options[:skip_helpers]
|
169
|
+
@used_helpers = self.routes - Array(skip).map(&singularizer)
|
170
|
+
else
|
171
|
+
@used_helpers = self.routes
|
172
|
+
end
|
173
|
+
end
|
148
174
|
end
|
149
175
|
end
|
@@ -27,7 +27,7 @@ module Devise
|
|
27
27
|
#
|
28
28
|
# == active_for_authentication?
|
29
29
|
#
|
30
|
-
#
|
30
|
+
# After authenticating a user and in each request, Devise checks if your model is active by
|
31
31
|
# calling model.active_for_authentication?. This method is overwriten by other devise modules. For instance,
|
32
32
|
# :confirmable overwrites .active_for_authentication? to only return true if your model was confirmed.
|
33
33
|
#
|
@@ -61,11 +61,7 @@ module Devise
|
|
61
61
|
# However, you should not overwrite this method, you should overwrite active_for_authentication?
|
62
62
|
# and inactive_message instead.
|
63
63
|
def valid_for_authentication?
|
64
|
-
|
65
|
-
block_given? ? yield : true
|
66
|
-
else
|
67
|
-
inactive_message
|
68
|
-
end
|
64
|
+
block_given? ? yield : true
|
69
65
|
end
|
70
66
|
|
71
67
|
def active_for_authentication?
|
@@ -79,6 +75,10 @@ module Devise
|
|
79
75
|
def authenticatable_salt
|
80
76
|
end
|
81
77
|
|
78
|
+
def devise_mailer
|
79
|
+
Devise.mailer
|
80
|
+
end
|
81
|
+
|
82
82
|
module ClassMethods
|
83
83
|
Devise::Models.config(self, :authentication_keys, :request_keys, :strip_whitespace_keys, :case_insensitive_keys, :http_authenticatable, :params_authenticatable)
|
84
84
|
|
@@ -112,10 +112,11 @@ module Devise
|
|
112
112
|
# end
|
113
113
|
#
|
114
114
|
def find_for_authentication(conditions)
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
115
|
+
find_first_by_auth_conditions(conditions)
|
116
|
+
end
|
117
|
+
|
118
|
+
def find_first_by_auth_conditions(conditions)
|
119
|
+
to_adapter.find_first devise_param_filter.filter(conditions)
|
119
120
|
end
|
120
121
|
|
121
122
|
# Find an initialize a record setting an error if it can't be found.
|
@@ -125,14 +126,11 @@ module Devise
|
|
125
126
|
|
126
127
|
# Find an initialize a group of attributes based on a list of required attributes.
|
127
128
|
def find_or_initialize_with_errors(required_attributes, attributes, error=:invalid) #:nodoc:
|
128
|
-
(case_insensitive_keys || []).each { |k| attributes[k].try(:downcase!) }
|
129
|
-
(strip_whitespace_keys || []).each { |k| attributes[k].try(:strip!) }
|
130
|
-
|
131
129
|
attributes = attributes.slice(*required_attributes)
|
132
130
|
attributes.delete_if { |key, value| value.blank? }
|
133
131
|
|
134
132
|
if attributes.size == required_attributes.size
|
135
|
-
record =
|
133
|
+
record = find_first_by_auth_conditions(attributes)
|
136
134
|
end
|
137
135
|
|
138
136
|
unless record
|
@@ -150,16 +148,8 @@ module Devise
|
|
150
148
|
|
151
149
|
protected
|
152
150
|
|
153
|
-
|
154
|
-
|
155
|
-
conditions.each do |k, v|
|
156
|
-
conditions[k] = v.to_s if auth_param_requires_string_conversion?(v)
|
157
|
-
end if conditions.is_a?(Hash)
|
158
|
-
end
|
159
|
-
|
160
|
-
# Determine which values should be transformed to string or passed as-is to the query builder underneath
|
161
|
-
def auth_param_requires_string_conversion?(value)
|
162
|
-
true unless value.is_a?(TrueClass) || value.is_a?(FalseClass) || value.is_a?(Fixnum)
|
151
|
+
def devise_param_filter
|
152
|
+
@devise_param_filter ||= Devise::ParamFilter.new(case_insensitive_keys, strip_whitespace_keys)
|
163
153
|
end
|
164
154
|
|
165
155
|
# Generate a token by looping and ensuring does not already exist.
|
@@ -34,7 +34,7 @@ module Devise
|
|
34
34
|
def confirm!
|
35
35
|
unless_confirmed do
|
36
36
|
self.confirmation_token = nil
|
37
|
-
self.confirmed_at = Time.now
|
37
|
+
self.confirmed_at = Time.now.utc
|
38
38
|
save(:validate => false)
|
39
39
|
end
|
40
40
|
end
|
@@ -47,7 +47,7 @@ module Devise
|
|
47
47
|
# Send confirmation instructions by email
|
48
48
|
def send_confirmation_instructions
|
49
49
|
generate_confirmation_token! if self.confirmation_token.nil?
|
50
|
-
|
50
|
+
self.devise_mailer.confirmation_instructions(self).deliver
|
51
51
|
end
|
52
52
|
|
53
53
|
# Resend confirmation token. This method does not need to generate a new token.
|
@@ -71,7 +71,7 @@ module Devise
|
|
71
71
|
# If you don't want confirmation to be sent on create, neither a code
|
72
72
|
# to be generated, call skip_confirmation!
|
73
73
|
def skip_confirmation!
|
74
|
-
self.confirmed_at = Time.now
|
74
|
+
self.confirmed_at = Time.now.utc
|
75
75
|
end
|
76
76
|
|
77
77
|
protected
|
@@ -73,7 +73,17 @@ module Devise
|
|
73
73
|
end
|
74
74
|
|
75
75
|
# Updates record attributes without asking for the current password.
|
76
|
-
# Never allows to change the current password
|
76
|
+
# Never allows to change the current password. If you are using this
|
77
|
+
# method, you should probably override this method to protect other
|
78
|
+
# attributes you would not like to be updated without a password.
|
79
|
+
#
|
80
|
+
# Example:
|
81
|
+
#
|
82
|
+
# def update_without_password(params={})
|
83
|
+
# params.delete(:email)
|
84
|
+
# super(params)
|
85
|
+
# end
|
86
|
+
#
|
77
87
|
def update_without_password(params={})
|
78
88
|
params.delete(:password)
|
79
89
|
params.delete(:password_confirmation)
|
@@ -24,7 +24,7 @@ module Devise
|
|
24
24
|
|
25
25
|
# Lock a user setting its locked_at to actual time.
|
26
26
|
def lock_access!
|
27
|
-
self.locked_at = Time.now
|
27
|
+
self.locked_at = Time.now.utc
|
28
28
|
|
29
29
|
if unlock_strategy_enabled?(:email)
|
30
30
|
generate_unlock_token
|
@@ -49,7 +49,7 @@ module Devise
|
|
49
49
|
|
50
50
|
# Send unlock instructions by email
|
51
51
|
def send_unlock_instructions
|
52
|
-
|
52
|
+
self.devise_mailer.unlock_instructions(self).deliver
|
53
53
|
end
|
54
54
|
|
55
55
|
# Resend the unlock instructions if the user is locked.
|
@@ -79,25 +79,21 @@ module Devise
|
|
79
79
|
# if the user can login or not (wrong password, etc)
|
80
80
|
unlock_access! if lock_expired?
|
81
81
|
|
82
|
-
|
83
|
-
when Symbol
|
84
|
-
return result
|
85
|
-
when TrueClass
|
82
|
+
if super
|
86
83
|
self.failed_attempts = 0
|
87
84
|
save(:validate => false)
|
88
|
-
|
89
|
-
|
85
|
+
true
|
86
|
+
else
|
90
87
|
self.failed_attempts ||= 0
|
91
88
|
self.failed_attempts += 1
|
92
89
|
if attempts_exceeded?
|
93
|
-
lock_access!
|
90
|
+
lock_access! unless access_locked?
|
94
91
|
return :locked
|
95
92
|
else
|
96
93
|
save(:validate => false)
|
97
94
|
end
|
95
|
+
false
|
98
96
|
end
|
99
|
-
|
100
|
-
result
|
101
97
|
end
|
102
98
|
|
103
99
|
protected
|