devise 3.0.0.rc → 3.0.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.

data/CHANGELOG.rdoc CHANGED
@@ -1,8 +1,12 @@
1
- == 3.0.0.rc
1
+ == 3.0.0
2
2
 
3
3
  * enhancements
4
- * Rails 4 and Strong Parameters compatibility. (@carlosantoniodasilva, @josevalim, @latortuga, @lucasmazza, @nashby, @rafaelfranca, @spastorino)
5
- * Drop support for Rails < 3.2 and Ruby < 1.9.3.
4
+ * Rails 4 and Strong Parameters compatibility (by @carlosantoniodasilva, @josevalim, @latortuga, @lucasmazza, @nashby, @rafaelfranca, @spastorino)
5
+ * Drop support for Rails < 3.2 and Ruby < 1.9.3
6
+ * Enable to skip sending reconfirmation email when reconfirmable is on and skip_confirmation_notification! is invoked (by @tkhr)
7
+
8
+ * bug fix
9
+ * Errors on unlock are now properly reflected on the first `unlock_keys`
6
10
 
7
11
  == 2.2.4
8
12
 
@@ -119,6 +123,7 @@ Security announcement: http://blog.plataformatec.com.br/2013/01/security-announc
119
123
  * Do not accidentally mark `_prefixes` as private
120
124
  * Better support for custom strategies on test helpers (by @mattconnolly)
121
125
  * Return `head :no_content` in SessionsController now that most JS libraries handle it (by @julianvargasalvarez)
126
+ * Reverted moving devise/shared/_links.erb to devise/_links.erb
122
127
 
123
128
  == 2.0.4
124
129
 
data/Gemfile CHANGED
@@ -2,7 +2,7 @@ source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
- gem "rails", "~> 4.0.0.rc1"
5
+ gem "rails", "~> 4.0.0"
6
6
  gem "omniauth", "~> 1.0.0"
7
7
  gem "omniauth-oauth2", "~> 1.0.0"
8
8
  gem "rdoc"
data/Gemfile.lock CHANGED
@@ -16,60 +16,59 @@ PATH
16
16
  bcrypt-ruby (~> 3.0)
17
17
  orm_adapter (~> 0.1)
18
18
  railties (>= 3.2.6, < 5)
19
- warden (~> 1.2.1)
19
+ warden (~> 1.2.3)
20
20
 
21
21
  GEM
22
22
  remote: https://rubygems.org/
23
23
  specs:
24
- actionmailer (4.0.0.rc1)
25
- actionpack (= 4.0.0.rc1)
24
+ actionmailer (4.0.0)
25
+ actionpack (= 4.0.0)
26
26
  mail (~> 2.5.3)
27
- actionpack (4.0.0.rc1)
28
- activesupport (= 4.0.0.rc1)
27
+ actionpack (4.0.0)
28
+ activesupport (= 4.0.0)
29
29
  builder (~> 3.1.0)
30
30
  erubis (~> 2.7.0)
31
31
  rack (~> 1.5.2)
32
32
  rack-test (~> 0.6.2)
33
- activemodel (4.0.0.rc1)
34
- activesupport (= 4.0.0.rc1)
33
+ activemodel (4.0.0)
34
+ activesupport (= 4.0.0)
35
35
  builder (~> 3.1.0)
36
- activerecord (4.0.0.rc1)
37
- activemodel (= 4.0.0.rc1)
36
+ activerecord (4.0.0)
37
+ activemodel (= 4.0.0)
38
38
  activerecord-deprecated_finders (~> 1.0.2)
39
- activesupport (= 4.0.0.rc1)
39
+ activesupport (= 4.0.0)
40
40
  arel (~> 4.0.0)
41
- activerecord-deprecated_finders (1.0.2)
42
- activesupport (4.0.0.rc1)
41
+ activerecord-deprecated_finders (1.0.3)
42
+ activesupport (4.0.0)
43
43
  i18n (~> 0.6, >= 0.6.4)
44
44
  minitest (~> 4.2)
45
45
  multi_json (~> 1.3)
46
46
  thread_safe (~> 0.1)
47
47
  tzinfo (~> 0.3.37)
48
48
  arel (4.0.0)
49
- atomic (1.1.8)
50
- bcrypt-ruby (3.0.1)
49
+ atomic (1.1.10)
50
+ bcrypt-ruby (3.1.1)
51
51
  builder (3.1.4)
52
52
  erubis (2.7.0)
53
53
  faraday (0.8.7)
54
54
  multipart-post (~> 1.1)
55
55
  hashie (1.2.0)
56
- hike (1.2.2)
56
+ hike (1.2.3)
57
57
  httpauth (0.2.0)
58
58
  i18n (0.6.4)
59
59
  json (1.7.7)
60
60
  jwt (0.1.8)
61
61
  multi_json (>= 1.5)
62
- mail (2.5.3)
63
- i18n (>= 0.4.0)
62
+ mail (2.5.4)
64
63
  mime-types (~> 1.16)
65
64
  treetop (~> 1.4.8)
66
65
  metaclass (0.0.1)
67
66
  mime-types (1.23)
68
- minitest (4.7.4)
67
+ minitest (4.7.5)
69
68
  mocha (0.13.3)
70
69
  metaclass (~> 0.0.1)
71
70
  moped (1.4.5)
72
- multi_json (1.7.2)
71
+ multi_json (1.7.7)
73
72
  multipart-post (1.2.0)
74
73
  nokogiri (1.5.9)
75
74
  oauth2 (0.8.1)
@@ -98,29 +97,29 @@ GEM
98
97
  ruby-openid (>= 2.1.8)
99
98
  rack-test (0.6.2)
100
99
  rack (>= 1.0)
101
- rails (4.0.0.rc1)
102
- actionmailer (= 4.0.0.rc1)
103
- actionpack (= 4.0.0.rc1)
104
- activerecord (= 4.0.0.rc1)
105
- activesupport (= 4.0.0.rc1)
100
+ rails (4.0.0)
101
+ actionmailer (= 4.0.0)
102
+ actionpack (= 4.0.0)
103
+ activerecord (= 4.0.0)
104
+ activesupport (= 4.0.0)
106
105
  bundler (>= 1.3.0, < 2.0)
107
- railties (= 4.0.0.rc1)
108
- sprockets-rails (~> 2.0.0.rc4)
109
- railties (4.0.0.rc1)
110
- actionpack (= 4.0.0.rc1)
111
- activesupport (= 4.0.0.rc1)
106
+ railties (= 4.0.0)
107
+ sprockets-rails (~> 2.0.0)
108
+ railties (4.0.0)
109
+ actionpack (= 4.0.0)
110
+ activesupport (= 4.0.0)
112
111
  rake (>= 0.8.7)
113
112
  thor (>= 0.18.1, < 2.0)
114
- rake (10.0.4)
113
+ rake (10.1.0)
115
114
  rdoc (4.0.1)
116
115
  json (~> 1.4)
117
116
  ruby-openid (2.2.3)
118
- sprockets (2.9.3)
117
+ sprockets (2.10.0)
119
118
  hike (~> 1.2)
120
119
  multi_json (~> 1.0)
121
120
  rack (~> 1.0)
122
121
  tilt (~> 1.1, != 1.3.0)
123
- sprockets-rails (2.0.0.rc4)
122
+ sprockets-rails (2.0.0)
124
123
  actionpack (>= 3.0)
125
124
  activesupport (>= 3.0)
126
125
  sprockets (~> 2.8)
@@ -128,12 +127,12 @@ GEM
128
127
  thor (0.18.1)
129
128
  thread_safe (0.1.0)
130
129
  atomic
131
- tilt (1.4.0)
132
- treetop (1.4.12)
130
+ tilt (1.4.1)
131
+ treetop (1.4.14)
133
132
  polyglot
134
133
  polyglot (>= 0.3.1)
135
134
  tzinfo (0.3.37)
136
- warden (1.2.1)
135
+ warden (1.2.3)
137
136
  rack (>= 1.0)
138
137
  webrat (0.7.3)
139
138
  nokogiri (>= 1.2.0)
@@ -154,7 +153,7 @@ DEPENDENCIES
154
153
  omniauth-facebook
155
154
  omniauth-oauth2 (~> 1.0.0)
156
155
  omniauth-openid (~> 1.0.1)
157
- rails (~> 4.0.0.rc1)
156
+ rails (~> 4.0.0)
158
157
  rdoc
159
158
  sqlite3
160
159
  webrat (= 0.7.3)
data/README.md CHANGED
@@ -29,6 +29,8 @@ It's composed of 11 modules:
29
29
  * [Validatable](http://rubydoc.info/github/plataformatec/devise/master/Devise/Models/Validatable): provides validations of email and password. It's optional and can be customized, so you're able to define your own validations.
30
30
  * [Lockable](http://rubydoc.info/github/plataformatec/devise/master/Devise/Models/Lockable): locks an account after a specified number of failed sign-in attempts. Can unlock via email or after a specified time period.
31
31
 
32
+ Devise is guaranteed to be thread-safe on YARV. Thread-safety support on JRuby is on progress.
33
+
32
34
  ## Information
33
35
 
34
36
  ### The Devise wiki
@@ -110,7 +112,7 @@ The generator will install an initializer which describes ALL Devise's configura
110
112
  rails generate devise MODEL
111
113
  ```
112
114
 
113
- Replace MODEL by the class name used for the applications users, it's frequently 'User' but could also be 'Admin'. This will create a model (if one does not exist) and configure it with default Devise modules. Next, you'll usually run "rake db:migrate" as the generator will have created a migration file (if your ORM supports them). This generator also configures your config/routes.rb file to point to the Devise controller.
115
+ Replace MODEL by the class name used for the applications users, it's frequently `User` but could also be `Admin`. This will create a model (if one does not exist) and configure it with default Devise modules. Next, you'll usually run `rake db:migrate` as the generator will have created a migration file (if your ORM supports them). This generator also configures your config/routes.rb file to point to the Devise controller.
114
116
 
115
117
  Note that you should re-start your app here if you've already started it. Otherwise you'll run into strange errors like users being unable to login and the route helpers being undefined.
116
118
 
@@ -200,6 +202,32 @@ class ApplicationController < ActionController::Base
200
202
  end
201
203
  ```
202
204
 
205
+ If you have multiple roles, you may want to set up different parameter sanitizer per role. In this case, we recommend inheriting from `Devise::ParameterSanitizer` and add your own logic:
206
+
207
+ ```ruby
208
+ class User::ParameterSanitizer < Devise::ParameterSanitizer
209
+ def sign_in
210
+ default_params.permit(:username, :email)
211
+ end
212
+ end
213
+ ```
214
+
215
+ And then configure your controllers to use it:
216
+
217
+ ```ruby
218
+ class ApplicationController < ActionController::Base
219
+ protected
220
+
221
+ def devise_parameter_sanitizer
222
+ if resource_class == User
223
+ User::ParameterSanitizer.new(User, :user, params)
224
+ else
225
+ super # Use the default one
226
+ end
227
+ end
228
+ end
229
+ ```
230
+
203
231
  The example above overrides the permitted parameters for the user to be both `:username` and `:email`. The non-lazy way to configure parameters would be by defining the before filter above in a custom controller. We detail how to configure and customize controllers in some sections below.
204
232
 
205
233
  ### Configuring views
@@ -224,22 +252,24 @@ rails generate devise:views users
224
252
 
225
253
  If the customization at the views level is not enough, you can customize each controller by following these steps:
226
254
 
227
- 1) Create your custom controller, for example a Admins::SessionsController:
255
+ 1. Create your custom controller, for example a `Admins::SessionsController`:
228
256
 
229
- ```ruby
230
- class Admins::SessionsController < Devise::SessionsController
231
- end
232
- ```
257
+ ```ruby
258
+ class Admins::SessionsController < Devise::SessionsController
259
+ end
260
+ ```
233
261
 
234
- 2) Tell the router to use this controller:
262
+ Note that in the above example, the controller needs to be created in the `app/controller/admins/` directory.
235
263
 
236
- ```ruby
237
- devise_for :admins, :controllers => { :sessions => "admins/sessions" }
238
- ```
264
+ 2. Tell the router to use this controller:
265
+
266
+ ```ruby
267
+ devise_for :admins, :controllers => { :sessions => "admins/sessions" }
268
+ ```
239
269
 
240
- 3) And since we changed the controller, it won't use the "devise/sessions" views, so remember to copy "devise/sessions" to "admin/sessions".
270
+ 3. And since we changed the controller, it won't use the `"devise/sessions"` views, so remember to copy `"devise/sessions"` to `"admin/sessions"`.
241
271
 
242
- Remember that Devise uses flash messages to let users know if sign in was successful or failed. Devise expects your application to call "flash[:notice]" and "flash[:alert]" as appropriate. Do not print the entire flash hash, print specific keys or at least remove the `:timedout` key from the hash as Devise adds this key in some circumstances, this key is not meant for display.
272
+ Remember that Devise uses flash messages to let users know if sign in was successful or failed. Devise expects your application to call `"flash[:notice]"` and `"flash[:alert]"` as appropriate. Do not print the entire flash hash, print specific keys or at least remove the `:timedout` key from the hash as Devise adds this key in some circumstances, this key is not meant for display.
243
273
 
244
274
  ### Configuring routes
245
275
 
@@ -331,12 +361,14 @@ sign_out @user # sign_out(resource)
331
361
 
332
362
  There are two things that is important to keep in mind:
333
363
 
334
- 1) These helpers are not going to work for integration tests driven by Capybara or Webrat. They are meant to be used with functional tests only. Instead, fill in the form or explicitly set the user in session;
364
+ 1. These helpers are not going to work for integration tests driven by Capybara or Webrat. They are meant to be used with functional tests only. Instead, fill in the form or explicitly set the user in session;
335
365
 
336
- 2) If you are testing Devise internal controllers or a controller that inherits from Devise's, you need to tell Devise which mapping should be used before a request. This is necessary because Devise gets this information from router, but since functional tests do not pass through the router, it needs to be told explicitly. For example, if you are testing the user scope, simply do:
366
+ 2. If you are testing Devise internal controllers or a controller that inherits from Devise's, you need to tell Devise which mapping should be used before a request. This is necessary because Devise gets this information from router, but since functional tests do not pass through the router, it needs to be told explicitly. For example, if you are testing the user scope, simply do:
337
367
 
368
+ ```ruby
338
369
  @request.env["devise.mapping"] = Devise.mappings[:user]
339
370
  get :new
371
+ ```
340
372
 
341
373
  ### Omniauth
342
374
 
@@ -53,7 +53,7 @@ class Devise::PasswordsController < DeviseController
53
53
  # Check if a reset_password_token is provided in the request
54
54
  def assert_reset_token_passed
55
55
  if params[:reset_password_token].blank?
56
- set_flash_message(:error, :no_token)
56
+ set_flash_message(:alert, :no_token)
57
57
  redirect_to new_session_path(resource_name)
58
58
  end
59
59
  end
@@ -10,7 +10,7 @@ class Devise::RegistrationsController < DeviseController
10
10
 
11
11
  # POST /resource
12
12
  def create
13
- self.resource = build_resource(sign_up_params)
13
+ build_resource(sign_up_params)
14
14
 
15
15
  if resource.save
16
16
  if resource.active_for_authentication?
data/devise.gemspec CHANGED
@@ -19,7 +19,7 @@ Gem::Specification.new do |s|
19
19
  s.test_files = `git ls-files -- test/*`.split("\n")
20
20
  s.require_paths = ["lib"]
21
21
 
22
- s.add_dependency("warden", "~> 1.2.1")
22
+ s.add_dependency("warden", "~> 1.2.3")
23
23
  s.add_dependency("orm_adapter", "~> 0.1")
24
24
  s.add_dependency("bcrypt-ruby", "~> 3.0")
25
25
  s.add_dependency("railties", ">= 3.2.6", "< 5")
data/lib/devise.rb CHANGED
@@ -9,7 +9,7 @@ module Devise
9
9
  autoload :Delegator, 'devise/delegator'
10
10
  autoload :FailureApp, 'devise/failure_app'
11
11
  autoload :OmniAuth, 'devise/omniauth'
12
- autoload :ParamFilter, 'devise/param_filter'
12
+ autoload :ParameterFilter, 'devise/parameter_filter'
13
13
  autoload :BaseSanitizer, 'devise/parameter_sanitizer'
14
14
  autoload :ParameterSanitizer, 'devise/parameter_sanitizer'
15
15
  autoload :TestHelpers, 'devise/test_helpers'
@@ -78,7 +78,14 @@ module Devise
78
78
  def redirect_url
79
79
  if warden_message == :timeout
80
80
  flash[:timedout] = true
81
- attempted_path || scope_path
81
+
82
+ path = if request.get?
83
+ attempted_path
84
+ else
85
+ request.referrer
86
+ end
87
+
88
+ path || scope_path
82
89
  else
83
90
  scope_path
84
91
  end
@@ -2,6 +2,6 @@
2
2
  # This is only triggered when the user is explicitly set (with set_user)
3
3
  Warden::Manager.after_set_user :except => :fetch do |record, warden, options|
4
4
  if record.respond_to?(:failed_attempts) && warden.authenticated?(options[:scope])
5
- record.update_attribute(:failed_attempts, 0)
5
+ record.update_attribute(:failed_attempts, 0) unless record.failed_attempts.zero?
6
6
  end
7
7
  end
@@ -29,17 +29,17 @@ module Devise
29
29
 
30
30
  # Receives an object and find a scope for it. If a scope cannot be found,
31
31
  # raises an error. If a symbol is given, it's considered to be the scope.
32
- def self.find_scope!(duck)
33
- case duck
32
+ def self.find_scope!(obj)
33
+ case obj
34
34
  when String, Symbol
35
- return duck
35
+ return obj
36
36
  when Class
37
- Devise.mappings.each_value { |m| return m.name if duck <= m.to }
37
+ Devise.mappings.each_value { |m| return m.name if obj <= m.to }
38
38
  else
39
- Devise.mappings.each_value { |m| return m.name if duck.is_a?(m.to) }
39
+ Devise.mappings.each_value { |m| return m.name if obj.is_a?(m.to) }
40
40
  end
41
41
 
42
- raise "Could not find a valid mapping for #{duck.inspect}"
42
+ raise "Could not find a valid mapping for #{obj.inspect}"
43
43
  end
44
44
 
45
45
  def self.find_by_path!(path, path_type=:fullpath)
@@ -21,7 +21,7 @@ module Devise
21
21
  # as key on authentication. This can also be a hash where the value is a boolean specifying
22
22
  # if the value is required or not.
23
23
  #
24
- # * +http_authenticatable+: if this model allows http authentication. By default true.
24
+ # * +http_authenticatable+: if this model allows http authentication. By default false.
25
25
  # It also accepts an array specifying the strategies that should allow http.
26
26
  #
27
27
  # * +params_authenticatable+: if this model allows authentication through request params. By default true.
@@ -243,7 +243,7 @@ module Devise
243
243
  end
244
244
 
245
245
  def find_first_by_auth_conditions(tainted_conditions, opts={})
246
- to_adapter.find_first(devise_param_filter.filter(tainted_conditions).merge(opts))
246
+ to_adapter.find_first(devise_parameter_filter.filter(tainted_conditions).merge(opts))
247
247
  end
248
248
 
249
249
  # Find an initialize a record setting an error if it can't be found.
@@ -275,8 +275,8 @@ module Devise
275
275
 
276
276
  protected
277
277
 
278
- def devise_param_filter
279
- @devise_param_filter ||= Devise::ParamFilter.new(case_insensitive_keys, strip_whitespace_keys)
278
+ def devise_parameter_filter
279
+ @devise_parameter_filter ||= Devise::ParameterFilter.new(case_insensitive_keys, strip_whitespace_keys)
280
280
  end
281
281
 
282
282
  # Generate a token by looping and ensuring does not already exist.
@@ -35,8 +35,8 @@ module Devise
35
35
  included do
36
36
  before_create :generate_confirmation_token, :if => :confirmation_required?
37
37
  after_create :send_on_create_confirmation_instructions, :if => :send_confirmation_notification?
38
- before_update :postpone_email_change_until_confirmation, :if => :postpone_email_change?
39
- after_update :send_confirmation_instructions, :if => :reconfirmation_required?
38
+ before_update :postpone_email_change_until_confirmation_and_regenerate_confirmation_token, :if => :postpone_email_change?
39
+ after_update :send_reconfirmation_instructions, :if => :reconfirmation_required?
40
40
  end
41
41
 
42
42
  def initialize(*args, &block)
@@ -90,22 +90,33 @@ module Devise
90
90
 
91
91
  # Send confirmation instructions by email
92
92
  def send_confirmation_instructions
93
- self.confirmation_token = nil if reconfirmation_required?
94
- @reconfirmation_required = false
95
-
96
- generate_confirmation_token! if self.confirmation_token.blank?
93
+ ensure_confirmation_token!
97
94
 
98
95
  opts = pending_reconfirmation? ? { :to => unconfirmed_email } : { }
99
96
  send_devise_notification(:confirmation_instructions, opts)
100
97
  end
101
98
 
102
- # Resend confirmation token. This method does not need to generate a new token.
99
+ def send_reconfirmation_instructions
100
+ @reconfirmation_required = false
101
+
102
+ unless @skip_confirmation_notification
103
+ send_confirmation_instructions
104
+ end
105
+ end
106
+
107
+ # Resend confirmation token.
108
+ # Regenerates the token if the period is expired.
103
109
  def resend_confirmation_token
104
110
  pending_any_confirmation do
105
- self.confirmation_token = nil if confirmation_period_expired?
111
+ regenerate_confirmation_token! if confirmation_period_expired?
106
112
  send_confirmation_instructions
107
113
  end
108
114
  end
115
+
116
+ # Generate a confirmation token unless already exists and save the record.
117
+ def ensure_confirmation_token!
118
+ generate_confirmation_token! if should_generate_confirmation_token?
119
+ end
109
120
 
110
121
  # Overwrites active_for_authentication? for confirmation
111
122
  # by verifying whether a user is active to sign in or not. If the user
@@ -126,7 +137,7 @@ module Devise
126
137
  self.confirmed_at = Time.now.utc
127
138
  end
128
139
 
129
- # Skips sending the confirmation notification email after_create. Unlike
140
+ # Skips sending the confirmation/reconfirmation notification email after_create/after_update. Unlike
130
141
  # #skip_confirmation!, record still requires confirmation.
131
142
  def skip_confirmation_notification!
132
143
  @skip_confirmation_notification = true
@@ -139,6 +150,9 @@ module Devise
139
150
  end
140
151
 
141
152
  protected
153
+ def should_generate_confirmation_token?
154
+ confirmation_token.nil? || confirmation_period_expired?
155
+ end
142
156
 
143
157
  # A callback method used to deliver confirmation
144
158
  # instructions on creation. This can be overriden
@@ -215,29 +229,39 @@ module Devise
215
229
  generate_confirmation_token && save(:validate => false)
216
230
  end
217
231
 
232
+ # Regenerates a new token.
233
+ def regenerate_confirmation_token
234
+ generate_confirmation_token
235
+ end
236
+
237
+ def regenerate_confirmation_token!
238
+ regenerate_confirmation_token && save(:validate => false)
239
+ end
240
+
218
241
  def after_password_reset
219
242
  super
220
243
  confirm! unless confirmed?
221
244
  end
222
245
 
223
- def postpone_email_change_until_confirmation
246
+ def postpone_email_change_until_confirmation_and_regenerate_confirmation_token
224
247
  @reconfirmation_required = true
225
248
  self.unconfirmed_email = self.email
226
249
  self.email = self.email_was
250
+ regenerate_confirmation_token
227
251
  end
228
252
 
229
253
  def postpone_email_change?
230
- postpone = self.class.reconfirmable && email_changed? && !@bypass_postpone
254
+ postpone = self.class.reconfirmable && email_changed? && !@bypass_postpone && !self.email.blank?
231
255
  @bypass_postpone = false
232
256
  postpone
233
257
  end
234
258
 
235
259
  def reconfirmation_required?
236
- self.class.reconfirmable && @reconfirmation_required
260
+ self.class.reconfirmable && @reconfirmation_required && !self.email.blank?
237
261
  end
238
262
 
239
263
  def send_confirmation_notification?
240
- confirmation_required? && !@skip_confirmation_notification
264
+ confirmation_required? && !@skip_confirmation_notification && !self.email.blank?
241
265
  end
242
266
 
243
267
  module ClassMethods
@@ -81,7 +81,7 @@ module Devise
81
81
  #
82
82
  # Example:
83
83
  #
84
- # def update_without_password(params={})
84
+ # def update_without_password(params, *options)
85
85
  # params.delete(:email)
86
86
  # super(params)
87
87
  # end
@@ -55,7 +55,7 @@ module Devise
55
55
 
56
56
  # Verifies whether a user is locked or not.
57
57
  def access_locked?
58
- locked_at && !lock_expired?
58
+ !!locked_at && !lock_expired?
59
59
  end
60
60
 
61
61
  # Send unlock instructions by email
@@ -146,16 +146,16 @@ module Devise
146
146
  if access_locked?
147
147
  yield
148
148
  else
149
- self.errors.add(:email, :not_locked)
149
+ self.errors.add(Devise.unlock_keys.first, :not_locked)
150
150
  false
151
151
  end
152
152
  end
153
153
 
154
154
  module ClassMethods
155
- # Attempt to find a user by its email. If a record is found, send new
155
+ # Attempt to find a user by its unlock keys. If a record is found, send new
156
156
  # unlock instructions to it. If not user is found, returns a new user
157
157
  # with an email not found error.
158
- # Options must contain the user email
158
+ # Options must contain the user's unlock keys
159
159
  def send_unlock_instructions(attributes={})
160
160
  lockable = find_or_initialize_with_errors(unlock_keys, attributes, :not_found)
161
161
  lockable.resend_unlock_token if lockable.persisted?
@@ -44,10 +44,15 @@ module Devise
44
44
 
45
45
  # Resets reset password token and send reset password instructions by email
46
46
  def send_reset_password_instructions
47
- generate_reset_password_token! if should_generate_reset_token?
47
+ ensure_reset_password_token!
48
48
  send_devise_notification(:reset_password_instructions)
49
49
  end
50
-
50
+
51
+ # Generate reset password token unless already exists and save the record.
52
+ def ensure_reset_password_token!
53
+ generate_reset_password_token! if should_generate_reset_token?
54
+ end
55
+
51
56
  # Checks if the reset password token sent is within the limit time.
52
57
  # We do this by calculating if the difference between today and the
53
58
  # sending date does not exceed the confirm in time configured.
@@ -50,7 +50,7 @@ module Devise
50
50
  def remember_me!(extend_period=false)
51
51
  self.remember_token = self.class.remember_token if generate_remember_token?
52
52
  self.remember_created_at = Time.now.utc if generate_remember_timestamp?(extend_period)
53
- save(:validate => false)
53
+ save(:validate => false) if self.changed?
54
54
  end
55
55
 
56
56
  # If the record is persisted, remove the remember token (but only if
@@ -1,5 +1,5 @@
1
1
  module Devise
2
- class ParamFilter
2
+ class ParameterFilter
3
3
  def initialize(case_insensitive_keys, strip_whitespace_keys)
4
4
  @case_insensitive_keys = case_insensitive_keys || []
5
5
  @strip_whitespace_keys = strip_whitespace_keys || []
@@ -40,20 +40,24 @@ module Devise
40
40
  end
41
41
  end
42
42
 
43
+ # These are the params used to sign in a user so we don't need to
44
+ # mass-assign the password param in order to authenticate. Excluding it
45
+ # here allows us to construct a new user without sensitive information if
46
+ # authentication fails.
43
47
  def sign_in
44
- default_params.permit(auth_keys)
48
+ default_params.permit(*auth_keys + [:password, :remember_me])
45
49
  end
46
50
 
47
51
  def sign_up
48
- default_params.permit(auth_keys + [:password, :password_confirmation])
52
+ default_params.permit(*(auth_keys + [:password, :password_confirmation]))
49
53
  end
50
54
 
51
55
  def account_update
52
- default_params.permit(auth_keys + [:password, :password_confirmation, :current_password])
56
+ default_params.permit(*(auth_keys + [:password, :password_confirmation, :current_password]))
53
57
  end
54
58
 
55
59
  def auth_keys
56
- resource_class.authentication_keys
60
+ resource_class.authentication_keys.respond_to?(:keys) ? resource_class.authentication_keys.keys : resource_class.authentication_keys
57
61
  end
58
62
  end
59
63
  end
@@ -1,3 +1,3 @@
1
1
  module Devise
2
- VERSION = "3.0.0.rc".freeze
2
+ VERSION = "3.0.0".freeze
3
3
  end
@@ -21,7 +21,7 @@ Some setup you must do manually if you haven't yet:
21
21
  <p class="notice"><%= notice %></p>
22
22
  <p class="alert"><%= alert %></p>
23
23
 
24
- 4. If you are deploying Rails 3.1+ on Heroku, you may want to set:
24
+ 4. If you are deploying on Heroku with Rails 3.2 only, you may want to set:
25
25
 
26
26
  config.assets.initialize_on_precompile = false
27
27
 
@@ -4,6 +4,20 @@ class SessionsControllerTest < ActionController::TestCase
4
4
  tests Devise::SessionsController
5
5
  include Devise::TestHelpers
6
6
 
7
+ test "#create doesn't raise unpermitted params when sign in fails" do
8
+ ActiveSupport::Notifications.subscribe /unpermitted_parameters/ do |name, start, finish, id, payload|
9
+ flunk "Unpermitted params: #{payload}"
10
+ end
11
+ request.env["devise.mapping"] = Devise.mappings[:user]
12
+ request.session["user_return_to"] = 'foo.bar'
13
+ user = create_user
14
+ post :create, :user => {
15
+ :email => "wrong@email.com",
16
+ :password => "wrongpassword"
17
+ }
18
+ assert_equal 200, @response.status
19
+ end
20
+
7
21
  test "#create works even with scoped views" do
8
22
  swap Devise, :scoped_views => true do
9
23
  request.env["devise.mapping"] = Devise.mappings[:user]
@@ -45,6 +45,16 @@ class SessionTimeoutTest < ActionDispatch::IntegrationTest
45
45
  assert_not warden.authenticated?(:user)
46
46
  end
47
47
 
48
+ test 'time out user session after deault limit time and redirect to latest get request' do
49
+ user = sign_in_as_user
50
+ visit edit_form_user_path(user)
51
+
52
+ click_button 'Update'
53
+ sign_in_as_user
54
+
55
+ assert_equal edit_form_user_url(user), current_url
56
+ end
57
+
48
58
  test 'time out is not triggered on sign out' do
49
59
  user = sign_in_as_user
50
60
  get expire_user_path(user)
@@ -114,6 +114,14 @@ class ConfirmableTest < ActiveSupport::TestCase
114
114
  end
115
115
  end
116
116
 
117
+ test 'should not send confirmation when no email is provided' do
118
+ assert_email_not_sent do
119
+ user = new_user
120
+ user.email = ''
121
+ user.save(:validate => false)
122
+ end
123
+ end
124
+
117
125
  test 'should find a user to send confirmation instructions' do
118
126
  user = create_user
119
127
  confirmation_user = User.send_confirmation_instructions(:email => user.email)
@@ -286,6 +294,24 @@ class ConfirmableTest < ActiveSupport::TestCase
286
294
  assert_not_equal user.confirmation_token, old
287
295
  end
288
296
  end
297
+
298
+ test 'should generate a new token when a valid one does not exist' do
299
+ swap Devise, :confirm_within => 3.days do
300
+ user = create_user
301
+ user.update_attribute(:confirmation_sent_at, 4.days.ago)
302
+ old = user.confirmation_token
303
+ user.ensure_confirmation_token!
304
+ assert_not_equal user.confirmation_token, old
305
+ end
306
+ end
307
+
308
+ test 'should not generate a new token when a valid one exists' do
309
+ user = create_user
310
+ assert_not_nil user.confirmation_token
311
+ old = user.confirmation_token
312
+ user.ensure_confirmation_token!
313
+ assert_equal user.confirmation_token, old
314
+ end
289
315
  end
290
316
 
291
317
  class ReconfirmableTest < ActiveSupport::TestCase
@@ -311,6 +337,15 @@ class ReconfirmableTest < ActiveSupport::TestCase
311
337
  assert_nil admin.confirmation_token
312
338
  end
313
339
 
340
+ test 'should skip sending reconfirmation email when email is changed and skip_confirmation_notification! is invoked' do
341
+ admin = create_admin
342
+ admin.skip_confirmation_notification!
343
+
344
+ assert_email_not_sent do
345
+ admin.update_attributes(:email => 'new_test@example.com')
346
+ end
347
+ end
348
+
314
349
  test 'should regenerate confirmation token after changing email' do
315
350
  admin = create_admin
316
351
  assert admin.confirm!
@@ -337,6 +372,15 @@ class ReconfirmableTest < ActiveSupport::TestCase
337
372
  end
338
373
  end
339
374
 
375
+ test 'should not send confirmation by email after changing to a blank email' do
376
+ admin = create_admin
377
+ assert admin.confirm!
378
+ assert_email_not_sent do
379
+ admin.email = ''
380
+ admin.save(:validate => false)
381
+ end
382
+ end
383
+
340
384
  test 'should stay confirmed when email is changed' do
341
385
  admin = create_admin
342
386
  assert admin.confirm!
@@ -48,19 +48,19 @@ class DatabaseAuthenticatableTest < ActiveSupport::TestCase
48
48
 
49
49
  test "param filter should not convert booleans and integer to strings" do
50
50
  conditions = { "login" => "foo@bar.com", "bool1" => true, "bool2" => false, "fixnum" => 123, "will_be_converted" => (1..10) }
51
- conditions = Devise::ParamFilter.new([], []).filter(conditions)
51
+ conditions = Devise::ParameterFilter.new([], []).filter(conditions)
52
52
  assert_equal( { "login" => "foo@bar.com", "bool1" => "true", "bool2" => "false", "fixnum" => "123", "will_be_converted" => "1..10" }, conditions)
53
53
  end
54
54
 
55
55
  test 'param filter should filter case_insensitive_keys as insensitive' do
56
56
  conditions = {'insensitive' => 'insensitive_VAL', 'sensitive' => 'sensitive_VAL'}
57
- conditions = Devise::ParamFilter.new(['insensitive'], []).filter(conditions)
57
+ conditions = Devise::ParameterFilter.new(['insensitive'], []).filter(conditions)
58
58
  assert_equal( {'insensitive' => 'insensitive_val', 'sensitive' => 'sensitive_VAL'}, conditions )
59
59
  end
60
60
 
61
61
  test 'param filter should filter strip_whitespace_keys stripping whitespaces' do
62
62
  conditions = {'strip_whitespace' => ' strip_whitespace_val ', 'do_not_strip_whitespace' => ' do_not_strip_whitespace_val '}
63
- conditions = Devise::ParamFilter.new([], ['strip_whitespace']).filter(conditions)
63
+ conditions = Devise::ParameterFilter.new([], ['strip_whitespace']).filter(conditions)
64
64
  assert_equal( {'strip_whitespace' => 'strip_whitespace_val', 'do_not_strip_whitespace' => ' do_not_strip_whitespace_val '}, conditions )
65
65
  end
66
66
 
@@ -185,12 +185,12 @@ class LockableTest < ActiveSupport::TestCase
185
185
  end
186
186
 
187
187
  test 'should require all unlock_keys' do
188
- swap Devise, :unlock_keys => [:username, :email] do
189
- user = create_user
190
- unlock_user = User.send_unlock_instructions(:email => user.email)
191
- assert_not unlock_user.persisted?
192
- assert_equal "can't be blank", unlock_user.errors[:username].join
193
- end
188
+ swap Devise, :unlock_keys => [:username, :email] do
189
+ user = create_user
190
+ unlock_user = User.send_unlock_instructions(:email => user.email)
191
+ assert_not unlock_user.persisted?
192
+ assert_equal "can't be blank", unlock_user.errors[:username].join
193
+ end
194
194
  end
195
195
 
196
196
  test 'should not be able to send instructions if the user is not locked' do
@@ -200,6 +200,15 @@ class LockableTest < ActiveSupport::TestCase
200
200
  assert_equal 'was not locked', user.errors[:email].join
201
201
  end
202
202
 
203
+ test 'should not be able to send instructions if the user if not locked and have username as unlock key' do
204
+ swap Devise, :unlock_keys => [:username] do
205
+ user = create_user
206
+ assert_not user.resend_unlock_token
207
+ assert_not user.access_locked?
208
+ assert_equal 'was not locked', user.errors[:username].join
209
+ end
210
+ end
211
+
203
212
  test 'should unlock account if lock has expired and increase attempts on failure' do
204
213
  swap Devise, :unlock_in => 1.minute do
205
214
  user = create_user
@@ -110,7 +110,7 @@ class RecoverableTest < ActiveSupport::TestCase
110
110
 
111
111
  test 'should find a user to reset his password based on reset_password_token' do
112
112
  user = create_user
113
- user.send :generate_reset_password_token!
113
+ user.ensure_reset_password_token!
114
114
 
115
115
  reset_password_user = User.reset_password_by_token(:reset_password_token => user.reset_password_token)
116
116
  assert_equal reset_password_user, user
@@ -130,7 +130,7 @@ class RecoverableTest < ActiveSupport::TestCase
130
130
 
131
131
  test 'should return a new record with errors if password is blank' do
132
132
  user = create_user
133
- user.send :generate_reset_password_token!
133
+ user.ensure_reset_password_token!
134
134
 
135
135
  reset_password_user = User.reset_password_by_token(:reset_password_token => user.reset_password_token, :password => '')
136
136
  assert_not reset_password_user.errors.empty?
@@ -140,7 +140,7 @@ class RecoverableTest < ActiveSupport::TestCase
140
140
  test 'should reset successfully user password given the new password and confirmation' do
141
141
  user = create_user
142
142
  old_password = user.password
143
- user.send :generate_reset_password_token!
143
+ user.ensure_reset_password_token!
144
144
 
145
145
  User.reset_password_by_token(
146
146
  :reset_password_token => user.reset_password_token,
@@ -179,7 +179,7 @@ class RecoverableTest < ActiveSupport::TestCase
179
179
  swap Devise, :reset_password_within => 1.hour do
180
180
  user = create_user
181
181
  old_password = user.password
182
- user.send :generate_reset_password_token!
182
+ user.ensure_reset_password_token!
183
183
  user.reset_password_sent_at = 2.days.ago
184
184
  user.save!
185
185
 
@@ -202,4 +202,21 @@ class RecoverableTest < ActiveSupport::TestCase
202
202
  :reset_password_token
203
203
  ]
204
204
  end
205
+
206
+ test 'should generate a new token when a valid one does not exist' do
207
+ user = create_user
208
+ assert_nil user.reset_password_token
209
+
210
+ user.ensure_reset_password_token!
211
+ assert_not_nil user.reset_password_token
212
+ end
213
+
214
+ test 'should not generate a new token when a valid one exists' do
215
+ user = create_user
216
+ user.send :generate_reset_password_token!
217
+ assert_not_nil user.reset_password_token
218
+ old = user.reset_password_token
219
+ user.ensure_reset_password_token!
220
+ assert_equal user.reset_password_token, old
221
+ end
205
222
  end
@@ -21,8 +21,15 @@ if defined?(ActionController::StrongParameters)
21
21
  end
22
22
 
23
23
  test 'filters some parameters on sign in by default' do
24
- sanitizer = sanitizer(user: { "email" => "jose", "password" => "invalid" })
25
- assert_equal({ "email" => "jose" }, sanitizer.for(:sign_in))
24
+ sanitizer = sanitizer(user: { "email" => "jose", "password" => "invalid", "remember_me" => "1" })
25
+ assert_equal({ "email" => "jose", "password" => "invalid", "remember_me" => "1" }, sanitizer.for(:sign_in))
26
+ end
27
+
28
+ test 'handles auth keys as a hash' do
29
+ swap Devise, :authentication_keys => {:email => true} do
30
+ sanitizer = sanitizer(user: { "email" => "jose", "password" => "invalid" })
31
+ assert_equal({ "email" => "jose", "password" => "invalid" }, sanitizer.for(:sign_in))
32
+ end
26
33
  end
27
34
 
28
35
  test 'filters some parameters on sign up by default' do
@@ -8,6 +8,14 @@ class UsersController < ApplicationController
8
8
  respond_with(current_user)
9
9
  end
10
10
 
11
+ def edit_form
12
+ user_session['last_request_at'] = 31.minutes.ago.utc
13
+ end
14
+
15
+ def update_form
16
+ render :text => 'Update'
17
+ end
18
+
11
19
  def accept
12
20
  @current_user = current_user
13
21
  end
@@ -0,0 +1 @@
1
+ <%= button_to 'Update', update_form_user_path(current_user), method: 'put' %>
@@ -1,8 +1,12 @@
1
1
  Rails.application.routes.draw do
2
2
  # Resources for testing
3
3
  resources :users, :only => [:index] do
4
- get :expire, :on => :member
5
- get :accept, :on => :member
4
+ member do
5
+ get :expire
6
+ get :accept
7
+ get :edit_form
8
+ put :update_form
9
+ end
6
10
 
7
11
  authenticate do
8
12
  post :exhibit, :on => :member
@@ -63,7 +63,7 @@ class ActiveSupport::TestCase
63
63
  def clear_cached_variables(options)
64
64
  if options.key?(:case_insensitive_keys) || options.key?(:strip_whitespace_keys)
65
65
  Devise.mappings.each do |_, mapping|
66
- mapping.to.instance_variable_set(:@devise_param_filter, nil)
66
+ mapping.to.instance_variable_set(:@devise_parameter_filter, nil)
67
67
  end
68
68
  end
69
69
  end
metadata CHANGED
@@ -1,7 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: devise
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0.rc
4
+ prerelease:
5
+ version: 3.0.0
5
6
  platform: ruby
6
7
  authors:
7
8
  - José Valim
@@ -9,70 +10,78 @@ authors:
9
10
  autorequire:
10
11
  bindir: bin
11
12
  cert_chain: []
12
- date: 2013-05-07 00:00:00.000000000 Z
13
+ date: 2013-07-14 00:00:00.000000000 Z
13
14
  dependencies:
14
15
  - !ruby/object:Gem::Dependency
15
- name: warden
16
- requirement: !ruby/object:Gem::Requirement
16
+ version_requirements: !ruby/object:Gem::Requirement
17
17
  requirements:
18
18
  - - ~>
19
19
  - !ruby/object:Gem::Version
20
- version: 1.2.1
20
+ version: 1.2.3
21
+ none: false
22
+ name: warden
21
23
  type: :runtime
22
24
  prerelease: false
23
- version_requirements: !ruby/object:Gem::Requirement
25
+ requirement: !ruby/object:Gem::Requirement
24
26
  requirements:
25
27
  - - ~>
26
28
  - !ruby/object:Gem::Version
27
- version: 1.2.1
29
+ version: 1.2.3
30
+ none: false
28
31
  - !ruby/object:Gem::Dependency
29
- name: orm_adapter
30
- requirement: !ruby/object:Gem::Requirement
32
+ version_requirements: !ruby/object:Gem::Requirement
31
33
  requirements:
32
34
  - - ~>
33
35
  - !ruby/object:Gem::Version
34
36
  version: '0.1'
37
+ none: false
38
+ name: orm_adapter
35
39
  type: :runtime
36
40
  prerelease: false
37
- version_requirements: !ruby/object:Gem::Requirement
41
+ requirement: !ruby/object:Gem::Requirement
38
42
  requirements:
39
43
  - - ~>
40
44
  - !ruby/object:Gem::Version
41
45
  version: '0.1'
46
+ none: false
42
47
  - !ruby/object:Gem::Dependency
43
- name: bcrypt-ruby
44
- requirement: !ruby/object:Gem::Requirement
48
+ version_requirements: !ruby/object:Gem::Requirement
45
49
  requirements:
46
50
  - - ~>
47
51
  - !ruby/object:Gem::Version
48
52
  version: '3.0'
53
+ none: false
54
+ name: bcrypt-ruby
49
55
  type: :runtime
50
56
  prerelease: false
51
- version_requirements: !ruby/object:Gem::Requirement
57
+ requirement: !ruby/object:Gem::Requirement
52
58
  requirements:
53
59
  - - ~>
54
60
  - !ruby/object:Gem::Version
55
61
  version: '3.0'
62
+ none: false
56
63
  - !ruby/object:Gem::Dependency
57
- name: railties
58
- requirement: !ruby/object:Gem::Requirement
64
+ version_requirements: !ruby/object:Gem::Requirement
59
65
  requirements:
60
- - - '>='
66
+ - - ! '>='
61
67
  - !ruby/object:Gem::Version
62
68
  version: 3.2.6
63
69
  - - <
64
70
  - !ruby/object:Gem::Version
65
71
  version: '5'
72
+ none: false
73
+ name: railties
66
74
  type: :runtime
67
75
  prerelease: false
68
- version_requirements: !ruby/object:Gem::Requirement
76
+ requirement: !ruby/object:Gem::Requirement
69
77
  requirements:
70
- - - '>='
78
+ - - ! '>='
71
79
  - !ruby/object:Gem::Version
72
80
  version: 3.2.6
73
81
  - - <
74
82
  - !ruby/object:Gem::Version
75
83
  version: '5'
84
+ none: false
76
85
  description: Flexible authentication solution for Rails with Warden
77
86
  email: contact@plataformatec.com.br
78
87
  executables: []
@@ -149,7 +158,7 @@ files:
149
158
  - lib/devise/omniauth/url_helpers.rb
150
159
  - lib/devise/orm/active_record.rb
151
160
  - lib/devise/orm/mongoid.rb
152
- - lib/devise/param_filter.rb
161
+ - lib/devise/parameter_filter.rb
153
162
  - lib/devise/parameter_sanitizer.rb
154
163
  - lib/devise/rails.rb
155
164
  - lib/devise/rails/routes.rb
@@ -257,6 +266,7 @@ files:
257
266
  - test/rails_app/app/views/home/private.html.erb
258
267
  - test/rails_app/app/views/home/user_dashboard.html.erb
259
268
  - test/rails_app/app/views/layouts/application.html.erb
269
+ - test/rails_app/app/views/users/edit_form.html.erb
260
270
  - test/rails_app/app/views/users/index.html.erb
261
271
  - test/rails_app/app/views/users/mailer/confirmation_instructions.erb
262
272
  - test/rails_app/app/views/users/sessions/new.html.erb
@@ -297,26 +307,27 @@ files:
297
307
  homepage: http://github.com/plataformatec/devise
298
308
  licenses:
299
309
  - MIT
300
- metadata: {}
301
310
  post_install_message:
302
311
  rdoc_options: []
303
312
  require_paths:
304
313
  - lib
305
314
  required_ruby_version: !ruby/object:Gem::Requirement
306
315
  requirements:
307
- - - '>='
316
+ - - ! '>='
308
317
  - !ruby/object:Gem::Version
309
318
  version: '0'
319
+ none: false
310
320
  required_rubygems_version: !ruby/object:Gem::Requirement
311
321
  requirements:
312
- - - '>'
322
+ - - ! '>='
313
323
  - !ruby/object:Gem::Version
314
- version: 1.3.1
324
+ version: '0'
325
+ none: false
315
326
  requirements: []
316
327
  rubyforge_project: devise
317
- rubygems_version: 2.0.3
328
+ rubygems_version: 1.8.23
318
329
  signing_key:
319
- specification_version: 4
330
+ specification_version: 3
320
331
  summary: Flexible authentication solution for Rails with Warden
321
332
  test_files:
322
333
  - test/controllers/custom_strategy_test.rb
@@ -394,6 +405,7 @@ test_files:
394
405
  - test/rails_app/app/views/home/private.html.erb
395
406
  - test/rails_app/app/views/home/user_dashboard.html.erb
396
407
  - test/rails_app/app/views/layouts/application.html.erb
408
+ - test/rails_app/app/views/users/edit_form.html.erb
397
409
  - test/rails_app/app/views/users/index.html.erb
398
410
  - test/rails_app/app/views/users/mailer/confirmation_instructions.erb
399
411
  - test/rails_app/app/views/users/sessions/new.html.erb
@@ -431,3 +443,4 @@ test_files:
431
443
  - test/test_helper.rb
432
444
  - test/test_helpers_test.rb
433
445
  - test/test_models.rb
446
+ has_rdoc:
checksums.yaml DELETED
@@ -1,7 +0,0 @@
1
- ---
2
- SHA1:
3
- metadata.gz: 24879e2076bf59ff1858c4127a2160531fc36db0
4
- data.tar.gz: a2999767bbfb525a1c54dc89b28123cf0b1754a2
5
- SHA512:
6
- metadata.gz: 67c36076ebacd8fa889c34ad979d64f1559f88fda310c9ed485bc6b8cf9c8028249784042fa1cce4685050f2d8ae00fac648bc93272a9ae0aa2a5b37e589fd23
7
- data.tar.gz: 34a6913c9ab6c546e8867d53b5573d606bf895cf194fe107375dc61dd5597635dd434bd92cb0095dfe51fd183b0f2310ee060b7eb6a27bb46bf3612522963f5a