devise 1.2.1 → 1.3.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.

Files changed (45) hide show
  1. data/.travis.yml +7 -1
  2. data/CHANGELOG.rdoc +21 -1
  3. data/Gemfile.lock +1 -1
  4. data/README.rdoc +4 -5
  5. data/app/controllers/devise/confirmations_controller.rb +14 -6
  6. data/app/controllers/devise/passwords_controller.rb +7 -6
  7. data/app/controllers/devise/registrations_controller.rb +12 -10
  8. data/app/controllers/devise/sessions_controller.rb +23 -1
  9. data/app/controllers/devise/unlocks_controller.rb +7 -6
  10. data/config/locales/en.yml +1 -0
  11. data/lib/devise.rb +7 -8
  12. data/lib/devise/controllers/helpers.rb +0 -6
  13. data/lib/devise/controllers/internal_helpers.rb +38 -2
  14. data/lib/devise/failure_app.rb +4 -10
  15. data/lib/devise/models.rb +27 -4
  16. data/lib/devise/models/authenticatable.rb +1 -13
  17. data/lib/devise/models/confirmable.rb +1 -1
  18. data/lib/devise/models/database_authenticatable.rb +2 -1
  19. data/lib/devise/models/recoverable.rb +41 -5
  20. data/lib/devise/models/validatable.rb +2 -3
  21. data/lib/devise/omniauth.rb +3 -3
  22. data/lib/devise/rails.rb +8 -25
  23. data/lib/devise/rails/routes.rb +8 -0
  24. data/lib/devise/rails/warden_compat.rb +2 -2
  25. data/lib/devise/schema.rb +8 -3
  26. data/lib/devise/strategies/authenticatable.rb +2 -1
  27. data/lib/devise/version.rb +1 -1
  28. data/lib/generators/devise/views_generator.rb +3 -9
  29. data/lib/generators/templates/devise.rb +11 -2
  30. data/test/controllers/internal_helpers_test.rb +15 -0
  31. data/test/controllers/sessions_controller_test.rb +17 -0
  32. data/test/devise_test.rb +0 -3
  33. data/test/integration/authenticatable_test.rb +27 -7
  34. data/test/integration/confirmable_test.rb +28 -0
  35. data/test/integration/lockable_test.rb +35 -1
  36. data/test/integration/recoverable_test.rb +37 -0
  37. data/test/integration/registerable_test.rb +45 -0
  38. data/test/models/database_authenticatable_test.rb +20 -2
  39. data/test/models/recoverable_test.rb +44 -9
  40. data/test/models/validatable_test.rb +3 -3
  41. data/test/models_test.rb +23 -0
  42. data/test/rails_app/config/initializers/devise.rb +7 -2
  43. data/test/rails_app/config/routes.rb +2 -0
  44. data/test/routes_test.rb +7 -0
  45. metadata +7 -5
@@ -1 +1,7 @@
1
- script: "rake test"
1
+ script: "rake test"
2
+ rvm:
3
+ - 1.8.7
4
+ - 1.9.2
5
+ - ree
6
+ - rbx
7
+ - jruby
@@ -1,7 +1,27 @@
1
+ == 1.3.0
2
+
3
+ * enhancements
4
+ * All controllers can now handle different mime types than html using Responders (by github.com/sikachu)
5
+ * Added reset_password_within as configuration option to send the token for recovery (by github.com/jdguyot)
6
+ * Bump password length to 128 characters (by github.com/k33l0r)
7
+ * Add :only as option to devise_for (by github.com/timoschilling)
8
+ * Allow to override path after sending password instructions (by github.com/irohiroki)
9
+ * require_no_authentication has its own flash message (by github.com/jackdempsey)
10
+
11
+ * bug fix
12
+ * Fix a bug where configuration options were being included too late
13
+ * Ensure Devise::TestHelpers can be used to tests Devise internal controllers (by github.com/jwilger)
14
+ * valid_password? should not choke on empty passwords (by github.com/mikel)
15
+ * Calling devise more than once does not include previously added modules anymore
16
+ * downcase_keys before validation
17
+
18
+ * backward incompatible changes
19
+ * authentication_keys are no longer considered when creating the e-mail validations, the previous behavior was buggy. You must double check if you were relying on such behavior.
20
+
1
21
  == 1.2.1
2
22
 
3
23
  * enhancements
4
- * better upgrade steps
24
+ * Improve update path messages
5
25
 
6
26
  == 1.2.0
7
27
 
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- devise (1.2.0)
4
+ devise (1.3.0.dev)
5
5
  bcrypt-ruby (~> 2.1.2)
6
6
  orm_adapter (~> 0.0.3)
7
7
  warden (~> 1.0.3)
@@ -152,7 +152,7 @@ You can access the session for this scope:
152
152
 
153
153
  After signing in a user, confirming the account or updating the password, Devise will look for a scoped root path to redirect. Example: For a :user resource, it will use user_root_path if it exists, otherwise default root_path will be used. This means that you need to set the root inside your routes:
154
154
 
155
- root :to => "home"
155
+ root :to => "home#index"
156
156
 
157
157
  You can also overwrite after_sign_in_path_for and after_sign_out_path_for to customize your redirect hooks.
158
158
 
@@ -315,12 +315,11 @@ If you're using RSpec and want the helpers automatically included within all +de
315
315
 
316
316
  Do not use such helpers for integration tests such as Cucumber or Webrat. Instead, fill in the form or explicitly set the user in session. For more tips, check the wiki (http://wiki.github.com/plataformatec/devise).
317
317
 
318
- === OAuth2
318
+ === Omniauth
319
319
 
320
- Devise comes with OAuth support out of the box if you're using Devise from the git repository (for now). You can read more about OAuth2 support in the wiki:
320
+ Devise comes with Omniauth support out of the box to authenticate from other providers. You can read more about Omniauth support in the wiki:
321
321
 
322
- * http://github.com/plataformatec/devise/wiki/OAuth2:-Overview
323
- * http://github.com/plataformatec/devise/wiki/OAuth2:-Testing
322
+ * https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview
324
323
 
325
324
  === Other ORMs
326
325
 
@@ -12,10 +12,10 @@ class Devise::ConfirmationsController < ApplicationController
12
12
  self.resource = resource_class.send_confirmation_instructions(params[resource_name])
13
13
 
14
14
  if resource.errors.empty?
15
- set_flash_message :notice, :send_instructions
16
- redirect_to new_session_path(resource_name)
15
+ set_flash_message(:notice, :send_instructions) if is_navigational_format?
16
+ respond_with resource, :location => after_resending_confirmation_instructions_path_for(resource_name)
17
17
  else
18
- render_with_scope :new
18
+ respond_with_navigational(resource){ render_with_scope :new }
19
19
  end
20
20
  end
21
21
 
@@ -24,10 +24,18 @@ class Devise::ConfirmationsController < ApplicationController
24
24
  self.resource = resource_class.confirm_by_token(params[:confirmation_token])
25
25
 
26
26
  if resource.errors.empty?
27
- set_flash_message :notice, :confirmed
28
- sign_in_and_redirect(resource_name, resource)
27
+ set_flash_message(:notice, :confirmed) if is_navigational_format?
28
+ sign_in(resource_name, resource)
29
+ respond_with_navigational(resource){ redirect_to redirect_location(resource_name, resource) }
29
30
  else
30
- render_with_scope :new
31
+ respond_with_navigational(resource.errors, :status => :unprocessable_entity){ render_with_scope :new }
31
32
  end
32
33
  end
34
+
35
+ protected
36
+
37
+ # The path used after resending confirmation instructions.
38
+ def after_resending_confirmation_instructions_path_for(resource_name)
39
+ new_session_path(resource_name)
40
+ end
33
41
  end
@@ -13,10 +13,10 @@ class Devise::PasswordsController < ApplicationController
13
13
  self.resource = resource_class.send_reset_password_instructions(params[resource_name])
14
14
 
15
15
  if resource.errors.empty?
16
- set_flash_message :notice, :send_instructions
17
- redirect_to new_session_path(resource_name)
16
+ set_flash_message(:notice, :send_instructions) if is_navigational_format?
17
+ respond_with resource, :location => new_session_path(resource_name)
18
18
  else
19
- render_with_scope :new
19
+ respond_with_navigational(resource){ render_with_scope :new }
20
20
  end
21
21
  end
22
22
 
@@ -32,10 +32,11 @@ class Devise::PasswordsController < ApplicationController
32
32
  self.resource = resource_class.reset_password_by_token(params[resource_name])
33
33
 
34
34
  if resource.errors.empty?
35
- set_flash_message :notice, :updated
36
- sign_in_and_redirect(resource_name, resource)
35
+ set_flash_message(:notice, :updated) if is_navigational_format?
36
+ sign_in(resource_name, resource)
37
+ respond_with resource, :location => redirect_location(resource_name, resource)
37
38
  else
38
- render_with_scope :edit
39
+ respond_with_navigational(resource){ render_with_scope :edit }
39
40
  end
40
41
  end
41
42
  end
@@ -15,16 +15,17 @@ class Devise::RegistrationsController < ApplicationController
15
15
 
16
16
  if resource.save
17
17
  if resource.active_for_authentication?
18
- set_flash_message :notice, :signed_up
19
- sign_in_and_redirect(resource_name, resource)
18
+ set_flash_message :notice, :signed_up if is_navigational_format?
19
+ sign_in(resource_name, resource)
20
+ respond_with resource, :location => redirect_location(resource_name, resource)
20
21
  else
21
- set_flash_message :notice, :inactive_signed_up, :reason => resource.inactive_message.to_s
22
+ set_flash_message :notice, :inactive_signed_up, :reason => resource.inactive_message.to_s if is_navigational_format?
22
23
  expire_session_data_after_sign_in!
23
- redirect_to after_inactive_sign_up_path_for(resource)
24
+ respond_with resource, :location => after_inactive_sign_up_path_for(resource)
24
25
  end
25
26
  else
26
27
  clean_up_passwords(resource)
27
- render_with_scope :new
28
+ respond_with_navigational(resource) { render_with_scope :new }
28
29
  end
29
30
  end
30
31
 
@@ -36,20 +37,21 @@ class Devise::RegistrationsController < ApplicationController
36
37
  # PUT /resource
37
38
  def update
38
39
  if resource.update_with_password(params[resource_name])
39
- set_flash_message :notice, :updated
40
+ set_flash_message :notice, :updated if is_navigational_format?
40
41
  sign_in resource_name, resource, :bypass => true
41
- redirect_to after_update_path_for(resource)
42
+ respond_with resource, :location => after_update_path_for(resource)
42
43
  else
43
44
  clean_up_passwords(resource)
44
- render_with_scope :edit
45
+ respond_with_navigational(resource){ render_with_scope :edit }
45
46
  end
46
47
  end
47
48
 
48
49
  # DELETE /resource
49
50
  def destroy
50
51
  resource.destroy
51
- sign_out_and_redirect(self.resource)
52
- set_flash_message :notice, :destroyed
52
+ Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name)
53
+ set_flash_message :notice, :destroyed if is_navigational_format?
54
+ respond_with_navigational(resource){ redirect_to after_sign_out_path_for(resource_name) }
53
55
  end
54
56
 
55
57
  # GET /resource/cancel
@@ -11,6 +11,17 @@ class Devise::SessionsController < ApplicationController
11
11
  # POST /resource/sign_in
12
12
  def create
13
13
  resource = warden.authenticate!(:scope => resource_name, :recall => "#{controller_path}#new")
14
+
15
+ # In the running app, the previous line would actually cause this method to
16
+ # exit by throwing `:warden` if the authentication failed. Unfortunately,
17
+ # this doesn't happen in the Rails test environment if you have included the
18
+ # Devise::TestHelpers (see `Devise::TestHelpers::TestWarden#authenticate!`),
19
+ # which makes it difficult to unit test extensions to this controller. Since
20
+ # the resource is nil if authentication fails, just short-circuit the method
21
+ # in that case. This should not affect the running app.
22
+
23
+ return if resource.nil?
24
+
14
25
  set_flash_message(:notice, :signed_in) if is_navigational_format?
15
26
  sign_in(resource_name, resource)
16
27
  respond_with resource, :location => redirect_location(resource_name, resource)
@@ -19,7 +30,18 @@ class Devise::SessionsController < ApplicationController
19
30
  # GET /resource/sign_out
20
31
  def destroy
21
32
  signed_in = signed_in?(resource_name)
22
- sign_out_and_redirect(resource_name)
33
+ Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name)
23
34
  set_flash_message :notice, :signed_out if signed_in
35
+
36
+ # We actually need to hardcode this, as Rails default responder doesn't
37
+ # support returning empty response on GET request
38
+ respond_to do |format|
39
+ format.any(*navigational_formats) { redirect_to after_sign_out_path_for(resource_name) }
40
+ format.all do
41
+ method = "to_#{request_format}"
42
+ text = {}.respond_to?(method) ? {}.send(method) : ""
43
+ render :text => text, :status => :ok
44
+ end
45
+ end
24
46
  end
25
47
  end
@@ -13,10 +13,10 @@ class Devise::UnlocksController < ApplicationController
13
13
  self.resource = resource_class.send_unlock_instructions(params[resource_name])
14
14
 
15
15
  if resource.errors.empty?
16
- set_flash_message :notice, :send_instructions
17
- redirect_to new_session_path(resource_name)
16
+ set_flash_message :notice, :send_instructions if is_navigational_format?
17
+ respond_with resource, :location => new_session_path(resource_name)
18
18
  else
19
- render_with_scope :new
19
+ respond_with_navigational(resource){ render_with_scope :new }
20
20
  end
21
21
  end
22
22
 
@@ -25,10 +25,11 @@ class Devise::UnlocksController < ApplicationController
25
25
  self.resource = resource_class.unlock_access_by_token(params[:unlock_token])
26
26
 
27
27
  if resource.errors.empty?
28
- set_flash_message :notice, :unlocked
29
- sign_in_and_redirect(resource_name, resource)
28
+ set_flash_message :notice, :unlocked if is_navigational_format?
29
+ sign_in(resource_name, resource)
30
+ respond_with_navigational(resource){ redirect_to redirect_location(resource_name, resource) }
30
31
  else
31
- render_with_scope :new
32
+ respond_with_navigational(resource.errors, :status => :unprocessable_entity){ render_with_scope :new }
32
33
  end
33
34
  end
34
35
  end
@@ -12,6 +12,7 @@ en:
12
12
 
13
13
  devise:
14
14
  failure:
15
+ already_authenticated: 'You are already signed in.'
15
16
  unauthenticated: 'You need to sign in or sign up before continuing.'
16
17
  unconfirmed: 'You have to confirm your account before continuing.'
17
18
  locked: 'Your account is locked.'
@@ -96,7 +96,7 @@ module Devise
96
96
 
97
97
  # Range validation for password length
98
98
  mattr_accessor :password_length
99
- @@password_length = 6..20
99
+ @@password_length = 6..128
100
100
 
101
101
  # The time the user will be remembered without asking for credentials again.
102
102
  mattr_accessor :remember_for
@@ -171,6 +171,10 @@ module Devise
171
171
  mattr_accessor :reset_password_keys
172
172
  @@reset_password_keys = [ :email ]
173
173
 
174
+ # Time interval you can reset your password with a reset password key
175
+ mattr_accessor :reset_password_within
176
+ @@reset_password_within = nil
177
+
174
178
  # The default scope which is used by warden.
175
179
  mattr_accessor :default_scope
176
180
  @@default_scope = nil
@@ -238,12 +242,6 @@ module Devise
238
242
  omniauth_configs.keys
239
243
  end
240
244
 
241
- def self.cookie_domain=(value)
242
- ActiveSupport::Deprecation.warn "Devise.cookie_domain=(value) is deprecated. "
243
- "Please use Devise.cookie_options = { :domain => value } instead."
244
- self.cookie_options[:domain] = value
245
- end
246
-
247
245
  # Get the mailer class from the mailer reference object.
248
246
  def self.mailer
249
247
  if defined?(ActiveSupport::Dependencies::ClassCache)
@@ -319,7 +317,8 @@ module Devise
319
317
 
320
318
  if options[:model]
321
319
  path = (options[:model] == true ? "devise/models/#{module_name}" : options[:model])
322
- Devise::Models.send(:autoload, module_name.to_s.camelize.to_sym, path)
320
+ camelized = ActiveSupport::Inflector.camelize(module_name.to_s)
321
+ Devise::Models.send(:autoload, camelized.to_sym, path)
323
322
  end
324
323
 
325
324
  Devise::Mapping.add_module module_name
@@ -80,12 +80,6 @@ module Devise
80
80
  end
81
81
  end
82
82
 
83
- def anybody_signed_in?
84
- ActiveSupport::Deprecation.warn "Devise#anybody_signed_in? is deprecated. "
85
- "Please use Devise#signed_in?(nil) instead."
86
- signed_in?
87
- end
88
-
89
83
  # Sign in a user that already was authenticated. This helper is useful for logging
90
84
  # users in after sign up.
91
85
  #
@@ -7,6 +7,19 @@ module Devise
7
7
  extend ActiveSupport::Concern
8
8
  include Devise::Controllers::ScopedViews
9
9
 
10
+ MIME_REFERENCES = Mime::HTML.respond_to?(:ref)
11
+
12
+ # Helper used by FailureApp and Devise controllers to retrieve proper formats.
13
+ def self.request_format(request)
14
+ if request.format.respond_to?(:ref)
15
+ request.format.ref
16
+ elsif MIME_REFERENCES
17
+ request.format
18
+ elsif request.format # Rails < 3.0.4
19
+ request.format.to_sym
20
+ end
21
+ end
22
+
10
23
  included do
11
24
  helper DeviseHelper
12
25
 
@@ -52,14 +65,30 @@ module Devise
52
65
 
53
66
  protected
54
67
 
68
+ def request_format
69
+ @request_format ||= Devise::Controllers::InternalHelpers.request_format(request)
70
+ end
71
+
55
72
  # Checks whether it's a devise mapped resource or not.
56
73
  def is_devise_resource? #:nodoc:
57
- unknown_action!("Could not find devise mapping for path #{request.fullpath.inspect}") unless devise_mapping
74
+ unknown_action! <<-MESSAGE unless devise_mapping
75
+ Could not find devise mapping for path #{request.fullpath.inspect}.
76
+ Maybe you forgot to wrap your route inside the scope block? For example:
77
+
78
+ devise_scope :user do
79
+ match "/some/route" => "some_devise_controller"
80
+ end
81
+ MESSAGE
58
82
  end
59
83
 
60
84
  # Check whether it's navigational format, such as :html or :iphone, or not.
61
85
  def is_navigational_format?
62
- Devise.navigational_formats.include?(request.format.to_sym)
86
+ Devise.navigational_formats.include?(request_format)
87
+ end
88
+
89
+ # Returns real navigational formats which are supported by Rails
90
+ def navigational_formats
91
+ @navigational_formats ||= Devise.navigational_formats.select{ |format| Mime::EXTENSION_LOOKUP[format.to_s] }
63
92
  end
64
93
 
65
94
  def unknown_action!(msg)
@@ -85,6 +114,7 @@ module Devise
85
114
  def require_no_authentication
86
115
  if warden.authenticated?(resource_name)
87
116
  resource = warden.user(resource_name)
117
+ flash[:alert] = I18n.t("devise.failure.already_authenticated")
88
118
  redirect_to after_sign_in_path_for(resource)
89
119
  end
90
120
  end
@@ -114,6 +144,12 @@ module Devise
114
144
  def clean_up_passwords(object) #:nodoc:
115
145
  object.clean_up_passwords if object.respond_to?(:clean_up_passwords)
116
146
  end
147
+
148
+ def respond_with_navigational(*args, &block)
149
+ respond_with(*args) do |format|
150
+ format.any(*navigational_formats, &block)
151
+ end
152
+ end
117
153
  end
118
154
  end
119
155
  end
@@ -101,7 +101,9 @@ module Devise
101
101
 
102
102
  def recall_app(app)
103
103
  controller, action = app.split("#")
104
- "#{controller.camelize}Controller".constantize.action(action)
104
+ controller_name = ActiveSupport::Inflector.camelize(controller)
105
+ controller_klass = ActiveSupport::Inflector.constantize("#{controller_name}Controller")
106
+ controller_klass.action(action)
105
107
  end
106
108
 
107
109
  def warden
@@ -128,16 +130,8 @@ module Devise
128
130
  session["#{scope}_return_to"] = attempted_path if request.get? && !http_auth?
129
131
  end
130
132
 
131
- MIME_REFERENCES = Mime::HTML.respond_to?(:ref)
132
-
133
133
  def request_format
134
- @request_format ||= if request.format.respond_to?(:ref)
135
- request.format.ref
136
- elsif MIME_REFERENCES
137
- request.format
138
- else # Rails < 3.0.4
139
- request.format.to_sym
140
- end
134
+ @request_format ||= Devise::Controllers::InternalHelpers.request_format(request)
141
135
  end
142
136
  end
143
137
  end
@@ -17,6 +17,9 @@ module Devise
17
17
  # inside the given class.
18
18
  #
19
19
  def self.config(mod, *accessors) #:nodoc:
20
+ (class << mod; self; end).send :attr_accessor, :available_configs
21
+ mod.available_configs = accessors
22
+
20
23
  accessors.each do |accessor|
21
24
  mod.class_eval <<-METHOD, __FILE__, __LINE__ + 1
22
25
  def #{accessor}
@@ -46,13 +49,33 @@ module Devise
46
49
  #
47
50
  def devise(*modules)
48
51
  include Devise::Models::Authenticatable
49
- options = modules.extract_options!
50
- self.devise_modules += modules.map(&:to_sym).uniq.sort_by { |s|
52
+ options = modules.extract_options!.dup
53
+
54
+ selected_modules = modules.map(&:to_sym).uniq.sort_by do |s|
51
55
  Devise::ALL.index(s) || -1 # follow Devise::ALL order
52
- }
56
+ end
53
57
 
54
58
  devise_modules_hook! do
55
- devise_modules.each { |m| include Devise::Models.const_get(m.to_s.classify) }
59
+ selected_modules.each do |m|
60
+ mod = Devise::Models.const_get(m.to_s.classify)
61
+
62
+ if mod.const_defined?("ClassMethods")
63
+ class_mod = mod.const_get("ClassMethods")
64
+ extend class_mod
65
+
66
+ if class_mod.respond_to?(:available_configs)
67
+ available_configs = class_mod.available_configs
68
+ available_configs.each do |config|
69
+ next unless options.key?(config)
70
+ send(:"#{config}=", options.delete(config))
71
+ end
72
+ end
73
+ end
74
+
75
+ include mod
76
+ end
77
+
78
+ self.devise_modules |= selected_modules
56
79
  options.each { |key, value| send(:"#{key}=", value) }
57
80
  end
58
81
  end